| ... | @@ -49,6 +49,8 @@ arg_index: u32, | ... | @@ -49,6 +49,8 @@ arg_index: u32, |
| 49 | src_loc: Module.SrcLoc, | 49 | src_loc: Module.SrcLoc, |
| 50 | stack_align: u32, | 50 | stack_align: u32, |
| 51 | | 51 | |
| | 52 | ret_backpatch: ?Mir.Inst.Index = null, |
| | 53 | |
| 52 | /// MIR Instructions | 54 | /// MIR Instructions |
| 53 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, | 55 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| 54 | /// MIR extra data | 56 | /// MIR extra data |
| ... | @@ -470,6 +472,20 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -470,6 +472,20 @@ fn gen(self: *Self) InnerError!void { |
| 470 | }; | 472 | }; |
| 471 | inline for (callee_preserved_regs) |reg, i| { | 473 | inline for (callee_preserved_regs) |reg, i| { |
| 472 | if (self.register_manager.isRegAllocated(reg)) { | 474 | 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 | } |
| 473 | data.regs |= 1 << @intCast(u5, i); | 489 | data.regs |= 1 << @intCast(u5, i); |
| 474 | self.max_end_stack += 8; | 490 | self.max_end_stack += 8; |
| 475 | } | 491 | } |
| ... | @@ -3143,14 +3159,28 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3143,14 +3159,28 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 3143 | return bt.finishAir(result); | 3159 | return bt.finishAir(result); |
| 3144 | } | 3160 | } |
| 3145 | | 3161 | |
| 3146 | fn ret(self: *Self, mcv: MCValue) !void { | 3162 | fn 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); |
| 3147 | const ret_ty = self.fn_type.fnReturnType(); | 3165 | const ret_ty = self.fn_type.fnReturnType(); |
| 3148 | switch (self.ret_mcv) { | 3166 | switch (self.ret_mcv) { |
| 3149 | .stack_offset => { | 3167 | .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); |
| 3151 | }, | 3181 | }, |
| 3152 | else => { | 3182 | else => { |
| 3153 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); | 3183 | try self.setRegOrMem(ret_ty, self.ret_mcv, operand); |
| 3154 | }, | 3184 | }, |
| 3155 | } | 3185 | } |
| 3156 | // TODO when implementing defer, this will need to jump to the appropriate defer expression. | 3186 | // 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 { | ... | @@ -3164,21 +3194,49 @@ fn ret(self: *Self, mcv: MCValue) !void { |
| 3164 | .data = .{ .inst = undefined }, | 3194 | .data = .{ .inst = undefined }, |
| 3165 | }); | 3195 | }); |
| 3166 | try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); | 3196 | try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); |
| 3167 | } | | |
| 3168 | | | |
| 3169 | fn 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); | | |
| 3173 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); | 3197 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 3174 | } | 3198 | } |
| 3175 | | 3199 | |
| 3176 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | 3200 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3177 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 3201 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 3178 | const ptr = try self.resolveInst(un_op); | 3202 | const ptr = try self.resolveInst(un_op); |
| 3179 | // we can reuse self.ret_mcv because it just gets returned | 3203 | const ptr_ty = self.air.typeOf(un_op); |
| 3180 | try self.load(self.ret_mcv, ptr, self.air.typeOf(un_op)); | 3204 | const elem_ty = ptr_ty.elemType(); |
| 3181 | try self.ret(self.ret_mcv); | 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); |
| 3182 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); | 3240 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 3183 | } | 3241 | } |
| 3184 | | 3242 | |
| ... | @@ -4190,7 +4248,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: | ... | @@ -4190,7 +4248,7 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, ty: Type, val: MCValue, opts: |
| 4190 | => { | 4248 | => { |
| 4191 | break :blk try self.loadMemPtrIntoRegister(Type.usize, val); | 4249 | break :blk try self.loadMemPtrIntoRegister(Type.usize, val); |
| 4192 | }, | 4250 | }, |
| 4193 | .stack_offset => |off| { | 4251 | .ptr_stack_offset, .stack_offset => |off| { |
| 4194 | const addr_reg = (try self.register_manager.allocReg(null)).to64(); | 4252 | const addr_reg = (try self.register_manager.allocReg(null)).to64(); |
| 4195 | _ = try self.addInst(.{ | 4253 | _ = try self.addInst(.{ |
| 4196 | .tag = .lea, | 4254 | .tag = .lea, |
| ... | @@ -5134,9 +5192,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -5134,9 +5192,6 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5134 | // First, split into args that can be passed via registers. | 5192 | // First, split into args that can be passed via registers. |
| 5135 | // This will make it easier to then push the rest of args in reverse | 5193 | // This will make it easier to then push the rest of args in reverse |
| 5136 | // order on the stack. | 5194 | // 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. | | |
| 5140 | var next_int_reg: usize = 0; | 5195 | var next_int_reg: usize = 0; |
| 5141 | var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator); | 5196 | var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator); |
| 5142 | defer by_reg.deinit(); | 5197 | defer by_reg.deinit(); |