| ... | ... | @@ -450,10 +450,22 @@ pub const Object = struct { |
| 450 | 450 | DeclGen.removeFnAttr(llvm_func, "cold"); |
| 451 | 451 | } |
| 452 | 452 | |
| 453 | // Remove all the basic blocks of a function in order to start over, generating |
| 454 | // LLVM IR from an empty function body. |
| 455 | while (llvm_func.getFirstBasicBlock()) |bb| { |
| 456 | bb.deleteBasicBlock(); |
| 457 | } |
| 458 | |
| 459 | const builder = dg.context.createBuilder(); |
| 460 | |
| 461 | const entry_block = dg.context.appendBasicBlock(llvm_func, "Entry"); |
| 462 | builder.positionBuilderAtEnd(entry_block); |
| 463 | |
| 453 | 464 | // This gets the LLVM values from the function and stores them in `dg.args`. |
| 454 | 465 | const fn_info = decl.ty.fnInfo(); |
| 455 | | const ret_ty_by_ref = isByRef(fn_info.return_type); |
| 456 | | const ret_ptr = if (ret_ty_by_ref) llvm_func.getParam(0) else null; |
| 466 | const target = dg.module.getTarget(); |
| 467 | const sret = firstParamSRet(fn_info, target); |
| 468 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; |
| 457 | 469 | |
| 458 | 470 | var args = std.ArrayList(*const llvm.Value).init(dg.gpa); |
| 459 | 471 | defer args.deinit(); |
| ... | ... | @@ -466,17 +478,6 @@ pub const Object = struct { |
| 466 | 478 | try args.append(llvm_func.getParam(llvm_arg_i)); |
| 467 | 479 | } |
| 468 | 480 | |
| 469 | | // Remove all the basic blocks of a function in order to start over, generating |
| 470 | | // LLVM IR from an empty function body. |
| 471 | | while (llvm_func.getFirstBasicBlock()) |bb| { |
| 472 | | bb.deleteBasicBlock(); |
| 473 | | } |
| 474 | | |
| 475 | | const builder = dg.context.createBuilder(); |
| 476 | | |
| 477 | | const entry_block = dg.context.appendBasicBlock(llvm_func, "Entry"); |
| 478 | | builder.positionBuilderAtEnd(entry_block); |
| 479 | | |
| 480 | 481 | var fg: FuncGen = .{ |
| 481 | 482 | .gpa = dg.gpa, |
| 482 | 483 | .air = air, |
| ... | ... | @@ -485,7 +486,7 @@ pub const Object = struct { |
| 485 | 486 | .dg = &dg, |
| 486 | 487 | .builder = builder, |
| 487 | 488 | .ret_ptr = ret_ptr, |
| 488 | | .args = args.toOwnedSlice(), |
| 489 | .args = args.items, |
| 489 | 490 | .arg_index = 0, |
| 490 | 491 | .func_inst_table = .{}, |
| 491 | 492 | .llvm_func = llvm_func, |
| ... | ... | @@ -1977,20 +1978,22 @@ pub const FuncGen = struct { |
| 1977 | 1978 | air: Air, |
| 1978 | 1979 | liveness: Liveness, |
| 1979 | 1980 | context: *const llvm.Context, |
| 1980 | | |
| 1981 | 1981 | builder: *const llvm.Builder, |
| 1982 | 1982 | |
| 1983 | 1983 | /// This stores the LLVM values used in a function, such that they can be referred to |
| 1984 | 1984 | /// in other instructions. This table is cleared before every function is generated. |
| 1985 | 1985 | func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *const llvm.Value), |
| 1986 | 1986 | |
| 1987 | | /// If the return type isByRef, this is the result pointer. Otherwise null. |
| 1987 | /// If the return type is sret, this is the result pointer. Otherwise null. |
| 1988 | /// Note that this can disagree with isByRef for the return type in the case |
| 1989 | /// of C ABI functions. |
| 1988 | 1990 | ret_ptr: ?*const llvm.Value, |
| 1989 | 1991 | /// These fields are used to refer to the LLVM value of the function parameters |
| 1990 | 1992 | /// in an Arg instruction. |
| 1991 | 1993 | /// This list may be shorter than the list according to the zig type system; |
| 1992 | | /// it omits 0-bit types. |
| 1993 | | args: []*const llvm.Value, |
| 1994 | /// it omits 0-bit types. If the function uses sret as the first parameter, |
| 1995 | /// this slice does not include it. |
| 1996 | args: []const *const llvm.Value, |
| 1994 | 1997 | arg_index: usize, |
| 1995 | 1998 | |
| 1996 | 1999 | llvm_func: *const llvm.Value, |
| ... | ... | @@ -2010,7 +2013,6 @@ pub const FuncGen = struct { |
| 2010 | 2013 | fn deinit(self: *FuncGen) void { |
| 2011 | 2014 | self.builder.dispose(); |
| 2012 | 2015 | self.func_inst_table.deinit(self.gpa); |
| 2013 | | self.gpa.free(self.args); |
| 2014 | 2016 | self.blocks.deinit(self.gpa); |
| 2015 | 2017 | } |
| 2016 | 2018 | |
| ... | ... | @@ -2283,12 +2285,35 @@ pub const FuncGen = struct { |
| 2283 | 2285 | if (return_type.isNoReturn()) { |
| 2284 | 2286 | _ = self.builder.buildUnreachable(); |
| 2285 | 2287 | return null; |
| 2286 | | } else if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits()) { |
| 2288 | } |
| 2289 | |
| 2290 | if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits()) { |
| 2287 | 2291 | return null; |
| 2288 | | } else if (sret) { |
| 2292 | } |
| 2293 | |
| 2294 | if (ret_ptr) |rp| { |
| 2289 | 2295 | const llvm_ret_ty = try self.dg.llvmType(return_type); |
| 2290 | 2296 | call.setCallSret(llvm_ret_ty); |
| 2291 | | return ret_ptr; |
| 2297 | if (isByRef(return_type)) { |
| 2298 | return rp; |
| 2299 | } else { |
| 2300 | // our by-ref status disagrees with sret so we must load. |
| 2301 | const loaded = self.builder.buildLoad(rp, ""); |
| 2302 | loaded.setAlignment(return_type.abiAlignment(target)); |
| 2303 | return loaded; |
| 2304 | } |
| 2305 | } |
| 2306 | |
| 2307 | if (isByRef(return_type)) { |
| 2308 | // our by-ref status disagrees with sret so we must allocate, store, |
| 2309 | // and return the allocation pointer. |
| 2310 | const llvm_ret_ty = try self.dg.llvmType(return_type); |
| 2311 | const rp = self.buildAlloca(llvm_ret_ty); |
| 2312 | const alignment = return_type.abiAlignment(target); |
| 2313 | rp.setAlignment(alignment); |
| 2314 | const store_inst = self.builder.buildStore(call, rp); |
| 2315 | store_inst.setAlignment(alignment); |
| 2316 | return rp; |
| 2292 | 2317 | } else { |
| 2293 | 2318 | return call; |
| 2294 | 2319 | } |
| ... | ... | @@ -2321,12 +2346,14 @@ pub const FuncGen = struct { |
| 2321 | 2346 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2322 | 2347 | const ptr_ty = self.air.typeOf(un_op); |
| 2323 | 2348 | const ret_ty = ptr_ty.childType(); |
| 2324 | | if (!ret_ty.hasRuntimeBits() or isByRef(ret_ty)) { |
| 2349 | if (!ret_ty.hasRuntimeBits() or self.ret_ptr != null) { |
| 2325 | 2350 | _ = self.builder.buildRetVoid(); |
| 2326 | 2351 | return null; |
| 2327 | 2352 | } |
| 2353 | const target = self.dg.module.getTarget(); |
| 2328 | 2354 | const ptr = try self.resolveInst(un_op); |
| 2329 | 2355 | const loaded = self.builder.buildLoad(ptr, ""); |
| 2356 | loaded.setAlignment(ret_ty.abiAlignment(target)); |
| 2330 | 2357 | _ = self.builder.buildRet(loaded); |
| 2331 | 2358 | return null; |
| 2332 | 2359 | } |
| ... | ... | @@ -5456,11 +5483,12 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool |
| 5456 | 5483 | .C => {}, |
| 5457 | 5484 | else => return false, |
| 5458 | 5485 | } |
| 5486 | const x86_64_abi = @import("../arch/x86_64/abi.zig"); |
| 5459 | 5487 | switch (target.cpu.arch) { |
| 5460 | 5488 | .mips, .mipsel => return false, |
| 5461 | 5489 | .x86_64 => switch (target.os.tag) { |
| 5462 | | .windows => return @import("../arch/x86_64/abi.zig").classifyWindows(fn_info.return_type, target) == .memory, |
| 5463 | | else => return @import("../arch/x86_64/abi.zig").classifySystemV(fn_info.return_type, target)[0] == .memory, |
| 5490 | .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, |
| 5491 | else => return x86_64_abi.classifySystemV(fn_info.return_type, target)[0] == .memory, |
| 5464 | 5492 | }, |
| 5465 | 5493 | else => return false, // TODO investigate C ABI for other architectures |
| 5466 | 5494 | } |