| ... | ... | @@ -439,16 +439,17 @@ fn gen(self: *Self) InnerError!void { |
| 439 | 439 | }); |
| 440 | 440 | |
| 441 | 441 | if (self.ret_mcv == .stack_offset) { |
| 442 | | // The address where to store the return value for the caller is in `.rdi` |
| 442 | // The address where to store the return value for the caller is in a |
| 443 | 443 | // register which the callee is free to clobber. Therefore, we purposely |
| 444 | 444 | // spill it to stack immediately. |
| 445 | 445 | const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset + 8, 8); |
| 446 | 446 | self.next_stack_offset = stack_offset; |
| 447 | 447 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 448 | 448 | |
| 449 | | try self.genSetStack(Type.usize, @intCast(i32, stack_offset), MCValue{ .register = .rdi }, .{}); |
| 449 | const ret_reg = abi.getCAbiIntParamRegs(self.target.*)[0]; |
| 450 | try self.genSetStack(Type.usize, @intCast(i32, stack_offset), MCValue{ .register = ret_reg }, .{}); |
| 450 | 451 | self.ret_mcv = MCValue{ .stack_offset = @intCast(i32, stack_offset) }; |
| 451 | | log.debug("gen: spilling .rdi to stack at offset {}", .{stack_offset}); |
| 452 | log.debug("gen: spilling {s} to stack at offset {}", .{ @tagName(ret_reg), stack_offset }); |
| 452 | 453 | } |
| 453 | 454 | |
| 454 | 455 | _ = try self.addInst(.{ |
| ... | ... | @@ -831,7 +832,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 831 | 832 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 832 | 833 | const air_tags = self.air.instructions.items(.tag); |
| 833 | 834 | if (air_tags[inst] == .constant) return; // Constants are immortal. |
| 834 | | log.debug("%{d} => {}", .{ inst, MCValue.dead }); |
| 835 | log.debug("%{d} => {}", .{ inst, MCValue{ .dead = {} } }); |
| 835 | 836 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 836 | 837 | const prev_value = self.getResolvedInstValue(inst); |
| 837 | 838 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | ... | @@ -3960,7 +3961,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3960 | 3961 | try self.register_manager.getReg(reg, null); |
| 3961 | 3962 | } |
| 3962 | 3963 | |
| 3963 | | const rdi_lock: ?RegisterLock = blk: { |
| 3964 | const ret_reg_lock: ?RegisterLock = blk: { |
| 3964 | 3965 | if (info.return_value == .stack_offset) { |
| 3965 | 3966 | const ret_ty = fn_ty.fnReturnType(); |
| 3966 | 3967 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| ... | ... | @@ -3968,17 +3969,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3968 | 3969 | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); |
| 3969 | 3970 | log.debug("airCall: return value on stack at offset {}", .{stack_offset}); |
| 3970 | 3971 | |
| 3971 | | try self.register_manager.getReg(.rdi, null); |
| 3972 | | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); |
| 3973 | | const rdi_lock = self.register_manager.lockRegAssumeUnused(.rdi); |
| 3972 | const ret_reg = abi.getCAbiIntParamRegs(self.target.*)[0]; |
| 3973 | try self.register_manager.getReg(ret_reg, null); |
| 3974 | try self.genSetReg(Type.usize, ret_reg, .{ .ptr_stack_offset = stack_offset }); |
| 3975 | const ret_reg_lock = self.register_manager.lockRegAssumeUnused(ret_reg); |
| 3974 | 3976 | |
| 3975 | 3977 | info.return_value.stack_offset = stack_offset; |
| 3976 | 3978 | |
| 3977 | | break :blk rdi_lock; |
| 3979 | break :blk ret_reg_lock; |
| 3978 | 3980 | } |
| 3979 | 3981 | break :blk null; |
| 3980 | 3982 | }; |
| 3981 | | defer if (rdi_lock) |lock| self.register_manager.unlockReg(lock); |
| 3983 | defer if (ret_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3982 | 3984 | |
| 3983 | 3985 | for (args) |arg, arg_i| { |
| 3984 | 3986 | const mc_arg = info.args[arg_i]; |
| ... | ... | @@ -7292,11 +7294,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 7292 | 7294 | assert(ret_ty.isError()); |
| 7293 | 7295 | result.return_value = .{ .immediate = 0 }; |
| 7294 | 7296 | } else if (ret_ty_size <= 8) { |
| 7295 | | result.return_value = .{ .register = .rdi }; |
| 7297 | const aliased_reg = registerAlias(abi.getCAbiIntReturnRegs(self.target.*)[0], ret_ty_size); |
| 7298 | result.return_value = .{ .register = aliased_reg }; |
| 7296 | 7299 | } else { |
| 7297 | 7300 | // We simply make the return MCValue a stack offset. However, the actual value |
| 7298 | 7301 | // for the offset will be populated later. We will also push the stack offset |
| 7299 | | // value into .rdi register when we resolve the offset. |
| 7302 | // value into an appropriate register when we resolve the offset. |
| 7300 | 7303 | result.return_value = .{ .stack_offset = 0 }; |
| 7301 | 7304 | } |
| 7302 | 7305 | } |