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