authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-20 15:36:11+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-22 21:56:34+01:00
log358b5441570916a48f2f7df9ebe8b9cb5f87676b
treefba2051ea63f29e5dd2e3ab705f81f148f5d0ba2
parent630da643c664591846c295d75277475ca1801d75

x64: recover address in rdi if was spilled


1 files changed, 71 insertions(+), 16 deletions(-)

src/arch/x86_64/CodeGen.zig+71-16
......@@ -49,6 +49,8 @@ arg_index: u32,
4949src_loc: Module.SrcLoc,
5050stack_align: u32,
5151
52ret_backpatch: ?Mir.Inst.Index = null,
53
5254/// MIR Instructions
5355mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
5456/// MIR extra data
......@@ -470,6 +472,20 @@ fn gen(self: *Self) InnerError!void {
470472 };
471473 inline for (callee_preserved_regs) |reg, i| {
472474 if (self.register_manager.isRegAllocated(reg)) {
475 if (self.ret_backpatch) |inst| {
476 if (reg.to64() == .rdi) {
477 const ops = Mir.Ops.decode(self.mir_instructions.items(.ops)[inst]);
478 self.mir_instructions.set(inst, Mir.Inst{
479 .tag = .mov,
480 .ops = (Mir.Ops{
481 .reg1 = ops.reg1,
482 .reg2 = .rbp,
483 .flags = 0b01,
484 }).encode(),
485 .data = .{ .imm = @bitCast(u32, -@intCast(i32, self.max_end_stack + 8)) },
486 });
487 }
488 }
473489 data.regs |= 1 << @intCast(u5, i);
474490 self.max_end_stack += 8;
475491 }
......@@ -3143,14 +3159,28 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
31433159 return bt.finishAir(result);
31443160}
31453161
3146fn ret(self: *Self, mcv: MCValue) !void {
3162fn airRet(self: *Self, inst: Air.Inst.Index) !void {
3163 const un_op = self.air.instructions.items(.data)[inst].un_op;
3164 const operand = try self.resolveInst(un_op);
31473165 const ret_ty = self.fn_type.fnReturnType();
31483166 switch (self.ret_mcv) {
31493167 .stack_offset => {
3150 try self.genSetStack(ret_ty, 0, .rdi, mcv);
3168 // TODO audit register allocation!
3169 self.register_manager.freezeRegs(&.{.rdi});
3170 defer self.register_manager.unfreezeRegs(&.{.rdi});
3171 const reg = try self.register_manager.allocReg(null);
3172 self.ret_backpatch = try self.addInst(.{
3173 .tag = .mov,
3174 .ops = (Mir.Ops{
3175 .reg1 = reg,
3176 .reg2 = .rdi,
3177 }).encode(),
3178 .data = undefined,
3179 });
3180 try self.genSetStack(ret_ty, 0, reg, operand);
31513181 },
31523182 else => {
3153 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
3183 try self.setRegOrMem(ret_ty, self.ret_mcv, operand);
31543184 },
31553185 }
31563186 // TODO when implementing defer, this will need to jump to the appropriate defer expression.
......@@ -3164,21 +3194,49 @@ fn ret(self: *Self, mcv: MCValue) !void {
31643194 .data = .{ .inst = undefined },
31653195 });
31663196 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
3167}
3168
3169fn airRet(self: *Self, inst: Air.Inst.Index) !void {
3170 const un_op = self.air.instructions.items(.data)[inst].un_op;
3171 const operand = try self.resolveInst(un_op);
3172 try self.ret(operand);
31733197 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
31743198}
31753199
31763200fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
31773201 const un_op = self.air.instructions.items(.data)[inst].un_op;
31783202 const ptr = try self.resolveInst(un_op);
3179 // we can reuse self.ret_mcv because it just gets returned
3180 try self.load(self.ret_mcv, ptr, self.air.typeOf(un_op));
3181 try self.ret(self.ret_mcv);
3203 const ptr_ty = self.air.typeOf(un_op);
3204 const elem_ty = ptr_ty.elemType();
3205 switch (self.ret_mcv) {
3206 .stack_offset => {
3207 // TODO audit register allocation!
3208 self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi });
3209 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi });
3210 const reg = try self.register_manager.allocReg(null);
3211 self.ret_backpatch = try self.addInst(.{
3212 .tag = .mov,
3213 .ops = (Mir.Ops{
3214 .reg1 = reg,
3215 .reg2 = .rdi,
3216 }).encode(),
3217 .data = undefined,
3218 });
3219 try self.genInlineMemcpy(0, elem_ty, ptr, .{
3220 .source_stack_base = .rbp,
3221 .dest_stack_base = reg,
3222 });
3223 },
3224 else => {
3225 try self.load(self.ret_mcv, ptr, ptr_ty);
3226 try self.setRegOrMem(elem_ty, self.ret_mcv, self.ret_mcv);
3227 },
3228 }
3229 // TODO when implementing defer, this will need to jump to the appropriate defer expression.
3230 // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
3231 // which is available if the jump is 127 bytes or less forward.
3232 const jmp_reloc = try self.addInst(.{
3233 .tag = .jmp,
3234 .ops = (Mir.Ops{
3235 .flags = 0b00,
3236 }).encode(),
3237 .data = .{ .inst = undefined },
3238 });
3239 try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc);
31823240 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
31833241}
31843242
......@@ -4190,7 +4248,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts:
41904248 => {
41914249 break :blk try self.loadMemPtrIntoRegister(Type.usize, val);
41924250 },
4193 .stack_offset => |off| {
4251 .ptr_stack_offset, .stack_offset => |off| {
41944252 const addr_reg = (try self.register_manager.allocReg(null)).to64();
41954253 _ = try self.addInst(.{
41964254 .tag = .lea,
......@@ -5134,9 +5192,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
51345192 // First, split into args that can be passed via registers.
51355193 // This will make it easier to then push the rest of args in reverse
51365194 // order on the stack.
5137 // TODO if we want to be C ABI compatible (well, SysV compatible), passing return value
5138 // on the stack requires consuming `.rdi` set with the stack location where to save
5139 // the return value.
51405195 var next_int_reg: usize = 0;
51415196 var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator);
51425197 defer by_reg.deinit();