| ... | ... | @@ -22,6 +22,8 @@ const Liveness = @import("../../Liveness.zig"); |
| 22 | 22 | const Mir = @import("Mir.zig"); |
| 23 | 23 | const Module = @import("../../Module.zig"); |
| 24 | 24 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 25 | const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers); |
| 26 | const RegisterLock = RegisterManager.RegisterLock; |
| 25 | 27 | const Target = std.Target; |
| 26 | 28 | const Type = @import("../../type.zig").Type; |
| 27 | 29 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | ... | @@ -42,8 +44,6 @@ const InnerError = error{ |
| 42 | 44 | OutOfRegisters, |
| 43 | 45 | }; |
| 44 | 46 | |
| 45 | | const RegisterManager = RegisterManagerFn(Self, Register, &allocatable_registers); |
| 46 | | |
| 47 | 47 | gpa: Allocator, |
| 48 | 48 | air: Air, |
| 49 | 49 | liveness: Liveness, |
| ... | ... | @@ -191,60 +191,12 @@ pub const MCValue = union(enum) { |
| 191 | 191 | }; |
| 192 | 192 | } |
| 193 | 193 | |
| 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 | | |
| 205 | 194 | fn isRegister(mcv: MCValue) bool { |
| 206 | 195 | return switch (mcv) { |
| 207 | | .register, |
| 208 | | .register_overflow_unsigned, |
| 209 | | .register_overflow_signed, |
| 210 | | => true, |
| 196 | .register => true, |
| 211 | 197 | else => false, |
| 212 | 198 | }; |
| 213 | 199 | } |
| 214 | | |
| 215 | | fn freezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { |
| 216 | | switch (mcv) { |
| 217 | | .register, |
| 218 | | .register_overflow_signed, |
| 219 | | .register_overflow_unsigned, |
| 220 | | => |reg| { |
| 221 | | mgr.freezeRegs(&.{reg}); |
| 222 | | }, |
| 223 | | else => {}, |
| 224 | | } |
| 225 | | } |
| 226 | | |
| 227 | | fn unfreezeIfRegister(mcv: MCValue, mgr: *RegisterManager) void { |
| 228 | | switch (mcv) { |
| 229 | | .register, |
| 230 | | .register_overflow_signed, |
| 231 | | .register_overflow_unsigned, |
| 232 | | => |reg| { |
| 233 | | mgr.unfreezeRegs(&.{reg}); |
| 234 | | }, |
| 235 | | else => {}, |
| 236 | | } |
| 237 | | } |
| 238 | | |
| 239 | | fn asRegister(mcv: MCValue) ?Register { |
| 240 | | return switch (mcv) { |
| 241 | | .register, |
| 242 | | .register_overflow_signed, |
| 243 | | .register_overflow_unsigned, |
| 244 | | => |reg| reg, |
| 245 | | else => null, |
| 246 | | }; |
| 247 | | } |
| 248 | 200 | }; |
| 249 | 201 | |
| 250 | 202 | const Branch = struct { |
| ... | ... | @@ -819,7 +771,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 819 | 771 | // zig fmt: on |
| 820 | 772 | } |
| 821 | 773 | |
| 822 | | assert(!self.register_manager.frozenRegsExist()); |
| 774 | assert(!self.register_manager.lockedRegsExist()); |
| 823 | 775 | |
| 824 | 776 | if (std.debug.runtime_safety) { |
| 825 | 777 | if (self.air_bookkeeping < old_air_bookkeeping + 1) { |
| ... | ... | @@ -876,15 +828,21 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 876 | 828 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 877 | 829 | branch.inst_table.putAssumeCapacityNoClobber(inst, result); |
| 878 | 830 | |
| 879 | | if (result.asRegister()) |reg| { |
| 880 | | // In some cases (such as bitcast), an operand |
| 881 | | // may be the same MCValue as the result. If |
| 882 | | // that operand died and was a register, it |
| 883 | | // was freed by processDeath. We have to |
| 884 | | // "re-allocate" the register. |
| 885 | | if (self.register_manager.isRegFree(reg)) { |
| 886 | | self.register_manager.getRegAssumeFree(reg, inst); |
| 887 | | } |
| 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 => {}, |
| 888 | 846 | } |
| 889 | 847 | } |
| 890 | 848 | self.finishAirBookkeeping(); |
| ... | ... | @@ -955,7 +913,15 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 955 | 913 | const stack_mcv = try self.allocRegOrMem(inst, false); |
| 956 | 914 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| 957 | 915 | const reg_mcv = self.getResolvedInstValue(inst); |
| 958 | | assert(reg.to64() == reg_mcv.asRegister().?.to64()); |
| 916 | switch (reg_mcv) { |
| 917 | .register, |
| 918 | .register_overflow_unsigned, |
| 919 | .register_overflow_signed, |
| 920 | => |other| { |
| 921 | assert(reg.to64() == other.to64()); |
| 922 | }, |
| 923 | else => {}, |
| 924 | } |
| 959 | 925 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 960 | 926 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 961 | 927 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv, .{}); |
| ... | ... | @@ -964,18 +930,32 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 964 | 930 | pub fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 965 | 931 | if (self.compare_flags_inst) |inst_to_save| { |
| 966 | 932 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 967 | | 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 | }; |
| 968 | 942 | |
| 969 | | const new_mcv = try self.allocRegOrMem(inst_to_save, !mcv.isRegister()); |
| 970 | 943 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); |
| 971 | 944 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| 945 | |
| 972 | 946 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 973 | 947 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 974 | 948 | |
| 975 | 949 | self.compare_flags_inst = null; |
| 950 | |
| 976 | 951 | // TODO consolidate with register manager and spillInstruction |
| 977 | 952 | // this call should really belong in the register manager! |
| 978 | | 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 | } |
| 979 | 959 | } |
| 980 | 960 | } |
| 981 | 961 | |
| ... | ... | @@ -1043,8 +1023,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1043 | 1023 | return self.fail("TODO implement intCast for abi sizes larger than 8", .{}); |
| 1044 | 1024 | } |
| 1045 | 1025 | |
| 1046 | | operand.freezeIfRegister(&self.register_manager); |
| 1047 | | defer operand.unfreezeIfRegister(&self.register_manager); |
| 1026 | const operand_lock: ?RegisterLock = switch (operand) { |
| 1027 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1028 | else => null, |
| 1029 | }; |
| 1030 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 1048 | 1031 | |
| 1049 | 1032 | const reg = try self.register_manager.allocReg(inst); |
| 1050 | 1033 | try self.genSetReg(dest_ty, reg, .{ .immediate = 0 }); |
| ... | ... | @@ -1071,8 +1054,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1071 | 1054 | return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); |
| 1072 | 1055 | } |
| 1073 | 1056 | |
| 1074 | | operand.freezeIfRegister(&self.register_manager); |
| 1075 | | defer operand.unfreezeIfRegister(&self.register_manager); |
| 1057 | const operand_lock: ?RegisterLock = switch (operand) { |
| 1058 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1059 | else => null, |
| 1060 | }; |
| 1061 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 1076 | 1062 | |
| 1077 | 1063 | const reg: Register = blk: { |
| 1078 | 1064 | if (operand.isRegister()) { |
| ... | ... | @@ -1156,16 +1142,22 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1156 | 1142 | // TODO improve by checking if any operand can be reused. |
| 1157 | 1143 | // TODO audit register allocation |
| 1158 | 1144 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1159 | | lhs.freezeIfRegister(&self.register_manager); |
| 1160 | | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 1145 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 1146 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1147 | else => null, |
| 1148 | }; |
| 1149 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1161 | 1150 | |
| 1162 | 1151 | const lhs_reg = try self.copyToTmpRegister(ty, lhs); |
| 1163 | | self.register_manager.freezeRegs(&.{lhs_reg}); |
| 1164 | | defer self.register_manager.unfreezeRegs(&.{lhs_reg}); |
| 1152 | const lhs_reg_lock = self.register_manager.lockRegAssumeUnused(lhs_reg); |
| 1153 | defer self.register_manager.unlockReg(lhs_reg_lock); |
| 1165 | 1154 | |
| 1166 | 1155 | const rhs_mcv = try self.limitImmediateType(bin_op.rhs, i32); |
| 1167 | | rhs_mcv.freezeIfRegister(&self.register_manager); |
| 1168 | | defer rhs_mcv.unfreezeIfRegister(&self.register_manager); |
| 1156 | const rhs_lock: ?RegisterLock = switch (rhs_mcv) { |
| 1157 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1158 | else => null, |
| 1159 | }; |
| 1160 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1169 | 1161 | |
| 1170 | 1162 | try self.genBinMathOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); |
| 1171 | 1163 | |
| ... | ... | @@ -1200,28 +1192,37 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r |
| 1200 | 1192 | const offset = try self.resolveInst(op_rhs); |
| 1201 | 1193 | const offset_ty = self.air.typeOf(op_rhs); |
| 1202 | 1194 | |
| 1203 | | offset.freezeIfRegister(&self.register_manager); |
| 1204 | | defer offset.unfreezeIfRegister(&self.register_manager); |
| 1195 | const offset_lock: ?RegisterLock = switch (offset) { |
| 1196 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1197 | else => null, |
| 1198 | }; |
| 1199 | defer if (offset_lock) |lock| self.register_manager.unlockReg(lock); |
| 1205 | 1200 | |
| 1206 | | const dst_mcv = blk: { |
| 1201 | const dst_mcv: MCValue = blk: { |
| 1207 | 1202 | if (self.reuseOperand(inst, op_lhs, 0, ptr)) { |
| 1208 | 1203 | if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; |
| 1209 | 1204 | } |
| 1210 | 1205 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, ptr) }; |
| 1211 | 1206 | }; |
| 1212 | 1207 | |
| 1213 | | dst_mcv.freezeIfRegister(&self.register_manager); |
| 1214 | | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 1208 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 1209 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1210 | else => null, |
| 1211 | }; |
| 1212 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1215 | 1213 | |
| 1216 | | const offset_mcv = blk: { |
| 1214 | const offset_mcv: MCValue = blk: { |
| 1217 | 1215 | if (self.reuseOperand(inst, op_rhs, 1, offset)) { |
| 1218 | 1216 | if (offset.isRegister()) break :blk offset; |
| 1219 | 1217 | } |
| 1220 | 1218 | break :blk MCValue{ .register = try self.copyToTmpRegister(offset_ty, offset) }; |
| 1221 | 1219 | }; |
| 1222 | 1220 | |
| 1223 | | offset_mcv.freezeIfRegister(&self.register_manager); |
| 1224 | | defer offset_mcv.unfreezeIfRegister(&self.register_manager); |
| 1221 | const offset_mcv_lock: ?RegisterLock = switch (offset_mcv) { |
| 1222 | .register => |reg| self.register_manager.lockReg(reg), |
| 1223 | else => null, |
| 1224 | }; |
| 1225 | defer if (offset_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1225 | 1226 | |
| 1226 | 1227 | try self.genIntMulComplexOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); |
| 1227 | 1228 | |
| ... | ... | @@ -1306,30 +1307,40 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air |
| 1306 | 1307 | const dst_ty = self.air.typeOf(op_lhs); |
| 1307 | 1308 | |
| 1308 | 1309 | const lhs = try self.resolveInst(op_lhs); |
| 1309 | | lhs.freezeIfRegister(&self.register_manager); |
| 1310 | | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 1310 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 1311 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1312 | else => null, |
| 1313 | }; |
| 1314 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1311 | 1315 | |
| 1312 | 1316 | const rhs = try self.resolveInst(op_rhs); |
| 1313 | | rhs.freezeIfRegister(&self.register_manager); |
| 1314 | | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1317 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1318 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1319 | else => null, |
| 1320 | }; |
| 1321 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1315 | 1322 | |
| 1316 | | const dst_mcv = blk: { |
| 1323 | const dst_mcv: MCValue = blk: { |
| 1317 | 1324 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 1318 | 1325 | break :blk lhs; |
| 1319 | 1326 | } |
| 1320 | 1327 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 1321 | 1328 | }; |
| 1329 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 1330 | .register => |reg| self.register_manager.lockReg(reg), |
| 1331 | else => null, |
| 1332 | }; |
| 1333 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1322 | 1334 | |
| 1323 | | dst_mcv.freezeIfRegister(&self.register_manager); |
| 1324 | | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 1325 | | |
| 1326 | | const rhs_mcv = blk: { |
| 1335 | const rhs_mcv: MCValue = blk: { |
| 1327 | 1336 | if (rhs.isMemory() or rhs.isRegister()) break :blk rhs; |
| 1328 | 1337 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; |
| 1329 | 1338 | }; |
| 1330 | | |
| 1331 | | rhs_mcv.freezeIfRegister(&self.register_manager); |
| 1332 | | defer rhs_mcv.unfreezeIfRegister(&self.register_manager); |
| 1339 | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { |
| 1340 | .register => |reg| self.register_manager.lockReg(reg), |
| 1341 | else => null, |
| 1342 | }; |
| 1343 | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1333 | 1344 | |
| 1334 | 1345 | try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, rhs_mcv); |
| 1335 | 1346 | |
| ... | ... | @@ -1366,8 +1377,10 @@ fn airMul(self: *Self, inst: Air.Inst.Index) !void { |
| 1366 | 1377 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1367 | 1378 | try self.register_manager.getReg(.rax, inst); |
| 1368 | 1379 | try self.register_manager.getReg(.rdx, null); |
| 1369 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1370 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1380 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1381 | defer for (reg_locks) |reg| { |
| 1382 | self.register_manager.unlockReg(reg); |
| 1383 | }; |
| 1371 | 1384 | |
| 1372 | 1385 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1373 | 1386 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1458,9 +1471,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1458 | 1471 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1459 | 1472 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1460 | 1473 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1461 | | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1462 | | const ty = self.air.typeOf(bin_op.lhs); |
| 1463 | 1474 | |
| 1475 | if (self.liveness.isUnused(inst)) { |
| 1476 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1477 | } |
| 1478 | |
| 1479 | const ty = self.air.typeOf(bin_op.lhs); |
| 1480 | const result: MCValue = result: { |
| 1464 | 1481 | switch (ty.zigTypeTag()) { |
| 1465 | 1482 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 1466 | 1483 | .Int => { |
| ... | ... | @@ -1477,8 +1494,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1477 | 1494 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1478 | 1495 | try self.register_manager.getReg(.rax, inst); |
| 1479 | 1496 | try self.register_manager.getReg(.rdx, null); |
| 1480 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1481 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1497 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1498 | defer for (reg_locks) |reg| { |
| 1499 | self.register_manager.unlockReg(reg); |
| 1500 | }; |
| 1482 | 1501 | |
| 1483 | 1502 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1484 | 1503 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1504,21 +1523,28 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1504 | 1523 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1505 | 1524 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1506 | 1525 | |
| 1507 | | rhs.freezeIfRegister(&self.register_manager); |
| 1508 | | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1526 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1527 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1528 | else => null, |
| 1529 | }; |
| 1530 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1509 | 1531 | |
| 1510 | 1532 | const dst_reg: Register = blk: { |
| 1511 | 1533 | if (lhs.isRegister()) break :blk lhs.register; |
| 1512 | 1534 | break :blk try self.copyToTmpRegister(ty, lhs); |
| 1513 | 1535 | }; |
| 1514 | | self.register_manager.freezeRegs(&.{dst_reg}); |
| 1536 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1537 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 1515 | 1538 | |
| 1516 | | const rhs_mcv = blk: { |
| 1539 | const rhs_mcv: MCValue = blk: { |
| 1517 | 1540 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; |
| 1518 | 1541 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; |
| 1519 | 1542 | }; |
| 1520 | | rhs_mcv.freezeIfRegister(&self.register_manager); |
| 1521 | | defer rhs_mcv.unfreezeIfRegister(&self.register_manager); |
| 1543 | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { |
| 1544 | .register => |reg| self.register_manager.lockReg(reg), |
| 1545 | else => null, |
| 1546 | }; |
| 1547 | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1522 | 1548 | |
| 1523 | 1549 | try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv); |
| 1524 | 1550 | |
| ... | ... | @@ -1528,8 +1554,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1528 | 1554 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1529 | 1555 | try self.register_manager.getReg(.rax, null); |
| 1530 | 1556 | try self.register_manager.getReg(.rdx, null); |
| 1531 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1532 | | defer self.register_manager.unfreezeRegs(&.{.rdx}); |
| 1557 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1558 | defer for (reg_locks) |reg| { |
| 1559 | self.register_manager.unlockReg(reg); |
| 1560 | }; |
| 1533 | 1561 | |
| 1534 | 1562 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1535 | 1563 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -1540,7 +1568,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1540 | 1568 | }, |
| 1541 | 1569 | } |
| 1542 | 1570 | }; |
| 1543 | | defer self.register_manager.unfreezeRegs(&.{dst_reg}); |
| 1571 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1572 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 1544 | 1573 | |
| 1545 | 1574 | const tuple_ty = self.air.typeOfIndex(inst); |
| 1546 | 1575 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| ... | ... | @@ -1554,8 +1583,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1554 | 1583 | }; |
| 1555 | 1584 | |
| 1556 | 1585 | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }); |
| 1557 | | self.register_manager.freezeRegs(&temp_regs); |
| 1558 | | defer self.register_manager.unfreezeRegs(&temp_regs); |
| 1586 | const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); |
| 1587 | defer for (temp_regs_locks) |reg| { |
| 1588 | self.register_manager.unlockReg(reg); |
| 1589 | }; |
| 1559 | 1590 | |
| 1560 | 1591 | const overflow_reg = temp_regs[0]; |
| 1561 | 1592 | const flags: u2 = switch (int_info.signedness) { |
| ... | ... | @@ -1699,18 +1730,19 @@ fn genIntMulDivOpMir( |
| 1699 | 1730 | /// Clobbers .rax and .rdx registers. |
| 1700 | 1731 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 1701 | 1732 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1702 | | const dividend = switch (lhs) { |
| 1733 | const dividend: Register = switch (lhs) { |
| 1703 | 1734 | .register => |reg| reg, |
| 1704 | 1735 | else => try self.copyToTmpRegister(ty, lhs), |
| 1705 | 1736 | }; |
| 1706 | | self.register_manager.freezeRegs(&.{dividend}); |
| 1737 | const dividend_lock = self.register_manager.lockReg(dividend); |
| 1738 | defer if (dividend_lock) |lock| self.register_manager.unlockReg(lock); |
| 1707 | 1739 | |
| 1708 | | const divisor = switch (rhs) { |
| 1740 | const divisor: Register = switch (rhs) { |
| 1709 | 1741 | .register => |reg| reg, |
| 1710 | 1742 | else => try self.copyToTmpRegister(ty, rhs), |
| 1711 | 1743 | }; |
| 1712 | | self.register_manager.freezeRegs(&.{divisor}); |
| 1713 | | defer self.register_manager.unfreezeRegs(&.{ dividend, divisor }); |
| 1744 | const divisor_lock = self.register_manager.lockReg(divisor); |
| 1745 | defer if (divisor_lock) |lock| self.register_manager.unlockReg(lock); |
| 1714 | 1746 | |
| 1715 | 1747 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1716 | 1748 | .signed => .idiv, |
| ... | ... | @@ -1755,54 +1787,71 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1755 | 1787 | |
| 1756 | 1788 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1757 | 1789 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1758 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1759 | | const tag = self.air.instructions.items(.tag)[inst]; |
| 1760 | | const ty = self.air.typeOfIndex(inst); |
| 1761 | 1790 | |
| 1762 | | if (ty.zigTypeTag() != .Int) { |
| 1763 | | return self.fail("TODO implement {} for operands of dst type {}", .{ tag, ty.zigTypeTag() }); |
| 1764 | | } |
| 1791 | if (self.liveness.isUnused(inst)) { |
| 1792 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1793 | } |
| 1794 | |
| 1795 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1796 | const ty = self.air.typeOfIndex(inst); |
| 1765 | 1797 | |
| 1766 | | if (tag == .div_float) { |
| 1767 | | return self.fail("TODO implement {}", .{tag}); |
| 1798 | if (ty.zigTypeTag() != .Int) { |
| 1799 | return self.fail("TODO implement {} for operands of dst type {}", .{ tag, ty.zigTypeTag() }); |
| 1800 | } |
| 1801 | |
| 1802 | if (tag == .div_float) { |
| 1803 | return self.fail("TODO implement {}", .{tag}); |
| 1804 | } |
| 1805 | |
| 1806 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1807 | |
| 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; |
| 1811 | switch (tag) { |
| 1812 | .div_exact, .div_trunc => break :blk inst, |
| 1813 | else => break :blk null, |
| 1768 | 1814 | } |
| 1815 | }; |
| 1816 | try self.register_manager.getReg(.rax, track_rax); |
| 1817 | try self.register_manager.getReg(.rdx, null); |
| 1818 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1819 | defer for (reg_locks) |reg| { |
| 1820 | self.register_manager.unlockReg(reg); |
| 1821 | }; |
| 1769 | 1822 | |
| 1770 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1823 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1824 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 1825 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1826 | else => null, |
| 1827 | }; |
| 1828 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1771 | 1829 | |
| 1772 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1773 | | const track_rax: ?Air.Inst.Index = blk: { |
| 1774 | | if (signedness == .unsigned) break :blk inst; |
| 1830 | const rhs: MCValue = blk: { |
| 1831 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1832 | if (signedness == .signed) { |
| 1775 | 1833 | switch (tag) { |
| 1776 | | .div_exact, .div_trunc => break :blk inst, |
| 1777 | | else => break :blk null, |
| 1778 | | } |
| 1779 | | }; |
| 1780 | | try self.register_manager.getReg(.rax, track_rax); |
| 1781 | | try self.register_manager.getReg(.rdx, null); |
| 1782 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1783 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1834 | .div_floor => { |
| 1835 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1836 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1837 | else => null, |
| 1838 | }; |
| 1839 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1784 | 1840 | |
| 1785 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1786 | | lhs.freezeIfRegister(&self.register_manager); |
| 1787 | | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 1788 | | |
| 1789 | | const rhs = blk: { |
| 1790 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1791 | | if (signedness == .signed) { |
| 1792 | | switch (tag) { |
| 1793 | | .div_floor => { |
| 1794 | | rhs.freezeIfRegister(&self.register_manager); |
| 1795 | | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1796 | | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); |
| 1797 | | }, |
| 1798 | | else => {}, |
| 1799 | | } |
| 1841 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); |
| 1842 | }, |
| 1843 | else => {}, |
| 1800 | 1844 | } |
| 1801 | | break :blk rhs; |
| 1802 | | }; |
| 1803 | | rhs.freezeIfRegister(&self.register_manager); |
| 1804 | | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 1845 | } |
| 1846 | break :blk rhs; |
| 1847 | }; |
| 1848 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1849 | .register => |reg| self.register_manager.lockReg(reg), |
| 1850 | else => null, |
| 1851 | }; |
| 1852 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1805 | 1853 | |
| 1854 | const result: MCValue = result: { |
| 1806 | 1855 | if (signedness == .unsigned) { |
| 1807 | 1856 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs); |
| 1808 | 1857 | break :result MCValue{ .register = .rax }; |
| ... | ... | @@ -1822,53 +1871,67 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1822 | 1871 | else => unreachable, |
| 1823 | 1872 | } |
| 1824 | 1873 | }; |
| 1874 | |
| 1825 | 1875 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1826 | 1876 | } |
| 1827 | 1877 | |
| 1828 | 1878 | fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1829 | 1879 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1830 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1831 | | const ty = self.air.typeOfIndex(inst); |
| 1832 | | if (ty.zigTypeTag() != .Int) { |
| 1833 | | return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1834 | | } |
| 1835 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1836 | | try self.register_manager.getReg(.rax, null); |
| 1837 | | try self.register_manager.getReg(.rdx, inst); |
| 1838 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1839 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1840 | | |
| 1841 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1842 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1843 | 1880 | |
| 1844 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1845 | | try self.genIntMulDivOpMir(switch (signedness) { |
| 1846 | | .signed => .idiv, |
| 1847 | | .unsigned => .div, |
| 1848 | | }, ty, signedness, lhs, rhs); |
| 1849 | | break :result MCValue{ .register = .rdx }; |
| 1881 | if (self.liveness.isUnused(inst)) { |
| 1882 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1883 | } |
| 1884 | const ty = self.air.typeOfIndex(inst); |
| 1885 | if (ty.zigTypeTag() != .Int) { |
| 1886 | return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1887 | } |
| 1888 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1889 | try self.register_manager.getReg(.rax, null); |
| 1890 | try self.register_manager.getReg(.rdx, inst); |
| 1891 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1892 | defer for (reg_locks) |reg| { |
| 1893 | self.register_manager.unlockReg(reg); |
| 1850 | 1894 | }; |
| 1895 | |
| 1896 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1897 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1898 | |
| 1899 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1900 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1901 | .signed => .idiv, |
| 1902 | .unsigned => .div, |
| 1903 | }, ty, signedness, lhs, rhs); |
| 1904 | |
| 1905 | const result: MCValue = .{ .register = .rdx }; |
| 1906 | |
| 1851 | 1907 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1852 | 1908 | } |
| 1853 | 1909 | |
| 1854 | 1910 | fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1855 | 1911 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1856 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1857 | | const ty = self.air.typeOfIndex(inst); |
| 1858 | | if (ty.zigTypeTag() != .Int) { |
| 1859 | | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1860 | | } |
| 1861 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1862 | 1912 | |
| 1863 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1864 | | try self.register_manager.getReg(.rax, null); |
| 1865 | | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); |
| 1866 | | self.register_manager.freezeRegs(&.{ .rax, .rdx }); |
| 1867 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx }); |
| 1913 | if (self.liveness.isUnused(inst)) { |
| 1914 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1915 | } |
| 1868 | 1916 | |
| 1869 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1870 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1917 | const ty = self.air.typeOfIndex(inst); |
| 1918 | if (ty.zigTypeTag() != .Int) { |
| 1919 | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1920 | } |
| 1921 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1922 | |
| 1923 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1924 | try self.register_manager.getReg(.rax, null); |
| 1925 | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); |
| 1926 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1927 | defer for (reg_locks) |reg| { |
| 1928 | self.register_manager.unlockReg(reg); |
| 1929 | }; |
| 1930 | |
| 1931 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1932 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1871 | 1933 | |
| 1934 | const result: MCValue = result: { |
| 1872 | 1935 | switch (signedness) { |
| 1873 | 1936 | .unsigned => { |
| 1874 | 1937 | try self.genIntMulDivOpMir(switch (signedness) { |
| ... | ... | @@ -1888,6 +1951,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1888 | 1951 | }, |
| 1889 | 1952 | } |
| 1890 | 1953 | }; |
| 1954 | |
| 1891 | 1955 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1892 | 1956 | } |
| 1893 | 1957 | |
| ... | ... | @@ -1954,12 +2018,15 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 1954 | 2018 | try self.register_manager.getReg(.rcx, null); |
| 1955 | 2019 | try self.genSetReg(shift_ty, .rcx, shift); |
| 1956 | 2020 | } |
| 1957 | | self.register_manager.freezeRegs(&.{.rcx}); |
| 1958 | | defer self.register_manager.unfreezeRegs(&.{.rcx}); |
| 2021 | const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx); |
| 2022 | defer self.register_manager.unlockReg(rcx_lock); |
| 1959 | 2023 | |
| 1960 | 2024 | const value = try self.resolveInst(bin_op.lhs); |
| 1961 | | value.freezeIfRegister(&self.register_manager); |
| 1962 | | defer value.unfreezeIfRegister(&self.register_manager); |
| 2025 | const value_lock: ?RegisterLock = switch (value) { |
| 2026 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2027 | else => null, |
| 2028 | }; |
| 2029 | defer if (value_lock) |lock| self.register_manager.unlockReg(lock); |
| 1963 | 2030 | |
| 1964 | 2031 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value); |
| 1965 | 2032 | _ = try self.addInst(.{ |
| ... | ... | @@ -2055,8 +2122,11 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2055 | 2122 | const err_ty = err_union_ty.errorUnionSet(); |
| 2056 | 2123 | const payload_ty = err_union_ty.errorUnionPayload(); |
| 2057 | 2124 | const operand = try self.resolveInst(ty_op.operand); |
| 2058 | | operand.freezeIfRegister(&self.register_manager); |
| 2059 | | defer operand.unfreezeIfRegister(&self.register_manager); |
| 2125 | const operand_lock: ?RegisterLock = switch (operand) { |
| 2126 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2127 | else => null, |
| 2128 | }; |
| 2129 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2060 | 2130 | |
| 2061 | 2131 | const result: MCValue = result: { |
| 2062 | 2132 | if (!payload_ty.hasRuntimeBits()) break :result operand; |
| ... | ... | @@ -2085,8 +2155,11 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2085 | 2155 | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; |
| 2086 | 2156 | |
| 2087 | 2157 | const operand = try self.resolveInst(ty_op.operand); |
| 2088 | | operand.freezeIfRegister(&self.register_manager); |
| 2089 | | defer operand.unfreezeIfRegister(&self.register_manager); |
| 2158 | const operand_lock: ?RegisterLock = switch (operand) { |
| 2159 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2160 | else => null, |
| 2161 | }; |
| 2162 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2090 | 2163 | |
| 2091 | 2164 | const abi_align = err_union_ty.abiAlignment(self.target.*); |
| 2092 | 2165 | const err_ty = err_union_ty.errorUnionSet(); |
| ... | ... | @@ -2154,8 +2227,11 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2154 | 2227 | |
| 2155 | 2228 | const optional_ty = self.air.typeOfIndex(inst); |
| 2156 | 2229 | const operand = try self.resolveInst(ty_op.operand); |
| 2157 | | operand.freezeIfRegister(&self.register_manager); |
| 2158 | | defer operand.unfreezeIfRegister(&self.register_manager); |
| 2230 | const operand_lock: ?RegisterLock = switch (operand) { |
| 2231 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2232 | else => null, |
| 2233 | }; |
| 2234 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2159 | 2235 | |
| 2160 | 2236 | if (optional_ty.isPtrLikeOptional()) { |
| 2161 | 2237 | // TODO should we check if we can reuse the operand? |
| ... | ... | @@ -2288,8 +2364,11 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi |
| 2288 | 2364 | fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2289 | 2365 | const slice_ty = self.air.typeOf(lhs); |
| 2290 | 2366 | const slice_mcv = try self.resolveInst(lhs); |
| 2291 | | slice_mcv.freezeIfRegister(&self.register_manager); |
| 2292 | | defer slice_mcv.unfreezeIfRegister(&self.register_manager); |
| 2367 | const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) { |
| 2368 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2369 | else => null, |
| 2370 | }; |
| 2371 | defer if (slice_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 2293 | 2372 | |
| 2294 | 2373 | const elem_ty = slice_ty.childType(); |
| 2295 | 2374 | const elem_size = elem_ty.abiSize(self.target.*); |
| ... | ... | @@ -2298,12 +2377,15 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2298 | 2377 | |
| 2299 | 2378 | const index_ty = self.air.typeOf(rhs); |
| 2300 | 2379 | const index_mcv = try self.resolveInst(rhs); |
| 2301 | | index_mcv.freezeIfRegister(&self.register_manager); |
| 2302 | | defer index_mcv.unfreezeIfRegister(&self.register_manager); |
| 2380 | const index_mcv_lock: ?RegisterLock = switch (index_mcv) { |
| 2381 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2382 | else => null, |
| 2383 | }; |
| 2384 | defer if (index_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 2303 | 2385 | |
| 2304 | 2386 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); |
| 2305 | | self.register_manager.freezeRegs(&.{offset_reg}); |
| 2306 | | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 2387 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2388 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2307 | 2389 | |
| 2308 | 2390 | const addr_reg = try self.register_manager.allocReg(null); |
| 2309 | 2391 | switch (slice_mcv) { |
| ... | ... | @@ -2356,98 +2438,119 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2356 | 2438 | |
| 2357 | 2439 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2358 | 2440 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2359 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2360 | | const array_ty = self.air.typeOf(bin_op.lhs); |
| 2361 | | const array = try self.resolveInst(bin_op.lhs); |
| 2362 | | array.freezeIfRegister(&self.register_manager); |
| 2363 | | defer array.unfreezeIfRegister(&self.register_manager); |
| 2364 | | |
| 2365 | | const elem_ty = array_ty.childType(); |
| 2366 | | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2367 | 2441 | |
| 2368 | | const index_ty = self.air.typeOf(bin_op.rhs); |
| 2369 | | const index = try self.resolveInst(bin_op.rhs); |
| 2370 | | index.freezeIfRegister(&self.register_manager); |
| 2371 | | defer index.unfreezeIfRegister(&self.register_manager); |
| 2442 | if (self.liveness.isUnused(inst)) { |
| 2443 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2444 | } |
| 2372 | 2445 | |
| 2373 | | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 2374 | | self.register_manager.freezeRegs(&.{offset_reg}); |
| 2375 | | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 2446 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 2447 | const array = try self.resolveInst(bin_op.lhs); |
| 2448 | const array_lock: ?RegisterLock = switch (array) { |
| 2449 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2450 | else => null, |
| 2451 | }; |
| 2452 | defer if (array_lock) |lock| self.register_manager.unlockReg(lock); |
| 2376 | 2453 | |
| 2377 | | const addr_reg = try self.register_manager.allocReg(null); |
| 2378 | | switch (array) { |
| 2379 | | .register => { |
| 2380 | | const off = @intCast(i32, try self.allocMem( |
| 2381 | | inst, |
| 2382 | | @intCast(u32, array_ty.abiSize(self.target.*)), |
| 2383 | | array_ty.abiAlignment(self.target.*), |
| 2384 | | )); |
| 2385 | | try self.genSetStack(array_ty, off, array, .{}); |
| 2386 | | // lea reg, [rbp] |
| 2387 | | _ = try self.addInst(.{ |
| 2388 | | .tag = .lea, |
| 2389 | | .ops = (Mir.Ops{ |
| 2390 | | .reg1 = addr_reg.to64(), |
| 2391 | | .reg2 = .rbp, |
| 2392 | | }).encode(), |
| 2393 | | .data = .{ .imm = @bitCast(u32, -off) }, |
| 2394 | | }); |
| 2395 | | }, |
| 2396 | | .stack_offset => |off| { |
| 2397 | | // lea reg, [rbp] |
| 2398 | | _ = try self.addInst(.{ |
| 2399 | | .tag = .lea, |
| 2400 | | .ops = (Mir.Ops{ |
| 2401 | | .reg1 = addr_reg.to64(), |
| 2402 | | .reg2 = .rbp, |
| 2403 | | }).encode(), |
| 2404 | | .data = .{ .imm = @bitCast(u32, -off) }, |
| 2405 | | }); |
| 2406 | | }, |
| 2407 | | .memory, |
| 2408 | | .got_load, |
| 2409 | | .direct_load, |
| 2410 | | => { |
| 2411 | | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array); |
| 2412 | | }, |
| 2413 | | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| 2414 | | } |
| 2454 | const elem_ty = array_ty.childType(); |
| 2455 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2415 | 2456 | |
| 2416 | | // TODO we could allocate register here, but need to expect addr register and potentially |
| 2417 | | // offset register. |
| 2418 | | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 2419 | | try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg }); |
| 2420 | | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); |
| 2421 | | break :result dst_mcv; |
| 2457 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 2458 | const index = try self.resolveInst(bin_op.rhs); |
| 2459 | const index_lock: ?RegisterLock = switch (index) { |
| 2460 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2461 | else => null, |
| 2422 | 2462 | }; |
| 2423 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2463 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 2464 | |
| 2465 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 2466 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2467 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2468 | |
| 2469 | const addr_reg = try self.register_manager.allocReg(null); |
| 2470 | switch (array) { |
| 2471 | .register => { |
| 2472 | const off = @intCast(i32, try self.allocMem( |
| 2473 | inst, |
| 2474 | @intCast(u32, array_ty.abiSize(self.target.*)), |
| 2475 | array_ty.abiAlignment(self.target.*), |
| 2476 | )); |
| 2477 | try self.genSetStack(array_ty, off, array, .{}); |
| 2478 | // lea reg, [rbp] |
| 2479 | _ = try self.addInst(.{ |
| 2480 | .tag = .lea, |
| 2481 | .ops = (Mir.Ops{ |
| 2482 | .reg1 = addr_reg.to64(), |
| 2483 | .reg2 = .rbp, |
| 2484 | }).encode(), |
| 2485 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 2486 | }); |
| 2487 | }, |
| 2488 | .stack_offset => |off| { |
| 2489 | // lea reg, [rbp] |
| 2490 | _ = try self.addInst(.{ |
| 2491 | .tag = .lea, |
| 2492 | .ops = (Mir.Ops{ |
| 2493 | .reg1 = addr_reg.to64(), |
| 2494 | .reg2 = .rbp, |
| 2495 | }).encode(), |
| 2496 | .data = .{ .imm = @bitCast(u32, -off) }, |
| 2497 | }); |
| 2498 | }, |
| 2499 | .memory, |
| 2500 | .got_load, |
| 2501 | .direct_load, |
| 2502 | => { |
| 2503 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array); |
| 2504 | }, |
| 2505 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| 2506 | } |
| 2507 | |
| 2508 | // TODO we could allocate register here, but need to expect addr register and potentially |
| 2509 | // offset register. |
| 2510 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 2511 | try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg }); |
| 2512 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); |
| 2513 | |
| 2514 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2424 | 2515 | } |
| 2425 | 2516 | |
| 2426 | 2517 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2427 | 2518 | const is_volatile = false; // TODO |
| 2428 | 2519 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2429 | | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { |
| 2430 | | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 2431 | | // additional `mov` is needed at the end to get the actual value |
| 2432 | | |
| 2433 | | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2434 | | const ptr = try self.resolveInst(bin_op.lhs); |
| 2435 | | ptr.freezeIfRegister(&self.register_manager); |
| 2436 | | defer ptr.unfreezeIfRegister(&self.register_manager); |
| 2437 | | |
| 2438 | | const elem_ty = ptr_ty.elemType2(); |
| 2439 | | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2440 | | const index_ty = self.air.typeOf(bin_op.rhs); |
| 2441 | | const index = try self.resolveInst(bin_op.rhs); |
| 2442 | | index.freezeIfRegister(&self.register_manager); |
| 2443 | | defer index.unfreezeIfRegister(&self.register_manager); |
| 2444 | | |
| 2445 | | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 2446 | | self.register_manager.freezeRegs(&.{offset_reg}); |
| 2447 | | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 2448 | | |
| 2449 | | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 2450 | | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2520 | |
| 2521 | if (!is_volatile and self.liveness.isUnused(inst)) { |
| 2522 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2523 | } |
| 2524 | |
| 2525 | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 2526 | // additional `mov` is needed at the end to get the actual value |
| 2527 | |
| 2528 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2529 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2530 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 2531 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2532 | else => null, |
| 2533 | }; |
| 2534 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2535 | |
| 2536 | const elem_ty = ptr_ty.elemType2(); |
| 2537 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2538 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 2539 | const index = try self.resolveInst(bin_op.rhs); |
| 2540 | const index_lock: ?RegisterLock = switch (index) { |
| 2541 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2542 | else => null, |
| 2543 | }; |
| 2544 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 2545 | |
| 2546 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 2547 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2548 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2549 | |
| 2550 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 2551 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2552 | |
| 2553 | const result: MCValue = result: { |
| 2451 | 2554 | if (elem_abi_size > 8) { |
| 2452 | 2555 | return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size}); |
| 2453 | 2556 | } else { |
| ... | ... | @@ -2464,34 +2567,44 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2464 | 2567 | break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) }; |
| 2465 | 2568 | } |
| 2466 | 2569 | }; |
| 2570 | |
| 2467 | 2571 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2468 | 2572 | } |
| 2469 | 2573 | |
| 2470 | 2574 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2471 | 2575 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2472 | 2576 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2473 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2474 | | const ptr_ty = self.air.typeOf(extra.lhs); |
| 2475 | | const ptr = try self.resolveInst(extra.lhs); |
| 2476 | | ptr.freezeIfRegister(&self.register_manager); |
| 2477 | | defer ptr.unfreezeIfRegister(&self.register_manager); |
| 2478 | | |
| 2479 | | const elem_ty = ptr_ty.elemType2(); |
| 2480 | | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2481 | | const index_ty = self.air.typeOf(extra.rhs); |
| 2482 | | const index = try self.resolveInst(extra.rhs); |
| 2483 | | index.freezeIfRegister(&self.register_manager); |
| 2484 | | defer index.unfreezeIfRegister(&self.register_manager); |
| 2485 | | |
| 2486 | | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 2487 | | self.register_manager.freezeRegs(&.{offset_reg}); |
| 2488 | | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 2489 | | |
| 2490 | | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 2491 | | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2492 | | break :result dst_mcv; |
| 2577 | |
| 2578 | if (self.liveness.isUnused(inst)) { |
| 2579 | return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 2580 | } |
| 2581 | |
| 2582 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 2583 | const ptr = try self.resolveInst(extra.lhs); |
| 2584 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 2585 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2586 | else => null, |
| 2493 | 2587 | }; |
| 2494 | | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| 2588 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2589 | |
| 2590 | const elem_ty = ptr_ty.elemType2(); |
| 2591 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2592 | const index_ty = self.air.typeOf(extra.rhs); |
| 2593 | const index = try self.resolveInst(extra.rhs); |
| 2594 | const index_lock: ?RegisterLock = switch (index) { |
| 2595 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2596 | else => null, |
| 2597 | }; |
| 2598 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| 2599 | |
| 2600 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| 2601 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2602 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2603 | |
| 2604 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| 2605 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| 2606 | |
| 2607 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 2495 | 2608 | } |
| 2496 | 2609 | |
| 2497 | 2610 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -2506,12 +2619,18 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 2506 | 2619 | } |
| 2507 | 2620 | |
| 2508 | 2621 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2509 | | ptr.freezeIfRegister(&self.register_manager); |
| 2510 | | defer ptr.unfreezeIfRegister(&self.register_manager); |
| 2622 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 2623 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2624 | else => null, |
| 2625 | }; |
| 2626 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2511 | 2627 | |
| 2512 | 2628 | const tag = try self.resolveInst(bin_op.rhs); |
| 2513 | | tag.freezeIfRegister(&self.register_manager); |
| 2514 | | defer tag.unfreezeIfRegister(&self.register_manager); |
| 2629 | const tag_lock: ?RegisterLock = switch (tag) { |
| 2630 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2631 | else => null, |
| 2632 | }; |
| 2633 | defer if (tag_lock) |lock| self.register_manager.unlockReg(lock); |
| 2515 | 2634 | |
| 2516 | 2635 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { |
| 2517 | 2636 | // TODO reusing the operand |
| ... | ... | @@ -2541,8 +2660,11 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 2541 | 2660 | |
| 2542 | 2661 | // TODO reusing the operand |
| 2543 | 2662 | const operand = try self.resolveInst(ty_op.operand); |
| 2544 | | operand.freezeIfRegister(&self.register_manager); |
| 2545 | | defer operand.unfreezeIfRegister(&self.register_manager); |
| 2663 | const operand_lock: ?RegisterLock = switch (operand) { |
| 2664 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2665 | else => null, |
| 2666 | }; |
| 2667 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2546 | 2668 | |
| 2547 | 2669 | const tag_abi_size = tag_ty.abiSize(self.target.*); |
| 2548 | 2670 | const dst_mcv: MCValue = blk: { |
| ... | ... | @@ -2689,8 +2811,8 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2689 | 2811 | try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }); |
| 2690 | 2812 | }, |
| 2691 | 2813 | .register => |reg| { |
| 2692 | | self.register_manager.freezeRegs(&.{reg}); |
| 2693 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 2814 | const reg_lock = self.register_manager.lockReg(reg); |
| 2815 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 2694 | 2816 | |
| 2695 | 2817 | switch (dst_mcv) { |
| 2696 | 2818 | .dead => unreachable, |
| ... | ... | @@ -2815,8 +2937,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2815 | 2937 | try self.genSetStack(value_ty, off, value, .{}); |
| 2816 | 2938 | }, |
| 2817 | 2939 | .register => |reg| { |
| 2818 | | self.register_manager.freezeRegs(&.{reg}); |
| 2819 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 2940 | const reg_lock = self.register_manager.lockReg(reg); |
| 2941 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 2820 | 2942 | |
| 2821 | 2943 | switch (value) { |
| 2822 | 2944 | .none => unreachable, |
| ... | ... | @@ -2906,12 +3028,15 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2906 | 3028 | .direct_load, |
| 2907 | 3029 | .memory, |
| 2908 | 3030 | => { |
| 2909 | | value.freezeIfRegister(&self.register_manager); |
| 2910 | | defer value.unfreezeIfRegister(&self.register_manager); |
| 3031 | const value_lock: ?RegisterLock = switch (value) { |
| 3032 | .register => |reg| self.register_manager.lockReg(reg), |
| 3033 | else => null, |
| 3034 | }; |
| 3035 | defer if (value_lock) |lock| self.register_manager.unlockReg(lock); |
| 2911 | 3036 | |
| 2912 | 3037 | const addr_reg = try self.register_manager.allocReg(null); |
| 2913 | | self.register_manager.freezeRegs(&.{addr_reg}); |
| 2914 | | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 3038 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 3039 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 2915 | 3040 | |
| 2916 | 3041 | try self.loadMemPtrIntoRegister(addr_reg, ptr_ty, ptr); |
| 2917 | 3042 | |
| ... | ... | @@ -2982,8 +3107,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2982 | 3107 | => { |
| 2983 | 3108 | if (abi_size <= 8) { |
| 2984 | 3109 | const tmp_reg = try self.register_manager.allocReg(null); |
| 2985 | | self.register_manager.freezeRegs(&.{tmp_reg}); |
| 2986 | | defer self.register_manager.unfreezeRegs(&.{tmp_reg}); |
| 3110 | const tmp_reg_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 3111 | defer self.register_manager.unlockReg(tmp_reg_lock); |
| 2987 | 3112 | |
| 2988 | 3113 | try self.loadMemPtrIntoRegister(tmp_reg, value_ty, value); |
| 2989 | 3114 | |
| ... | ... | @@ -3073,8 +3198,8 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3073 | 3198 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ |
| 3074 | 3199 | .immediate = struct_field_offset, |
| 3075 | 3200 | }); |
| 3076 | | self.register_manager.freezeRegs(&.{offset_reg}); |
| 3077 | | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 3201 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 3202 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3078 | 3203 | |
| 3079 | 3204 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, mcv); |
| 3080 | 3205 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| ... | ... | @@ -3085,24 +3210,27 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3085 | 3210 | break :result MCValue{ .ptr_stack_offset = ptr_stack_offset }; |
| 3086 | 3211 | }, |
| 3087 | 3212 | .register => |reg| { |
| 3213 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 3214 | defer self.register_manager.unlockReg(reg_lock); |
| 3215 | |
| 3088 | 3216 | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ |
| 3089 | 3217 | .immediate = struct_field_offset, |
| 3090 | 3218 | }); |
| 3091 | | self.register_manager.freezeRegs(&.{offset_reg}); |
| 3092 | | defer self.register_manager.unfreezeRegs(&.{offset_reg}); |
| 3219 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 3220 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3093 | 3221 | |
| 3094 | 3222 | const can_reuse_operand = self.reuseOperand(inst, operand, 0, mcv); |
| 3095 | | const result_reg = blk: { |
| 3223 | const result_reg: Register = blk: { |
| 3096 | 3224 | if (can_reuse_operand) { |
| 3097 | 3225 | break :blk reg; |
| 3098 | 3226 | } else { |
| 3099 | | self.register_manager.freezeRegs(&.{reg}); |
| 3100 | 3227 | const result_reg = try self.register_manager.allocReg(inst); |
| 3101 | 3228 | try self.genSetReg(ptr_ty, result_reg, mcv); |
| 3102 | 3229 | break :blk result_reg; |
| 3103 | 3230 | } |
| 3104 | 3231 | }; |
| 3105 | | defer if (!can_reuse_operand) self.register_manager.unfreezeRegs(&.{reg}); |
| 3232 | const result_reg_lock = self.register_manager.lockReg(result_reg); |
| 3233 | defer if (result_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3106 | 3234 | |
| 3107 | 3235 | try self.genBinMathOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg }); |
| 3108 | 3236 | break :result MCValue{ .register = result_reg }; |
| ... | ... | @@ -3118,22 +3246,27 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3118 | 3246 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3119 | 3247 | const operand = extra.struct_operand; |
| 3120 | 3248 | const index = extra.field_index; |
| 3121 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3122 | | const mcv = try self.resolveInst(operand); |
| 3123 | | const struct_ty = self.air.typeOf(operand); |
| 3124 | | const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*); |
| 3125 | | const struct_field_ty = struct_ty.structFieldType(index); |
| 3126 | 3249 | |
| 3250 | if (self.liveness.isUnused(inst)) { |
| 3251 | return self.finishAir(inst, .dead, .{ extra.struct_operand, .none, .none }); |
| 3252 | } |
| 3253 | |
| 3254 | const mcv = try self.resolveInst(operand); |
| 3255 | const struct_ty = self.air.typeOf(operand); |
| 3256 | const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*); |
| 3257 | const struct_field_ty = struct_ty.structFieldType(index); |
| 3258 | |
| 3259 | const result: MCValue = result: { |
| 3127 | 3260 | switch (mcv) { |
| 3128 | 3261 | .stack_offset => |off| { |
| 3129 | 3262 | const stack_offset = off - @intCast(i32, struct_field_offset); |
| 3130 | 3263 | break :result MCValue{ .stack_offset = stack_offset }; |
| 3131 | 3264 | }, |
| 3132 | 3265 | .register => |reg| { |
| 3133 | | self.register_manager.freezeRegs(&.{reg}); |
| 3134 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 3266 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 3267 | defer self.register_manager.unlockReg(reg_lock); |
| 3135 | 3268 | |
| 3136 | | const dst_mcv = blk: { |
| 3269 | const dst_mcv: MCValue = blk: { |
| 3137 | 3270 | if (self.reuseOperand(inst, operand, 0, mcv)) { |
| 3138 | 3271 | break :blk mcv; |
| 3139 | 3272 | } else { |
| ... | ... | @@ -3143,8 +3276,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3143 | 3276 | break :blk dst_mcv; |
| 3144 | 3277 | } |
| 3145 | 3278 | }; |
| 3146 | | dst_mcv.freezeIfRegister(&self.register_manager); |
| 3147 | | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 3279 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3280 | .register => |a_reg| self.register_manager.lockReg(a_reg), |
| 3281 | else => null, |
| 3282 | }; |
| 3283 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3148 | 3284 | |
| 3149 | 3285 | // Shift by struct_field_offset. |
| 3150 | 3286 | const shift = @intCast(u8, struct_field_offset * @sizeOf(usize)); |
| ... | ... | @@ -3186,8 +3322,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3186 | 3322 | }, |
| 3187 | 3323 | 1 => { |
| 3188 | 3324 | // Get overflow bit. |
| 3189 | | mcv.freezeIfRegister(&self.register_manager); |
| 3190 | | defer mcv.unfreezeIfRegister(&self.register_manager); |
| 3325 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 3326 | defer self.register_manager.unlockReg(reg_lock); |
| 3191 | 3327 | |
| 3192 | 3328 | const dst_reg = try self.register_manager.allocReg(inst); |
| 3193 | 3329 | const flags: u2 = switch (mcv) { |
| ... | ... | @@ -3229,15 +3365,21 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3229 | 3365 | const dst_ty = self.air.typeOf(op_lhs); |
| 3230 | 3366 | |
| 3231 | 3367 | const lhs = try self.resolveInst(op_lhs); |
| 3232 | | lhs.freezeIfRegister(&self.register_manager); |
| 3233 | | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 3368 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 3369 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3370 | else => null, |
| 3371 | }; |
| 3372 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3234 | 3373 | |
| 3235 | 3374 | const rhs = try self.resolveInst(op_rhs); |
| 3236 | | rhs.freezeIfRegister(&self.register_manager); |
| 3237 | | defer rhs.unfreezeIfRegister(&self.register_manager); |
| 3375 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 3376 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3377 | else => null, |
| 3378 | }; |
| 3379 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3238 | 3380 | |
| 3239 | 3381 | var flipped: bool = false; |
| 3240 | | const dst_mcv = blk: { |
| 3382 | const dst_mcv: MCValue = blk: { |
| 3241 | 3383 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 3242 | 3384 | break :blk lhs; |
| 3243 | 3385 | } |
| ... | ... | @@ -3247,16 +3389,22 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3247 | 3389 | } |
| 3248 | 3390 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 3249 | 3391 | }; |
| 3250 | | dst_mcv.freezeIfRegister(&self.register_manager); |
| 3251 | | defer dst_mcv.unfreezeIfRegister(&self.register_manager); |
| 3392 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3393 | .register => |reg| self.register_manager.lockReg(reg), |
| 3394 | else => null, |
| 3395 | }; |
| 3396 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3252 | 3397 | |
| 3253 | | const src_mcv = blk: { |
| 3398 | const src_mcv: MCValue = blk: { |
| 3254 | 3399 | const mcv = if (flipped) lhs else rhs; |
| 3255 | 3400 | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; |
| 3256 | 3401 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, mcv) }; |
| 3257 | 3402 | }; |
| 3258 | | src_mcv.freezeIfRegister(&self.register_manager); |
| 3259 | | defer src_mcv.unfreezeIfRegister(&self.register_manager); |
| 3403 | const src_mcv_lock: ?RegisterLock = switch (src_mcv) { |
| 3404 | .register => |reg| self.register_manager.lockReg(reg), |
| 3405 | else => null, |
| 3406 | }; |
| 3407 | defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3260 | 3408 | |
| 3261 | 3409 | const tag = self.air.instructions.items(.tag)[inst]; |
| 3262 | 3410 | switch (tag) { |
| ... | ... | @@ -3287,8 +3435,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3287 | 3435 | .register_overflow_unsigned => unreachable, |
| 3288 | 3436 | .register_overflow_signed => unreachable, |
| 3289 | 3437 | .ptr_stack_offset => { |
| 3290 | | self.register_manager.freezeRegs(&.{dst_reg}); |
| 3291 | | defer self.register_manager.unfreezeRegs(&.{dst_reg}); |
| 3438 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 3439 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3440 | |
| 3292 | 3441 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 3293 | 3442 | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| 3294 | 3443 | }, |
| ... | ... | @@ -3318,8 +3467,9 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3318 | 3467 | .compare_flags_unsigned, |
| 3319 | 3468 | => { |
| 3320 | 3469 | assert(abi_size <= 8); |
| 3321 | | self.register_manager.freezeRegs(&.{dst_reg}); |
| 3322 | | defer self.register_manager.unfreezeRegs(&.{dst_reg}); |
| 3470 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 3471 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3472 | |
| 3323 | 3473 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 3324 | 3474 | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| 3325 | 3475 | }, |
| ... | ... | @@ -3659,20 +3809,25 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3659 | 3809 | try self.register_manager.getReg(reg, null); |
| 3660 | 3810 | } |
| 3661 | 3811 | |
| 3662 | | if (info.return_value == .stack_offset) { |
| 3663 | | const ret_ty = fn_ty.fnReturnType(); |
| 3664 | | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3665 | | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 3666 | | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); |
| 3667 | | log.debug("airCall: return value on stack at offset {}", .{stack_offset}); |
| 3812 | const rdi_lock: ?RegisterLock = blk: { |
| 3813 | if (info.return_value == .stack_offset) { |
| 3814 | const ret_ty = fn_ty.fnReturnType(); |
| 3815 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3816 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 3817 | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); |
| 3818 | log.debug("airCall: return value on stack at offset {}", .{stack_offset}); |
| 3668 | 3819 | |
| 3669 | | try self.register_manager.getReg(.rdi, null); |
| 3670 | | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); |
| 3671 | | self.register_manager.freezeRegs(&.{.rdi}); |
| 3820 | try self.register_manager.getReg(.rdi, null); |
| 3821 | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); |
| 3822 | const rdi_lock = self.register_manager.lockRegAssumeUnused(.rdi); |
| 3672 | 3823 | |
| 3673 | | info.return_value.stack_offset = stack_offset; |
| 3674 | | } |
| 3675 | | defer if (info.return_value == .stack_offset) self.register_manager.unfreezeRegs(&.{.rdi}); |
| 3824 | info.return_value.stack_offset = stack_offset; |
| 3825 | |
| 3826 | break :blk rdi_lock; |
| 3827 | } |
| 3828 | break :blk null; |
| 3829 | }; |
| 3830 | defer if (rdi_lock) |lock| self.register_manager.unlockReg(lock); |
| 3676 | 3831 | |
| 3677 | 3832 | for (args) |arg, arg_i| { |
| 3678 | 3833 | const mc_arg = info.args[arg_i]; |
| ... | ... | @@ -3891,11 +4046,10 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 3891 | 4046 | const ret_ty = self.fn_type.fnReturnType(); |
| 3892 | 4047 | switch (self.ret_mcv) { |
| 3893 | 4048 | .stack_offset => { |
| 3894 | | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3895 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3896 | 4049 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3897 | | self.register_manager.freezeRegs(&.{reg}); |
| 3898 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 4050 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 4051 | defer self.register_manager.unlockReg(reg_lock); |
| 4052 | |
| 3899 | 4053 | try self.genSetStack(ret_ty, 0, operand, .{ |
| 3900 | 4054 | .source_stack_base = .rbp, |
| 3901 | 4055 | .dest_stack_base = reg, |
| ... | ... | @@ -3926,11 +4080,10 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3926 | 4080 | const elem_ty = ptr_ty.elemType(); |
| 3927 | 4081 | switch (self.ret_mcv) { |
| 3928 | 4082 | .stack_offset => { |
| 3929 | | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 3930 | | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 3931 | 4083 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 3932 | | self.register_manager.freezeRegs(&.{reg}); |
| 3933 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 4084 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 4085 | defer self.register_manager.unlockReg(reg_lock); |
| 4086 | |
| 3934 | 4087 | try self.genInlineMemcpy(.{ .stack_offset = 0 }, ptr, .{ .immediate = elem_ty.abiSize(self.target.*) }, .{ |
| 3935 | 4088 | .source_stack_base = .rbp, |
| 3936 | 4089 | .dest_stack_base = reg, |
| ... | ... | @@ -3980,12 +4133,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 3980 | 4133 | // Source operand can be an immediate, 8 bits or 32 bits. |
| 3981 | 4134 | // TODO look into reusing the operand |
| 3982 | 4135 | const lhs = try self.resolveInst(bin_op.lhs); |
| 3983 | | lhs.freezeIfRegister(&self.register_manager); |
| 3984 | | defer lhs.unfreezeIfRegister(&self.register_manager); |
| 4136 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 4137 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4138 | else => null, |
| 4139 | }; |
| 4140 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3985 | 4141 | |
| 3986 | 4142 | const dst_reg = try self.copyToTmpRegister(ty, lhs); |
| 3987 | | self.register_manager.freezeRegs(&.{dst_reg}); |
| 3988 | | defer self.register_manager.unfreezeRegs(&.{dst_reg}); |
| 4143 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 4144 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 3989 | 4145 | |
| 3990 | 4146 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 3991 | 4147 | |
| ... | ... | @@ -4446,22 +4602,31 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4446 | 4602 | |
| 4447 | 4603 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4448 | 4604 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4449 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4450 | | const operand_ptr = try self.resolveInst(un_op); |
| 4451 | | operand_ptr.freezeIfRegister(&self.register_manager); |
| 4452 | | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 4453 | | const operand: MCValue = blk: { |
| 4454 | | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4455 | | // The MCValue that holds the pointer can be re-used as the value. |
| 4456 | | break :blk operand_ptr; |
| 4457 | | } else { |
| 4458 | | break :blk try self.allocRegOrMem(inst, true); |
| 4459 | | } |
| 4460 | | }; |
| 4461 | | const ptr_ty = self.air.typeOf(un_op); |
| 4462 | | try self.load(operand, operand_ptr, ptr_ty); |
| 4463 | | break :result try self.isNull(inst, ptr_ty.elemType(), operand); |
| 4605 | |
| 4606 | if (self.liveness.isUnused(inst)) { |
| 4607 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4608 | } |
| 4609 | |
| 4610 | const operand_ptr = try self.resolveInst(un_op); |
| 4611 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4612 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4613 | else => null, |
| 4614 | }; |
| 4615 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4616 | |
| 4617 | const operand: MCValue = blk: { |
| 4618 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4619 | // The MCValue that holds the pointer can be re-used as the value. |
| 4620 | break :blk operand_ptr; |
| 4621 | } else { |
| 4622 | break :blk try self.allocRegOrMem(inst, true); |
| 4623 | } |
| 4464 | 4624 | }; |
| 4625 | const ptr_ty = self.air.typeOf(un_op); |
| 4626 | try self.load(operand, operand_ptr, ptr_ty); |
| 4627 | |
| 4628 | const result = try self.isNull(inst, ptr_ty.elemType(), operand); |
| 4629 | |
| 4465 | 4630 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4466 | 4631 | } |
| 4467 | 4632 | |
| ... | ... | @@ -4477,22 +4642,31 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4477 | 4642 | |
| 4478 | 4643 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4479 | 4644 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4480 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4481 | | const operand_ptr = try self.resolveInst(un_op); |
| 4482 | | operand_ptr.freezeIfRegister(&self.register_manager); |
| 4483 | | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 4484 | | const operand: MCValue = blk: { |
| 4485 | | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4486 | | // The MCValue that holds the pointer can be re-used as the value. |
| 4487 | | break :blk operand_ptr; |
| 4488 | | } else { |
| 4489 | | break :blk try self.allocRegOrMem(inst, true); |
| 4490 | | } |
| 4491 | | }; |
| 4492 | | const ptr_ty = self.air.typeOf(un_op); |
| 4493 | | try self.load(operand, operand_ptr, ptr_ty); |
| 4494 | | break :result try self.isNonNull(inst, ptr_ty.elemType(), operand); |
| 4645 | |
| 4646 | if (self.liveness.isUnused(inst)) { |
| 4647 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4648 | } |
| 4649 | |
| 4650 | const operand_ptr = try self.resolveInst(un_op); |
| 4651 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4652 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4653 | else => null, |
| 4654 | }; |
| 4655 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4656 | |
| 4657 | const operand: MCValue = blk: { |
| 4658 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4659 | // The MCValue that holds the pointer can be re-used as the value. |
| 4660 | break :blk operand_ptr; |
| 4661 | } else { |
| 4662 | break :blk try self.allocRegOrMem(inst, true); |
| 4663 | } |
| 4495 | 4664 | }; |
| 4665 | const ptr_ty = self.air.typeOf(un_op); |
| 4666 | try self.load(operand, operand_ptr, ptr_ty); |
| 4667 | |
| 4668 | const result = try self.isNonNull(inst, ptr_ty.elemType(), operand); |
| 4669 | |
| 4496 | 4670 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4497 | 4671 | } |
| 4498 | 4672 | |
| ... | ... | @@ -4508,22 +4682,31 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4508 | 4682 | |
| 4509 | 4683 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4510 | 4684 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4511 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4512 | | const operand_ptr = try self.resolveInst(un_op); |
| 4513 | | operand_ptr.freezeIfRegister(&self.register_manager); |
| 4514 | | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 4515 | | const operand: MCValue = blk: { |
| 4516 | | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4517 | | // The MCValue that holds the pointer can be re-used as the value. |
| 4518 | | break :blk operand_ptr; |
| 4519 | | } else { |
| 4520 | | break :blk try self.allocRegOrMem(inst, true); |
| 4521 | | } |
| 4522 | | }; |
| 4523 | | const ptr_ty = self.air.typeOf(un_op); |
| 4524 | | try self.load(operand, operand_ptr, ptr_ty); |
| 4525 | | break :result try self.isErr(inst, ptr_ty.elemType(), operand); |
| 4685 | |
| 4686 | if (self.liveness.isUnused(inst)) { |
| 4687 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4688 | } |
| 4689 | |
| 4690 | const operand_ptr = try self.resolveInst(un_op); |
| 4691 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4692 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4693 | else => null, |
| 4526 | 4694 | }; |
| 4695 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4696 | |
| 4697 | const operand: MCValue = blk: { |
| 4698 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4699 | // The MCValue that holds the pointer can be re-used as the value. |
| 4700 | break :blk operand_ptr; |
| 4701 | } else { |
| 4702 | break :blk try self.allocRegOrMem(inst, true); |
| 4703 | } |
| 4704 | }; |
| 4705 | const ptr_ty = self.air.typeOf(un_op); |
| 4706 | try self.load(operand, operand_ptr, ptr_ty); |
| 4707 | |
| 4708 | const result = try self.isErr(inst, ptr_ty.elemType(), operand); |
| 4709 | |
| 4527 | 4710 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4528 | 4711 | } |
| 4529 | 4712 | |
| ... | ... | @@ -4539,22 +4722,31 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4539 | 4722 | |
| 4540 | 4723 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4541 | 4724 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4542 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4543 | | const operand_ptr = try self.resolveInst(un_op); |
| 4544 | | operand_ptr.freezeIfRegister(&self.register_manager); |
| 4545 | | defer operand_ptr.unfreezeIfRegister(&self.register_manager); |
| 4546 | | const operand: MCValue = blk: { |
| 4547 | | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4548 | | // The MCValue that holds the pointer can be re-used as the value. |
| 4549 | | break :blk operand_ptr; |
| 4550 | | } else { |
| 4551 | | break :blk try self.allocRegOrMem(inst, true); |
| 4552 | | } |
| 4553 | | }; |
| 4554 | | const ptr_ty = self.air.typeOf(un_op); |
| 4555 | | try self.load(operand, operand_ptr, ptr_ty); |
| 4556 | | break :result try self.isNonErr(inst, ptr_ty.elemType(), operand); |
| 4725 | |
| 4726 | if (self.liveness.isUnused(inst)) { |
| 4727 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4728 | } |
| 4729 | |
| 4730 | const operand_ptr = try self.resolveInst(un_op); |
| 4731 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4732 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4733 | else => null, |
| 4734 | }; |
| 4735 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4736 | |
| 4737 | const operand: MCValue = blk: { |
| 4738 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4739 | // The MCValue that holds the pointer can be re-used as the value. |
| 4740 | break :blk operand_ptr; |
| 4741 | } else { |
| 4742 | break :blk try self.allocRegOrMem(inst, true); |
| 4743 | } |
| 4557 | 4744 | }; |
| 4745 | const ptr_ty = self.air.typeOf(un_op); |
| 4746 | try self.load(operand, operand_ptr, ptr_ty); |
| 4747 | |
| 4748 | const result = try self.isNonErr(inst, ptr_ty.elemType(), operand); |
| 4749 | |
| 4558 | 4750 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4559 | 4751 | } |
| 4560 | 4752 | |
| ... | ... | @@ -4610,8 +4802,8 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u |
| 4610 | 4802 | .register => |cond_reg| { |
| 4611 | 4803 | try self.spillCompareFlagsIfOccupied(); |
| 4612 | 4804 | |
| 4613 | | self.register_manager.freezeRegs(&.{cond_reg}); |
| 4614 | | defer self.register_manager.unfreezeRegs(&.{cond_reg}); |
| 4805 | const cond_reg_lock = self.register_manager.lockReg(cond_reg); |
| 4806 | defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 4615 | 4807 | |
| 4616 | 4808 | switch (case) { |
| 4617 | 4809 | .none => unreachable, |
| ... | ... | @@ -4670,8 +4862,8 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u |
| 4670 | 4862 | |
| 4671 | 4863 | if (abi_size <= 8) { |
| 4672 | 4864 | const reg = try self.copyToTmpRegister(ty, condition); |
| 4673 | | self.register_manager.freezeRegs(&.{reg}); |
| 4674 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 4865 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 4866 | defer self.register_manager.unlockReg(reg_lock); |
| 4675 | 4867 | return self.genCondSwitchMir(ty, .{ .register = reg }, case); |
| 4676 | 4868 | } |
| 4677 | 4869 | |
| ... | ... | @@ -5158,8 +5350,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5158 | 5350 | .register_overflow_unsigned, |
| 5159 | 5351 | .register_overflow_signed, |
| 5160 | 5352 | => |reg| { |
| 5161 | | self.register_manager.freezeRegs(&.{reg}); |
| 5162 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 5353 | const reg_lock = self.register_manager.lockReg(reg); |
| 5354 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5163 | 5355 | |
| 5164 | 5356 | const wrapped_ty = ty.structFieldType(0); |
| 5165 | 5357 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{}); |
| ... | ... | @@ -5260,8 +5452,8 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5260 | 5452 | |
| 5261 | 5453 | const base_reg = opts.dest_stack_base orelse .rbp; |
| 5262 | 5454 | if (!math.isPowerOfTwo(abi_size)) { |
| 5263 | | self.register_manager.freezeRegs(&.{reg}); |
| 5264 | | defer self.register_manager.unfreezeRegs(&.{reg}); |
| 5455 | const reg_lock = self.register_manager.lockReg(reg); |
| 5456 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5265 | 5457 | |
| 5266 | 5458 | const tmp_reg = try self.copyToTmpRegister(ty, mcv); |
| 5267 | 5459 | |
| ... | ... | @@ -5350,13 +5542,25 @@ fn genInlineMemcpy( |
| 5350 | 5542 | len: MCValue, |
| 5351 | 5543 | opts: InlineMemcpyOpts, |
| 5352 | 5544 | ) InnerError!void { |
| 5353 | | self.register_manager.freezeRegs(&.{ .rax, .rcx }); |
| 5545 | try self.register_manager.getReg(.rax, null); |
| 5546 | try self.register_manager.getReg(.rcx, null); |
| 5354 | 5547 | |
| 5355 | | if (opts.source_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 5356 | | defer if (opts.source_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| 5548 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rcx }); |
| 5549 | defer for (reg_locks) |lock| { |
| 5550 | self.register_manager.unlockReg(lock); |
| 5551 | }; |
| 5552 | |
| 5553 | const ssbase_lock: ?RegisterLock = if (opts.source_stack_base) |reg| |
| 5554 | self.register_manager.lockReg(reg) |
| 5555 | else |
| 5556 | null; |
| 5557 | defer if (ssbase_lock) |reg| self.register_manager.unlockReg(reg); |
| 5357 | 5558 | |
| 5358 | | if (opts.dest_stack_base) |reg| self.register_manager.freezeRegs(&.{reg}); |
| 5359 | | defer if (opts.dest_stack_base) |reg| self.register_manager.unfreezeRegs(&.{reg}); |
| 5559 | const dsbase_lock: ?RegisterLock = if (opts.dest_stack_base) |reg| |
| 5560 | self.register_manager.lockReg(reg) |
| 5561 | else |
| 5562 | null; |
| 5563 | defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock); |
| 5360 | 5564 | |
| 5361 | 5565 | const dst_addr_reg = try self.register_manager.allocReg(null); |
| 5362 | 5566 | switch (dst_ptr) { |
| ... | ... | @@ -5390,8 +5594,8 @@ fn genInlineMemcpy( |
| 5390 | 5594 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); |
| 5391 | 5595 | }, |
| 5392 | 5596 | } |
| 5393 | | self.register_manager.freezeRegs(&.{dst_addr_reg}); |
| 5394 | | defer self.register_manager.unfreezeRegs(&.{dst_addr_reg}); |
| 5597 | const dst_addr_reg_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| 5598 | defer self.register_manager.unlockReg(dst_addr_reg_lock); |
| 5395 | 5599 | |
| 5396 | 5600 | const src_addr_reg = try self.register_manager.allocReg(null); |
| 5397 | 5601 | switch (src_ptr) { |
| ... | ... | @@ -5425,18 +5629,13 @@ fn genInlineMemcpy( |
| 5425 | 5629 | return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr}); |
| 5426 | 5630 | }, |
| 5427 | 5631 | } |
| 5428 | | self.register_manager.freezeRegs(&.{src_addr_reg}); |
| 5429 | | defer self.register_manager.unfreezeRegs(&.{src_addr_reg}); |
| 5632 | const src_addr_reg_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg); |
| 5633 | defer self.register_manager.unlockReg(src_addr_reg_lock); |
| 5430 | 5634 | |
| 5431 | 5635 | const regs = try self.register_manager.allocRegs(2, .{ null, null }); |
| 5432 | 5636 | const count_reg = regs[0].to64(); |
| 5433 | 5637 | const tmp_reg = regs[1].to8(); |
| 5434 | 5638 | |
| 5435 | | self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); |
| 5436 | | |
| 5437 | | try self.register_manager.getReg(.rax, null); |
| 5438 | | try self.register_manager.getReg(.rcx, null); |
| 5439 | | |
| 5440 | 5639 | try self.genSetReg(Type.usize, count_reg, len); |
| 5441 | 5640 | |
| 5442 | 5641 | // mov rcx, 0 |
| ... | ... | @@ -5540,7 +5739,9 @@ fn genInlineMemset( |
| 5540 | 5739 | len: MCValue, |
| 5541 | 5740 | opts: InlineMemcpyOpts, |
| 5542 | 5741 | ) InnerError!void { |
| 5543 | | self.register_manager.freezeRegs(&.{.rax}); |
| 5742 | try self.register_manager.getReg(.rax, null); |
| 5743 | const rax_lock = self.register_manager.lockRegAssumeUnused(.rax); |
| 5744 | defer self.register_manager.unlockReg(rax_lock); |
| 5544 | 5745 | |
| 5545 | 5746 | const addr_reg = try self.register_manager.allocReg(null); |
| 5546 | 5747 | switch (dst_ptr) { |
| ... | ... | @@ -5574,11 +5775,8 @@ fn genInlineMemset( |
| 5574 | 5775 | return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr}); |
| 5575 | 5776 | }, |
| 5576 | 5777 | } |
| 5577 | | self.register_manager.freezeRegs(&.{addr_reg}); |
| 5578 | | defer self.register_manager.unfreezeRegs(&.{addr_reg}); |
| 5579 | | |
| 5580 | | self.register_manager.unfreezeRegs(&.{.rax}); |
| 5581 | | try self.register_manager.getReg(.rax, null); |
| 5778 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 5779 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 5582 | 5780 | |
| 5583 | 5781 | try self.genSetReg(Type.usize, .rax, len); |
| 5584 | 5782 | try self.genBinMathOpMir(.sub, Type.usize, .{ .register = .rax }, .{ .immediate = 1 }); |
| ... | ... | @@ -6017,16 +6215,25 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void { |
| 6017 | 6215 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 6018 | 6216 | |
| 6019 | 6217 | const dst_ptr = try self.resolveInst(pl_op.operand); |
| 6020 | | dst_ptr.freezeIfRegister(&self.register_manager); |
| 6021 | | defer dst_ptr.unfreezeIfRegister(&self.register_manager); |
| 6218 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 6219 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6220 | else => null, |
| 6221 | }; |
| 6222 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 6022 | 6223 | |
| 6023 | 6224 | const src_val = try self.resolveInst(extra.lhs); |
| 6024 | | src_val.freezeIfRegister(&self.register_manager); |
| 6025 | | defer src_val.unfreezeIfRegister(&self.register_manager); |
| 6225 | const src_val_lock: ?RegisterLock = switch (src_val) { |
| 6226 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6227 | else => null, |
| 6228 | }; |
| 6229 | defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock); |
| 6026 | 6230 | |
| 6027 | 6231 | const len = try self.resolveInst(extra.rhs); |
| 6028 | | len.freezeIfRegister(&self.register_manager); |
| 6029 | | defer len.unfreezeIfRegister(&self.register_manager); |
| 6232 | const len_lock: ?RegisterLock = switch (len) { |
| 6233 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6234 | else => null, |
| 6235 | }; |
| 6236 | defer if (len_lock) |lock| self.register_manager.unlockReg(lock); |
| 6030 | 6237 | |
| 6031 | 6238 | try self.genInlineMemset(dst_ptr, src_val, len, .{}); |
| 6032 | 6239 | |
| ... | ... | @@ -6038,17 +6245,26 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 6038 | 6245 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 6039 | 6246 | |
| 6040 | 6247 | const dst_ptr = try self.resolveInst(pl_op.operand); |
| 6041 | | dst_ptr.freezeIfRegister(&self.register_manager); |
| 6042 | | defer dst_ptr.unfreezeIfRegister(&self.register_manager); |
| 6248 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 6249 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6250 | else => null, |
| 6251 | }; |
| 6252 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 6043 | 6253 | |
| 6044 | 6254 | const src_ty = self.air.typeOf(extra.lhs); |
| 6045 | 6255 | const src_ptr = try self.resolveInst(extra.lhs); |
| 6046 | | src_ptr.freezeIfRegister(&self.register_manager); |
| 6047 | | defer src_ptr.unfreezeIfRegister(&self.register_manager); |
| 6256 | const src_ptr_lock: ?RegisterLock = switch (src_ptr) { |
| 6257 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6258 | else => null, |
| 6259 | }; |
| 6260 | defer if (src_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 6048 | 6261 | |
| 6049 | 6262 | const len = try self.resolveInst(extra.rhs); |
| 6050 | | len.freezeIfRegister(&self.register_manager); |
| 6051 | | defer len.unfreezeIfRegister(&self.register_manager); |
| 6263 | const len_lock: ?RegisterLock = switch (len) { |
| 6264 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6265 | else => null, |
| 6266 | }; |
| 6267 | defer if (len_lock) |lock| self.register_manager.unlockReg(lock); |
| 6052 | 6268 | |
| 6053 | 6269 | // TODO Is this the only condition for pointer dereference for memcpy? |
| 6054 | 6270 | const src: MCValue = blk: { |
| ... | ... | @@ -6070,8 +6286,11 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 6070 | 6286 | else => break :blk src_ptr, |
| 6071 | 6287 | } |
| 6072 | 6288 | }; |
| 6073 | | src.freezeIfRegister(&self.register_manager); |
| 6074 | | defer src.unfreezeIfRegister(&self.register_manager); |
| 6289 | const src_lock: ?RegisterLock = switch (src) { |
| 6290 | .register => |reg| self.register_manager.lockReg(reg), |
| 6291 | else => null, |
| 6292 | }; |
| 6293 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 6075 | 6294 | |
| 6076 | 6295 | try self.genInlineMemcpy(dst_ptr, src, len, .{}); |
| 6077 | 6296 | |