| ... | @@ -191,36 +191,12 @@ pub const MCValue = union(enum) { | ... | @@ -191,36 +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 | fn isRegister(mcv: MCValue) bool { | 194 | fn isRegister(mcv: MCValue) bool { |
| 206 | return switch (mcv) { | 195 | return switch (mcv) { |
| 207 | .register, | 196 | .register => true, |
| 208 | .register_overflow_unsigned, | | |
| 209 | .register_overflow_signed, | | |
| 210 | => true, | | |
| 211 | else => false, | 197 | else => false, |
| 212 | }; | 198 | }; |
| 213 | } | 199 | } |
| 214 | | | |
| 215 | fn asRegister(mcv: MCValue) ?Register { | | |
| 216 | return switch (mcv) { | | |
| 217 | .register, | | |
| 218 | .register_overflow_unsigned, | | |
| 219 | .register_overflow_signed, | | |
| 220 | => |reg| reg, | | |
| 221 | else => null, | | |
| 222 | }; | | |
| 223 | } | | |
| 224 | }; | 200 | }; |
| 225 | | 201 | |
| 226 | const Branch = struct { | 202 | const Branch = struct { |
| ... | @@ -852,15 +828,21 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -852,15 +828,21 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 852 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 828 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 853 | branch.inst_table.putAssumeCapacityNoClobber(inst, result); | 829 | branch.inst_table.putAssumeCapacityNoClobber(inst, result); |
| 854 | | 830 | |
| 855 | if (result.asRegister()) |reg| { | 831 | switch (result) { |
| 856 | // In some cases (such as bitcast), an operand | 832 | .register, |
| 857 | // may be the same MCValue as the result. If | 833 | .register_overflow_signed, |
| 858 | // that operand died and was a register, it | 834 | .register_overflow_unsigned, |
| 859 | // was freed by processDeath. We have to | 835 | => |reg| { |
| 860 | // "re-allocate" the register. | 836 | // In some cases (such as bitcast), an operand |
| 861 | if (self.register_manager.isRegFree(reg)) { | 837 | // may be the same MCValue as the result. If |
| 862 | self.register_manager.getRegAssumeFree(reg, inst); | 838 | // that operand died and was a register, it |
| 863 | } | 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 => {}, |
| 864 | } | 846 | } |
| 865 | } | 847 | } |
| 866 | self.finishAirBookkeeping(); | 848 | self.finishAirBookkeeping(); |
| ... | @@ -948,18 +930,32 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -948,18 +930,32 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 948 | pub fn spillCompareFlagsIfOccupied(self: *Self) !void { | 930 | pub fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 949 | if (self.compare_flags_inst) |inst_to_save| { | 931 | if (self.compare_flags_inst) |inst_to_save| { |
| 950 | const mcv = self.getResolvedInstValue(inst_to_save); | 932 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 951 | assert(mcv.usesCompareFlags()); | 933 | const new_mcv = switch (mcv) { |
| | 934 | .register_overflow_signed, |
| | 935 | .register_overflow_unsigned, |
| | 936 | => try self.allocRegOrMem(inst_to_save, false), |
| | 937 | .compare_flags_signed, |
| | 938 | .compare_flags_unsigned, |
| | 939 | => try self.allocRegOrMem(inst_to_save, true), |
| | 940 | else => unreachable, |
| | 941 | }; |
| 952 | | 942 | |
| 953 | const new_mcv = try self.allocRegOrMem(inst_to_save, !mcv.isRegister()); | | |
| 954 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); | 943 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); |
| 955 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); | 944 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| | 945 | |
| 956 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 946 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 957 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); | 947 | try branch.inst_table.put(self.gpa, inst_to_save, new_mcv); |
| 958 | | 948 | |
| 959 | self.compare_flags_inst = null; | 949 | self.compare_flags_inst = null; |
| | 950 | |
| 960 | // TODO consolidate with register manager and spillInstruction | 951 | // TODO consolidate with register manager and spillInstruction |
| 961 | // this call should really belong in the register manager! | 952 | // this call should really belong in the register manager! |
| 962 | if (mcv.isRegister()) self.register_manager.freeReg(mcv.asRegister().?); | 953 | switch (mcv) { |
| | 954 | .register_overflow_signed, |
| | 955 | .register_overflow_unsigned, |
| | 956 | => |reg| self.register_manager.freeReg(reg), |
| | 957 | else => {}, |
| | 958 | } |
| 963 | } | 959 | } |
| 964 | } | 960 | } |
| 965 | | 961 | |
| ... | @@ -1031,7 +1027,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1031,7 +1027,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1031 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1027 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1032 | else => null, | 1028 | else => null, |
| 1033 | }; | 1029 | }; |
| 1034 | defer if (operand_lock) |reg| self.register_manager.unlockReg(reg); | 1030 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 1035 | | 1031 | |
| 1036 | const reg = try self.register_manager.allocReg(inst); | 1032 | const reg = try self.register_manager.allocReg(inst); |
| 1037 | try self.genSetReg(dest_ty, reg, .{ .immediate = 0 }); | 1033 | try self.genSetReg(dest_ty, reg, .{ .immediate = 0 }); |
| ... | @@ -1062,7 +1058,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1062,7 +1058,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1062 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1058 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1063 | else => null, | 1059 | else => null, |
| 1064 | }; | 1060 | }; |
| 1065 | defer if (operand_lock) |reg| self.register_manager.unlockReg(reg); | 1061 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 1066 | | 1062 | |
| 1067 | const reg: Register = blk: { | 1063 | const reg: Register = blk: { |
| 1068 | if (operand.isRegister()) { | 1064 | if (operand.isRegister()) { |
| ... | @@ -1150,7 +1146,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1150,7 +1146,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1150 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1146 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1151 | else => null, | 1147 | else => null, |
| 1152 | }; | 1148 | }; |
| 1153 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | 1149 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1154 | | 1150 | |
| 1155 | const lhs_reg = try self.copyToTmpRegister(ty, lhs); | 1151 | const lhs_reg = try self.copyToTmpRegister(ty, lhs); |
| 1156 | const lhs_reg_lock = self.register_manager.lockRegAssumeUnused(lhs_reg); | 1152 | const lhs_reg_lock = self.register_manager.lockRegAssumeUnused(lhs_reg); |
| ... | @@ -1161,7 +1157,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1161,7 +1157,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { |
| 1161 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1157 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1162 | else => null, | 1158 | else => null, |
| 1163 | }; | 1159 | }; |
| 1164 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | 1160 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1165 | | 1161 | |
| 1166 | try self.genBinMathOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); | 1162 | try self.genBinMathOpMir(.cmp, ty, .{ .register = lhs_reg }, rhs_mcv); |
| 1167 | | 1163 | |
| ... | @@ -1200,9 +1196,9 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r | ... | @@ -1200,9 +1196,9 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r |
| 1200 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1196 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1201 | else => null, | 1197 | else => null, |
| 1202 | }; | 1198 | }; |
| 1203 | defer if (offset_lock) |reg| self.register_manager.unlockReg(reg); | 1199 | defer if (offset_lock) |lock| self.register_manager.unlockReg(lock); |
| 1204 | | 1200 | |
| 1205 | const dst_mcv = blk: { | 1201 | const dst_mcv: MCValue = blk: { |
| 1206 | if (self.reuseOperand(inst, op_lhs, 0, ptr)) { | 1202 | if (self.reuseOperand(inst, op_lhs, 0, ptr)) { |
| 1207 | if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; | 1203 | if (ptr.isMemory() or ptr.isRegister()) break :blk ptr; |
| 1208 | } | 1204 | } |
| ... | @@ -1213,9 +1209,9 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r | ... | @@ -1213,9 +1209,9 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r |
| 1213 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1209 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1214 | else => null, | 1210 | else => null, |
| 1215 | }; | 1211 | }; |
| 1216 | defer if (dst_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 1212 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1217 | | 1213 | |
| 1218 | const offset_mcv = blk: { | 1214 | const offset_mcv: MCValue = blk: { |
| 1219 | if (self.reuseOperand(inst, op_rhs, 1, offset)) { | 1215 | if (self.reuseOperand(inst, op_rhs, 1, offset)) { |
| 1220 | if (offset.isRegister()) break :blk offset; | 1216 | if (offset.isRegister()) break :blk offset; |
| 1221 | } | 1217 | } |
| ... | @@ -1226,7 +1222,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r | ... | @@ -1226,7 +1222,7 @@ fn genPtrBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_r |
| 1226 | .register => |reg| self.register_manager.lockReg(reg), | 1222 | .register => |reg| self.register_manager.lockReg(reg), |
| 1227 | else => null, | 1223 | else => null, |
| 1228 | }; | 1224 | }; |
| 1229 | defer if (offset_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 1225 | defer if (offset_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1230 | | 1226 | |
| 1231 | try self.genIntMulComplexOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); | 1227 | try self.genIntMulComplexOpMir(offset_ty, offset_mcv, .{ .immediate = elem_size }); |
| 1232 | | 1228 | |
| ... | @@ -1315,16 +1311,16 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air | ... | @@ -1315,16 +1311,16 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air |
| 1315 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1311 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1316 | else => null, | 1312 | else => null, |
| 1317 | }; | 1313 | }; |
| 1318 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | 1314 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1319 | | 1315 | |
| 1320 | const rhs = try self.resolveInst(op_rhs); | 1316 | const rhs = try self.resolveInst(op_rhs); |
| 1321 | const rhs_lock: ?RegisterLock = switch (rhs) { | 1317 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1322 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1318 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1323 | else => null, | 1319 | else => null, |
| 1324 | }; | 1320 | }; |
| 1325 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | 1321 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1326 | | 1322 | |
| 1327 | const dst_mcv = blk: { | 1323 | const dst_mcv: MCValue = blk: { |
| 1328 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { | 1324 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 1329 | break :blk lhs; | 1325 | break :blk lhs; |
| 1330 | } | 1326 | } |
| ... | @@ -1334,9 +1330,9 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air | ... | @@ -1334,9 +1330,9 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air |
| 1334 | .register => |reg| self.register_manager.lockReg(reg), | 1330 | .register => |reg| self.register_manager.lockReg(reg), |
| 1335 | else => null, | 1331 | else => null, |
| 1336 | }; | 1332 | }; |
| 1337 | defer if (dst_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 1333 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1338 | | 1334 | |
| 1339 | const rhs_mcv = blk: { | 1335 | const rhs_mcv: MCValue = blk: { |
| 1340 | if (rhs.isMemory() or rhs.isRegister()) break :blk rhs; | 1336 | if (rhs.isMemory() or rhs.isRegister()) break :blk rhs; |
| 1341 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; | 1337 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; |
| 1342 | }; | 1338 | }; |
| ... | @@ -1344,7 +1340,7 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air | ... | @@ -1344,7 +1340,7 @@ fn genSubOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air |
| 1344 | .register => |reg| self.register_manager.lockReg(reg), | 1340 | .register => |reg| self.register_manager.lockReg(reg), |
| 1345 | else => null, | 1341 | else => null, |
| 1346 | }; | 1342 | }; |
| 1347 | defer if (rhs_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 1343 | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1348 | | 1344 | |
| 1349 | try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, rhs_mcv); | 1345 | try self.genBinMathOpMir(.sub, dst_ty, dst_mcv, rhs_mcv); |
| 1350 | | 1346 | |
| ... | @@ -1476,9 +1472,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1476,9 +1472,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1476 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1472 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1477 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1473 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1478 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1474 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1479 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 1480 | const ty = self.air.typeOf(bin_op.lhs); | | |
| 1481 | | 1475 | |
| | 1476 | if (self.liveness.isUnused(inst)) { |
| | 1477 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 1478 | } |
| | 1479 | |
| | 1480 | const ty = self.air.typeOf(bin_op.lhs); |
| | 1481 | const result: MCValue = result: { |
| 1482 | switch (ty.zigTypeTag()) { | 1482 | switch (ty.zigTypeTag()) { |
| 1483 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), | 1483 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 1484 | .Int => { | 1484 | .Int => { |
| ... | @@ -1529,7 +1529,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1529,7 +1529,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1529 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1529 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1530 | else => null, | 1530 | else => null, |
| 1531 | }; | 1531 | }; |
| 1532 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | 1532 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1533 | | 1533 | |
| 1534 | const dst_reg: Register = blk: { | 1534 | const dst_reg: Register = blk: { |
| 1535 | if (lhs.isRegister()) break :blk lhs.register; | 1535 | if (lhs.isRegister()) break :blk lhs.register; |
| ... | @@ -1538,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1538,7 +1538,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1538 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 1538 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 1539 | defer self.register_manager.unlockReg(dst_reg_lock); | 1539 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 1540 | | 1540 | |
| 1541 | const rhs_mcv = blk: { | 1541 | const rhs_mcv: MCValue = blk: { |
| 1542 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; | 1542 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; |
| 1543 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; | 1543 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; |
| 1544 | }; | 1544 | }; |
| ... | @@ -1546,7 +1546,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1546,7 +1546,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1546 | .register => |reg| self.register_manager.lockReg(reg), | 1546 | .register => |reg| self.register_manager.lockReg(reg), |
| 1547 | else => null, | 1547 | else => null, |
| 1548 | }; | 1548 | }; |
| 1549 | defer if (rhs_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 1549 | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 1550 | | 1550 | |
| 1551 | try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv); | 1551 | try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv); |
| 1552 | | 1552 | |
| ... | @@ -1734,19 +1734,19 @@ fn genIntMulDivOpMir( | ... | @@ -1734,19 +1734,19 @@ fn genIntMulDivOpMir( |
| 1734 | /// Clobbers .rax and .rdx registers. | 1734 | /// Clobbers .rax and .rdx registers. |
| 1735 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { | 1735 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 1736 | const signedness = ty.intInfo(self.target.*).signedness; | 1736 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1737 | const dividend = switch (lhs) { | 1737 | const dividend: Register = switch (lhs) { |
| 1738 | .register => |reg| reg, | 1738 | .register => |reg| reg, |
| 1739 | else => try self.copyToTmpRegister(ty, lhs), | 1739 | else => try self.copyToTmpRegister(ty, lhs), |
| 1740 | }; | 1740 | }; |
| 1741 | const dividend_lock = self.register_manager.lockReg(dividend); | 1741 | const dividend_lock = self.register_manager.lockReg(dividend); |
| 1742 | defer if (dividend_lock) |reg| self.register_manager.unlockReg(reg); | 1742 | defer if (dividend_lock) |lock| self.register_manager.unlockReg(lock); |
| 1743 | | 1743 | |
| 1744 | const divisor = switch (rhs) { | 1744 | const divisor: Register = switch (rhs) { |
| 1745 | .register => |reg| reg, | 1745 | .register => |reg| reg, |
| 1746 | else => try self.copyToTmpRegister(ty, rhs), | 1746 | else => try self.copyToTmpRegister(ty, rhs), |
| 1747 | }; | 1747 | }; |
| 1748 | const divisor_lock = self.register_manager.lockReg(divisor); | 1748 | const divisor_lock = self.register_manager.lockReg(divisor); |
| 1749 | defer if (divisor_lock) |reg| self.register_manager.unlockReg(reg); | 1749 | defer if (divisor_lock) |lock| self.register_manager.unlockReg(lock); |
| 1750 | | 1750 | |
| 1751 | try self.genIntMulDivOpMir(switch (signedness) { | 1751 | try self.genIntMulDivOpMir(switch (signedness) { |
| 1752 | .signed => .idiv, | 1752 | .signed => .idiv, |
| ... | @@ -1791,67 +1791,72 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa | ... | @@ -1791,67 +1791,72 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa |
| 1791 | | 1791 | |
| 1792 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { | 1792 | fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1793 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1793 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1794 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 1795 | const tag = self.air.instructions.items(.tag)[inst]; | | |
| 1796 | const ty = self.air.typeOfIndex(inst); | | |
| 1797 | | 1794 | |
| 1798 | if (ty.zigTypeTag() != .Int) { | 1795 | if (self.liveness.isUnused(inst)) { |
| 1799 | return self.fail("TODO implement {} for operands of dst type {}", .{ tag, ty.zigTypeTag() }); | 1796 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1800 | } | 1797 | } |
| 1801 | | 1798 | |
| 1802 | if (tag == .div_float) { | 1799 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1803 | return self.fail("TODO implement {}", .{tag}); | 1800 | const ty = self.air.typeOfIndex(inst); |
| | 1801 | |
| | 1802 | if (ty.zigTypeTag() != .Int) { |
| | 1803 | return self.fail("TODO implement {} for operands of dst type {}", .{ tag, ty.zigTypeTag() }); |
| | 1804 | } |
| | 1805 | |
| | 1806 | if (tag == .div_float) { |
| | 1807 | return self.fail("TODO implement {}", .{tag}); |
| | 1808 | } |
| | 1809 | |
| | 1810 | const signedness = ty.intInfo(self.target.*).signedness; |
| | 1811 | |
| | 1812 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| | 1813 | const track_rax: ?Air.Inst.Index = blk: { |
| | 1814 | if (signedness == .unsigned) break :blk inst; |
| | 1815 | switch (tag) { |
| | 1816 | .div_exact, .div_trunc => break :blk inst, |
| | 1817 | else => break :blk null, |
| 1804 | } | 1818 | } |
| | 1819 | }; |
| | 1820 | try self.register_manager.getReg(.rax, track_rax); |
| | 1821 | try self.register_manager.getReg(.rdx, null); |
| | 1822 | var reg_locks: [2]RegisterLock = undefined; |
| | 1823 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks); |
| | 1824 | defer for (reg_locks) |reg| { |
| | 1825 | self.register_manager.unlockReg(reg); |
| | 1826 | }; |
| 1805 | | 1827 | |
| 1806 | const signedness = ty.intInfo(self.target.*).signedness; | 1828 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1829 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| | 1830 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 1831 | else => null, |
| | 1832 | }; |
| | 1833 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1807 | | 1834 | |
| 1808 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | 1835 | const rhs: MCValue = blk: { |
| 1809 | const track_rax: ?Air.Inst.Index = blk: { | 1836 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1810 | if (signedness == .unsigned) break :blk inst; | 1837 | if (signedness == .signed) { |
| 1811 | switch (tag) { | 1838 | switch (tag) { |
| 1812 | .div_exact, .div_trunc => break :blk inst, | 1839 | .div_floor => { |
| 1813 | else => break :blk null, | 1840 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1814 | } | 1841 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1815 | }; | 1842 | else => null, |
| 1816 | try self.register_manager.getReg(.rax, track_rax); | 1843 | }; |
| 1817 | try self.register_manager.getReg(.rdx, null); | 1844 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1818 | var reg_locks: [2]RegisterLock = undefined; | | |
| 1819 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks); | | |
| 1820 | defer for (reg_locks) |reg| { | | |
| 1821 | self.register_manager.unlockReg(reg); | | |
| 1822 | }; | | |
| 1823 | | | |
| 1824 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1825 | const lhs_lock: ?RegisterLock = switch (lhs) { | | |
| 1826 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1827 | else => null, | | |
| 1828 | }; | | |
| 1829 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1830 | | | |
| 1831 | const rhs = blk: { | | |
| 1832 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1833 | if (signedness == .signed) { | | |
| 1834 | switch (tag) { | | |
| 1835 | .div_floor => { | | |
| 1836 | const rhs_lock: ?RegisterLock = switch (rhs) { | | |
| 1837 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1838 | else => null, | | |
| 1839 | }; | | |
| 1840 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 1841 | | 1845 | |
| 1842 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); | 1846 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); |
| 1843 | }, | 1847 | }, |
| 1844 | else => {}, | 1848 | else => {}, |
| 1845 | } | | |
| 1846 | } | 1849 | } |
| 1847 | break :blk rhs; | 1850 | } |
| 1848 | }; | 1851 | break :blk rhs; |
| 1849 | const rhs_lock: ?RegisterLock = switch (rhs) { | 1852 | }; |
| 1850 | .register => |reg| self.register_manager.lockReg(reg), | 1853 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 1851 | else => null, | 1854 | .register => |reg| self.register_manager.lockReg(reg), |
| 1852 | }; | 1855 | else => null, |
| 1853 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | 1856 | }; |
| | 1857 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1854 | | 1858 | |
| | 1859 | const result: MCValue = result: { |
| 1855 | if (signedness == .unsigned) { | 1860 | if (signedness == .unsigned) { |
| 1856 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs); | 1861 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, rhs); |
| 1857 | break :result MCValue{ .register = .rax }; | 1862 | break :result MCValue{ .register = .rax }; |
| ... | @@ -1871,59 +1876,69 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1871,59 +1876,69 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void { |
| 1871 | else => unreachable, | 1876 | else => unreachable, |
| 1872 | } | 1877 | } |
| 1873 | }; | 1878 | }; |
| | 1879 | |
| 1874 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1880 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1875 | } | 1881 | } |
| 1876 | | 1882 | |
| 1877 | fn airRem(self: *Self, inst: Air.Inst.Index) !void { | 1883 | fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 1878 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1884 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1879 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 1880 | const ty = self.air.typeOfIndex(inst); | | |
| 1881 | if (ty.zigTypeTag() != .Int) { | | |
| 1882 | return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()}); | | |
| 1883 | } | | |
| 1884 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | | |
| 1885 | try self.register_manager.getReg(.rax, null); | | |
| 1886 | try self.register_manager.getReg(.rdx, inst); | | |
| 1887 | var reg_locks: [2]RegisterLock = undefined; | | |
| 1888 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks); | | |
| 1889 | defer for (reg_locks) |reg| { | | |
| 1890 | self.register_manager.unlockReg(reg); | | |
| 1891 | }; | | |
| 1892 | | | |
| 1893 | const lhs = try self.resolveInst(bin_op.lhs); | | |
| 1894 | const rhs = try self.resolveInst(bin_op.rhs); | | |
| 1895 | | 1885 | |
| 1896 | const signedness = ty.intInfo(self.target.*).signedness; | 1886 | if (self.liveness.isUnused(inst)) { |
| 1897 | try self.genIntMulDivOpMir(switch (signedness) { | 1887 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1898 | .signed => .idiv, | 1888 | } |
| 1899 | .unsigned => .div, | 1889 | const ty = self.air.typeOfIndex(inst); |
| 1900 | }, ty, signedness, lhs, rhs); | 1890 | if (ty.zigTypeTag() != .Int) { |
| 1901 | break :result MCValue{ .register = .rdx }; | 1891 | return self.fail("TODO implement .rem for operands of dst type {}", .{ty.zigTypeTag()}); |
| | 1892 | } |
| | 1893 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| | 1894 | try self.register_manager.getReg(.rax, null); |
| | 1895 | try self.register_manager.getReg(.rdx, inst); |
| | 1896 | var reg_locks: [2]RegisterLock = undefined; |
| | 1897 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks); |
| | 1898 | defer for (reg_locks) |reg| { |
| | 1899 | self.register_manager.unlockReg(reg); |
| 1902 | }; | 1900 | }; |
| | 1901 | |
| | 1902 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1903 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1904 | |
| | 1905 | const signedness = ty.intInfo(self.target.*).signedness; |
| | 1906 | try self.genIntMulDivOpMir(switch (signedness) { |
| | 1907 | .signed => .idiv, |
| | 1908 | .unsigned => .div, |
| | 1909 | }, ty, signedness, lhs, rhs); |
| | 1910 | |
| | 1911 | const result: MCValue = .{ .register = .rdx }; |
| | 1912 | |
| 1903 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1913 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1904 | } | 1914 | } |
| 1905 | | 1915 | |
| 1906 | fn airMod(self: *Self, inst: Air.Inst.Index) !void { | 1916 | fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1907 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1917 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1908 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 1909 | const ty = self.air.typeOfIndex(inst); | | |
| 1910 | if (ty.zigTypeTag() != .Int) { | | |
| 1911 | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); | | |
| 1912 | } | | |
| 1913 | const signedness = ty.intInfo(self.target.*).signedness; | | |
| 1914 | | 1918 | |
| 1915 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. | 1919 | if (self.liveness.isUnused(inst)) { |
| 1916 | try self.register_manager.getReg(.rax, null); | 1920 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1917 | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); | 1921 | } |
| 1918 | var reg_locks: [2]RegisterLock = undefined; | | |
| 1919 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks); | | |
| 1920 | defer for (reg_locks) |reg| { | | |
| 1921 | self.register_manager.unlockReg(reg); | | |
| 1922 | }; | | |
| 1923 | | 1922 | |
| 1924 | const lhs = try self.resolveInst(bin_op.lhs); | 1923 | const ty = self.air.typeOfIndex(inst); |
| 1925 | const rhs = try self.resolveInst(bin_op.rhs); | 1924 | if (ty.zigTypeTag() != .Int) { |
| | 1925 | return self.fail("TODO implement .mod for operands of dst type {}", .{ty.zigTypeTag()}); |
| | 1926 | } |
| | 1927 | const signedness = ty.intInfo(self.target.*).signedness; |
| 1926 | | 1928 | |
| | 1929 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| | 1930 | try self.register_manager.getReg(.rax, null); |
| | 1931 | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) inst else null); |
| | 1932 | var reg_locks: [2]RegisterLock = undefined; |
| | 1933 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }, &reg_locks); |
| | 1934 | defer for (reg_locks) |reg| { |
| | 1935 | self.register_manager.unlockReg(reg); |
| | 1936 | }; |
| | 1937 | |
| | 1938 | const lhs = try self.resolveInst(bin_op.lhs); |
| | 1939 | const rhs = try self.resolveInst(bin_op.rhs); |
| | 1940 | |
| | 1941 | const result: MCValue = result: { |
| 1927 | switch (signedness) { | 1942 | switch (signedness) { |
| 1928 | .unsigned => { | 1943 | .unsigned => { |
| 1929 | try self.genIntMulDivOpMir(switch (signedness) { | 1944 | try self.genIntMulDivOpMir(switch (signedness) { |
| ... | @@ -1943,6 +1958,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1943,6 +1958,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1943 | }, | 1958 | }, |
| 1944 | } | 1959 | } |
| 1945 | }; | 1960 | }; |
| | 1961 | |
| 1946 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1962 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1947 | } | 1963 | } |
| 1948 | | 1964 | |
| ... | @@ -2017,7 +2033,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2017,7 +2033,7 @@ fn airShl(self: *Self, inst: Air.Inst.Index) !void { |
| 2017 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2033 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2018 | else => null, | 2034 | else => null, |
| 2019 | }; | 2035 | }; |
| 2020 | defer if (value_lock) |reg| self.register_manager.unlockReg(reg); | 2036 | defer if (value_lock) |lock| self.register_manager.unlockReg(lock); |
| 2021 | | 2037 | |
| 2022 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value); | 2038 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, value); |
| 2023 | _ = try self.addInst(.{ | 2039 | _ = try self.addInst(.{ |
| ... | @@ -2117,7 +2133,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2117,7 +2133,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2117 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2133 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2118 | else => null, | 2134 | else => null, |
| 2119 | }; | 2135 | }; |
| 2120 | defer if (operand_lock) |reg| self.register_manager.unlockReg(reg); | 2136 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2121 | | 2137 | |
| 2122 | const result: MCValue = result: { | 2138 | const result: MCValue = result: { |
| 2123 | if (!payload_ty.hasRuntimeBits()) break :result operand; | 2139 | if (!payload_ty.hasRuntimeBits()) break :result operand; |
| ... | @@ -2150,7 +2166,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2150,7 +2166,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2150 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2166 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2151 | else => null, | 2167 | else => null, |
| 2152 | }; | 2168 | }; |
| 2153 | defer if (operand_lock) |reg| self.register_manager.unlockReg(reg); | 2169 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2154 | | 2170 | |
| 2155 | const abi_align = err_union_ty.abiAlignment(self.target.*); | 2171 | const abi_align = err_union_ty.abiAlignment(self.target.*); |
| 2156 | const err_ty = err_union_ty.errorUnionSet(); | 2172 | const err_ty = err_union_ty.errorUnionSet(); |
| ... | @@ -2222,7 +2238,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2222,7 +2238,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2222 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2238 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2223 | else => null, | 2239 | else => null, |
| 2224 | }; | 2240 | }; |
| 2225 | defer if (operand_lock) |reg| self.register_manager.unlockReg(reg); | 2241 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2226 | | 2242 | |
| 2227 | if (optional_ty.isPtrLikeOptional()) { | 2243 | if (optional_ty.isPtrLikeOptional()) { |
| 2228 | // TODO should we check if we can reuse the operand? | 2244 | // TODO should we check if we can reuse the operand? |
| ... | @@ -2359,7 +2375,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { | ... | @@ -2359,7 +2375,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2359 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2375 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2360 | else => null, | 2376 | else => null, |
| 2361 | }; | 2377 | }; |
| 2362 | defer if (slice_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 2378 | defer if (slice_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 2363 | | 2379 | |
| 2364 | const elem_ty = slice_ty.childType(); | 2380 | const elem_ty = slice_ty.childType(); |
| 2365 | const elem_size = elem_ty.abiSize(self.target.*); | 2381 | const elem_size = elem_ty.abiSize(self.target.*); |
| ... | @@ -2372,7 +2388,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { | ... | @@ -2372,7 +2388,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 2372 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2388 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2373 | else => null, | 2389 | else => null, |
| 2374 | }; | 2390 | }; |
| 2375 | defer if (index_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 2391 | defer if (index_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 2376 | | 2392 | |
| 2377 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); | 2393 | const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size); |
| 2378 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); | 2394 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| ... | @@ -2429,110 +2445,119 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2429,110 +2445,119 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2429 | | 2445 | |
| 2430 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2446 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2431 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2447 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2432 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 2433 | const array_ty = self.air.typeOf(bin_op.lhs); | | |
| 2434 | const array = try self.resolveInst(bin_op.lhs); | | |
| 2435 | const array_lock: ?RegisterLock = switch (array) { | | |
| 2436 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 2437 | else => null, | | |
| 2438 | }; | | |
| 2439 | defer if (array_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2440 | | 2448 | |
| 2441 | const elem_ty = array_ty.childType(); | 2449 | if (self.liveness.isUnused(inst)) { |
| 2442 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 2450 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| | 2451 | } |
| 2443 | | 2452 | |
| 2444 | const index_ty = self.air.typeOf(bin_op.rhs); | 2453 | const array_ty = self.air.typeOf(bin_op.lhs); |
| 2445 | const index = try self.resolveInst(bin_op.rhs); | 2454 | const array = try self.resolveInst(bin_op.lhs); |
| 2446 | const index_lock: ?RegisterLock = switch (index) { | 2455 | const array_lock: ?RegisterLock = switch (array) { |
| 2447 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2456 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2448 | else => null, | 2457 | else => null, |
| 2449 | }; | 2458 | }; |
| 2450 | defer if (index_lock) |reg| self.register_manager.unlockReg(reg); | 2459 | defer if (array_lock) |lock| self.register_manager.unlockReg(lock); |
| 2451 | | 2460 | |
| 2452 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 2461 | const elem_ty = array_ty.childType(); |
| 2453 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); | 2462 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2454 | defer self.register_manager.unlockReg(offset_reg_lock); | | |
| 2455 | | 2463 | |
| 2456 | const addr_reg = try self.register_manager.allocReg(null); | 2464 | const index_ty = self.air.typeOf(bin_op.rhs); |
| 2457 | switch (array) { | 2465 | const index = try self.resolveInst(bin_op.rhs); |
| 2458 | .register => { | 2466 | const index_lock: ?RegisterLock = switch (index) { |
| 2459 | const off = @intCast(i32, try self.allocMem( | 2467 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2460 | inst, | 2468 | else => null, |
| 2461 | @intCast(u32, array_ty.abiSize(self.target.*)), | | |
| 2462 | array_ty.abiAlignment(self.target.*), | | |
| 2463 | )); | | |
| 2464 | try self.genSetStack(array_ty, off, array, .{}); | | |
| 2465 | // lea reg, [rbp] | | |
| 2466 | _ = try self.addInst(.{ | | |
| 2467 | .tag = .lea, | | |
| 2468 | .ops = (Mir.Ops{ | | |
| 2469 | .reg1 = addr_reg.to64(), | | |
| 2470 | .reg2 = .rbp, | | |
| 2471 | }).encode(), | | |
| 2472 | .data = .{ .imm = @bitCast(u32, -off) }, | | |
| 2473 | }); | | |
| 2474 | }, | | |
| 2475 | .stack_offset => |off| { | | |
| 2476 | // lea reg, [rbp] | | |
| 2477 | _ = try self.addInst(.{ | | |
| 2478 | .tag = .lea, | | |
| 2479 | .ops = (Mir.Ops{ | | |
| 2480 | .reg1 = addr_reg.to64(), | | |
| 2481 | .reg2 = .rbp, | | |
| 2482 | }).encode(), | | |
| 2483 | .data = .{ .imm = @bitCast(u32, -off) }, | | |
| 2484 | }); | | |
| 2485 | }, | | |
| 2486 | .memory, | | |
| 2487 | .got_load, | | |
| 2488 | .direct_load, | | |
| 2489 | => { | | |
| 2490 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array); | | |
| 2491 | }, | | |
| 2492 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), | | |
| 2493 | } | | |
| 2494 | | | |
| 2495 | // TODO we could allocate register here, but need to expect addr register and potentially | | |
| 2496 | // offset register. | | |
| 2497 | const dst_mcv = try self.allocRegOrMem(inst, false); | | |
| 2498 | try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg }); | | |
| 2499 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); | | |
| 2500 | break :result dst_mcv; | | |
| 2501 | }; | 2469 | }; |
| 2502 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2470 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| | 2471 | |
| | 2472 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| | 2473 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| | 2474 | defer self.register_manager.unlockReg(offset_reg_lock); |
| | 2475 | |
| | 2476 | const addr_reg = try self.register_manager.allocReg(null); |
| | 2477 | switch (array) { |
| | 2478 | .register => { |
| | 2479 | const off = @intCast(i32, try self.allocMem( |
| | 2480 | inst, |
| | 2481 | @intCast(u32, array_ty.abiSize(self.target.*)), |
| | 2482 | array_ty.abiAlignment(self.target.*), |
| | 2483 | )); |
| | 2484 | try self.genSetStack(array_ty, off, array, .{}); |
| | 2485 | // lea reg, [rbp] |
| | 2486 | _ = try self.addInst(.{ |
| | 2487 | .tag = .lea, |
| | 2488 | .ops = (Mir.Ops{ |
| | 2489 | .reg1 = addr_reg.to64(), |
| | 2490 | .reg2 = .rbp, |
| | 2491 | }).encode(), |
| | 2492 | .data = .{ .imm = @bitCast(u32, -off) }, |
| | 2493 | }); |
| | 2494 | }, |
| | 2495 | .stack_offset => |off| { |
| | 2496 | // lea reg, [rbp] |
| | 2497 | _ = try self.addInst(.{ |
| | 2498 | .tag = .lea, |
| | 2499 | .ops = (Mir.Ops{ |
| | 2500 | .reg1 = addr_reg.to64(), |
| | 2501 | .reg2 = .rbp, |
| | 2502 | }).encode(), |
| | 2503 | .data = .{ .imm = @bitCast(u32, -off) }, |
| | 2504 | }); |
| | 2505 | }, |
| | 2506 | .memory, |
| | 2507 | .got_load, |
| | 2508 | .direct_load, |
| | 2509 | => { |
| | 2510 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, array); |
| | 2511 | }, |
| | 2512 | else => return self.fail("TODO implement array_elem_val when array is {}", .{array}), |
| | 2513 | } |
| | 2514 | |
| | 2515 | // TODO we could allocate register here, but need to expect addr register and potentially |
| | 2516 | // offset register. |
| | 2517 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| | 2518 | try self.genBinMathOpMir(.add, Type.usize, .{ .register = addr_reg }, .{ .register = offset_reg }); |
| | 2519 | try self.load(dst_mcv, .{ .register = addr_reg.to64() }, array_ty); |
| | 2520 | |
| | 2521 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2503 | } | 2522 | } |
| 2504 | | 2523 | |
| 2505 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2524 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2506 | const is_volatile = false; // TODO | 2525 | const is_volatile = false; // TODO |
| 2507 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2526 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2508 | const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: { | | |
| 2509 | // this is identical to the `airPtrElemPtr` codegen expect here an | | |
| 2510 | // additional `mov` is needed at the end to get the actual value | | |
| 2511 | | 2527 | |
| 2512 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2528 | if (!is_volatile and self.liveness.isUnused(inst)) { |
| 2513 | const ptr = try self.resolveInst(bin_op.lhs); | 2529 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2514 | const ptr_lock: ?RegisterLock = switch (ptr) { | 2530 | } |
| 2515 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 2516 | else => null, | | |
| 2517 | }; | | |
| 2518 | defer if (ptr_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2519 | | 2531 | |
| 2520 | const elem_ty = ptr_ty.elemType2(); | 2532 | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 2521 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 2533 | // additional `mov` is needed at the end to get the actual value |
| 2522 | const index_ty = self.air.typeOf(bin_op.rhs); | | |
| 2523 | const index = try self.resolveInst(bin_op.rhs); | | |
| 2524 | const index_lock: ?RegisterLock = switch (index) { | | |
| 2525 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 2526 | else => null, | | |
| 2527 | }; | | |
| 2528 | defer if (index_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2529 | | 2534 | |
| 2530 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 2535 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2531 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); | 2536 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2532 | defer self.register_manager.unlockReg(offset_reg_lock); | 2537 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| | 2538 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 2539 | else => null, |
| | 2540 | }; |
| | 2541 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2533 | | 2542 | |
| 2534 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); | 2543 | const elem_ty = ptr_ty.elemType2(); |
| 2535 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); | 2544 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| | 2545 | const index_ty = self.air.typeOf(bin_op.rhs); |
| | 2546 | const index = try self.resolveInst(bin_op.rhs); |
| | 2547 | const index_lock: ?RegisterLock = switch (index) { |
| | 2548 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 2549 | else => null, |
| | 2550 | }; |
| | 2551 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| | 2552 | |
| | 2553 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| | 2554 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| | 2555 | defer self.register_manager.unlockReg(offset_reg_lock); |
| | 2556 | |
| | 2557 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| | 2558 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| | 2559 | |
| | 2560 | const result: MCValue = result: { |
| 2536 | if (elem_abi_size > 8) { | 2561 | if (elem_abi_size > 8) { |
| 2537 | return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size}); | 2562 | return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size}); |
| 2538 | } else { | 2563 | } else { |
| ... | @@ -2549,40 +2574,44 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2549,40 +2574,44 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2549 | break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) }; | 2574 | break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) }; |
| 2550 | } | 2575 | } |
| 2551 | }; | 2576 | }; |
| | 2577 | |
| 2552 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2578 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2553 | } | 2579 | } |
| 2554 | | 2580 | |
| 2555 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 2581 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2556 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2582 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2557 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2583 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2558 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 2559 | const ptr_ty = self.air.typeOf(extra.lhs); | | |
| 2560 | const ptr = try self.resolveInst(extra.lhs); | | |
| 2561 | const ptr_lock: ?RegisterLock = switch (ptr) { | | |
| 2562 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 2563 | else => null, | | |
| 2564 | }; | | |
| 2565 | defer if (ptr_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2566 | | 2584 | |
| 2567 | const elem_ty = ptr_ty.elemType2(); | 2585 | if (self.liveness.isUnused(inst)) { |
| 2568 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 2586 | return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 2569 | const index_ty = self.air.typeOf(extra.rhs); | 2587 | } |
| 2570 | const index = try self.resolveInst(extra.rhs); | | |
| 2571 | const index_lock: ?RegisterLock = switch (index) { | | |
| 2572 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 2573 | else => null, | | |
| 2574 | }; | | |
| 2575 | defer if (index_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 2576 | | 2588 | |
| 2577 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); | 2589 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 2578 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); | 2590 | const ptr = try self.resolveInst(extra.lhs); |
| 2579 | defer self.register_manager.unlockReg(offset_reg_lock); | 2591 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| | 2592 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 2593 | else => null, |
| | 2594 | }; |
| | 2595 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2580 | | 2596 | |
| 2581 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); | 2597 | const elem_ty = ptr_ty.elemType2(); |
| 2582 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); | 2598 | const elem_abi_size = elem_ty.abiSize(self.target.*); |
| 2583 | break :result dst_mcv; | 2599 | const index_ty = self.air.typeOf(extra.rhs); |
| | 2600 | const index = try self.resolveInst(extra.rhs); |
| | 2601 | const index_lock: ?RegisterLock = switch (index) { |
| | 2602 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 2603 | else => null, |
| 2584 | }; | 2604 | }; |
| 2585 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); | 2605 | defer if (index_lock) |lock| self.register_manager.unlockReg(lock); |
| | 2606 | |
| | 2607 | const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size); |
| | 2608 | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| | 2609 | defer self.register_manager.unlockReg(offset_reg_lock); |
| | 2610 | |
| | 2611 | const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr); |
| | 2612 | try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg }); |
| | 2613 | |
| | 2614 | return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none }); |
| 2586 | } | 2615 | } |
| 2587 | | 2616 | |
| 2588 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | 2617 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -2601,14 +2630,14 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2601,14 +2630,14 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 2601 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2630 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2602 | else => null, | 2631 | else => null, |
| 2603 | }; | 2632 | }; |
| 2604 | defer if (ptr_lock) |reg| self.register_manager.unlockReg(reg); | 2633 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 2605 | | 2634 | |
| 2606 | const tag = try self.resolveInst(bin_op.rhs); | 2635 | const tag = try self.resolveInst(bin_op.rhs); |
| 2607 | const tag_lock: ?RegisterLock = switch (tag) { | 2636 | const tag_lock: ?RegisterLock = switch (tag) { |
| 2608 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2637 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2609 | else => null, | 2638 | else => null, |
| 2610 | }; | 2639 | }; |
| 2611 | defer if (tag_lock) |reg| self.register_manager.unlockReg(reg); | 2640 | defer if (tag_lock) |lock| self.register_manager.unlockReg(lock); |
| 2612 | | 2641 | |
| 2613 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { | 2642 | const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: { |
| 2614 | // TODO reusing the operand | 2643 | // TODO reusing the operand |
| ... | @@ -2642,7 +2671,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2642,7 +2671,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 2642 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2671 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2643 | else => null, | 2672 | else => null, |
| 2644 | }; | 2673 | }; |
| 2645 | defer if (operand_lock) |reg| self.register_manager.unlockReg(reg); | 2674 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2646 | | 2675 | |
| 2647 | const tag_abi_size = tag_ty.abiSize(self.target.*); | 2676 | const tag_abi_size = tag_ty.abiSize(self.target.*); |
| 2648 | const dst_mcv: MCValue = blk: { | 2677 | const dst_mcv: MCValue = blk: { |
| ... | @@ -2790,7 +2819,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2790,7 +2819,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2790 | }, | 2819 | }, |
| 2791 | .register => |reg| { | 2820 | .register => |reg| { |
| 2792 | const reg_lock = self.register_manager.lockReg(reg); | 2821 | const reg_lock = self.register_manager.lockReg(reg); |
| 2793 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); | 2822 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 2794 | | 2823 | |
| 2795 | switch (dst_mcv) { | 2824 | switch (dst_mcv) { |
| 2796 | .dead => unreachable, | 2825 | .dead => unreachable, |
| ... | @@ -2916,7 +2945,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -2916,7 +2945,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 2916 | }, | 2945 | }, |
| 2917 | .register => |reg| { | 2946 | .register => |reg| { |
| 2918 | const reg_lock = self.register_manager.lockReg(reg); | 2947 | const reg_lock = self.register_manager.lockReg(reg); |
| 2919 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); | 2948 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 2920 | | 2949 | |
| 2921 | switch (value) { | 2950 | switch (value) { |
| 2922 | .none => unreachable, | 2951 | .none => unreachable, |
| ... | @@ -3010,7 +3039,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -3010,7 +3039,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 3010 | .register => |reg| self.register_manager.lockReg(reg), | 3039 | .register => |reg| self.register_manager.lockReg(reg), |
| 3011 | else => null, | 3040 | else => null, |
| 3012 | }; | 3041 | }; |
| 3013 | defer if (value_lock) |reg| self.register_manager.unlockReg(reg); | 3042 | defer if (value_lock) |lock| self.register_manager.unlockReg(lock); |
| 3014 | | 3043 | |
| 3015 | const addr_reg = try self.register_manager.allocReg(null); | 3044 | const addr_reg = try self.register_manager.allocReg(null); |
| 3016 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | 3045 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| ... | @@ -3198,7 +3227,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -3198,7 +3227,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3198 | defer self.register_manager.unlockReg(offset_reg_lock); | 3227 | defer self.register_manager.unlockReg(offset_reg_lock); |
| 3199 | | 3228 | |
| 3200 | const can_reuse_operand = self.reuseOperand(inst, operand, 0, mcv); | 3229 | const can_reuse_operand = self.reuseOperand(inst, operand, 0, mcv); |
| 3201 | const result_reg = blk: { | 3230 | const result_reg: Register = blk: { |
| 3202 | if (can_reuse_operand) { | 3231 | if (can_reuse_operand) { |
| 3203 | break :blk reg; | 3232 | break :blk reg; |
| 3204 | } else { | 3233 | } else { |
| ... | @@ -3208,7 +3237,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde | ... | @@ -3208,7 +3237,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 3208 | } | 3237 | } |
| 3209 | }; | 3238 | }; |
| 3210 | const result_reg_lock = self.register_manager.lockReg(result_reg); | 3239 | const result_reg_lock = self.register_manager.lockReg(result_reg); |
| 3211 | defer if (result_reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 3240 | defer if (result_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3212 | | 3241 | |
| 3213 | try self.genBinMathOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg }); | 3242 | try self.genBinMathOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg }); |
| 3214 | break :result MCValue{ .register = result_reg }; | 3243 | break :result MCValue{ .register = result_reg }; |
| ... | @@ -3224,12 +3253,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3224,12 +3253,17 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3224 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 3253 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3225 | const operand = extra.struct_operand; | 3254 | const operand = extra.struct_operand; |
| 3226 | const index = extra.field_index; | 3255 | const index = extra.field_index; |
| 3227 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 3228 | const mcv = try self.resolveInst(operand); | | |
| 3229 | const struct_ty = self.air.typeOf(operand); | | |
| 3230 | const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*); | | |
| 3231 | const struct_field_ty = struct_ty.structFieldType(index); | | |
| 3232 | | 3256 | |
| | 3257 | if (self.liveness.isUnused(inst)) { |
| | 3258 | return self.finishAir(inst, .dead, .{ extra.struct_operand, .none, .none }); |
| | 3259 | } |
| | 3260 | |
| | 3261 | const mcv = try self.resolveInst(operand); |
| | 3262 | const struct_ty = self.air.typeOf(operand); |
| | 3263 | const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*); |
| | 3264 | const struct_field_ty = struct_ty.structFieldType(index); |
| | 3265 | |
| | 3266 | const result: MCValue = result: { |
| 3233 | switch (mcv) { | 3267 | switch (mcv) { |
| 3234 | .stack_offset => |off| { | 3268 | .stack_offset => |off| { |
| 3235 | const stack_offset = off - @intCast(i32, struct_field_offset); | 3269 | const stack_offset = off - @intCast(i32, struct_field_offset); |
| ... | @@ -3239,7 +3273,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3239,7 +3273,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3239 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); | 3273 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| 3240 | defer self.register_manager.unlockReg(reg_lock); | 3274 | defer self.register_manager.unlockReg(reg_lock); |
| 3241 | | 3275 | |
| 3242 | const dst_mcv = blk: { | 3276 | const dst_mcv: MCValue = blk: { |
| 3243 | if (self.reuseOperand(inst, operand, 0, mcv)) { | 3277 | if (self.reuseOperand(inst, operand, 0, mcv)) { |
| 3244 | break :blk mcv; | 3278 | break :blk mcv; |
| 3245 | } else { | 3279 | } else { |
| ... | @@ -3250,10 +3284,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3250,10 +3284,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3250 | } | 3284 | } |
| 3251 | }; | 3285 | }; |
| 3252 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { | 3286 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3253 | .register => |reg| self.register_manager.lockReg(reg), | 3287 | .register => |a_reg| self.register_manager.lockReg(a_reg), |
| 3254 | else => null, | 3288 | else => null, |
| 3255 | }; | 3289 | }; |
| 3256 | defer if (dst_mcv_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 3290 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3257 | | 3291 | |
| 3258 | // Shift by struct_field_offset. | 3292 | // Shift by struct_field_offset. |
| 3259 | const shift = @intCast(u8, struct_field_offset * @sizeOf(usize)); | 3293 | const shift = @intCast(u8, struct_field_offset * @sizeOf(usize)); |
| ... | @@ -3342,17 +3376,17 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -3342,17 +3376,17 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3342 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 3376 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3343 | else => null, | 3377 | else => null, |
| 3344 | }; | 3378 | }; |
| 3345 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | 3379 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3346 | | 3380 | |
| 3347 | const rhs = try self.resolveInst(op_rhs); | 3381 | const rhs = try self.resolveInst(op_rhs); |
| 3348 | const rhs_lock: ?RegisterLock = switch (rhs) { | 3382 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 3349 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 3383 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3350 | else => null, | 3384 | else => null, |
| 3351 | }; | 3385 | }; |
| 3352 | defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg); | 3386 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3353 | | 3387 | |
| 3354 | var flipped: bool = false; | 3388 | var flipped: bool = false; |
| 3355 | const dst_mcv = blk: { | 3389 | const dst_mcv: MCValue = blk: { |
| 3356 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { | 3390 | if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) { |
| 3357 | break :blk lhs; | 3391 | break :blk lhs; |
| 3358 | } | 3392 | } |
| ... | @@ -3366,9 +3400,9 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -3366,9 +3400,9 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3366 | .register => |reg| self.register_manager.lockReg(reg), | 3400 | .register => |reg| self.register_manager.lockReg(reg), |
| 3367 | else => null, | 3401 | else => null, |
| 3368 | }; | 3402 | }; |
| 3369 | defer if (dst_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 3403 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3370 | | 3404 | |
| 3371 | const src_mcv = blk: { | 3405 | const src_mcv: MCValue = blk: { |
| 3372 | const mcv = if (flipped) lhs else rhs; | 3406 | const mcv = if (flipped) lhs else rhs; |
| 3373 | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; | 3407 | if (mcv.isRegister() or mcv.isMemory()) break :blk mcv; |
| 3374 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, mcv) }; | 3408 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, mcv) }; |
| ... | @@ -3377,7 +3411,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: | ... | @@ -3377,7 +3411,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: |
| 3377 | .register => |reg| self.register_manager.lockReg(reg), | 3411 | .register => |reg| self.register_manager.lockReg(reg), |
| 3378 | else => null, | 3412 | else => null, |
| 3379 | }; | 3413 | }; |
| 3380 | defer if (src_mcv_lock) |reg| self.register_manager.unlockReg(reg); | 3414 | defer if (src_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3381 | | 3415 | |
| 3382 | const tag = self.air.instructions.items(.tag)[inst]; | 3416 | const tag = self.air.instructions.items(.tag)[inst]; |
| 3383 | switch (tag) { | 3417 | switch (tag) { |
| ... | @@ -3409,7 +3443,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -3409,7 +3443,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3409 | .register_overflow_signed => unreachable, | 3443 | .register_overflow_signed => unreachable, |
| 3410 | .ptr_stack_offset => { | 3444 | .ptr_stack_offset => { |
| 3411 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | 3445 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 3412 | defer if (dst_reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 3446 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3413 | | 3447 | |
| 3414 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); | 3448 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 3415 | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); | 3449 | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| ... | @@ -3441,7 +3475,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC | ... | @@ -3441,7 +3475,7 @@ fn genBinMathOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MC |
| 3441 | => { | 3475 | => { |
| 3442 | assert(abi_size <= 8); | 3476 | assert(abi_size <= 8); |
| 3443 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | 3477 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 3444 | defer if (dst_reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 3478 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3445 | | 3479 | |
| 3446 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); | 3480 | const reg = try self.copyToTmpRegister(dst_ty, src_mcv); |
| 3447 | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); | 3481 | return self.genBinMathOpMir(mir_tag, dst_ty, dst_mcv, .{ .register = reg }); |
| ... | @@ -3782,22 +3816,25 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -3782,22 +3816,25 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 3782 | try self.register_manager.getReg(reg, null); | 3816 | try self.register_manager.getReg(reg, null); |
| 3783 | } | 3817 | } |
| 3784 | | 3818 | |
| 3785 | const rdi_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { | 3819 | const rdi_lock: ?RegisterLock = blk: { |
| 3786 | const ret_ty = fn_ty.fnReturnType(); | 3820 | if (info.return_value == .stack_offset) { |
| 3787 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 3821 | const ret_ty = fn_ty.fnReturnType(); |
| 3788 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); | 3822 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 3789 | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); | 3823 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); |
| 3790 | log.debug("airCall: return value on stack at offset {}", .{stack_offset}); | 3824 | const stack_offset = @intCast(i32, try self.allocMem(inst, ret_abi_size, ret_abi_align)); |
| | 3825 | log.debug("airCall: return value on stack at offset {}", .{stack_offset}); |
| 3791 | | 3826 | |
| 3792 | try self.register_manager.getReg(.rdi, null); | 3827 | try self.register_manager.getReg(.rdi, null); |
| 3793 | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); | 3828 | try self.genSetReg(Type.usize, .rdi, .{ .ptr_stack_offset = stack_offset }); |
| 3794 | const rdi_lock = self.register_manager.lockRegAssumeUnused(.rdi); | 3829 | const rdi_lock = self.register_manager.lockRegAssumeUnused(.rdi); |
| 3795 | | 3830 | |
| 3796 | info.return_value.stack_offset = stack_offset; | 3831 | info.return_value.stack_offset = stack_offset; |
| 3797 | | 3832 | |
| 3798 | break :blk rdi_lock; | 3833 | break :blk rdi_lock; |
| 3799 | } else null; | 3834 | } |
| 3800 | defer if (rdi_lock) |reg| self.register_manager.unlockReg(reg); | 3835 | break :blk null; |
| | 3836 | }; |
| | 3837 | defer if (rdi_lock) |lock| self.register_manager.unlockReg(lock); |
| 3801 | | 3838 | |
| 3802 | for (args) |arg, arg_i| { | 3839 | for (args) |arg, arg_i| { |
| 3803 | const mc_arg = info.args[arg_i]; | 3840 | const mc_arg = info.args[arg_i]; |
| ... | @@ -4107,7 +4144,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -4107,7 +4144,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4107 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4144 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4108 | else => null, | 4145 | else => null, |
| 4109 | }; | 4146 | }; |
| 4110 | defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg); | 4147 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4111 | | 4148 | |
| 4112 | const dst_reg = try self.copyToTmpRegister(ty, lhs); | 4149 | const dst_reg = try self.copyToTmpRegister(ty, lhs); |
| 4113 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 4150 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| ... | @@ -4572,27 +4609,31 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4572,27 +4609,31 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4572 | | 4609 | |
| 4573 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 4610 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4574 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4611 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4575 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 4576 | const operand_ptr = try self.resolveInst(un_op); | | |
| 4577 | | 4612 | |
| 4578 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | 4613 | if (self.liveness.isUnused(inst)) { |
| 4579 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4614 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4580 | else => null, | 4615 | } |
| 4581 | }; | | |
| 4582 | defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 4583 | | 4616 | |
| 4584 | const operand: MCValue = blk: { | 4617 | const operand_ptr = try self.resolveInst(un_op); |
| 4585 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 4618 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4586 | // The MCValue that holds the pointer can be re-used as the value. | 4619 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4587 | break :blk operand_ptr; | 4620 | else => null, |
| 4588 | } else { | 4621 | }; |
| 4589 | break :blk try self.allocRegOrMem(inst, true); | 4622 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4590 | } | 4623 | |
| 4591 | }; | 4624 | const operand: MCValue = blk: { |
| 4592 | const ptr_ty = self.air.typeOf(un_op); | 4625 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4593 | try self.load(operand, operand_ptr, ptr_ty); | 4626 | // The MCValue that holds the pointer can be re-used as the value. |
| 4594 | break :result try self.isNull(inst, ptr_ty.elemType(), operand); | 4627 | break :blk operand_ptr; |
| | 4628 | } else { |
| | 4629 | break :blk try self.allocRegOrMem(inst, true); |
| | 4630 | } |
| 4595 | }; | 4631 | }; |
| | 4632 | const ptr_ty = self.air.typeOf(un_op); |
| | 4633 | try self.load(operand, operand_ptr, ptr_ty); |
| | 4634 | |
| | 4635 | const result = try self.isNull(inst, ptr_ty.elemType(), operand); |
| | 4636 | |
| 4596 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 4637 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4597 | } | 4638 | } |
| 4598 | | 4639 | |
| ... | @@ -4608,27 +4649,31 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4608,27 +4649,31 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4608 | | 4649 | |
| 4609 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 4650 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4610 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4651 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4611 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 4612 | const operand_ptr = try self.resolveInst(un_op); | | |
| 4613 | | 4652 | |
| 4614 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | 4653 | if (self.liveness.isUnused(inst)) { |
| 4615 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4654 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4616 | else => null, | 4655 | } |
| 4617 | }; | | |
| 4618 | defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 4619 | | 4656 | |
| 4620 | const operand: MCValue = blk: { | 4657 | const operand_ptr = try self.resolveInst(un_op); |
| 4621 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 4658 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4622 | // The MCValue that holds the pointer can be re-used as the value. | 4659 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4623 | break :blk operand_ptr; | 4660 | else => null, |
| 4624 | } else { | | |
| 4625 | break :blk try self.allocRegOrMem(inst, true); | | |
| 4626 | } | | |
| 4627 | }; | | |
| 4628 | const ptr_ty = self.air.typeOf(un_op); | | |
| 4629 | try self.load(operand, operand_ptr, ptr_ty); | | |
| 4630 | break :result try self.isNonNull(inst, ptr_ty.elemType(), operand); | | |
| 4631 | }; | 4661 | }; |
| | 4662 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| | 4663 | |
| | 4664 | const operand: MCValue = blk: { |
| | 4665 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| | 4666 | // The MCValue that holds the pointer can be re-used as the value. |
| | 4667 | break :blk operand_ptr; |
| | 4668 | } else { |
| | 4669 | break :blk try self.allocRegOrMem(inst, true); |
| | 4670 | } |
| | 4671 | }; |
| | 4672 | const ptr_ty = self.air.typeOf(un_op); |
| | 4673 | try self.load(operand, operand_ptr, ptr_ty); |
| | 4674 | |
| | 4675 | const result = try self.isNonNull(inst, ptr_ty.elemType(), operand); |
| | 4676 | |
| 4632 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 4677 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4633 | } | 4678 | } |
| 4634 | | 4679 | |
| ... | @@ -4644,27 +4689,31 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4644,27 +4689,31 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4644 | | 4689 | |
| 4645 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 4690 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4646 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4691 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4647 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 4648 | const operand_ptr = try self.resolveInst(un_op); | | |
| 4649 | | 4692 | |
| 4650 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | 4693 | if (self.liveness.isUnused(inst)) { |
| 4651 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4694 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4652 | else => null, | 4695 | } |
| 4653 | }; | | |
| 4654 | defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 4655 | | 4696 | |
| 4656 | const operand: MCValue = blk: { | 4697 | const operand_ptr = try self.resolveInst(un_op); |
| 4657 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 4698 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4658 | // The MCValue that holds the pointer can be re-used as the value. | 4699 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4659 | break :blk operand_ptr; | 4700 | else => null, |
| 4660 | } else { | 4701 | }; |
| 4661 | break :blk try self.allocRegOrMem(inst, true); | 4702 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4662 | } | 4703 | |
| 4663 | }; | 4704 | const operand: MCValue = blk: { |
| 4664 | const ptr_ty = self.air.typeOf(un_op); | 4705 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4665 | try self.load(operand, operand_ptr, ptr_ty); | 4706 | // The MCValue that holds the pointer can be re-used as the value. |
| 4666 | break :result try self.isErr(inst, ptr_ty.elemType(), operand); | 4707 | break :blk operand_ptr; |
| | 4708 | } else { |
| | 4709 | break :blk try self.allocRegOrMem(inst, true); |
| | 4710 | } |
| 4667 | }; | 4711 | }; |
| | 4712 | const ptr_ty = self.air.typeOf(un_op); |
| | 4713 | try self.load(operand, operand_ptr, ptr_ty); |
| | 4714 | |
| | 4715 | const result = try self.isErr(inst, ptr_ty.elemType(), operand); |
| | 4716 | |
| 4668 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 4717 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4669 | } | 4718 | } |
| 4670 | | 4719 | |
| ... | @@ -4680,27 +4729,31 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4680,27 +4729,31 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4680 | | 4729 | |
| 4681 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 4730 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4682 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4731 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4683 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | | |
| 4684 | const operand_ptr = try self.resolveInst(un_op); | | |
| 4685 | | 4732 | |
| 4686 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | 4733 | if (self.liveness.isUnused(inst)) { |
| 4687 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4734 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); |
| 4688 | else => null, | 4735 | } |
| 4689 | }; | | |
| 4690 | defer if (operand_ptr_lock) |reg| self.register_manager.unlockReg(reg); | | |
| 4691 | | 4736 | |
| 4692 | const operand: MCValue = blk: { | 4737 | const operand_ptr = try self.resolveInst(un_op); |
| 4693 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { | 4738 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { |
| 4694 | // The MCValue that holds the pointer can be re-used as the value. | 4739 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 4695 | break :blk operand_ptr; | 4740 | else => null, |
| 4696 | } else { | 4741 | }; |
| 4697 | break :blk try self.allocRegOrMem(inst, true); | 4742 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4698 | } | 4743 | |
| 4699 | }; | 4744 | const operand: MCValue = blk: { |
| 4700 | const ptr_ty = self.air.typeOf(un_op); | 4745 | if (self.reuseOperand(inst, un_op, 0, operand_ptr)) { |
| 4701 | try self.load(operand, operand_ptr, ptr_ty); | 4746 | // The MCValue that holds the pointer can be re-used as the value. |
| 4702 | break :result try self.isNonErr(inst, ptr_ty.elemType(), operand); | 4747 | break :blk operand_ptr; |
| | 4748 | } else { |
| | 4749 | break :blk try self.allocRegOrMem(inst, true); |
| | 4750 | } |
| 4703 | }; | 4751 | }; |
| | 4752 | const ptr_ty = self.air.typeOf(un_op); |
| | 4753 | try self.load(operand, operand_ptr, ptr_ty); |
| | 4754 | |
| | 4755 | const result = try self.isNonErr(inst, ptr_ty.elemType(), operand); |
| | 4756 | |
| 4704 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 4757 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 4705 | } | 4758 | } |
| 4706 | | 4759 | |
| ... | @@ -4757,7 +4810,7 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u | ... | @@ -4757,7 +4810,7 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u |
| 4757 | try self.spillCompareFlagsIfOccupied(); | 4810 | try self.spillCompareFlagsIfOccupied(); |
| 4758 | | 4811 | |
| 4759 | const cond_reg_lock = self.register_manager.lockReg(cond_reg); | 4812 | const cond_reg_lock = self.register_manager.lockReg(cond_reg); |
| 4760 | defer if (cond_reg_lock) |reg| self.register_manager.unlockReg(reg); | 4813 | defer if (cond_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 4761 | | 4814 | |
| 4762 | switch (case) { | 4815 | switch (case) { |
| 4763 | .none => unreachable, | 4816 | .none => unreachable, |
| ... | @@ -5305,7 +5358,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -5305,7 +5358,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5305 | .register_overflow_signed, | 5358 | .register_overflow_signed, |
| 5306 | => |reg| { | 5359 | => |reg| { |
| 5307 | const reg_lock = self.register_manager.lockReg(reg); | 5360 | const reg_lock = self.register_manager.lockReg(reg); |
| 5308 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 5361 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5309 | | 5362 | |
| 5310 | const wrapped_ty = ty.structFieldType(0); | 5363 | const wrapped_ty = ty.structFieldType(0); |
| 5311 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{}); | 5364 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }, .{}); |
| ... | @@ -5407,7 +5460,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -5407,7 +5460,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5407 | const base_reg = opts.dest_stack_base orelse .rbp; | 5460 | const base_reg = opts.dest_stack_base orelse .rbp; |
| 5408 | if (!math.isPowerOfTwo(abi_size)) { | 5461 | if (!math.isPowerOfTwo(abi_size)) { |
| 5409 | const reg_lock = self.register_manager.lockReg(reg); | 5462 | const reg_lock = self.register_manager.lockReg(reg); |
| 5410 | defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked); | 5463 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5411 | | 5464 | |
| 5412 | const tmp_reg = try self.copyToTmpRegister(ty, mcv); | 5465 | const tmp_reg = try self.copyToTmpRegister(ty, mcv); |
| 5413 | | 5466 | |
| ... | @@ -5501,8 +5554,8 @@ fn genInlineMemcpy( | ... | @@ -5501,8 +5554,8 @@ fn genInlineMemcpy( |
| 5501 | | 5554 | |
| 5502 | var reg_locks: [2]RegisterLock = undefined; | 5555 | var reg_locks: [2]RegisterLock = undefined; |
| 5503 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rcx }, &reg_locks); | 5556 | self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rcx }, &reg_locks); |
| 5504 | defer for (reg_locks) |reg| { | 5557 | defer for (reg_locks) |lock| { |
| 5505 | self.register_manager.unlockReg(reg); | 5558 | self.register_manager.unlockReg(lock); |
| 5506 | }; | 5559 | }; |
| 5507 | | 5560 | |
| 5508 | const ssbase_lock: ?RegisterLock = if (opts.source_stack_base) |reg| | 5561 | const ssbase_lock: ?RegisterLock = if (opts.source_stack_base) |reg| |
| ... | @@ -5515,7 +5568,7 @@ fn genInlineMemcpy( | ... | @@ -5515,7 +5568,7 @@ fn genInlineMemcpy( |
| 5515 | self.register_manager.lockReg(reg) | 5568 | self.register_manager.lockReg(reg) |
| 5516 | else | 5569 | else |
| 5517 | null; | 5570 | null; |
| 5518 | defer if (dsbase_lock) |reg| self.register_manager.unlockReg(reg); | 5571 | defer if (dsbase_lock) |lock| self.register_manager.unlockReg(lock); |
| 5519 | | 5572 | |
| 5520 | const dst_addr_reg = try self.register_manager.allocReg(null); | 5573 | const dst_addr_reg = try self.register_manager.allocReg(null); |
| 5521 | switch (dst_ptr) { | 5574 | switch (dst_ptr) { |
| ... | @@ -6174,21 +6227,21 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6174,21 +6227,21 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) !void { |
| 6174 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6227 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6175 | else => null, | 6228 | else => null, |
| 6176 | }; | 6229 | }; |
| 6177 | defer if (dst_ptr_lock) |reg| self.register_manager.unlockReg(reg); | 6230 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 6178 | | 6231 | |
| 6179 | const src_val = try self.resolveInst(extra.lhs); | 6232 | const src_val = try self.resolveInst(extra.lhs); |
| 6180 | const src_val_lock: ?RegisterLock = switch (src_val) { | 6233 | const src_val_lock: ?RegisterLock = switch (src_val) { |
| 6181 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6234 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6182 | else => null, | 6235 | else => null, |
| 6183 | }; | 6236 | }; |
| 6184 | defer if (src_val_lock) |reg| self.register_manager.unlockReg(reg); | 6237 | defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock); |
| 6185 | | 6238 | |
| 6186 | const len = try self.resolveInst(extra.rhs); | 6239 | const len = try self.resolveInst(extra.rhs); |
| 6187 | const len_lock: ?RegisterLock = switch (len) { | 6240 | const len_lock: ?RegisterLock = switch (len) { |
| 6188 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6241 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6189 | else => null, | 6242 | else => null, |
| 6190 | }; | 6243 | }; |
| 6191 | defer if (len_lock) |reg| self.register_manager.unlockReg(reg); | 6244 | defer if (len_lock) |lock| self.register_manager.unlockReg(lock); |
| 6192 | | 6245 | |
| 6193 | try self.genInlineMemset(dst_ptr, src_val, len, .{}); | 6246 | try self.genInlineMemset(dst_ptr, src_val, len, .{}); |
| 6194 | | 6247 | |
| ... | @@ -6204,7 +6257,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6204,7 +6257,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 6204 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6257 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6205 | else => null, | 6258 | else => null, |
| 6206 | }; | 6259 | }; |
| 6207 | defer if (dst_ptr_lock) |reg| self.register_manager.unlockReg(reg); | 6260 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 6208 | | 6261 | |
| 6209 | const src_ty = self.air.typeOf(extra.lhs); | 6262 | const src_ty = self.air.typeOf(extra.lhs); |
| 6210 | const src_ptr = try self.resolveInst(extra.lhs); | 6263 | const src_ptr = try self.resolveInst(extra.lhs); |
| ... | @@ -6212,14 +6265,14 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6212,14 +6265,14 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 6212 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6265 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6213 | else => null, | 6266 | else => null, |
| 6214 | }; | 6267 | }; |
| 6215 | defer if (src_ptr_lock) |reg| self.register_manager.unlockReg(reg); | 6268 | defer if (src_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 6216 | | 6269 | |
| 6217 | const len = try self.resolveInst(extra.rhs); | 6270 | const len = try self.resolveInst(extra.rhs); |
| 6218 | const len_lock: ?RegisterLock = switch (len) { | 6271 | const len_lock: ?RegisterLock = switch (len) { |
| 6219 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 6272 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 6220 | else => null, | 6273 | else => null, |
| 6221 | }; | 6274 | }; |
| 6222 | defer if (len_lock) |reg| self.register_manager.unlockReg(reg); | 6275 | defer if (len_lock) |lock| self.register_manager.unlockReg(lock); |
| 6223 | | 6276 | |
| 6224 | // TODO Is this the only condition for pointer dereference for memcpy? | 6277 | // TODO Is this the only condition for pointer dereference for memcpy? |
| 6225 | const src: MCValue = blk: { | 6278 | const src: MCValue = blk: { |
| ... | @@ -6245,7 +6298,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6245,7 +6298,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 6245 | .register => |reg| self.register_manager.lockReg(reg), | 6298 | .register => |reg| self.register_manager.lockReg(reg), |
| 6246 | else => null, | 6299 | else => null, |
| 6247 | }; | 6300 | }; |
| 6248 | defer if (src_lock) |reg| self.register_manager.unlockReg(reg); | 6301 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 6249 | | 6302 | |
| 6250 | try self.genInlineMemcpy(dst_ptr, src, len, .{}); | 6303 | try self.genInlineMemcpy(dst_ptr, src, len, .{}); |
| 6251 | | 6304 | |