| ... | @@ -807,7 +807,7 @@ pub fn generate( | ... | @@ -807,7 +807,7 @@ pub fn generate( |
| 807 | .lower = .{ | 807 | .lower = .{ |
| 808 | .allocator = bin_file.allocator, | 808 | .allocator = bin_file.allocator, |
| 809 | .mir = mir, | 809 | .mir = mir, |
| 810 | .target = &bin_file.options.target, | 810 | .cc = abi.resolveCallingConvention(fn_info.cc, function.target.*), |
| 811 | .src_loc = src_loc, | 811 | .src_loc = src_loc, |
| 812 | }, | 812 | }, |
| 813 | .bin_file = bin_file, | 813 | .bin_file = bin_file, |
| ... | @@ -893,7 +893,7 @@ pub fn generateLazy( | ... | @@ -893,7 +893,7 @@ pub fn generateLazy( |
| 893 | .lower = .{ | 893 | .lower = .{ |
| 894 | .allocator = bin_file.allocator, | 894 | .allocator = bin_file.allocator, |
| 895 | .mir = mir, | 895 | .mir = mir, |
| 896 | .target = &bin_file.options.target, | 896 | .cc = abi.resolveCallingConvention(.Unspecified, function.target.*), |
| 897 | .src_loc = src_loc, | 897 | .src_loc = src_loc, |
| 898 | }, | 898 | }, |
| 899 | .bin_file = bin_file, | 899 | .bin_file = bin_file, |
| ... | @@ -980,6 +980,7 @@ fn formatWipMir( | ... | @@ -980,6 +980,7 @@ fn formatWipMir( |
| 980 | _: std.fmt.FormatOptions, | 980 | _: std.fmt.FormatOptions, |
| 981 | writer: anytype, | 981 | writer: anytype, |
| 982 | ) @TypeOf(writer).Error!void { | 982 | ) @TypeOf(writer).Error!void { |
| | 983 | const mod = data.self.bin_file.options.module.?; |
| 983 | var lower = Lower{ | 984 | var lower = Lower{ |
| 984 | .allocator = data.self.gpa, | 985 | .allocator = data.self.gpa, |
| 985 | .mir = .{ | 986 | .mir = .{ |
| ... | @@ -987,7 +988,7 @@ fn formatWipMir( | ... | @@ -987,7 +988,7 @@ fn formatWipMir( |
| 987 | .extra = data.self.mir_extra.items, | 988 | .extra = data.self.mir_extra.items, |
| 988 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), | 989 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), |
| 989 | }, | 990 | }, |
| 990 | .target = data.self.target, | 991 | .cc = mod.typeToFunc(data.self.fn_type).?.cc, |
| 991 | .src_loc = data.self.src_loc, | 992 | .src_loc = data.self.src_loc, |
| 992 | }; | 993 | }; |
| 993 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { | 994 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { |
| ... | @@ -1680,7 +1681,7 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -1680,7 +1681,7 @@ fn gen(self: *Self) InnerError!void { |
| 1680 | try self.asmRegister(.{ ._, .pop }, .rbp); | 1681 | try self.asmRegister(.{ ._, .pop }, .rbp); |
| 1681 | try self.asmOpOnly(.{ ._, .ret }); | 1682 | try self.asmOpOnly(.{ ._, .ret }); |
| 1682 | | 1683 | |
| 1683 | const frame_layout = try self.computeFrameLayout(); | 1684 | const frame_layout = try self.computeFrameLayout(cc); |
| 1684 | const need_frame_align = frame_layout.stack_mask != math.maxInt(u32); | 1685 | const need_frame_align = frame_layout.stack_mask != math.maxInt(u32); |
| 1685 | const need_stack_adjust = frame_layout.stack_adjust > 0; | 1686 | const need_stack_adjust = frame_layout.stack_adjust > 0; |
| 1686 | const need_save_reg = frame_layout.save_reg_list.count() > 0; | 1687 | const need_save_reg = frame_layout.save_reg_list.count() > 0; |
| ... | @@ -2075,7 +2076,8 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -2075,7 +2076,8 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2075 | const enum_ty = lazy_sym.ty; | 2076 | const enum_ty = lazy_sym.ty; |
| 2076 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); | 2077 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); |
| 2077 | | 2078 | |
| 2078 | const param_regs = abi.getCAbiIntParamRegs(self.target.*); | 2079 | const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*); |
| | 2080 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 2079 | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); | 2081 | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); |
| 2080 | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); | 2082 | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); |
| 2081 | | 2083 | |
| ... | @@ -2208,7 +2210,7 @@ fn setFrameLoc( | ... | @@ -2208,7 +2210,7 @@ fn setFrameLoc( |
| 2208 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; | 2210 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; |
| 2209 | } | 2211 | } |
| 2210 | | 2212 | |
| 2211 | fn computeFrameLayout(self: *Self) !FrameLayout { | 2213 | fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayout { |
| 2212 | const frame_allocs_len = self.frame_allocs.len; | 2214 | const frame_allocs_len = self.frame_allocs.len; |
| 2213 | try self.frame_locs.resize(self.gpa, frame_allocs_len); | 2215 | try self.frame_locs.resize(self.gpa, frame_allocs_len); |
| 2214 | const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count); | 2216 | const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count); |
| ... | @@ -2240,7 +2242,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2240,7 +2242,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2240 | // Create list of registers to save in the prologue. | 2242 | // Create list of registers to save in the prologue. |
| 2241 | // TODO handle register classes | 2243 | // TODO handle register classes |
| 2242 | var save_reg_list = Mir.RegisterList{}; | 2244 | var save_reg_list = Mir.RegisterList{}; |
| 2243 | const callee_preserved_regs = abi.getCalleePreservedRegs(self.target.*); | 2245 | const callee_preserved_regs = |
| | 2246 | abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*)); |
| 2244 | for (callee_preserved_regs) |reg| { | 2247 | for (callee_preserved_regs) |reg| { |
| 2245 | if (self.register_manager.isRegAllocated(reg)) { | 2248 | if (self.register_manager.isRegAllocated(reg)) { |
| 2246 | save_reg_list.push(callee_preserved_regs, reg); | 2249 | save_reg_list.push(callee_preserved_regs, reg); |
| ... | @@ -8477,8 +8480,7 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8477,8 +8480,7 @@ fn genCall(self: *Self, info: union(enum) { |
| 8477 | try arg_locks.ensureTotalCapacity(16); | 8480 | try arg_locks.ensureTotalCapacity(16); |
| 8478 | defer for (arg_locks.items) |arg_lock| if (arg_lock) |lock| self.register_manager.unlockReg(lock); | 8481 | defer for (arg_locks.items) |arg_lock| if (arg_lock) |lock| self.register_manager.unlockReg(lock); |
| 8479 | | 8482 | |
| 8480 | var call_info = | 8483 | var call_info = try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); |
| 8481 | try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); | | |
| 8482 | defer call_info.deinit(self); | 8484 | defer call_info.deinit(self); |
| 8483 | | 8485 | |
| 8484 | // We need a properly aligned and sized call frame to be able to call this function. | 8486 | // We need a properly aligned and sized call frame to be able to call this function. |
| ... | @@ -8497,7 +8499,9 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8497,7 +8499,9 @@ fn genCall(self: *Self, info: union(enum) { |
| 8497 | } | 8499 | } |
| 8498 | | 8500 | |
| 8499 | try self.spillEflagsIfOccupied(); | 8501 | try self.spillEflagsIfOccupied(); |
| 8500 | try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*)); | 8502 | try self.spillRegisters(abi.getCallerPreservedRegs( |
| | 8503 | abi.resolveCallingConvention(fn_info.cc, self.target.*), |
| | 8504 | )); |
| 8501 | | 8505 | |
| 8502 | // set stack arguments first because this can clobber registers | 8506 | // set stack arguments first because this can clobber registers |
| 8503 | // also clobber spill arguments as we go | 8507 | // also clobber spill arguments as we go |
| ... | @@ -11727,6 +11731,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11727,6 +11731,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 11727 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 11731 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 11728 | const inst_ty = self.typeOfIndex(inst); | 11732 | const inst_ty = self.typeOfIndex(inst); |
| 11729 | const enum_ty = self.typeOf(un_op); | 11733 | const enum_ty = self.typeOf(un_op); |
| | 11734 | const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*); |
| 11730 | | 11735 | |
| 11731 | // We need a properly aligned and sized call frame to be able to call this function. | 11736 | // We need a properly aligned and sized call frame to be able to call this function. |
| 11732 | { | 11737 | { |
| ... | @@ -11744,9 +11749,9 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11744,9 +11749,9 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 11744 | } | 11749 | } |
| 11745 | | 11750 | |
| 11746 | try self.spillEflagsIfOccupied(); | 11751 | try self.spillEflagsIfOccupied(); |
| 11747 | try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*)); | 11752 | try self.spillRegisters(abi.getCallerPreservedRegs(resolved_cc)); |
| 11748 | | 11753 | |
| 11749 | const param_regs = abi.getCAbiIntParamRegs(self.target.*); | 11754 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 11750 | | 11755 | |
| 11751 | const dst_mcv = try self.allocRegOrMem(inst, false); | 11756 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 11752 | try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address()); | 11757 | try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address()); |
| ... | @@ -12523,23 +12528,25 @@ fn resolveCallingConventionValues( | ... | @@ -12523,23 +12528,25 @@ fn resolveCallingConventionValues( |
| 12523 | | 12528 | |
| 12524 | const ret_ty = fn_info.return_type.toType(); | 12529 | const ret_ty = fn_info.return_type.toType(); |
| 12525 | | 12530 | |
| | 12531 | const resolved_cc = abi.resolveCallingConvention(cc, self.target.*); |
| 12526 | switch (cc) { | 12532 | switch (cc) { |
| 12527 | .Naked => { | 12533 | .Naked => { |
| 12528 | assert(result.args.len == 0); | 12534 | assert(result.args.len == 0); |
| 12529 | result.return_value = InstTracking.init(.unreach); | 12535 | result.return_value = InstTracking.init(.unreach); |
| 12530 | result.stack_align = .@"8"; | 12536 | result.stack_align = .@"8"; |
| 12531 | }, | 12537 | }, |
| 12532 | .C => { | 12538 | .C, .SysV, .Win64 => { |
| 12533 | var param_reg_i: usize = 0; | 12539 | var param_reg_i: usize = 0; |
| 12534 | var param_sse_reg_i: usize = 0; | 12540 | var param_sse_reg_i: usize = 0; |
| 12535 | result.stack_align = .@"16"; | 12541 | result.stack_align = .@"16"; |
| 12536 | | 12542 | |
| 12537 | switch (self.target.os.tag) { | 12543 | switch (resolved_cc) { |
| 12538 | .windows => { | 12544 | .SysV => {}, |
| | 12545 | .Win64 => { |
| 12539 | // Align the stack to 16bytes before allocating shadow stack space (if any). | 12546 | // Align the stack to 16bytes before allocating shadow stack space (if any). |
| 12540 | result.stack_byte_count += @intCast(4 * Type.usize.abiSize(mod)); | 12547 | result.stack_byte_count += @intCast(4 * Type.usize.abiSize(mod)); |
| 12541 | }, | 12548 | }, |
| 12542 | else => {}, | 12549 | else => unreachable, |
| 12543 | } | 12550 | } |
| 12544 | | 12551 | |
| 12545 | // Return values | 12552 | // Return values |
| ... | @@ -12549,13 +12556,14 @@ fn resolveCallingConventionValues( | ... | @@ -12549,13 +12556,14 @@ fn resolveCallingConventionValues( |
| 12549 | // TODO: is this even possible for C calling convention? | 12556 | // TODO: is this even possible for C calling convention? |
| 12550 | result.return_value = InstTracking.init(.none); | 12557 | result.return_value = InstTracking.init(.none); |
| 12551 | } else { | 12558 | } else { |
| 12552 | const classes = switch (self.target.os.tag) { | 12559 | const classes = switch (resolved_cc) { |
| 12553 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, | 12560 | .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), |
| 12554 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), | 12561 | .Win64 => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, |
| | 12562 | else => unreachable, |
| 12555 | }; | 12563 | }; |
| 12556 | for ( | 12564 | for ( |
| 12557 | classes, | 12565 | classes, |
| 12558 | abi.getCAbiIntReturnRegs(self.target.*)[0..classes.len], | 12566 | abi.getCAbiIntReturnRegs(resolved_cc)[0..classes.len], |
| 12559 | 0.., | 12567 | 0.., |
| 12560 | ) |class, ret_reg, ret_reg_i| { | 12568 | ) |class, ret_reg, ret_reg_i| { |
| 12561 | result.return_value = switch (classes[0]) { | 12569 | result.return_value = switch (classes[0]) { |
| ... | @@ -12577,7 +12585,7 @@ fn resolveCallingConventionValues( | ... | @@ -12577,7 +12585,7 @@ fn resolveCallingConventionValues( |
| 12577 | .memory => switch (ret_reg_i) { | 12585 | .memory => switch (ret_reg_i) { |
| 12578 | 0 => ret: { | 12586 | 0 => ret: { |
| 12579 | const ret_indirect_reg = | 12587 | const ret_indirect_reg = |
| 12580 | abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; | 12588 | abi.getCAbiIntParamRegs(resolved_cc)[param_reg_i]; |
| 12581 | param_reg_i += 1; | 12589 | param_reg_i += 1; |
| 12582 | break :ret .{ | 12590 | break :ret .{ |
| 12583 | .short = .{ .indirect = .{ .reg = ret_reg } }, | 12591 | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| ... | @@ -12603,8 +12611,8 @@ fn resolveCallingConventionValues( | ... | @@ -12603,8 +12611,8 @@ fn resolveCallingConventionValues( |
| 12603 | }; | 12611 | }; |
| 12604 | for (classes, 0..) |class, class_i| { | 12612 | for (classes, 0..) |class, class_i| { |
| 12605 | switch (class) { | 12613 | switch (class) { |
| 12606 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { | 12614 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(resolved_cc).len) { |
| 12607 | const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; | 12615 | const param_reg = abi.getCAbiIntParamRegs(resolved_cc)[param_reg_i]; |
| 12608 | param_reg_i += 1; | 12616 | param_reg_i += 1; |
| 12609 | | 12617 | |
| 12610 | arg.* = switch (class_i) { | 12618 | arg.* = switch (class_i) { |
| ... | @@ -12661,13 +12669,13 @@ fn resolveCallingConventionValues( | ... | @@ -12661,13 +12669,13 @@ fn resolveCallingConventionValues( |
| 12661 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 12669 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 12662 | result.return_value = InstTracking.init(.none); | 12670 | result.return_value = InstTracking.init(.none); |
| 12663 | } else { | 12671 | } else { |
| 12664 | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; | 12672 | const ret_reg = abi.getCAbiIntReturnRegs(resolved_cc)[0]; |
| 12665 | const ret_ty_size: u31 = @intCast(ret_ty.abiSize(mod)); | 12673 | const ret_ty_size: u31 = @intCast(ret_ty.abiSize(mod)); |
| 12666 | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { | 12674 | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { |
| 12667 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); | 12675 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); |
| 12668 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; | 12676 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; |
| 12669 | } else { | 12677 | } else { |
| 12670 | const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[0]; | 12678 | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[0]; |
| 12671 | result.return_value = .{ | 12679 | result.return_value = .{ |
| 12672 | .short = .{ .indirect = .{ .reg = ret_reg } }, | 12680 | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 12673 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, | 12681 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |