| ... | ... | @@ -58,7 +58,6 @@ arg_index: u32, |
| 58 | 58 | src_loc: Module.SrcLoc, |
| 59 | 59 | stack_align: u32, |
| 60 | 60 | |
| 61 | | ret_backpatches: std.ArrayListUnmanaged(Mir.Inst.Index) = .{}, |
| 62 | 61 | compare_flags_inst: ?Air.Inst.Index = null, |
| 63 | 62 | |
| 64 | 63 | /// MIR Instructions |
| ... | ... | @@ -353,7 +352,6 @@ pub fn generate( |
| 353 | 352 | std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index).init(bin_file.allocator) |
| 354 | 353 | else {}, |
| 355 | 354 | }; |
| 356 | | defer function.ret_backpatches.deinit(bin_file.allocator); |
| 357 | 355 | defer function.stack.deinit(bin_file.allocator); |
| 358 | 356 | defer function.blocks.deinit(bin_file.allocator); |
| 359 | 357 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| ... | ... | @@ -482,6 +480,21 @@ fn gen(self: *Self) InnerError!void { |
| 482 | 480 | .data = undefined, |
| 483 | 481 | }); |
| 484 | 482 | |
| 483 | if (self.ret_mcv == .stack_offset) { |
| 484 | // The address where to store the return value for the caller is in `.rdi` |
| 485 | // register which the callee is free to clobber. Therefore, we purposely |
| 486 | // spill it to stack immediately. |
| 487 | const ptr_ty = Type.usize; |
| 488 | const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*)); |
| 489 | const abi_align = ptr_ty.abiAlignment(self.target.*); |
| 490 | const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align); |
| 491 | self.next_stack_offset = stack_offset; |
| 492 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 493 | try self.genSetStack(ptr_ty, @intCast(i32, stack_offset), MCValue{ .register = .rdi }, .{}); |
| 494 | self.ret_mcv = MCValue{ .stack_offset = @intCast(i32, stack_offset) }; |
| 495 | log.debug("gen: spilling .rdi to stack at offset {}", .{stack_offset}); |
| 496 | } |
| 497 | |
| 485 | 498 | _ = try self.addInst(.{ |
| 486 | 499 | .tag = .dbg_prologue_end, |
| 487 | 500 | .ops = undefined, |
| ... | ... | @@ -519,23 +532,6 @@ fn gen(self: *Self) InnerError!void { |
| 519 | 532 | var disp = data.disp + 8; |
| 520 | 533 | inline for (callee_preserved_regs) |reg, i| { |
| 521 | 534 | if (self.register_manager.isRegAllocated(reg)) { |
| 522 | | if (reg.to64() == .rdi) { |
| 523 | | for (self.ret_backpatches.items) |inst| { |
| 524 | | log.debug(".rdi was spilled, backpatching with mov from stack at offset {}", .{ |
| 525 | | -@intCast(i32, disp), |
| 526 | | }); |
| 527 | | const ops = Mir.Ops.decode(self.mir_instructions.items(.ops)[inst]); |
| 528 | | self.mir_instructions.set(inst, Mir.Inst{ |
| 529 | | .tag = .mov, |
| 530 | | .ops = (Mir.Ops{ |
| 531 | | .reg1 = ops.reg1, |
| 532 | | .reg2 = .rbp, |
| 533 | | .flags = 0b01, |
| 534 | | }).encode(), |
| 535 | | .data = .{ .imm = @bitCast(u32, -@intCast(i32, disp)) }, |
| 536 | | }); |
| 537 | | } |
| 538 | | } |
| 539 | 535 | data.regs |= 1 << @intCast(u5, i); |
| 540 | 536 | self.max_end_stack += 8; |
| 541 | 537 | disp += 8; |
| ... | ... | @@ -912,8 +908,7 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 912 | 908 | // TODO find a free slot instead of always appending |
| 913 | 909 | const offset = mem.alignForwardGeneric(u32, self.next_stack_offset + abi_size, abi_align); |
| 914 | 910 | self.next_stack_offset = offset; |
| 915 | | if (self.next_stack_offset > self.max_end_stack) |
| 916 | | self.max_end_stack = self.next_stack_offset; |
| 911 | self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset); |
| 917 | 912 | try self.stack.putNoClobber(self.gpa, offset, .{ |
| 918 | 913 | .inst = inst, |
| 919 | 914 | .size = abi_size, |
| ... | ... | @@ -3316,7 +3311,6 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3316 | 3311 | } |
| 3317 | 3312 | |
| 3318 | 3313 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 3319 | | /// Does not use/spill .rax/.rdx. |
| 3320 | 3314 | /// Does not support byte-size operands. |
| 3321 | 3315 | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 3322 | 3316 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| ... | ... | @@ -3530,10 +3524,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3530 | 3524 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3531 | 3525 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 3532 | 3526 | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); |
| 3527 | log.debug("airCall: return value on stack at offset {}", .{stack_offset}); |
| 3533 | 3528 | |
| 3534 | 3529 | try self.register_manager.getReg(.rdi, null); |
| 3535 | | self.register_manager.freezeRegs(&.{.rdi}); |
| 3536 | 3530 | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); |
| 3531 | self.register_manager.freezeRegs(&.{.rdi}); |
| 3537 | 3532 | |
| 3538 | 3533 | info.return_value.stack_offset = stack_offset; |
| 3539 | 3534 | } |
| ... | ... | @@ -3720,15 +3715,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3720 | 3715 | |
| 3721 | 3716 | const result: MCValue = result: { |
| 3722 | 3717 | switch (info.return_value) { |
| 3723 | | .register => |reg| { |
| 3724 | | if (RegisterManager.indexOfRegIntoTracked(reg) == null) { |
| 3725 | | // Save function return value in a callee saved register |
| 3726 | | break :result try self.copyToRegisterWithInstTracking( |
| 3727 | | inst, |
| 3728 | | self.air.typeOfIndex(inst), |
| 3729 | | info.return_value, |
| 3730 | | ); |
| 3731 | | } |
| 3718 | .register => { |
| 3719 | // Save function return value in a new register |
| 3720 | break :result try self.copyToRegisterWithInstTracking( |
| 3721 | inst, |
| 3722 | self.air.typeOfIndex(inst), |
| 3723 | info.return_value, |
| 3724 | ); |
| 3732 | 3725 | }, |
| 3733 | 3726 | else => {}, |
| 3734 | 3727 | } |
| ... | ... | @@ -3755,19 +3748,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 3755 | 3748 | const ret_ty = self.fn_type.fnReturnType(); |
| 3756 | 3749 | switch (self.ret_mcv) { |
| 3757 | 3750 | .stack_offset => { |
| 3758 | | // TODO audit register allocation! |
| 3759 | | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3760 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3761 | | const reg = try self.register_manager.allocReg(null); |
| 3762 | | const backpatch = try self.addInst(.{ |
| 3763 | | .tag = .mov, |
| 3764 | | .ops = (Mir.Ops{ |
| 3765 | | .reg1 = reg, |
| 3766 | | .reg2 = .rdi, |
| 3767 | | }).encode(), |
| 3768 | | .data = undefined, |
| 3769 | | }); |
| 3770 | | try self.ret_backpatches.append(self.gpa, backpatch); |
| 3751 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3752 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3753 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3754 | self.register_manager.freezeRegs(&.{reg}); |
| 3755 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 3771 | 3756 | try self.genSetStack(ret_ty, 0, operand, .{ |
| 3772 | 3757 | .source_stack_base = .rbp, |
| 3773 | 3758 | .dest_stack_base = reg, |
| ... | ... | @@ -3798,19 +3783,11 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3798 | 3783 | const elem_ty = ptr_ty.elemType(); |
| 3799 | 3784 | switch (self.ret_mcv) { |
| 3800 | 3785 | .stack_offset => { |
| 3801 | | // TODO audit register allocation! |
| 3802 | | self.register_manager.freezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3803 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rdi }); |
| 3804 | | const reg = try self.register_manager.allocReg(null); |
| 3805 | | const backpatch = try self.addInst(.{ |
| 3806 | | .tag = .mov, |
| 3807 | | .ops = (Mir.Ops{ |
| 3808 | | .reg1 = reg, |
| 3809 | | .reg2 = .rdi, |
| 3810 | | }).encode(), |
| 3811 | | .data = undefined, |
| 3812 | | }); |
| 3813 | | try self.ret_backpatches.append(self.gpa, backpatch); |
| 3786 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3787 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3788 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3789 | self.register_manager.freezeRegs(&.{reg}); |
| 3790 | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 3814 | 3791 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, ptr, .{ .immediate = elem_ty.abiSize(self.target.*) }, .{ |
| 3815 | 3792 | .source_stack_base = .rbp, |
| 3816 | 3793 | .dest_stack_base = reg, |
| ... | ... | @@ -5092,6 +5069,7 @@ const InlineMemcpyOpts = struct { |
| 5092 | 5069 | dest_stack_base: ?Register = null, |
| 5093 | 5070 | }; |
| 5094 | 5071 | |
| 5072 | /// Spills .rax and .rcx. |
| 5095 | 5073 | fn genInlineMemcpy( |
| 5096 | 5074 | self: *Self, |
| 5097 | 5075 | dst_ptr: MCValue, |
| ... | ... | @@ -5099,13 +5077,7 @@ fn genInlineMemcpy( |
| 5099 | 5077 | len: MCValue, |
| 5100 | 5078 | opts: InlineMemcpyOpts, |
| 5101 | 5079 | ) InnerError!void { |
| 5102 | | // TODO this is wrong. We should check first if any of the operands is in `.rax` or `.rcx` before |
| 5103 | | // spilling. Consolidate with other TODOs regarding register allocation mechanics. |
| 5104 | | try self.register_manager.getReg(.rax, null); |
| 5105 | | try self.register_manager.getReg(.rcx, null); |
| 5106 | | |
| 5107 | 5080 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 5108 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 5109 | 5081 | |
| 5110 | 5082 | if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 5111 | 5083 | defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| ... | ... | @@ -5145,7 +5117,6 @@ fn genInlineMemcpy( |
| 5145 | 5117 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); |
| 5146 | 5118 | }, |
| 5147 | 5119 | } |
| 5148 | | |
| 5149 | 5120 | self.register_manager.freezeRegs(&.{dst_addr_reg}); |
| 5150 | 5121 | defer self.register_manager.unfreezeRegs(&.{dst_addr_reg}); |
| 5151 | 5122 | |
| ... | ... | @@ -5181,7 +5152,6 @@ fn genInlineMemcpy( |
| 5181 | 5152 | return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr}); |
| 5182 | 5153 | }, |
| 5183 | 5154 | } |
| 5184 | | |
| 5185 | 5155 | self.register_manager.freezeRegs(&.{src_addr_reg}); |
| 5186 | 5156 | defer self.register_manager.unfreezeRegs(&.{src_addr_reg}); |
| 5187 | 5157 | |
| ... | ... | @@ -5189,6 +5159,11 @@ fn genInlineMemcpy( |
| 5189 | 5159 | const count_reg = regs[0].to64(); |
| 5190 | 5160 | const tmp_reg = regs[1].to8(); |
| 5191 | 5161 | |
| 5162 | self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 5163 | |
| 5164 | try self.register_manager.getReg(.rax, null); |
| 5165 | try self.register_manager.getReg(.rcx, null); |
| 5166 | |
| 5192 | 5167 | try self.genSetReg(Type.usize, count_reg, len); |
| 5193 | 5168 | |
| 5194 | 5169 | // mov rcx, 0 |
| ... | ... | @@ -5284,6 +5259,7 @@ fn genInlineMemcpy( |
| 5284 | 5259 | try self.performReloc(loop_reloc); |
| 5285 | 5260 | } |
| 5286 | 5261 | |
| 5262 | /// Spills .rax register. |
| 5287 | 5263 | fn genInlineMemset( |
| 5288 | 5264 | self: *Self, |
| 5289 | 5265 | dst_ptr: MCValue, |
| ... | ... | @@ -5291,9 +5267,7 @@ fn genInlineMemset( |
| 5291 | 5267 | len: MCValue, |
| 5292 | 5268 | opts: InlineMemcpyOpts, |
| 5293 | 5269 | ) InnerError!void { |
| 5294 | | try self.register_manager.getReg(.rax, null); |
| 5295 | 5270 | self.register_manager.freezeRegs(&.{.rax}); |
| 5296 | | defer self.register_manager.unfreezeRegs(&.{.rax}); |
| 5297 | 5271 | |
| 5298 | 5272 | const addr_reg = try self.register_manager.allocReg(null); |
| 5299 | 5273 | switch (dst_ptr) { |
| ... | ... | @@ -5330,6 +5304,9 @@ fn genInlineMemset( |
| 5330 | 5304 | self.register_manager.freezeRegs(&.{addr_reg}); |
| 5331 | 5305 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 5332 | 5306 | |
| 5307 | self.register_manager.unfreezeRegs(&.{.rax}); |
| 5308 | try self.register_manager.getReg(.rax, null); |
| 5309 | |
| 5333 | 5310 | try self.genSetReg(Type.usize, .rax, len); |
| 5334 | 5311 | try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); |
| 5335 | 5312 | |