| ... | ... | @@ -952,7 +952,6 @@ pub fn generate( |
| 952 | 952 | ); |
| 953 | 953 | |
| 954 | 954 | const fn_info = zcu.typeToFunc(fn_type).?; |
| 955 | | const cc = abi.resolveCallingConvention(fn_info.cc, function.target.*); |
| 956 | 955 | var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) { |
| 957 | 956 | error.CodegenFail => return error.CodegenFail, |
| 958 | 957 | else => |e| return e, |
| ... | ... | @@ -978,7 +977,7 @@ pub fn generate( |
| 978 | 977 | .alignment = call_info.stack_align, |
| 979 | 978 | }), |
| 980 | 979 | ); |
| 981 | | function.va_info = switch (cc) { |
| 980 | function.va_info = switch (fn_info.cc) { |
| 982 | 981 | else => undefined, |
| 983 | 982 | .x86_64_sysv => .{ .sysv = .{ |
| 984 | 983 | .gp_count = call_info.gp_count, |
| ... | ... | @@ -1010,7 +1009,7 @@ pub fn generate( |
| 1010 | 1009 | .target = function.target, |
| 1011 | 1010 | .allocator = gpa, |
| 1012 | 1011 | .mir = mir, |
| 1013 | | .cc = cc, |
| 1012 | .cc = fn_info.cc, |
| 1014 | 1013 | .src_loc = src_loc, |
| 1015 | 1014 | .output_mode = comp.config.output_mode, |
| 1016 | 1015 | .link_mode = comp.config.link_mode, |
| ... | ... | @@ -1100,7 +1099,7 @@ pub fn generateLazy( |
| 1100 | 1099 | .target = function.target, |
| 1101 | 1100 | .allocator = gpa, |
| 1102 | 1101 | .mir = mir, |
| 1103 | | .cc = abi.resolveCallingConvention(.auto, function.target.*), |
| 1102 | .cc = .auto, |
| 1104 | 1103 | .src_loc = src_loc, |
| 1105 | 1104 | .output_mode = comp.config.output_mode, |
| 1106 | 1105 | .link_mode = comp.config.link_mode, |
| ... | ... | @@ -2126,8 +2125,7 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2126 | 2125 | const pt = self.pt; |
| 2127 | 2126 | const zcu = pt.zcu; |
| 2128 | 2127 | const fn_info = zcu.typeToFunc(self.fn_type).?; |
| 2129 | | const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); |
| 2130 | | if (cc != .naked) { |
| 2128 | if (fn_info.cc != .naked) { |
| 2131 | 2129 | try self.asmRegister(.{ ._, .push }, .rbp); |
| 2132 | 2130 | try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, .s(8)); |
| 2133 | 2131 | try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, .s(0)); |
| ... | ... | @@ -2159,7 +2157,7 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2159 | 2157 | else => unreachable, |
| 2160 | 2158 | } |
| 2161 | 2159 | |
| 2162 | | if (fn_info.is_var_args) switch (cc) { |
| 2160 | if (fn_info.is_var_args) switch (fn_info.cc) { |
| 2163 | 2161 | .x86_64_sysv => { |
| 2164 | 2162 | const info = &self.va_info.sysv; |
| 2165 | 2163 | const reg_save_area_fi = try self.allocFrameIndex(.init(.{ |
| ... | ... | @@ -2188,7 +2186,7 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2188 | 2186 | self.performReloc(skip_sse_reloc); |
| 2189 | 2187 | }, |
| 2190 | 2188 | .x86_64_win => return self.fail("TODO implement gen var arg function for Win64", .{}), |
| 2191 | | else => unreachable, |
| 2189 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 2192 | 2190 | }; |
| 2193 | 2191 | |
| 2194 | 2192 | try self.asmPseudo(.pseudo_dbg_prologue_end_none); |
| ... | ... | @@ -2214,7 +2212,7 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2214 | 2212 | try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, .s(8)); |
| 2215 | 2213 | try self.asmOpOnly(.{ ._, .ret }); |
| 2216 | 2214 | |
| 2217 | | const frame_layout = try self.computeFrameLayout(cc); |
| 2215 | const frame_layout = try self.computeFrameLayout(fn_info.cc); |
| 2218 | 2216 | const need_frame_align = frame_layout.stack_mask != std.math.maxInt(u32); |
| 2219 | 2217 | const need_stack_adjust = frame_layout.stack_adjust > 0; |
| 2220 | 2218 | const need_save_reg = frame_layout.save_reg_list.count() > 0; |
| ... | ... | @@ -2262,12 +2260,13 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2262 | 2260 | } }, |
| 2263 | 2261 | }); |
| 2264 | 2262 | } else { |
| 2263 | const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); |
| 2265 | 2264 | self.mir_instructions.set(backpatch_stack_alloc, .{ |
| 2266 | 2265 | .tag = .pseudo, |
| 2267 | 2266 | .ops = .pseudo_probe_adjust_setup_rri_s, |
| 2268 | 2267 | .data = .{ .rri = .{ |
| 2269 | 2268 | .r1 = .rsp, |
| 2270 | | .r2 = .rax, |
| 2269 | .r2 = scratch_reg, |
| 2271 | 2270 | .i = frame_layout.stack_adjust, |
| 2272 | 2271 | } }, |
| 2273 | 2272 | }); |
| ... | ... | @@ -2276,25 +2275,35 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2276 | 2275 | .ops = .pseudo_probe_adjust_loop_rr, |
| 2277 | 2276 | .data = .{ .rr = .{ |
| 2278 | 2277 | .r1 = .rsp, |
| 2279 | | .r2 = .rax, |
| 2278 | .r2 = scratch_reg, |
| 2280 | 2279 | } }, |
| 2281 | 2280 | }); |
| 2282 | 2281 | } |
| 2283 | 2282 | } |
| 2284 | 2283 | if (need_frame_align or need_stack_adjust) { |
| 2285 | | self.mir_instructions.set(backpatch_stack_dealloc, .{ |
| 2286 | | .tag = .lea, |
| 2287 | | .ops = .rm, |
| 2288 | | .data = .{ .rx = .{ |
| 2289 | | .r1 = .rsp, |
| 2290 | | .payload = try self.addExtra(Mir.Memory.encode(.{ |
| 2291 | | .base = .{ .reg = .rbp }, |
| 2292 | | .mod = .{ .rm = .{ |
| 2293 | | .size = .qword, |
| 2294 | | .disp = -frame_layout.save_reg_list.size(), |
| 2295 | | } }, |
| 2296 | | })), |
| 2297 | | } }, |
| 2284 | self.mir_instructions.set(backpatch_stack_dealloc, switch (-frame_layout.save_reg_list.size(self.target)) { |
| 2285 | 0 => .{ |
| 2286 | .tag = .mov, |
| 2287 | .ops = .rr, |
| 2288 | .data = .{ .rr = .{ |
| 2289 | .r1 = .rsp, |
| 2290 | .r2 = .rbp, |
| 2291 | } }, |
| 2292 | }, |
| 2293 | else => |disp| .{ |
| 2294 | .tag = .lea, |
| 2295 | .ops = .rm, |
| 2296 | .data = .{ .rx = .{ |
| 2297 | .r1 = .rsp, |
| 2298 | .payload = try self.addExtra(Mir.Memory.encode(.{ |
| 2299 | .base = .{ .reg = .rbp }, |
| 2300 | .mod = .{ .rm = .{ |
| 2301 | .size = .qword, |
| 2302 | .disp = disp, |
| 2303 | } }, |
| 2304 | })), |
| 2305 | } }, |
| 2306 | }, |
| 2298 | 2307 | }); |
| 2299 | 2308 | } |
| 2300 | 2309 | if (need_save_reg) { |
| ... | ... | @@ -9552,8 +9561,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 9552 | 9561 | const enum_ty: Type = .fromInterned(lazy_sym.ty); |
| 9553 | 9562 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)}); |
| 9554 | 9563 | |
| 9555 | | const resolved_cc = abi.resolveCallingConvention(.auto, self.target.*); |
| 9556 | | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 9564 | const param_regs = abi.getCAbiIntParamRegs(.auto); |
| 9557 | 9565 | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); |
| 9558 | 9566 | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); |
| 9559 | 9567 | |
| ... | ... | @@ -9700,7 +9708,7 @@ fn setFrameLoc( |
| 9700 | 9708 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; |
| 9701 | 9709 | } |
| 9702 | 9710 | |
| 9703 | | fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention) !FrameLayout { |
| 9711 | fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention.Tag) !FrameLayout { |
| 9704 | 9712 | const frame_allocs_len = self.frame_allocs.len; |
| 9705 | 9713 | try self.frame_locs.resize(self.gpa, frame_allocs_len); |
| 9706 | 9714 | const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count); |
| ... | ... | @@ -9732,8 +9740,7 @@ fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention) !FrameL |
| 9732 | 9740 | // Create list of registers to save in the prologue. |
| 9733 | 9741 | // TODO handle register classes |
| 9734 | 9742 | var save_reg_list: Mir.RegisterList = .empty; |
| 9735 | | const callee_preserved_regs = |
| 9736 | | abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*)); |
| 9743 | const callee_preserved_regs = abi.getCalleePreservedRegs(cc); |
| 9737 | 9744 | for (callee_preserved_regs) |reg| { |
| 9738 | 9745 | if (self.register_manager.isRegAllocated(reg)) { |
| 9739 | 9746 | save_reg_list.push(callee_preserved_regs, reg); |
| ... | ... | @@ -9747,7 +9754,7 @@ fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention) !FrameL |
| 9747 | 9754 | const stack_frame_align_offset = if (need_align_stack) |
| 9748 | 9755 | 0 |
| 9749 | 9756 | else |
| 9750 | | save_reg_list.size() + frame_offset[@intFromEnum(FrameIndex.args_frame)]; |
| 9757 | save_reg_list.size(self.target) + frame_offset[@intFromEnum(FrameIndex.args_frame)]; |
| 9751 | 9758 | |
| 9752 | 9759 | var rsp_offset: i32 = 0; |
| 9753 | 9760 | self.setFrameLoc(.call_frame, .rsp, &rsp_offset, true); |
| ... | ... | @@ -10036,10 +10043,9 @@ pub fn spillEflagsIfOccupied(self: *CodeGen) !void { |
| 10036 | 10043 | } |
| 10037 | 10044 | } |
| 10038 | 10045 | |
| 10039 | | pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention) !void { |
| 10046 | pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention.Tag) !void { |
| 10040 | 10047 | switch (cc) { |
| 10041 | | .x86_64_sysv => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_sysv = .{} })), |
| 10042 | | .x86_64_win => try self.spillRegisters(abi.getCallerPreservedRegs(.{ .x86_64_win = .{} })), |
| 10048 | inline .auto, .x86_64_sysv, .x86_64_win => |tag| try self.spillRegisters(abi.getCallerPreservedRegs(tag)), |
| 10043 | 10049 | else => unreachable, |
| 10044 | 10050 | } |
| 10045 | 10051 | } |
| ... | ... | @@ -19127,8 +19133,7 @@ fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 19127 | 19133 | try self.spillEflagsIfOccupied(); |
| 19128 | 19134 | |
| 19129 | 19135 | const fn_info = zcu.typeToFunc(self.fn_type).?; |
| 19130 | | const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); |
| 19131 | | const param_int_regs = abi.getCAbiIntParamRegs(cc); |
| 19136 | const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); |
| 19132 | 19137 | var prev_reg: Register = undefined; |
| 19133 | 19138 | for ( |
| 19134 | 19139 | param_int_regs[param_int_regs.len - regs_frame_addr.regs ..], |
| ... | ... | @@ -19228,8 +19233,7 @@ fn airDbgArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 19228 | 19233 | } |
| 19229 | 19234 | |
| 19230 | 19235 | fn airDbgVarArgs(self: *CodeGen) !void { |
| 19231 | | if (self.pt.zcu.typeToFunc(self.fn_type).?.is_var_args) |
| 19232 | | try self.asmPseudo(.pseudo_dbg_var_args_none); |
| 19236 | if (self.pt.zcu.typeToFunc(self.fn_type).?.is_var_args) try self.asmPseudo(.pseudo_dbg_var_args_none); |
| 19233 | 19237 | } |
| 19234 | 19238 | |
| 19235 | 19239 | fn genLocalDebugInfo( |
| ... | ... | @@ -19364,7 +19368,6 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 19364 | 19368 | }), |
| 19365 | 19369 | }; |
| 19366 | 19370 | const fn_info = zcu.typeToFunc(fn_ty).?; |
| 19367 | | const resolved_cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); |
| 19368 | 19371 | |
| 19369 | 19372 | const ExpectedContents = extern struct { |
| 19370 | 19373 | var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)), |
| ... | ... | @@ -19406,7 +19409,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 19406 | 19409 | } |
| 19407 | 19410 | |
| 19408 | 19411 | try self.spillEflagsIfOccupied(); |
| 19409 | | try self.spillCallerPreservedRegs(resolved_cc); |
| 19412 | try self.spillCallerPreservedRegs(fn_info.cc); |
| 19410 | 19413 | |
| 19411 | 19414 | // set stack arguments first because this can clobber registers |
| 19412 | 19415 | // also clobber spill arguments as we go |
| ... | ... | @@ -19482,7 +19485,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 19482 | 19485 | ); |
| 19483 | 19486 | _ = try self.asmJccReloc(.b, loop); |
| 19484 | 19487 | |
| 19485 | | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 19488 | const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); |
| 19486 | 19489 | for (param_int_regs[param_int_regs.len - regs_frame_addr.regs ..]) |dst_reg| { |
| 19487 | 19490 | try self.register_manager.getReg(dst_reg, null); |
| 19488 | 19491 | try reg_locks.append(self.register_manager.lockReg(dst_reg)); |
| ... | ... | @@ -19546,7 +19549,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 19546 | 19549 | }; |
| 19547 | 19550 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 19548 | 19551 | |
| 19549 | | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 19552 | const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); |
| 19550 | 19553 | for ( |
| 19551 | 19554 | param_int_regs[param_int_regs.len - regs_frame_addr.regs ..], |
| 19552 | 19555 | 0.., |
| ... | ... | @@ -19559,8 +19562,7 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 19559 | 19562 | else => unreachable, |
| 19560 | 19563 | }; |
| 19561 | 19564 | |
| 19562 | | if (fn_info.is_var_args) |
| 19563 | | try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); |
| 19565 | if (fn_info.is_var_args) try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); |
| 19564 | 19566 | |
| 19565 | 19567 | // Due to incremental compilation, how function calls are generated depends |
| 19566 | 19568 | // on linking. |
| ... | ... | @@ -19582,8 +19584,9 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 19582 | 19584 | } else if (self.bin_file.cast(.coff)) |coff_file| { |
| 19583 | 19585 | const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); |
| 19584 | 19586 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| 19585 | | try self.genSetReg(.rax, .usize, .{ .lea_got = sym_index }, .{}); |
| 19586 | | try self.asmRegister(.{ ._, .call }, .rax); |
| 19587 | const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); |
| 19588 | try self.genSetReg(scratch_reg, .usize, .{ .lea_got = sym_index }, .{}); |
| 19589 | try self.asmRegister(.{ ._, .call }, scratch_reg); |
| 19587 | 19590 | } else if (self.bin_file.cast(.macho)) |macho_file| { |
| 19588 | 19591 | const zo = macho_file.getZigObject().?; |
| 19589 | 19592 | const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav); |
| ... | ... | @@ -19622,8 +19625,9 @@ fn genCall(self: *CodeGen, info: union(enum) { |
| 19622 | 19625 | } |
| 19623 | 19626 | } else { |
| 19624 | 19627 | assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer); |
| 19625 | | try self.genSetReg(.rax, .usize, .{ .air_ref = callee }, .{}); |
| 19626 | | try self.asmRegister(.{ ._, .call }, .rax); |
| 19628 | const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); |
| 19629 | try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{}); |
| 19630 | try self.asmRegister(.{ ._, .call }, scratch_reg); |
| 19627 | 19631 | }, |
| 19628 | 19632 | .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| { |
| 19629 | 19633 | const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib); |
| ... | ... | @@ -23095,11 +23099,12 @@ fn genExternSymbolRef( |
| 23095 | 23099 | ) InnerError!void { |
| 23096 | 23100 | if (self.bin_file.cast(.coff)) |coff_file| { |
| 23097 | 23101 | const global_index = try coff_file.getGlobalSymbol(callee, lib); |
| 23102 | const scratch_reg = abi.getCAbiLinkerScratchReg(self.fn_type.fnCallingConvention(self.pt.zcu)); |
| 23098 | 23103 | _ = try self.addInst(.{ |
| 23099 | 23104 | .tag = .mov, |
| 23100 | 23105 | .ops = .import_reloc, |
| 23101 | 23106 | .data = .{ .rx = .{ |
| 23102 | | .r1 = .rax, |
| 23107 | .r1 = scratch_reg, |
| 23103 | 23108 | .payload = try self.addExtra(bits.SymbolOffset{ |
| 23104 | 23109 | .sym_index = link.File.Coff.global_symbol_bit | global_index, |
| 23105 | 23110 | }), |
| ... | ... | @@ -23107,7 +23112,7 @@ fn genExternSymbolRef( |
| 23107 | 23112 | }); |
| 23108 | 23113 | switch (tag) { |
| 23109 | 23114 | .mov => {}, |
| 23110 | | .call => try self.asmRegister(.{ ._, .call }, .rax), |
| 23115 | .call => try self.asmRegister(.{ ._, .call }, scratch_reg), |
| 23111 | 23116 | else => unreachable, |
| 23112 | 23117 | } |
| 23113 | 23118 | } else return self.fail("TODO implement calling extern functions", .{}); |
| ... | ... | @@ -24226,7 +24231,6 @@ fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 24226 | 24231 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 24227 | 24232 | const inst_ty = self.typeOfIndex(inst); |
| 24228 | 24233 | const enum_ty = self.typeOf(un_op); |
| 24229 | | const resolved_cc = abi.resolveCallingConvention(.auto, self.target.*); |
| 24230 | 24234 | |
| 24231 | 24235 | // We need a properly aligned and sized call frame to be able to call this function. |
| 24232 | 24236 | { |
| ... | ... | @@ -24244,9 +24248,9 @@ fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 24244 | 24248 | } |
| 24245 | 24249 | |
| 24246 | 24250 | try self.spillEflagsIfOccupied(); |
| 24247 | | try self.spillCallerPreservedRegs(resolved_cc); |
| 24251 | try self.spillCallerPreservedRegs(.auto); |
| 24248 | 24252 | |
| 24249 | | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 24253 | const param_regs = abi.getCAbiIntParamRegs(.auto); |
| 24250 | 24254 | |
| 24251 | 24255 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 24252 | 24256 | try self.genSetReg(param_regs[0], .usize, dst_mcv.address(), .{}); |
| ... | ... | @@ -24255,7 +24259,7 @@ fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 24255 | 24259 | try self.genSetReg(param_regs[1], enum_ty, operand, .{}); |
| 24256 | 24260 | |
| 24257 | 24261 | const enum_lazy_sym: link.File.LazySymbol = .{ .kind = .code, .ty = enum_ty.toIntern() }; |
| 24258 | | try self.genLazySymbolRef(.call, .rax, enum_lazy_sym); |
| 24262 | try self.genLazySymbolRef(.call, abi.getCAbiLinkerScratchReg(self.fn_type.fnCallingConvention(zcu)), enum_lazy_sym); |
| 24259 | 24263 | |
| 24260 | 24264 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 24261 | 24265 | } |
| ... | ... | @@ -26349,10 +26353,7 @@ fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26349 | 26353 | const va_list_ty = self.air.instructions.items(.data)[@intFromEnum(inst)].ty; |
| 26350 | 26354 | const ptr_anyopaque_ty = try pt.singleMutPtrType(.anyopaque); |
| 26351 | 26355 | |
| 26352 | | const result: MCValue = switch (abi.resolveCallingConvention( |
| 26353 | | self.fn_type.fnCallingConvention(zcu), |
| 26354 | | self.target.*, |
| 26355 | | )) { |
| 26356 | const result: MCValue = switch (self.fn_type.fnCallingConvention(zcu)) { |
| 26356 | 26357 | .x86_64_sysv => result: { |
| 26357 | 26358 | const info = self.va_info.sysv; |
| 26358 | 26359 | const dst_fi = try self.allocFrameIndex(.initSpill(va_list_ty, zcu)); |
| ... | ... | @@ -26396,7 +26397,7 @@ fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26396 | 26397 | break :result .{ .load_frame = .{ .index = dst_fi } }; |
| 26397 | 26398 | }, |
| 26398 | 26399 | .x86_64_win => return self.fail("TODO implement c_va_start for Win64", .{}), |
| 26399 | | else => unreachable, |
| 26400 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 26400 | 26401 | }; |
| 26401 | 26402 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 26402 | 26403 | } |
| ... | ... | @@ -26410,10 +26411,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26410 | 26411 | const ptr_anyopaque_ty = try pt.singleMutPtrType(.anyopaque); |
| 26411 | 26412 | const unused = self.liveness.isUnused(inst); |
| 26412 | 26413 | |
| 26413 | | const result: MCValue = switch (abi.resolveCallingConvention( |
| 26414 | | self.fn_type.fnCallingConvention(zcu), |
| 26415 | | self.target.*, |
| 26416 | | )) { |
| 26414 | const result: MCValue = switch (self.fn_type.fnCallingConvention(zcu)) { |
| 26417 | 26415 | .x86_64_sysv => result: { |
| 26418 | 26416 | try self.spillEflagsIfOccupied(); |
| 26419 | 26417 | |
| ... | ... | @@ -26592,7 +26590,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 26592 | 26590 | break :result promote_mcv; |
| 26593 | 26591 | }, |
| 26594 | 26592 | .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}), |
| 26595 | | else => unreachable, |
| 26593 | else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), |
| 26596 | 26594 | }; |
| 26597 | 26595 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 26598 | 26596 | } |
| ... | ... | @@ -26753,13 +26751,15 @@ fn resolveCallingConventionValues( |
| 26753 | 26751 | errdefer self.gpa.free(result.args); |
| 26754 | 26752 | |
| 26755 | 26753 | const ret_ty: Type = .fromInterned(fn_info.return_type); |
| 26756 | | |
| 26757 | | const resolved_cc = abi.resolveCallingConvention(cc, self.target.*); |
| 26758 | 26754 | switch (cc) { |
| 26759 | 26755 | .naked => { |
| 26760 | 26756 | assert(result.args.len == 0); |
| 26761 | 26757 | result.return_value = .init(.unreach); |
| 26762 | | result.stack_align = .@"8"; |
| 26758 | result.stack_align = switch (self.target.cpu.arch) { |
| 26759 | else => unreachable, |
| 26760 | .x86 => .@"4", |
| 26761 | .x86_64 => .@"8", |
| 26762 | }; |
| 26763 | 26763 | }, |
| 26764 | 26764 | .x86_64_sysv, .x86_64_win => |cc_opts| { |
| 26765 | 26765 | var ret_int_reg_i: u32 = 0; |
| ... | ... | @@ -26768,17 +26768,14 @@ fn resolveCallingConventionValues( |
| 26768 | 26768 | var param_sse_reg_i: u32 = 0; |
| 26769 | 26769 | result.stack_align = .fromByteUnits(cc_opts.incoming_stack_alignment orelse 16); |
| 26770 | 26770 | |
| 26771 | | switch (resolved_cc) { |
| 26771 | switch (cc) { |
| 26772 | 26772 | .x86_64_sysv => {}, |
| 26773 | | .x86_64_win => { |
| 26774 | | // Align the stack to 16bytes before allocating shadow stack space (if any). |
| 26775 | | result.stack_byte_count += @intCast(4 * Type.usize.abiSize(zcu)); |
| 26776 | | }, |
| 26773 | .x86_64_win => result.stack_byte_count += @intCast(4 * 8), |
| 26777 | 26774 | else => unreachable, |
| 26778 | 26775 | } |
| 26779 | 26776 | |
| 26780 | 26777 | // Return values |
| 26781 | | if (ret_ty.zigTypeTag(zcu) == .noreturn) { |
| 26778 | if (ret_ty.isNoReturn(zcu)) { |
| 26782 | 26779 | result.return_value = .init(.unreach); |
| 26783 | 26780 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 26784 | 26781 | // TODO: is this even possible for C calling convention? |
| ... | ... | @@ -26787,7 +26784,7 @@ fn resolveCallingConventionValues( |
| 26787 | 26784 | var ret_tracking: [4]InstTracking = undefined; |
| 26788 | 26785 | var ret_tracking_i: usize = 0; |
| 26789 | 26786 | |
| 26790 | | const classes = switch (resolved_cc) { |
| 26787 | const classes = switch (cc) { |
| 26791 | 26788 | .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none), |
| 26792 | 26789 | .x86_64_win => &.{abi.classifyWindows(ret_ty, zcu)}, |
| 26793 | 26790 | else => unreachable, |
| ... | ... | @@ -26795,7 +26792,7 @@ fn resolveCallingConventionValues( |
| 26795 | 26792 | for (classes) |class| switch (class) { |
| 26796 | 26793 | .integer => { |
| 26797 | 26794 | const ret_int_reg = registerAlias( |
| 26798 | | abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i], |
| 26795 | abi.getCAbiIntReturnRegs(cc)[ret_int_reg_i], |
| 26799 | 26796 | @intCast(@min(ret_ty.abiSize(zcu), 8)), |
| 26800 | 26797 | ); |
| 26801 | 26798 | ret_int_reg_i += 1; |
| ... | ... | @@ -26804,7 +26801,7 @@ fn resolveCallingConventionValues( |
| 26804 | 26801 | ret_tracking_i += 1; |
| 26805 | 26802 | }, |
| 26806 | 26803 | .sse, .float, .float_combine, .win_i128 => { |
| 26807 | | const ret_sse_regs = abi.getCAbiSseReturnRegs(resolved_cc); |
| 26804 | const ret_sse_regs = abi.getCAbiSseReturnRegs(cc); |
| 26808 | 26805 | const abi_size: u32 = @intCast(ret_ty.abiSize(zcu)); |
| 26809 | 26806 | const reg_size = @min(abi_size, self.vectorSize(.float)); |
| 26810 | 26807 | var byte_offset: u32 = 0; |
| ... | ... | @@ -26818,18 +26815,18 @@ fn resolveCallingConventionValues( |
| 26818 | 26815 | }, |
| 26819 | 26816 | .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse), |
| 26820 | 26817 | .x87 => { |
| 26821 | | ret_tracking[ret_tracking_i] = .init(.{ .register = .st0 }); |
| 26818 | ret_tracking[ret_tracking_i] = .init(.{ .register = abi.getCAbiX87ReturnRegs(cc)[0] }); |
| 26822 | 26819 | ret_tracking_i += 1; |
| 26823 | 26820 | }, |
| 26824 | 26821 | .x87up => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .x87), |
| 26825 | 26822 | .complex_x87 => { |
| 26826 | | ret_tracking[ret_tracking_i] = .init(.{ .register_pair = .{ .st0, .st1 } }); |
| 26823 | ret_tracking[ret_tracking_i] = .init(.{ .register_pair = abi.getCAbiX87ReturnRegs(cc)[0..2].* }); |
| 26827 | 26824 | ret_tracking_i += 1; |
| 26828 | 26825 | }, |
| 26829 | 26826 | .memory => { |
| 26830 | | const ret_int_reg = abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i].to64(); |
| 26827 | const ret_int_reg = abi.getCAbiIntReturnRegs(cc)[ret_int_reg_i].to64(); |
| 26831 | 26828 | ret_int_reg_i += 1; |
| 26832 | | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i]; |
| 26829 | const ret_indirect_reg = abi.getCAbiIntParamRegs(cc)[param_int_reg_i]; |
| 26833 | 26830 | param_int_reg_i += 1; |
| 26834 | 26831 | |
| 26835 | 26832 | ret_tracking[ret_tracking_i] = .{ |
| ... | ... | @@ -26864,7 +26861,7 @@ fn resolveCallingConventionValues( |
| 26864 | 26861 | // Input params |
| 26865 | 26862 | for (param_types, result.args) |ty, *arg| { |
| 26866 | 26863 | assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); |
| 26867 | | switch (resolved_cc) { |
| 26864 | switch (cc) { |
| 26868 | 26865 | .x86_64_sysv => {}, |
| 26869 | 26866 | .x86_64_win => { |
| 26870 | 26867 | param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i); |
| ... | ... | @@ -26876,14 +26873,14 @@ fn resolveCallingConventionValues( |
| 26876 | 26873 | var arg_mcv: [4]MCValue = undefined; |
| 26877 | 26874 | var arg_mcv_i: usize = 0; |
| 26878 | 26875 | |
| 26879 | | const classes = switch (resolved_cc) { |
| 26876 | const classes = switch (cc) { |
| 26880 | 26877 | .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none), |
| 26881 | 26878 | .x86_64_win => &.{abi.classifyWindows(ty, zcu)}, |
| 26882 | 26879 | else => unreachable, |
| 26883 | 26880 | }; |
| 26884 | 26881 | classes: for (classes) |class| switch (class) { |
| 26885 | 26882 | .integer => { |
| 26886 | | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 26883 | const param_int_regs = abi.getCAbiIntParamRegs(cc); |
| 26887 | 26884 | if (param_int_reg_i >= param_int_regs.len) break; |
| 26888 | 26885 | |
| 26889 | 26886 | const param_int_reg = |
| ... | ... | @@ -26894,7 +26891,7 @@ fn resolveCallingConventionValues( |
| 26894 | 26891 | arg_mcv_i += 1; |
| 26895 | 26892 | }, |
| 26896 | 26893 | .sse, .float, .float_combine => { |
| 26897 | | const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc); |
| 26894 | const param_sse_regs = abi.getCAbiSseParamRegs(cc); |
| 26898 | 26895 | const abi_size: u32 = @intCast(ty.abiSize(zcu)); |
| 26899 | 26896 | const reg_size = @min(abi_size, self.vectorSize(.float)); |
| 26900 | 26897 | var byte_offset: u32 = 0; |
| ... | ... | @@ -26909,14 +26906,13 @@ fn resolveCallingConventionValues( |
| 26909 | 26906 | } |
| 26910 | 26907 | }, |
| 26911 | 26908 | .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse), |
| 26912 | | .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (resolved_cc) { |
| 26909 | .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (cc) { |
| 26913 | 26910 | .x86_64_sysv => switch (class) { |
| 26914 | 26911 | .x87, .x87up, .complex_x87, .memory => break, |
| 26915 | 26912 | else => unreachable, |
| 26916 | 26913 | }, |
| 26917 | 26914 | .x86_64_win => if (ty.abiSize(zcu) > 8) { |
| 26918 | | const param_int_reg = |
| 26919 | | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64(); |
| 26915 | const param_int_reg = abi.getCAbiIntParamRegs(cc)[param_int_reg_i].to64(); |
| 26920 | 26916 | param_int_reg_i += 1; |
| 26921 | 26917 | |
| 26922 | 26918 | arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; |
| ... | ... | @@ -26927,7 +26923,7 @@ fn resolveCallingConventionValues( |
| 26927 | 26923 | .none => unreachable, |
| 26928 | 26924 | .integer_per_element => { |
| 26929 | 26925 | const param_int_regs_len: u32 = |
| 26930 | | @intCast(abi.getCAbiIntParamRegs(resolved_cc).len); |
| 26926 | @intCast(abi.getCAbiIntParamRegs(cc).len); |
| 26931 | 26927 | const remaining_param_int_regs: u3 = |
| 26932 | 26928 | @intCast(param_int_regs_len - param_int_reg_i); |
| 26933 | 26929 | param_int_reg_i = param_int_regs_len; |
| ... | ... | @@ -26989,42 +26985,86 @@ fn resolveCallingConventionValues( |
| 26989 | 26985 | result.fp_count = param_sse_reg_i; |
| 26990 | 26986 | }, |
| 26991 | 26987 | .auto => { |
| 26992 | | result.stack_align = .@"16"; |
| 26988 | result.stack_align = abi.zigcc.stack_align orelse .fromByteUnits(self.vectorSize(.float)); |
| 26989 | |
| 26990 | var param_gpr = abi.getCAbiIntParamRegs(cc); |
| 26991 | var param_x87 = abi.getCAbiX87ParamRegs(cc); |
| 26992 | var param_sse = abi.getCAbiSseParamRegs(cc); |
| 26993 | 26993 | |
| 26994 | 26994 | // Return values |
| 26995 | | if (ret_ty.zigTypeTag(zcu) == .noreturn) { |
| 26996 | | result.return_value = .init(.unreach); |
| 26997 | | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 26998 | | result.return_value = .init(.none); |
| 26999 | | } else { |
| 27000 | | const ret_reg = abi.getCAbiIntReturnRegs(resolved_cc)[0]; |
| 27001 | | const ret_ty_size: u31 = @intCast(ret_ty.abiSize(zcu)); |
| 27002 | | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { |
| 27003 | | const aliased_reg = registerAlias(ret_reg, ret_ty_size); |
| 27004 | | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; |
| 27005 | | } else { |
| 27006 | | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[0]; |
| 27007 | | result.return_value = .{ |
| 27008 | | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 27009 | | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 27010 | | }; |
| 27011 | | } |
| 27012 | | } |
| 26995 | result.return_value = if (ret_ty.isNoReturn(zcu)) |
| 26996 | .init(.unreach) |
| 26997 | else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) |
| 26998 | .init(.none) |
| 26999 | else return_value: { |
| 27000 | const ret_gpr = abi.getCAbiIntReturnRegs(cc); |
| 27001 | const ret_size: u31 = @intCast(ret_ty.abiSize(zcu)); |
| 27002 | if (abi.zigcc.return_in_regs) switch (self.regClassForType(ret_ty)) { |
| 27003 | .general_purpose => if (ret_size <= @as(u4, switch (self.target.cpu.arch) { |
| 27004 | else => unreachable, |
| 27005 | .x86 => 4, |
| 27006 | .x86_64 => 8, |
| 27007 | })) |
| 27008 | break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) }) |
| 27009 | else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu)) |
| 27010 | break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }), |
| 27011 | .segment, .mmx, .ip => unreachable, |
| 27012 | .x87 => break :return_value .init(.{ .register = .st0 }), |
| 27013 | .sse => if (ret_size <= self.vectorSize(.float)) break :return_value .init(.{ |
| 27014 | .register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)), |
| 27015 | }), |
| 27016 | }; |
| 27017 | const ret_indirect_reg = param_gpr[0]; |
| 27018 | param_gpr = param_gpr[1..]; |
| 27019 | break :return_value .{ |
| 27020 | .short = .{ .indirect = .{ .reg = ret_gpr[0] } }, |
| 27021 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 27022 | }; |
| 27023 | }; |
| 27013 | 27024 | |
| 27014 | 27025 | // Input params |
| 27015 | | for (param_types, result.args) |ty, *arg| { |
| 27016 | | if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 27026 | for (param_types, result.args) |param_ty, *arg| { |
| 27027 | if (!param_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 27017 | 27028 | arg.* = .none; |
| 27018 | 27029 | continue; |
| 27019 | 27030 | } |
| 27020 | | const param_align = ty.abiAlignment(zcu); |
| 27031 | const param_size: u31 = @intCast(param_ty.abiSize(zcu)); |
| 27032 | if (abi.zigcc.params_in_regs) switch (self.regClassForType(param_ty)) { |
| 27033 | .general_purpose => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (self.target.cpu.arch) { |
| 27034 | else => unreachable, |
| 27035 | .x86 => 4, |
| 27036 | .x86_64 => 8, |
| 27037 | })) { |
| 27038 | arg.* = .{ .register = registerAlias(param_gpr[0], param_size) }; |
| 27039 | param_gpr = param_gpr[1..]; |
| 27040 | continue; |
| 27041 | } else if (param_gpr.len >= 2 and param_ty.isSliceAtRuntime(zcu)) { |
| 27042 | arg.* = .{ .register_pair = param_gpr[0..2].* }; |
| 27043 | param_gpr = param_gpr[2..]; |
| 27044 | continue; |
| 27045 | }, |
| 27046 | .segment, .mmx, .ip => unreachable, |
| 27047 | .x87 => if (param_x87.len >= 1) { |
| 27048 | arg.* = .{ .register = param_x87[0] }; |
| 27049 | param_x87 = param_x87[1..]; |
| 27050 | continue; |
| 27051 | }, |
| 27052 | .sse => if (param_sse.len >= 1 and param_size <= self.vectorSize(.float)) { |
| 27053 | arg.* = .{ |
| 27054 | .register = registerAlias(param_sse[0], @max(param_size, 16)), |
| 27055 | }; |
| 27056 | param_sse = param_sse[1..]; |
| 27057 | continue; |
| 27058 | }, |
| 27059 | }; |
| 27060 | const param_align = param_ty.abiAlignment(zcu); |
| 27021 | 27061 | result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count)); |
| 27022 | 27062 | result.stack_align = result.stack_align.max(param_align); |
| 27023 | 27063 | arg.* = .{ .load_frame = .{ |
| 27024 | 27064 | .index = stack_frame_base, |
| 27025 | 27065 | .off = result.stack_byte_count, |
| 27026 | 27066 | } }; |
| 27027 | | result.stack_byte_count += @intCast(ty.abiSize(zcu)); |
| 27067 | result.stack_byte_count += param_size; |
| 27028 | 27068 | } |
| 27029 | 27069 | }, |
| 27030 | 27070 | else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}), |