| ... | ... | @@ -680,6 +680,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 680 | 680 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 681 | 681 | // zig fmt: on |
| 682 | 682 | } |
| 683 | |
| 684 | assert(!self.register_manager.frozenRegsExist()); |
| 685 | |
| 683 | 686 | if (std.debug.runtime_safety) { |
| 684 | 687 | if (self.air_bookkeeping < old_air_bookkeeping + 1) { |
| 685 | 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 | 830 | /// Allocates a new register and copies `mcv` into it. |
| 828 | 831 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 829 | 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 | 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 | 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 | 841 | fn copyToNewRegisterWithExceptions( |
| 839 | 842 | self: *Self, |
| 840 | 843 | reg_owner: Air.Inst.Index, |
| 844 | ty: Type, |
| 841 | 845 | mcv: MCValue, |
| 842 | 846 | exceptions: []const Register, |
| 843 | 847 | ) !MCValue { |
| 844 | 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 | 850 | return MCValue{ .register = reg }; |
| 847 | 851 | } |
| 848 | 852 | |
| ... | ... | @@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 892 | 896 | if (operand_abi_size > 8 or dest_abi_size > 8) { |
| 893 | 897 | return self.fail("TODO implement intCast for abi sizes larger than 8", .{}); |
| 894 | 898 | } |
| 895 | | const reg = switch (operand) { |
| 896 | | .register => |src_reg| try self.register_manager.allocReg(inst, &.{src_reg}), |
| 897 | | else => try self.register_manager.allocReg(inst, &.{}), |
| 898 | | }; |
| 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)) }; |
| 899 | |
| 900 | if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register}); |
| 901 | defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register}); |
| 902 | break :blk try self.copyToNewRegister(inst, dest_ty, operand); |
| 902 | 903 | }; |
| 903 | 904 | |
| 904 | 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 | 1209 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 1209 | 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 | 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 | 1480 | const index_ty = self.air.typeOf(extra.rhs); |
| 1480 | 1481 | const index = try self.resolveInst(extra.rhs); |
| 1481 | 1482 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 1482 | | const dst_mcv = blk: { |
| 1483 | | switch (ptr) { |
| 1484 | | .ptr_stack_offset => { |
| 1485 | | const reg = try self.register_manager.allocReg(inst, &.{offset_reg}); |
| 1486 | | try self.genSetReg(ptr_ty, reg, ptr); |
| 1487 | | break :blk .{ .register = reg }; |
| 1488 | | }, |
| 1489 | | else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}), |
| 1490 | | } |
| 1491 | | }; |
| 1483 | |
| 1484 | self.register_manager.freezeRegs(&.{offset_reg}); |
| 1485 | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 1486 | |
| 1487 | const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, ptr); |
| 1492 | 1488 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 1493 | 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 | 1855 | // Source operand can be an immediate, 8 bits or 32 bits. |
| 1860 | 1856 | // So, if either one of the operands dies with this instruction, we can use it |
| 1861 | 1857 | // as the result MCValue. |
| 1858 | const dst_ty = self.air.typeOfIndex(inst); |
| 1862 | 1859 | var dst_mcv: MCValue = undefined; |
| 1863 | 1860 | var src_mcv: MCValue = undefined; |
| 1864 | 1861 | if (self.reuseOperand(inst, op_lhs, 0, lhs)) { |
| 1865 | 1862 | // LHS dies; use it as the destination. |
| 1866 | 1863 | // Both operands cannot be memory. |
| 1867 | 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 | 1866 | src_mcv = rhs; |
| 1870 | 1867 | } else { |
| 1871 | 1868 | dst_mcv = lhs; |
| ... | ... | @@ -1875,7 +1872,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 1875 | 1872 | // RHS dies; use it as the destination. |
| 1876 | 1873 | // Both operands cannot be memory. |
| 1877 | 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 | 1876 | src_mcv = lhs; |
| 1880 | 1877 | } else { |
| 1881 | 1878 | dst_mcv = rhs; |
| ... | ... | @@ -1887,18 +1884,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 1887 | 1884 | // If the allocated register is the same as the rhs register, don't allocate that one |
| 1888 | 1885 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation |
| 1889 | 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 | 1888 | else |
| 1892 | | try self.copyToNewRegister(inst, lhs); |
| 1889 | try self.copyToNewRegister(inst, dst_ty, lhs); |
| 1893 | 1890 | src_mcv = rhs; |
| 1894 | 1891 | } else { |
| 1895 | 1892 | dst_mcv = if (lhs.isRegister()) |
| 1896 | 1893 | // If the allocated register is the same as the rhs register, don't allocate that one |
| 1897 | 1894 | // and instead spill a subsequent one. Otherwise, this can result in a miscompilation |
| 1898 | 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 | 1897 | else |
| 1901 | | try self.copyToNewRegister(inst, rhs); |
| 1898 | try self.copyToNewRegister(inst, dst_ty, rhs); |
| 1902 | 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 | 1914 | } |
| 1918 | 1915 | |
| 1919 | 1916 | // Now for step 2, we assing an MIR instruction |
| 1920 | | const dst_ty = self.air.typeOfIndex(inst); |
| 1921 | 1917 | const air_tags = self.air.instructions.items(.tag); |
| 1922 | 1918 | switch (air_tags[inst]) { |
| 1923 | 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 | 2413 | .register => |reg| { |
| 2418 | 2414 | if (Register.allocIndex(reg) == null) { |
| 2419 | 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 | 2419 | else => {}, |
| ... | ... | @@ -2494,7 +2490,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 2494 | 2490 | // Either one, but not both, can be a memory operand. |
| 2495 | 2491 | // Source operand can be an immediate, 8 bits or 32 bits. |
| 2496 | 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 | 2494 | else |
| 2499 | 2495 | lhs; |
| 2500 | 2496 | // This instruction supports only signed 32-bit immediates at most. |