authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-01 00:28:22+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-02 10:48:21+01:00
log09e69c8c776d21be5441a0b15f13a3ce9608ab87
tree7a0186cfb08b184778ff0a9d5f0cbed01c696a3d
parent5cf918143c7c5857142ac12c3587928ed74b2052

x86_64: start moving to new regalloc freeze API


2 files changed, 26 insertions(+), 34 deletions(-)

src/arch/x86_64/CodeGen.zig+26-30
...@@ -680,6 +680,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -680,6 +680,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
680 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),680 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
681 // zig fmt: on681 // zig fmt: on
682 }682 }
683
684 assert(!self.register_manager.frozenRegsExist());
685
683 if (std.debug.runtime_safety) {686 if (std.debug.runtime_safety) {
684 if (self.air_bookkeeping < old_air_bookkeeping + 1) {687 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
685 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] });688 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 {...@@ -827,9 +830,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
827/// Allocates a new register and copies `mcv` into it.830/// Allocates a new register and copies `mcv` into it.
828/// `reg_owner` is the instruction that gets associated with the register in the register table.831/// `reg_owner` is the instruction that gets associated with the register in the register table.
829/// This can have a side effect of spilling instructions to the stack to free up a register.832/// This can have a side effect of spilling instructions to the stack to free up a register.
830fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {833fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
831 const reg = try self.register_manager.allocReg(reg_owner, &.{});834 const reg = try self.register_manager.allocReg(reg_owner, &.{});
832 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);835 try self.genSetReg(ty, reg, mcv);
833 return MCValue{ .register = reg };836 return MCValue{ .register = reg };
834}837}
835838
...@@ -838,11 +841,12 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa...@@ -838,11 +841,12 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa
838fn copyToNewRegisterWithExceptions(841fn copyToNewRegisterWithExceptions(
839 self: *Self,842 self: *Self,
840 reg_owner: Air.Inst.Index,843 reg_owner: Air.Inst.Index,
844 ty: Type,
841 mcv: MCValue,845 mcv: MCValue,
842 exceptions: []const Register,846 exceptions: []const Register,
843) !MCValue {847) !MCValue {
844 const reg = try self.register_manager.allocReg(reg_owner, exceptions);848 const reg = try self.register_manager.allocReg(reg_owner, exceptions);
845 try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);849 try self.genSetReg(ty, reg, mcv);
846 return MCValue{ .register = reg };850 return MCValue{ .register = reg };
847}851}
848852
...@@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
892 if (operand_abi_size > 8 or dest_abi_size > 8) {896 if (operand_abi_size > 8 or dest_abi_size > 8) {
893 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});897 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
894 }898 }
895 const reg = switch (operand) {899
896 .register => |src_reg| try self.register_manager.allocReg(inst, &.{src_reg}),900 if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register});
897 else => try self.register_manager.allocReg(inst, &.{}),901 defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register});
898 };902 break :blk try self.copyToNewRegister(inst, dest_ty, operand);
899 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
900 try self.genSetReg(dest_ty, reg, operand);
901 break :blk .{ .register = registerAlias(reg, @intCast(u32, dest_abi_size)) };
902 };903 };
903904
904 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });905 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
...@@ -1208,7 +1209,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1208,7 +1209,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
1208 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {1209 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
1209 break :result operand;1210 break :result operand;
1210 }1211 }
1211 break :result try self.copyToNewRegister(inst, operand);1212 break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), operand);
1212 };1213 };
1213 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1214 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1214}1215}
...@@ -1479,16 +1480,11 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1479,16 +1480,11 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1479 const index_ty = self.air.typeOf(extra.rhs);1480 const index_ty = self.air.typeOf(extra.rhs);
1480 const index = try self.resolveInst(extra.rhs);1481 const index = try self.resolveInst(extra.rhs);
1481 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);1482 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
1482 const dst_mcv = blk: {1483
1483 switch (ptr) {1484 self.register_manager.freezeRegs(&.{offset_reg});
1484 .ptr_stack_offset => {1485 defer self.register_manager.unfreezeRegs(&.{offset_reg});
1485 const reg = try self.register_manager.allocReg(inst, &.{offset_reg});1486
1486 try self.genSetReg(ptr_ty, reg, ptr);1487 const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, ptr);
1487 break :blk .{ .register = reg };
1488 },
1489 else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}),
1490 }
1491 };
1492 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });1488 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
1493 break :result dst_mcv;1489 break :result dst_mcv;
1494 };1490 };
...@@ -1859,13 +1855,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -1859,13 +1855,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1859 // Source operand can be an immediate, 8 bits or 32 bits.1855 // Source operand can be an immediate, 8 bits or 32 bits.
1860 // So, if either one of the operands dies with this instruction, we can use it1856 // So, if either one of the operands dies with this instruction, we can use it
1861 // as the result MCValue.1857 // as the result MCValue.
1858 const dst_ty = self.air.typeOfIndex(inst);
1862 var dst_mcv: MCValue = undefined;1859 var dst_mcv: MCValue = undefined;
1863 var src_mcv: MCValue = undefined;1860 var src_mcv: MCValue = undefined;
1864 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {1861 if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
1865 // LHS dies; use it as the destination.1862 // LHS dies; use it as the destination.
1866 // Both operands cannot be memory.1863 // Both operands cannot be memory.
1867 if (lhs.isMemory() and rhs.isMemory()) {1864 if (lhs.isMemory() and rhs.isMemory()) {
1868 dst_mcv = try self.copyToNewRegister(inst, lhs);1865 dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs);
1869 src_mcv = rhs;1866 src_mcv = rhs;
1870 } else {1867 } else {
1871 dst_mcv = lhs;1868 dst_mcv = lhs;
...@@ -1875,7 +1872,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -1875,7 +1872,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1875 // RHS dies; use it as the destination.1872 // RHS dies; use it as the destination.
1876 // Both operands cannot be memory.1873 // Both operands cannot be memory.
1877 if (lhs.isMemory() and rhs.isMemory()) {1874 if (lhs.isMemory() and rhs.isMemory()) {
1878 dst_mcv = try self.copyToNewRegister(inst, rhs);1875 dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs);
1879 src_mcv = lhs;1876 src_mcv = lhs;
1880 } else {1877 } else {
1881 dst_mcv = rhs;1878 dst_mcv = rhs;
...@@ -1887,18 +1884,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -1887,18 +1884,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1887 // If the allocated register is the same as the rhs register, don't allocate that one1884 // If the allocated register is the same as the rhs register, don't allocate that one
1888 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation1885 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
1889 // in the presence of several binary operations performed in a single block.1886 // in the presence of several binary operations performed in a single block.
1890 try self.copyToNewRegisterWithExceptions(inst, lhs, &.{rhs.register})1887 try self.copyToNewRegisterWithExceptions(inst, dst_ty, lhs, &.{rhs.register})
1891 else1888 else
1892 try self.copyToNewRegister(inst, lhs);1889 try self.copyToNewRegister(inst, dst_ty, lhs);
1893 src_mcv = rhs;1890 src_mcv = rhs;
1894 } else {1891 } else {
1895 dst_mcv = if (lhs.isRegister())1892 dst_mcv = if (lhs.isRegister())
1896 // If the allocated register is the same as the rhs register, don't allocate that one1893 // If the allocated register is the same as the rhs register, don't allocate that one
1897 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation1894 // and instead spill a subsequent one. Otherwise, this can result in a miscompilation
1898 // in the presence of several binary operations performed in a single block.1895 // in the presence of several binary operations performed in a single block.
1899 try self.copyToNewRegisterWithExceptions(inst, rhs, &.{lhs.register})1896 try self.copyToNewRegisterWithExceptions(inst, dst_ty, rhs, &.{lhs.register})
1900 else1897 else
1901 try self.copyToNewRegister(inst, rhs);1898 try self.copyToNewRegister(inst, dst_ty, rhs);
1902 src_mcv = lhs;1899 src_mcv = lhs;
1903 }1900 }
1904 }1901 }
...@@ -1917,7 +1914,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:...@@ -1917,7 +1914,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
1917 }1914 }
19181915
1919 // Now for step 2, we assing an MIR instruction1916 // Now for step 2, we assing an MIR instruction
1920 const dst_ty = self.air.typeOfIndex(inst);
1921 const air_tags = self.air.instructions.items(.tag);1917 const air_tags = self.air.instructions.items(.tag);
1922 switch (air_tags[inst]) {1918 switch (air_tags[inst]) {
1923 .add, .addwrap, .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),1919 .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 {...@@ -2417,7 +2413,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2417 .register => |reg| {2413 .register => |reg| {
2418 if (Register.allocIndex(reg) == null) {2414 if (Register.allocIndex(reg) == null) {
2419 // Save function return value in a callee saved register2415 // Save function return value in a callee saved register
2420 break :result try self.copyToNewRegister(inst, info.return_value);2416 break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), info.return_value);
2421 }2417 }
2422 },2418 },
2423 else => {},2419 else => {},
...@@ -2494,7 +2490,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2494,7 +2490,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2494 // Either one, but not both, can be a memory operand.2490 // Either one, but not both, can be a memory operand.
2495 // Source operand can be an immediate, 8 bits or 32 bits.2491 // Source operand can be an immediate, 8 bits or 32 bits.
2496 const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))2492 const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))
2497 try self.copyToNewRegister(inst, lhs)2493 try self.copyToNewRegister(inst, ty, lhs)
2498 else2494 else
2499 lhs;2495 lhs;
2500 // This instruction supports only signed 32-bit immediates at most.2496 // This instruction supports only signed 32-bit immediates at most.
test/behavior/cast.zig-4
...@@ -5,8 +5,6 @@ const maxInt = std.math.maxInt;...@@ -5,8 +5,6 @@ const maxInt = std.math.maxInt;
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7test "int to ptr cast" {7test "int to ptr cast" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
9
10 const x = @as(usize, 13);8 const x = @as(usize, 13);
11 const y = @intToPtr(*u8, x);9 const y = @intToPtr(*u8, x);
12 const z = @ptrToInt(y);10 const z = @ptrToInt(y);
...@@ -14,8 +12,6 @@ test "int to ptr cast" {...@@ -14,8 +12,6 @@ test "int to ptr cast" {
14}12}
1513
16test "integer literal to pointer cast" {14test "integer literal to pointer cast" {
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
18
19 const vga_mem = @intToPtr(*u16, 0xB8000);15 const vga_mem = @intToPtr(*u16, 0xB8000);
20 try expect(@ptrToInt(vga_mem) == 0xB8000);16 try expect(@ptrToInt(vga_mem) == 0xB8000);
21}17}