| ... | @@ -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: on | 681 | // 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. |
| 830 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 833 | fn 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 | } |
| 835 | | 838 | |
| ... | @@ -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 |
| 838 | fn copyToNewRegisterWithExceptions( | 841 | fn 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 | } |
| 848 | | 852 | |
| ... | @@ -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 | }; |
| 903 | | 904 | |
| 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 it | 1856 | // 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 one | 1884 | // 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 miscompilation | 1885 | // 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 | else | 1888 | 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 one | 1893 | // 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 miscompilation | 1894 | // 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 | else | 1897 | 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 | } |
| 1918 | | 1915 | |
| 1919 | // Now for step 2, we assing an MIR instruction | 1916 | // 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 register | 2415 | // 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 | else | 2494 | 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. |