Commit 09e69c8c77

Jakub Konka <kubkon@jakubkonka.com>
2022-02-01 00:28:22
x86_64: start moving to new regalloc freeze API
1 parent 5cf9181
Changed files (2)
src
arch
test
behavior
src/arch/x86_64/CodeGen.zig
@@ -680,6 +680,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .wrap_errunion_err     => try self.airWrapErrUnionErr(inst),
             // zig fmt: on
         }
+
+        assert(!self.register_manager.frozenRegsExist());
+
         if (std.debug.runtime_safety) {
             if (self.air_bookkeeping < old_air_bookkeeping + 1) {
                 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[inst] });
@@ -827,9 +830,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
 /// Allocates a new register and copies `mcv` into it.
 /// `reg_owner` is the instruction that gets associated with the register in the register table.
 /// This can have a side effect of spilling instructions to the stack to free up a register.
-fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
+fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
     const reg = try self.register_manager.allocReg(reg_owner, &.{});
-    try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
+    try self.genSetReg(ty, reg, mcv);
     return MCValue{ .register = reg };
 }
 
@@ -838,11 +841,12 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa
 fn copyToNewRegisterWithExceptions(
     self: *Self,
     reg_owner: Air.Inst.Index,
+    ty: Type,
     mcv: MCValue,
     exceptions: []const Register,
 ) !MCValue {
     const reg = try self.register_manager.allocReg(reg_owner, exceptions);
-    try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
+    try self.genSetReg(ty, reg, mcv);
     return MCValue{ .register = reg };
 }
 
@@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
         if (operand_abi_size > 8 or dest_abi_size > 8) {
             return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
         }
-        const reg = switch (operand) {
-            .register => |src_reg| try self.register_manager.allocReg(inst, &.{src_reg}),
-            else => try self.register_manager.allocReg(inst, &.{}),
-        };
-        try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
-        try self.genSetReg(dest_ty, reg, operand);
-        break :blk .{ .register = registerAlias(reg, @intCast(u32, dest_abi_size)) };
+
+        if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register});
+        defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register});
+        break :blk try self.copyToNewRegister(inst, dest_ty, operand);
     };
 
     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
@@ -1208,7 +1209,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
         if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
             break :result operand;
         }
-        break :result try self.copyToNewRegister(inst, operand);
+        break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), operand);
     };
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
@@ -1479,16 +1480,11 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
         const index_ty = self.air.typeOf(extra.rhs);
         const index = try self.resolveInst(extra.rhs);
         const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
-        const dst_mcv = blk: {
-            switch (ptr) {
-                .ptr_stack_offset => {
-                    const reg = try self.register_manager.allocReg(inst, &.{offset_reg});
-                    try self.genSetReg(ptr_ty, reg, ptr);
-                    break :blk .{ .register = reg };
-                },
-                else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}),
-            }
-        };
+
+        self.register_manager.freezeRegs(&.{offset_reg});
+        defer self.register_manager.unfreezeRegs(&.{offset_reg});
+
+        const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, ptr);
         try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
         break :result dst_mcv;
     };
@@ -1859,13 +1855,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
     // Source operand can be an immediate, 8 bits or 32 bits.
     // So, if either one of the operands dies with this instruction, we can use it
     // as the result MCValue.
+    const dst_ty = self.air.typeOfIndex(inst);
     var dst_mcv: MCValue = undefined;
     var src_mcv: MCValue = undefined;
     if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
         // LHS dies; use it as the destination.
         // Both operands cannot be memory.
         if (lhs.isMemory() and rhs.isMemory()) {
-            dst_mcv = try self.copyToNewRegister(inst, lhs);
+            dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs);
             src_mcv = rhs;
         } else {
             dst_mcv = lhs;
@@ -1875,7 +1872,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
         // RHS dies; use it as the destination.
         // Both operands cannot be memory.
         if (lhs.isMemory() and rhs.isMemory()) {
-            dst_mcv = try self.copyToNewRegister(inst, rhs);
+            dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs);
             src_mcv = lhs;
         } else {
             dst_mcv = rhs;
@@ -1887,18 +1884,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
                 // If the allocated register is the same as the rhs register, don't allocate that one
                 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
                 // in the presence of several binary operations performed in a single block.
-                try self.copyToNewRegisterWithExceptions(inst, lhs, &.{rhs.register})
+                try self.copyToNewRegisterWithExceptions(inst, dst_ty, lhs, &.{rhs.register})
             else
-                try self.copyToNewRegister(inst, lhs);
+                try self.copyToNewRegister(inst, dst_ty, lhs);
             src_mcv = rhs;
         } else {
             dst_mcv = if (lhs.isRegister())
                 // If the allocated register is the same as the rhs register, don't allocate that one
                 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
                 // in the presence of several binary operations performed in a single block.
-                try self.copyToNewRegisterWithExceptions(inst, rhs, &.{lhs.register})
+                try self.copyToNewRegisterWithExceptions(inst, dst_ty, rhs, &.{lhs.register})
             else
-                try self.copyToNewRegister(inst, rhs);
+                try self.copyToNewRegister(inst, dst_ty, rhs);
             src_mcv = lhs;
         }
     }
@@ -1917,7 +1914,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
     }
 
     // Now for step 2, we assing an MIR instruction
-    const dst_ty = self.air.typeOfIndex(inst);
     const air_tags = self.air.instructions.items(.tag);
     switch (air_tags[inst]) {
         .add, .addwrap, .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
@@ -2417,7 +2413,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
             .register => |reg| {
                 if (Register.allocIndex(reg) == null) {
                     // Save function return value in a callee saved register
-                    break :result try self.copyToNewRegister(inst, info.return_value);
+                    break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), info.return_value);
                 }
             },
             else => {},
@@ -2494,7 +2490,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
         // Either one, but not both, can be a memory operand.
         // Source operand can be an immediate, 8 bits or 32 bits.
         const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))
-            try self.copyToNewRegister(inst, lhs)
+            try self.copyToNewRegister(inst, ty, lhs)
         else
             lhs;
         // This instruction supports only signed 32-bit immediates at most.
test/behavior/cast.zig
@@ -5,8 +5,6 @@ const maxInt = std.math.maxInt;
 const builtin = @import("builtin");
 
 test "int to ptr cast" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-
     const x = @as(usize, 13);
     const y = @intToPtr(*u8, x);
     const z = @ptrToInt(y);
@@ -14,8 +12,6 @@ test "int to ptr cast" {
 }
 
 test "integer literal to pointer cast" {
-    if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
-
     const vga_mem = @intToPtr(*u16, 0xB8000);
     try expect(@ptrToInt(vga_mem) == 0xB8000);
 }