authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-07 11:28:57+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-07 13:19:53+02:00
logbf11cdc9d880555aee087a9bc0ecd1424428b63b
tree910d4ef4450555b104ba1aefa535b69d9318e85b
parent197c2a465f51b61bd3d2e58c5e6fecadacb20894

x64: refactor code to avoid stage1 sema limitations


2 files changed, 448 insertions(+), 395 deletions(-)

src/arch/x86_64/CodeGen.zig+447-394
......@@ -191,36 +191,12 @@ pub const MCValue = union(enum) {
191191 };
192192 }
193193
194 fn usesCompareFlags(mcv: MCValue) bool {
195 return switch (mcv) {
196 .compare_flags_unsigned,
197 .compare_flags_signed,
198 .register_overflow_unsigned,
199 .register_overflow_signed,
200 => true,
201 else => false,
202 };
203 }
204
205194 fn isRegister(mcv: MCValue) bool {
206195 return switch (mcv) {
207 .register,
208 .register_overflow_unsigned,
209 .register_overflow_signed,
210 => true,
196 .register => true,
211197 else => false,
212198 };
213199 }
214
215 fn asRegister(mcv: MCValue) ?Register {
216 return switch (mcv) {
217 .register,
218 .register_overflow_unsigned,
219 .register_overflow_signed,
220 => |reg| reg,
221 else => null,
222 };
223 }
224200};
225201
226202const Branch = struct {
......@@ -852,15 +828,21 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
852828 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
853829 branch.inst_table.putAssumeCapacityNoClobber(inst, result);
854830
855 if (result.asRegister()) |reg| {
856 // In some cases (such as bitcast), an operand
857 // may be the same MCValue as the result. If
858 // that operand died and was a register, it
859 // was freed by processDeath. We have to
860 // "re-allocate" the register.
861 if (self.register_manager.isRegFree(reg)) {
862 self.register_manager.getRegAssumeFree(reg, inst);
863 }
831 switch (result) {
832 .register,
833 .register_overflow_signed,
834 .register_overflow_unsigned,
835 => |reg| {
836 // In some cases (such as bitcast), an operand
837 // may be the same MCValue as the result. If
838 // that operand died and was a register, it
839 // was freed by processDeath. We have to
840 // "re-allocate" the register.
841 if (self.register_manager.isRegFree(reg)) {
842 self.register_manager.getRegAssumeFree(reg, inst);
843 }
844 },
845 else => {},
864846 }
865847 }
866848 self.finishAirBookkeeping();
......@@ -948,18 +930,32 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
948930pub fn spillCompareFlagsIfOccupied(self: *Self) !void {
949931 if (self.compare_flags_inst) |inst_to_save| {
950932 const mcv = self.getResolvedInstValue(inst_to_save);
951 assert(mcv.usesCompareFlags());
933 const new_mcv = switch (mcv) {
934 .register_overflow_signed,
935 .register_overflow_unsigned,
936 => try self.allocRegOrMem(inst_to_save, false),
937 .compare_flags_signed,
938 .compare_flags_unsigned,
939 => try self.allocRegOrMem(inst_to_save, true),
940 else => unreachable,
941 };
952942
953 const new_mcv = try self.allocRegOrMem(inst_to_save, !mcv.isRegister());
954943 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
955944 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });
945
956946 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
957947 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
958948
959949 self.compare_flags_inst = null;
950
960951 // TODO consolidate with register manager and spillInstruction
961952 // this call should really belong in the register manager!
962 if (mcv.isRegister()) self.register_manager.freeReg(mcv.asRegister().?);
953 switch (mcv) {
954 .register_overflow_signed,
955 .register_overflow_unsigned,
956 => |reg| self.register_manager.freeReg(reg),
957 else => {},
958 }
963959 }
964960}
965961
......@@ -1031,7 +1027,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10311027 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
10321028 else => null,
10331029 };
1034 defer if (operand_lock) |reg| self.register_manager.unlockReg(reg);
1030 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10351031
10361032 const reg = try self.register_manager.allocReg(inst);
10371033 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
......@@ -1062,7 +1058,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
10621058 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
10631059 else => null,
10641060 };
1065 defer if (operand_lock) |reg| self.register_manager.unlockReg(reg);
1061 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
10661062
10671063 const reg: Register = blk: {
10681064 if (operand.isRegister()) {
......@@ -1150,7 +1146,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
11501146 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
11511147 else => null,
11521148 };
1153 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1149 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
11541150
11551151 const lhs_reg = try self.copyToTmpRegister(ty, lhs);
11561152 const lhs_reg_lock = self.register_manager.lockRegAssumeUnused(lhs_reg);
......@@ -1161,7 +1157,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
11611157 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
11621158 else => null,
11631159 };
1164 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1160 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
11651161
11661162 try self.genBinMathOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv);
11671163
......@@ -1200,9 +1196,9 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r
12001196 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
12011197 else => null,
12021198 };
1203 defer if (offset_lock) |reg| self.register_manager.unlockReg(reg);
1199 defer if (offset_lock) |lock| self.register_manager.unlockReg(lock);
12041200
1205 const dst_mcv = blk: {
1201 const dst_mcv: MCValue = blk: {
12061202 if (self.reuseOperand(inst, op_lhs, 0, ptr)) {
12071203 if (ptr.isMemory() or ptr.isRegister()) break :blk ptr;
12081204 }
......@@ -1213,9 +1209,9 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r
12131209 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
12141210 else => null,
12151211 };
1216 defer if (dst_mcv_lock) |reg| self.register_manager.unlockReg(reg);
1212 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
12171213
1218 const offset_mcv = blk: {
1214 const offset_mcv: MCValue = blk: {
12191215 if (self.reuseOperand(inst, op_rhs, 1, offset)) {
12201216 if (offset.isRegister()) break :blk offset;
12211217 }
......@@ -1226,7 +1222,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r
12261222 .register => |reg| self.register_manager.lockReg(reg),
12271223 else => null,
12281224 };
1229 defer if (offset_mcv_lock) |reg| self.register_manager.unlockReg(reg);
1225 defer if (offset_mcv_lock) |lock| self.register_manager.unlockReg(lock);
12301226
12311227 try self.genIntMulComplexOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size });
12321228
......@@ -1315,16 +1311,16 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air
13151311 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
13161312 else => null,
13171313 };
1318 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1314 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
13191315
13201316 const rhs = try self.resolveInst(op_rhs);
13211317 const rhs_lock: ?RegisterLock = switch (rhs) {
13221318 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
13231319 else => null,
13241320 };
1325 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1321 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
13261322
1327 const dst_mcv = blk: {
1323 const dst_mcv: MCValue = blk: {
13281324 if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) {
13291325 break :blk lhs;
13301326 }
......@@ -1334,9 +1330,9 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air
13341330 .register => |reg| self.register_manager.lockReg(reg),
13351331 else => null,
13361332 };
1337 defer if (dst_mcv_lock) |reg| self.register_manager.unlockReg(reg);
1333 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
13381334
1339 const rhs_mcv = blk: {
1335 const rhs_mcv: MCValue = blk: {
13401336 if (rhs.isMemory() or rhs.isRegister()) break :blk rhs;
13411337 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) };
13421338 };
......@@ -1344,7 +1340,7 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air
13441340 .register => |reg| self.register_manager.lockReg(reg),
13451341 else => null,
13461342 };
1347 defer if (rhs_mcv_lock) |reg| self.register_manager.unlockReg(reg);
1343 defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock);
13481344
13491345 try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, rhs_mcv);
13501346
......@@ -1476,9 +1472,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14761472fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
14771473 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
14781474 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1479 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1480 const ty = self.air.typeOf(bin_op.lhs);
14811475
1476 if (self.liveness.isUnused(inst)) {
1477 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1478 }
1479
1480 const ty = self.air.typeOf(bin_op.lhs);
1481 const result: MCValue = result: {
14821482 switch (ty.zigTypeTag()) {
14831483 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
14841484 .Int => {
......@@ -1529,7 +1529,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15291529 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
15301530 else => null,
15311531 };
1532 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1532 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
15331533
15341534 const dst_reg: Register = blk: {
15351535 if (lhs.isRegister()) break :blk lhs.register;
......@@ -1538,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15381538 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
15391539 defer self.register_manager.unlockReg(dst_reg_lock);
15401540
1541 const rhs_mcv = blk: {
1541 const rhs_mcv: MCValue = blk: {
15421542 if (rhs.isRegister() or rhs.isMemory()) break :blk rhs;
15431543 break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) };
15441544 };
......@@ -1546,7 +1546,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15461546 .register => |reg| self.register_manager.lockReg(reg),
15471547 else => null,
15481548 };
1549 defer if (rhs_mcv_lock) |reg| self.register_manager.unlockReg(reg);
1549 defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock);
15501550
15511551 try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv);
15521552
......@@ -1734,19 +1734,19 @@ fn genIntMulDivOpMir(
17341734/// Clobbers .rax and .rdx registers.
17351735fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue {
17361736 const signedness = ty.intInfo(self.target.*).signedness;
1737 const dividend = switch (lhs) {
1737 const dividend: Register = switch (lhs) {
17381738 .register => |reg| reg,
17391739 else => try self.copyToTmpRegister(ty, lhs),
17401740 };
17411741 const dividend_lock = self.register_manager.lockReg(dividend);
1742 defer if (dividend_lock) |reg| self.register_manager.unlockReg(reg);
1742 defer if (dividend_lock) |lock| self.register_manager.unlockReg(lock);
17431743
1744 const divisor = switch (rhs) {
1744 const divisor: Register = switch (rhs) {
17451745 .register => |reg| reg,
17461746 else => try self.copyToTmpRegister(ty, rhs),
17471747 };
17481748 const divisor_lock = self.register_manager.lockReg(divisor);
1749 defer if (divisor_lock) |reg| self.register_manager.unlockReg(reg);
1749 defer if (divisor_lock) |lock| self.register_manager.unlockReg(lock);
17501750
17511751 try self.genIntMulDivOpMir(switch (signedness) {
17521752 .signed => .idiv,
......@@ -1791,67 +1791,72 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
17911791
17921792fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
17931793 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1794 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1795 const tag = self.air.instructions.items(.tag)[inst];
1796 const ty = self.air.typeOfIndex(inst);
17971794
1798 if (ty.zigTypeTag() != .Int) {
1799 return self.fail("TODO implement {} for operands of dst type {}", .{ tag, ty.zigTypeTag() });
1800 }
1795 if (self.liveness.isUnused(inst)) {
1796 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1797 }
18011798
1802 if (tag == .div_float) {
1803 return self.fail("TODO implement {}", .{tag});
1799 const tag = self.air.instructions.items(.tag)[inst];
1800 const ty = self.air.typeOfIndex(inst);
1801
1802 if (ty.zigTypeTag() != .Int) {
1803 return self.fail("TODO implement {} for operands of dst type {}", .{ tag, ty.zigTypeTag() });
1804 }
1805
1806 if (tag == .div_float) {
1807 return self.fail("TODO implement {}", .{tag});
1808 }
1809
1810 const signedness = ty.intInfo(self.target.*).signedness;
1811
1812 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1813 const track_rax: ?Air.Inst.Index = blk: {
1814 if (signedness == .unsigned) break :blk inst;
1815 switch (tag) {
1816 .div_exact, .div_trunc => break :blk inst,
1817 else => break :blk null,
18041818 }
1819 };
1820 try self.register_manager.getReg(.rax, track_rax);
1821 try self.register_manager.getReg(.rdx, null);
1822 var reg_locks: [2]RegisterLock = undefined;
1823 self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks);
1824 defer for (reg_locks) |reg| {
1825 self.register_manager.unlockReg(reg);
1826 };
18051827
1806 const signedness = ty.intInfo(self.target.*).signedness;
1828 const lhs = try self.resolveInst(bin_op.lhs);
1829 const lhs_lock: ?RegisterLock = switch (lhs) {
1830 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1831 else => null,
1832 };
1833 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
18071834
1808 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1809 const track_rax: ?Air.Inst.Index = blk: {
1810 if (signedness == .unsigned) break :blk inst;
1835 const rhs: MCValue = blk: {
1836 const rhs = try self.resolveInst(bin_op.rhs);
1837 if (signedness == .signed) {
18111838 switch (tag) {
1812 .div_exact, .div_trunc => break :blk inst,
1813 else => break :blk null,
1814 }
1815 };
1816 try self.register_manager.getReg(.rax, track_rax);
1817 try self.register_manager.getReg(.rdx, null);
1818 var reg_locks: [2]RegisterLock = undefined;
1819 self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks);
1820 defer for (reg_locks) |reg| {
1821 self.register_manager.unlockReg(reg);
1822 };
1823
1824 const lhs = try self.resolveInst(bin_op.lhs);
1825 const lhs_lock: ?RegisterLock = switch (lhs) {
1826 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1827 else => null,
1828 };
1829 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1830
1831 const rhs = blk: {
1832 const rhs = try self.resolveInst(bin_op.rhs);
1833 if (signedness == .signed) {
1834 switch (tag) {
1835 .div_floor => {
1836 const rhs_lock: ?RegisterLock = switch (rhs) {
1837 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1838 else => null,
1839 };
1840 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1839 .div_floor => {
1840 const rhs_lock: ?RegisterLock = switch (rhs) {
1841 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1842 else => null,
1843 };
1844 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
18411845
1842 break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs);
1843 },
1844 else => {},
1845 }
1846 break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs);
1847 },
1848 else => {},
18461849 }
1847 break :blk rhs;
1848 };
1849 const rhs_lock: ?RegisterLock = switch (rhs) {
1850 .register => |reg| self.register_manager.lockReg(reg),
1851 else => null,
1852 };
1853 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1850 }
1851 break :blk rhs;
1852 };
1853 const rhs_lock: ?RegisterLock = switch (rhs) {
1854 .register => |reg| self.register_manager.lockReg(reg),
1855 else => null,
1856 };
1857 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
18541858
1859 const result: MCValue = result: {
18551860 if (signedness == .unsigned) {
18561861 try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs);
18571862 break :result MCValue{ .register = .rax };
......@@ -1871,59 +1876,69 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
18711876 else => unreachable,
18721877 }
18731878 };
1879
18741880 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
18751881}
18761882
18771883fn airRem(self: *Self, inst: Air.Inst.Index) !void {
18781884 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1879 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1880 const ty = self.air.typeOfIndex(inst);
1881 if (ty.zigTypeTag() != .Int) {
1882 return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()});
1883 }
1884 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1885 try self.register_manager.getReg(.rax, null);
1886 try self.register_manager.getReg(.rdx, inst);
1887 var reg_locks: [2]RegisterLock = undefined;
1888 self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks);
1889 defer for (reg_locks) |reg| {
1890 self.register_manager.unlockReg(reg);
1891 };
1892
1893 const lhs = try self.resolveInst(bin_op.lhs);
1894 const rhs = try self.resolveInst(bin_op.rhs);
18951885
1896 const signedness = ty.intInfo(self.target.*).signedness;
1897 try self.genIntMulDivOpMir(switch (signedness) {
1898 .signed => .idiv,
1899 .unsigned => .div,
1900 }, ty, signedness, lhs, rhs);
1901 break :result MCValue{ .register = .rdx };
1886 if (self.liveness.isUnused(inst)) {
1887 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1888 }
1889 const ty = self.air.typeOfIndex(inst);
1890 if (ty.zigTypeTag() != .Int) {
1891 return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()});
1892 }
1893 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1894 try self.register_manager.getReg(.rax, null);
1895 try self.register_manager.getReg(.rdx, inst);
1896 var reg_locks: [2]RegisterLock = undefined;
1897 self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks);
1898 defer for (reg_locks) |reg| {
1899 self.register_manager.unlockReg(reg);
19021900 };
1901
1902 const lhs = try self.resolveInst(bin_op.lhs);
1903 const rhs = try self.resolveInst(bin_op.rhs);
1904
1905 const signedness = ty.intInfo(self.target.*).signedness;
1906 try self.genIntMulDivOpMir(switch (signedness) {
1907 .signed => .idiv,
1908 .unsigned => .div,
1909 }, ty, signedness, lhs, rhs);
1910
1911 const result: MCValue = .{ .register = .rdx };
1912
19031913 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
19041914}
19051915
19061916fn airMod(self: *Self, inst: Air.Inst.Index) !void {
19071917 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1908 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1909 const ty = self.air.typeOfIndex(inst);
1910 if (ty.zigTypeTag() != .Int) {
1911 return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()});
1912 }
1913 const signedness = ty.intInfo(self.target.*).signedness;
19141918
1915 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1916 try self.register_manager.getReg(.rax, null);
1917 try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null);
1918 var reg_locks: [2]RegisterLock = undefined;
1919 self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks);
1920 defer for (reg_locks) |reg| {
1921 self.register_manager.unlockReg(reg);
1922 };
1919 if (self.liveness.isUnused(inst)) {
1920 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1921 }
19231922
1924 const lhs = try self.resolveInst(bin_op.lhs);
1925 const rhs = try self.resolveInst(bin_op.rhs);
1923 const ty = self.air.typeOfIndex(inst);
1924 if (ty.zigTypeTag() != .Int) {
1925 return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()});
1926 }
1927 const signedness = ty.intInfo(self.target.*).signedness;
19261928
1929 // Spill .rax and .rdx upfront to ensure we don't spill the operands too late.
1930 try self.register_manager.getReg(.rax, null);
1931 try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null);
1932 var reg_locks: [2]RegisterLock = undefined;
1933 self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks);
1934 defer for (reg_locks) |reg| {
1935 self.register_manager.unlockReg(reg);
1936 };
1937
1938 const lhs = try self.resolveInst(bin_op.lhs);
1939 const rhs = try self.resolveInst(bin_op.rhs);
1940
1941 const result: MCValue = result: {
19271942 switch (signedness) {
19281943 .unsigned => {
19291944 try self.genIntMulDivOpMir(switch (signedness) {
......@@ -1943,6 +1958,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
19431958 },
19441959 }
19451960 };
1961
19461962 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
19471963}
19481964
......@@ -2017,7 +2033,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void {
20172033 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
20182034 else => null,
20192035 };
2020 defer if (value_lock) |reg| self.register_manager.unlockReg(reg);
2036 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);
20212037
20222038 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value);
20232039 _ = try self.addInst(.{
......@@ -2117,7 +2133,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
21172133 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
21182134 else => null,
21192135 };
2120 defer if (operand_lock) |reg| self.register_manager.unlockReg(reg);
2136 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
21212137
21222138 const result: MCValue = result: {
21232139 if (!payload_ty.hasRuntimeBits()) break :result operand;
......@@ -2150,7 +2166,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
21502166 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
21512167 else => null,
21522168 };
2153 defer if (operand_lock) |reg| self.register_manager.unlockReg(reg);
2169 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
21542170
21552171 const abi_align = err_union_ty.abiAlignment(self.target.*);
21562172 const err_ty = err_union_ty.errorUnionSet();
......@@ -2222,7 +2238,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
22222238 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
22232239 else => null,
22242240 };
2225 defer if (operand_lock) |reg| self.register_manager.unlockReg(reg);
2241 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
22262242
22272243 if (optional_ty.isPtrLikeOptional()) {
22282244 // TODO should we check if we can reuse the operand?
......@@ -2359,7 +2375,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
23592375 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
23602376 else => null,
23612377 };
2362 defer if (slice_mcv_lock) |reg| self.register_manager.unlockReg(reg);
2378 defer if (slice_mcv_lock) |lock| self.register_manager.unlockReg(lock);
23632379
23642380 const elem_ty = slice_ty.childType();
23652381 const elem_size = elem_ty.abiSize(self.target.*);
......@@ -2372,7 +2388,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
23722388 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
23732389 else => null,
23742390 };
2375 defer if (index_mcv_lock) |reg| self.register_manager.unlockReg(reg);
2391 defer if (index_mcv_lock) |lock| self.register_manager.unlockReg(lock);
23762392
23772393 const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size);
23782394 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
......@@ -2429,110 +2445,119 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
24292445
24302446fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
24312447 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2432 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2433 const array_ty = self.air.typeOf(bin_op.lhs);
2434 const array = try self.resolveInst(bin_op.lhs);
2435 const array_lock: ?RegisterLock = switch (array) {
2436 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2437 else => null,
2438 };
2439 defer if (array_lock) |reg| self.register_manager.unlockReg(reg);
24402448
2441 const elem_ty = array_ty.childType();
2442 const elem_abi_size = elem_ty.abiSize(self.target.*);
2449 if (self.liveness.isUnused(inst)) {
2450 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2451 }
24432452
2444 const index_ty = self.air.typeOf(bin_op.rhs);
2445 const index = try self.resolveInst(bin_op.rhs);
2446 const index_lock: ?RegisterLock = switch (index) {
2447 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2448 else => null,
2449 };
2450 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
2453 const array_ty = self.air.typeOf(bin_op.lhs);
2454 const array = try self.resolveInst(bin_op.lhs);
2455 const array_lock: ?RegisterLock = switch (array) {
2456 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2457 else => null,
2458 };
2459 defer if (array_lock) |lock| self.register_manager.unlockReg(lock);
24512460
2452 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2453 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2454 defer self.register_manager.unlockReg(offset_reg_lock);
2461 const elem_ty = array_ty.childType();
2462 const elem_abi_size = elem_ty.abiSize(self.target.*);
24552463
2456 const addr_reg = try self.register_manager.allocReg(null);
2457 switch (array) {
2458 .register => {
2459 const off = @intCast(i32, try self.allocMem(
2460 inst,
2461 @intCast(u32, array_ty.abiSize(self.target.*)),
2462 array_ty.abiAlignment(self.target.*),
2463 ));
2464 try self.genSetStack(array_ty, off, array, .{});
2465 // lea reg, [rbp]
2466 _ = try self.addInst(.{
2467 .tag = .lea,
2468 .ops = (Mir.Ops{
2469 .reg1 = addr_reg.to64(),
2470 .reg2 = .rbp,
2471 }).encode(),
2472 .data = .{ .imm = @bitCast(u32, -off) },
2473 });
2474 },
2475 .stack_offset => |off| {
2476 // lea reg, [rbp]
2477 _ = try self.addInst(.{
2478 .tag = .lea,
2479 .ops = (Mir.Ops{
2480 .reg1 = addr_reg.to64(),
2481 .reg2 = .rbp,
2482 }).encode(),
2483 .data = .{ .imm = @bitCast(u32, -off) },
2484 });
2485 },
2486 .memory,
2487 .got_load,
2488 .direct_load,
2489 => {
2490 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);
2491 },
2492 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
2493 }
2494
2495 // TODO we could allocate register here, but need to expect addr register and potentially
2496 // offset register.
2497 const dst_mcv = try self.allocRegOrMem(inst, false);
2498 try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg });
2499 try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty);
2500 break :result dst_mcv;
2464 const index_ty = self.air.typeOf(bin_op.rhs);
2465 const index = try self.resolveInst(bin_op.rhs);
2466 const index_lock: ?RegisterLock = switch (index) {
2467 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2468 else => null,
25012469 };
2502 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2470 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
2471
2472 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2473 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2474 defer self.register_manager.unlockReg(offset_reg_lock);
2475
2476 const addr_reg = try self.register_manager.allocReg(null);
2477 switch (array) {
2478 .register => {
2479 const off = @intCast(i32, try self.allocMem(
2480 inst,
2481 @intCast(u32, array_ty.abiSize(self.target.*)),
2482 array_ty.abiAlignment(self.target.*),
2483 ));
2484 try self.genSetStack(array_ty, off, array, .{});
2485 // lea reg, [rbp]
2486 _ = try self.addInst(.{
2487 .tag = .lea,
2488 .ops = (Mir.Ops{
2489 .reg1 = addr_reg.to64(),
2490 .reg2 = .rbp,
2491 }).encode(),
2492 .data = .{ .imm = @bitCast(u32, -off) },
2493 });
2494 },
2495 .stack_offset => |off| {
2496 // lea reg, [rbp]
2497 _ = try self.addInst(.{
2498 .tag = .lea,
2499 .ops = (Mir.Ops{
2500 .reg1 = addr_reg.to64(),
2501 .reg2 = .rbp,
2502 }).encode(),
2503 .data = .{ .imm = @bitCast(u32, -off) },
2504 });
2505 },
2506 .memory,
2507 .got_load,
2508 .direct_load,
2509 => {
2510 try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array);
2511 },
2512 else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
2513 }
2514
2515 // TODO we could allocate register here, but need to expect addr register and potentially
2516 // offset register.
2517 const dst_mcv = try self.allocRegOrMem(inst, false);
2518 try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg });
2519 try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty);
2520
2521 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
25032522}
25042523
25052524fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
25062525 const is_volatile = false; // TODO
25072526 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2508 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {
2509 // this is identical to the `airPtrElemPtr` codegen expect here an
2510 // additional `mov` is needed at the end to get the actual value
25112527
2512 const ptr_ty = self.air.typeOf(bin_op.lhs);
2513 const ptr = try self.resolveInst(bin_op.lhs);
2514 const ptr_lock: ?RegisterLock = switch (ptr) {
2515 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2516 else => null,
2517 };
2518 defer if (ptr_lock) |reg| self.register_manager.unlockReg(reg);
2528 if (!is_volatile and self.liveness.isUnused(inst)) {
2529 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2530 }
25192531
2520 const elem_ty = ptr_ty.elemType2();
2521 const elem_abi_size = elem_ty.abiSize(self.target.*);
2522 const index_ty = self.air.typeOf(bin_op.rhs);
2523 const index = try self.resolveInst(bin_op.rhs);
2524 const index_lock: ?RegisterLock = switch (index) {
2525 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2526 else => null,
2527 };
2528 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
2532 // this is identical to the `airPtrElemPtr` codegen expect here an
2533 // additional `mov` is needed at the end to get the actual value
25292534
2530 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2531 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2532 defer self.register_manager.unlockReg(offset_reg_lock);
2535 const ptr_ty = self.air.typeOf(bin_op.lhs);
2536 const ptr = try self.resolveInst(bin_op.lhs);
2537 const ptr_lock: ?RegisterLock = switch (ptr) {
2538 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2539 else => null,
2540 };
2541 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
25332542
2534 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2535 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2543 const elem_ty = ptr_ty.elemType2();
2544 const elem_abi_size = elem_ty.abiSize(self.target.*);
2545 const index_ty = self.air.typeOf(bin_op.rhs);
2546 const index = try self.resolveInst(bin_op.rhs);
2547 const index_lock: ?RegisterLock = switch (index) {
2548 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2549 else => null,
2550 };
2551 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
2552
2553 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2554 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2555 defer self.register_manager.unlockReg(offset_reg_lock);
2556
2557 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2558 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2559
2560 const result: MCValue = result: {
25362561 if (elem_abi_size > 8) {
25372562 return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size});
25382563 } else {
......@@ -2549,40 +2574,44 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
25492574 break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
25502575 }
25512576 };
2577
25522578 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
25532579}
25542580
25552581fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
25562582 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
25572583 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2558 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2559 const ptr_ty = self.air.typeOf(extra.lhs);
2560 const ptr = try self.resolveInst(extra.lhs);
2561 const ptr_lock: ?RegisterLock = switch (ptr) {
2562 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2563 else => null,
2564 };
2565 defer if (ptr_lock) |reg| self.register_manager.unlockReg(reg);
25662584
2567 const elem_ty = ptr_ty.elemType2();
2568 const elem_abi_size = elem_ty.abiSize(self.target.*);
2569 const index_ty = self.air.typeOf(extra.rhs);
2570 const index = try self.resolveInst(extra.rhs);
2571 const index_lock: ?RegisterLock = switch (index) {
2572 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2573 else => null,
2574 };
2575 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
2585 if (self.liveness.isUnused(inst)) {
2586 return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
2587 }
25762588
2577 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2578 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2579 defer self.register_manager.unlockReg(offset_reg_lock);
2589 const ptr_ty = self.air.typeOf(extra.lhs);
2590 const ptr = try self.resolveInst(extra.lhs);
2591 const ptr_lock: ?RegisterLock = switch (ptr) {
2592 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2593 else => null,
2594 };
2595 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
25802596
2581 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2582 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2583 break :result dst_mcv;
2597 const elem_ty = ptr_ty.elemType2();
2598 const elem_abi_size = elem_ty.abiSize(self.target.*);
2599 const index_ty = self.air.typeOf(extra.rhs);
2600 const index = try self.resolveInst(extra.rhs);
2601 const index_lock: ?RegisterLock = switch (index) {
2602 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2603 else => null,
25842604 };
2585 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2605 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
2606
2607 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2608 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2609 defer self.register_manager.unlockReg(offset_reg_lock);
2610
2611 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2612 try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2613
2614 return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
25862615}
25872616
25882617fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2601,14 +2630,14 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
26012630 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
26022631 else => null,
26032632 };
2604 defer if (ptr_lock) |reg| self.register_manager.unlockReg(reg);
2633 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
26052634
26062635 const tag = try self.resolveInst(bin_op.rhs);
26072636 const tag_lock: ?RegisterLock = switch (tag) {
26082637 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
26092638 else => null,
26102639 };
2611 defer if (tag_lock) |reg| self.register_manager.unlockReg(reg);
2640 defer if (tag_lock) |lock| self.register_manager.unlockReg(lock);
26122641
26132642 const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: {
26142643 // TODO reusing the operand
......@@ -2642,7 +2671,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
26422671 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
26432672 else => null,
26442673 };
2645 defer if (operand_lock) |reg| self.register_manager.unlockReg(reg);
2674 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
26462675
26472676 const tag_abi_size = tag_ty.abiSize(self.target.*);
26482677 const dst_mcv: MCValue = blk: {
......@@ -2790,7 +2819,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
27902819 },
27912820 .register => |reg| {
27922821 const reg_lock = self.register_manager.lockReg(reg);
2793 defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg);
2822 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
27942823
27952824 switch (dst_mcv) {
27962825 .dead => unreachable,
......@@ -2916,7 +2945,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
29162945 },
29172946 .register => |reg| {
29182947 const reg_lock = self.register_manager.lockReg(reg);
2919 defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg);
2948 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
29202949
29212950 switch (value) {
29222951 .none => unreachable,
......@@ -3010,7 +3039,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
30103039 .register => |reg| self.register_manager.lockReg(reg),
30113040 else => null,
30123041 };
3013 defer if (value_lock) |reg| self.register_manager.unlockReg(reg);
3042 defer if (value_lock) |lock| self.register_manager.unlockReg(lock);
30143043
30153044 const addr_reg = try self.register_manager.allocReg(null);
30163045 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
......@@ -3198,7 +3227,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
31983227 defer self.register_manager.unlockReg(offset_reg_lock);
31993228
32003229 const can_reuse_operand = self.reuseOperand(inst, operand, 0, mcv);
3201 const result_reg = blk: {
3230 const result_reg: Register = blk: {
32023231 if (can_reuse_operand) {
32033232 break :blk reg;
32043233 } else {
......@@ -3208,7 +3237,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
32083237 }
32093238 };
32103239 const result_reg_lock = self.register_manager.lockReg(result_reg);
3211 defer if (result_reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
3240 defer if (result_reg_lock) |lock| self.register_manager.unlockReg(lock);
32123241
32133242 try self.genBinMathOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });
32143243 break :result MCValue{ .register = result_reg };
......@@ -3224,12 +3253,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
32243253 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
32253254 const operand = extra.struct_operand;
32263255 const index = extra.field_index;
3227 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3228 const mcv = try self.resolveInst(operand);
3229 const struct_ty = self.air.typeOf(operand);
3230 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
3231 const struct_field_ty = struct_ty.structFieldType(index);
32323256
3257 if (self.liveness.isUnused(inst)) {
3258 return self.finishAir(inst, .dead, .{ extra.struct_operand, .none, .none });
3259 }
3260
3261 const mcv = try self.resolveInst(operand);
3262 const struct_ty = self.air.typeOf(operand);
3263 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
3264 const struct_field_ty = struct_ty.structFieldType(index);
3265
3266 const result: MCValue = result: {
32333267 switch (mcv) {
32343268 .stack_offset => |off| {
32353269 const stack_offset = off - @intCast(i32, struct_field_offset);
......@@ -3239,7 +3273,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
32393273 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
32403274 defer self.register_manager.unlockReg(reg_lock);
32413275
3242 const dst_mcv = blk: {
3276 const dst_mcv: MCValue = blk: {
32433277 if (self.reuseOperand(inst, operand, 0, mcv)) {
32443278 break :blk mcv;
32453279 } else {
......@@ -3250,10 +3284,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
32503284 }
32513285 };
32523286 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
3253 .register => |reg| self.register_manager.lockReg(reg),
3287 .register => |a_reg| self.register_manager.lockReg(a_reg),
32543288 else => null,
32553289 };
3256 defer if (dst_mcv_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
3290 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
32573291
32583292 // Shift by struct_field_offset.
32593293 const shift = @intCast(u8, struct_field_offset * @sizeOf(usize));
......@@ -3342,17 +3376,17 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
33423376 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
33433377 else => null,
33443378 };
3345 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
3379 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
33463380
33473381 const rhs = try self.resolveInst(op_rhs);
33483382 const rhs_lock: ?RegisterLock = switch (rhs) {
33493383 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
33503384 else => null,
33513385 };
3352 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
3386 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
33533387
33543388 var flipped: bool = false;
3355 const dst_mcv = blk: {
3389 const dst_mcv: MCValue = blk: {
33563390 if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) {
33573391 break :blk lhs;
33583392 }
......@@ -3366,9 +3400,9 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
33663400 .register => |reg| self.register_manager.lockReg(reg),
33673401 else => null,
33683402 };
3369 defer if (dst_mcv_lock) |reg| self.register_manager.unlockReg(reg);
3403 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
33703404
3371 const src_mcv = blk: {
3405 const src_mcv: MCValue = blk: {
33723406 const mcv = if (flipped) lhs else rhs;
33733407 if (mcv.isRegister() or mcv.isMemory()) break :blk mcv;
33743408 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, mcv) };
......@@ -3377,7 +3411,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
33773411 .register => |reg| self.register_manager.lockReg(reg),
33783412 else => null,
33793413 };
3380 defer if (src_mcv_lock) |reg| self.register_manager.unlockReg(reg);
3414 defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock);
33813415
33823416 const tag = self.air.instructions.items(.tag)[inst];
33833417 switch (tag) {
......@@ -3409,7 +3443,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
34093443 .register_overflow_signed => unreachable,
34103444 .ptr_stack_offset => {
34113445 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
3412 defer if (dst_reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
3446 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
34133447
34143448 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
34153449 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
......@@ -3441,7 +3475,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC
34413475 => {
34423476 assert(abi_size <= 8);
34433477 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
3444 defer if (dst_reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
3478 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
34453479
34463480 const reg = try self.copyToTmpRegister(dst_ty, src_mcv);
34473481 return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg });
......@@ -3782,22 +3816,25 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
37823816 try self.register_manager.getReg(reg, null);
37833817 }
37843818
3785 const rdi_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: {
3786 const ret_ty = fn_ty.fnReturnType();
3787 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3788 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3789 const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align));
3790 log.debug("airCall: return value on stack at offset {}", .{stack_offset});
3819 const rdi_lock: ?RegisterLock = blk: {
3820 if (info.return_value == .stack_offset) {
3821 const ret_ty = fn_ty.fnReturnType();
3822 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3823 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3824 const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align));
3825 log.debug("airCall: return value on stack at offset {}", .{stack_offset});
37913826
3792 try self.register_manager.getReg(.rdi, null);
3793 try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset });
3794 const rdi_lock = self.register_manager.lockRegAssumeUnused(.rdi);
3827 try self.register_manager.getReg(.rdi, null);
3828 try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset });
3829 const rdi_lock = self.register_manager.lockRegAssumeUnused(.rdi);
37953830
3796 info.return_value.stack_offset = stack_offset;
3831 info.return_value.stack_offset = stack_offset;
37973832
3798 break :blk rdi_lock;
3799 } else null;
3800 defer if (rdi_lock) |reg| self.register_manager.unlockReg(reg);
3833 break :blk rdi_lock;
3834 }
3835 break :blk null;
3836 };
3837 defer if (rdi_lock) |lock| self.register_manager.unlockReg(lock);
38013838
38023839 for (args) |arg, arg_i| {
38033840 const mc_arg = info.args[arg_i];
......@@ -4107,7 +4144,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
41074144 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
41084145 else => null,
41094146 };
4110 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
4147 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
41114148
41124149 const dst_reg = try self.copyToTmpRegister(ty, lhs);
41134150 const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
......@@ -4572,27 +4609,31 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void {
45724609
45734610fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {
45744611 const un_op = self.air.instructions.items(.data)[inst].un_op;
4575 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4576 const operand_ptr = try self.resolveInst(un_op);
45774612
4578 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4579 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4580 else => null,
4581 };
4582 defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg);
4613 if (self.liveness.isUnused(inst)) {
4614 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
4615 }
45834616
4584 const operand: MCValue = blk: {
4585 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4586 // The MCValue that holds the pointer can be re-used as the value.
4587 break :blk operand_ptr;
4588 } else {
4589 break :blk try self.allocRegOrMem(inst, true);
4590 }
4591 };
4592 const ptr_ty = self.air.typeOf(un_op);
4593 try self.load(operand, operand_ptr, ptr_ty);
4594 break :result try self.isNull(inst, ptr_ty.elemType(), operand);
4617 const operand_ptr = try self.resolveInst(un_op);
4618 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4619 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4620 else => null,
4621 };
4622 defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock);
4623
4624 const operand: MCValue = blk: {
4625 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4626 // The MCValue that holds the pointer can be re-used as the value.
4627 break :blk operand_ptr;
4628 } else {
4629 break :blk try self.allocRegOrMem(inst, true);
4630 }
45954631 };
4632 const ptr_ty = self.air.typeOf(un_op);
4633 try self.load(operand, operand_ptr, ptr_ty);
4634
4635 const result = try self.isNull(inst, ptr_ty.elemType(), operand);
4636
45964637 return self.finishAir(inst, result, .{ un_op, .none, .none });
45974638}
45984639
......@@ -4608,27 +4649,31 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void {
46084649
46094650fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {
46104651 const un_op = self.air.instructions.items(.data)[inst].un_op;
4611 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4612 const operand_ptr = try self.resolveInst(un_op);
46134652
4614 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4615 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4616 else => null,
4617 };
4618 defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg);
4653 if (self.liveness.isUnused(inst)) {
4654 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
4655 }
46194656
4620 const operand: MCValue = blk: {
4621 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4622 // The MCValue that holds the pointer can be re-used as the value.
4623 break :blk operand_ptr;
4624 } else {
4625 break :blk try self.allocRegOrMem(inst, true);
4626 }
4627 };
4628 const ptr_ty = self.air.typeOf(un_op);
4629 try self.load(operand, operand_ptr, ptr_ty);
4630 break :result try self.isNonNull(inst, ptr_ty.elemType(), operand);
4657 const operand_ptr = try self.resolveInst(un_op);
4658 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4659 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4660 else => null,
46314661 };
4662 defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock);
4663
4664 const operand: MCValue = blk: {
4665 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4666 // The MCValue that holds the pointer can be re-used as the value.
4667 break :blk operand_ptr;
4668 } else {
4669 break :blk try self.allocRegOrMem(inst, true);
4670 }
4671 };
4672 const ptr_ty = self.air.typeOf(un_op);
4673 try self.load(operand, operand_ptr, ptr_ty);
4674
4675 const result = try self.isNonNull(inst, ptr_ty.elemType(), operand);
4676
46324677 return self.finishAir(inst, result, .{ un_op, .none, .none });
46334678}
46344679
......@@ -4644,27 +4689,31 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void {
46444689
46454690fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void {
46464691 const un_op = self.air.instructions.items(.data)[inst].un_op;
4647 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4648 const operand_ptr = try self.resolveInst(un_op);
46494692
4650 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4651 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4652 else => null,
4653 };
4654 defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg);
4693 if (self.liveness.isUnused(inst)) {
4694 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
4695 }
46554696
4656 const operand: MCValue = blk: {
4657 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4658 // The MCValue that holds the pointer can be re-used as the value.
4659 break :blk operand_ptr;
4660 } else {
4661 break :blk try self.allocRegOrMem(inst, true);
4662 }
4663 };
4664 const ptr_ty = self.air.typeOf(un_op);
4665 try self.load(operand, operand_ptr, ptr_ty);
4666 break :result try self.isErr(inst, ptr_ty.elemType(), operand);
4697 const operand_ptr = try self.resolveInst(un_op);
4698 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4699 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4700 else => null,
4701 };
4702 defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock);
4703
4704 const operand: MCValue = blk: {
4705 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4706 // The MCValue that holds the pointer can be re-used as the value.
4707 break :blk operand_ptr;
4708 } else {
4709 break :blk try self.allocRegOrMem(inst, true);
4710 }
46674711 };
4712 const ptr_ty = self.air.typeOf(un_op);
4713 try self.load(operand, operand_ptr, ptr_ty);
4714
4715 const result = try self.isErr(inst, ptr_ty.elemType(), operand);
4716
46684717 return self.finishAir(inst, result, .{ un_op, .none, .none });
46694718}
46704719
......@@ -4680,27 +4729,31 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void {
46804729
46814730fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void {
46824731 const un_op = self.air.instructions.items(.data)[inst].un_op;
4683 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
4684 const operand_ptr = try self.resolveInst(un_op);
46854732
4686 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4687 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4688 else => null,
4689 };
4690 defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg);
4733 if (self.liveness.isUnused(inst)) {
4734 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
4735 }
46914736
4692 const operand: MCValue = blk: {
4693 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4694 // The MCValue that holds the pointer can be re-used as the value.
4695 break :blk operand_ptr;
4696 } else {
4697 break :blk try self.allocRegOrMem(inst, true);
4698 }
4699 };
4700 const ptr_ty = self.air.typeOf(un_op);
4701 try self.load(operand, operand_ptr, ptr_ty);
4702 break :result try self.isNonErr(inst, ptr_ty.elemType(), operand);
4737 const operand_ptr = try self.resolveInst(un_op);
4738 const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) {
4739 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
4740 else => null,
4741 };
4742 defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock);
4743
4744 const operand: MCValue = blk: {
4745 if (self.reuseOperand(inst, un_op, 0, operand_ptr)) {
4746 // The MCValue that holds the pointer can be re-used as the value.
4747 break :blk operand_ptr;
4748 } else {
4749 break :blk try self.allocRegOrMem(inst, true);
4750 }
47034751 };
4752 const ptr_ty = self.air.typeOf(un_op);
4753 try self.load(operand, operand_ptr, ptr_ty);
4754
4755 const result = try self.isNonErr(inst, ptr_ty.elemType(), operand);
4756
47044757 return self.finishAir(inst, result, .{ un_op, .none, .none });
47054758}
47064759
......@@ -4757,7 +4810,7 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
47574810 try self.spillCompareFlagsIfOccupied();
47584811
47594812 const cond_reg_lock = self.register_manager.lockReg(cond_reg);
4760 defer if (cond_reg_lock) |reg| self.register_manager.unlockReg(reg);
4813 defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock);
47614814
47624815 switch (case) {
47634816 .none => unreachable,
......@@ -5305,7 +5358,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
53055358 .register_overflow_signed,
53065359 => |reg| {
53075360 const reg_lock = self.register_manager.lockReg(reg);
5308 defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
5361 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
53095362
53105363 const wrapped_ty = ty.structFieldType(0);
53115364 try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{});
......@@ -5407,7 +5460,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
54075460 const base_reg = opts.dest_stack_base orelse .rbp;
54085461 if (!math.isPowerOfTwo(abi_size)) {
54095462 const reg_lock = self.register_manager.lockReg(reg);
5410 defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
5463 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
54115464
54125465 const tmp_reg = try self.copyToTmpRegister(ty, mcv);
54135466
......@@ -5501,8 +5554,8 @@ fn genInlineMemcpy(
55015554
55025555 var reg_locks: [2]RegisterLock = undefined;
55035556 self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rcx }, &reg_locks);
5504 defer for (reg_locks) |reg| {
5505 self.register_manager.unlockReg(reg);
5557 defer for (reg_locks) |lock| {
5558 self.register_manager.unlockReg(lock);
55065559 };
55075560
55085561 const ssbase_lock: ?RegisterLock = if (opts.source_stack_base) |reg|
......@@ -5515,7 +5568,7 @@ fn genInlineMemcpy(
55155568 self.register_manager.lockReg(reg)
55165569 else
55175570 null;
5518 defer if (dsbase_lock) |reg| self.register_manager.unlockReg(reg);
5571 defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock);
55195572
55205573 const dst_addr_reg = try self.register_manager.allocReg(null);
55215574 switch (dst_ptr) {
......@@ -6174,21 +6227,21 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void {
61746227 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
61756228 else => null,
61766229 };
6177 defer if (dst_ptr_lock) |reg| self.register_manager.unlockReg(reg);
6230 defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock);
61786231
61796232 const src_val = try self.resolveInst(extra.lhs);
61806233 const src_val_lock: ?RegisterLock = switch (src_val) {
61816234 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
61826235 else => null,
61836236 };
6184 defer if (src_val_lock) |reg| self.register_manager.unlockReg(reg);
6237 defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock);
61856238
61866239 const len = try self.resolveInst(extra.rhs);
61876240 const len_lock: ?RegisterLock = switch (len) {
61886241 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
61896242 else => null,
61906243 };
6191 defer if (len_lock) |reg| self.register_manager.unlockReg(reg);
6244 defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
61926245
61936246 try self.genInlineMemset(dst_ptr, src_val, len, .{});
61946247
......@@ -6204,7 +6257,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
62046257 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
62056258 else => null,
62066259 };
6207 defer if (dst_ptr_lock) |reg| self.register_manager.unlockReg(reg);
6260 defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock);
62086261
62096262 const src_ty = self.air.typeOf(extra.lhs);
62106263 const src_ptr = try self.resolveInst(extra.lhs);
......@@ -6212,14 +6265,14 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
62126265 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
62136266 else => null,
62146267 };
6215 defer if (src_ptr_lock) |reg| self.register_manager.unlockReg(reg);
6268 defer if (src_ptr_lock) |lock| self.register_manager.unlockReg(lock);
62166269
62176270 const len = try self.resolveInst(extra.rhs);
62186271 const len_lock: ?RegisterLock = switch (len) {
62196272 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
62206273 else => null,
62216274 };
6222 defer if (len_lock) |reg| self.register_manager.unlockReg(reg);
6275 defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
62236276
62246277 // TODO Is this the only condition for pointer dereference for memcpy?
62256278 const src: MCValue = blk: {
......@@ -6245,7 +6298,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void {
62456298 .register => |reg| self.register_manager.lockReg(reg),
62466299 else => null,
62476300 };
6248 defer if (src_lock) |reg| self.register_manager.unlockReg(reg);
6301 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
62496302
62506303 try self.genInlineMemcpy(dst_ptr, src, len, .{});
62516304
src/register_manager.zig+1-1
......@@ -153,7 +153,7 @@ pub fn RegisterManager(
153153 regs: [count]Register,
154154 buf: *[count]RegisterLock,
155155 ) void {
156 for (&regs) |reg, i| {
156 for (regs) |reg, i| {
157157 buf[i] = self.lockRegAssumeUnused(reg);
158158 }
159159 }