| ... | ... | @@ -592,8 +592,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 592 | 592 | .sub => try self.airBinOp(inst), |
| 593 | 593 | .subwrap => try self.airBinOp(inst), |
| 594 | 594 | .sub_sat => try self.airSubSat(inst), |
| 595 | | .mul => try self.airMul(inst), |
| 596 | | .mulwrap => try self.airMul(inst), |
| 595 | .mul => try self.airBinOp(inst), |
| 596 | .mulwrap => try self.airBinOp(inst), |
| 597 | 597 | .mul_sat => try self.airMulSat(inst), |
| 598 | 598 | .rem => try self.airRem(inst), |
| 599 | 599 | .mod => try self.airMod(inst), |
| ... | ... | @@ -1122,7 +1122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1122 | 1122 | }, |
| 1123 | 1123 | else => {}, |
| 1124 | 1124 | } |
| 1125 | | break :result try self.genBinOp(inst, ty_op.operand, .bool_true); |
| 1125 | break :result try self.genBinOp(inst, ty_op.operand, .bool_true, true); |
| 1126 | 1126 | }; |
| 1127 | 1127 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1128 | 1128 | } |
| ... | ... | @@ -1185,24 +1185,6 @@ fn airMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1185 | 1185 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1186 | 1186 | } |
| 1187 | 1187 | |
| 1188 | | fn airPtrAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 1189 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1190 | | const result = if (self.liveness.isUnused(inst)) |
| 1191 | | .dead |
| 1192 | | else |
| 1193 | | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1194 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1195 | | } |
| 1196 | | |
| 1197 | | fn airPtrSub(self: *Self, inst: Air.Inst.Index) !void { |
| 1198 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1199 | | const result = if (self.liveness.isUnused(inst)) |
| 1200 | | .dead |
| 1201 | | else |
| 1202 | | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1203 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1204 | | } |
| 1205 | | |
| 1206 | 1188 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1207 | 1189 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1208 | 1190 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | ... | @@ -1229,7 +1211,7 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 1229 | 1211 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1230 | 1212 | .dead |
| 1231 | 1213 | else |
| 1232 | | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1214 | try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); |
| 1233 | 1215 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1234 | 1216 | } |
| 1235 | 1217 | |
| ... | ... | @@ -1251,36 +1233,6 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1251 | 1233 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1252 | 1234 | } |
| 1253 | 1235 | |
| 1254 | | fn airMul(self: *Self, inst: Air.Inst.Index) !void { |
| 1255 | | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1256 | | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1257 | | const ty = self.air.typeOfIndex(inst); |
| 1258 | | |
| 1259 | | if (ty.zigTypeTag() != .Int) { |
| 1260 | | return self.fail("TODO implement 'mul' for operands of dst type {}", .{ty.zigTypeTag()}); |
| 1261 | | } |
| 1262 | | |
| 1263 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1264 | | try self.register_manager.getReg(.rax, inst); |
| 1265 | | try self.register_manager.getReg(.rdx, null); |
| 1266 | | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1267 | | defer for (reg_locks) |reg| { |
| 1268 | | self.register_manager.unlockReg(reg); |
| 1269 | | }; |
| 1270 | | |
| 1271 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1272 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1273 | | |
| 1274 | | const signedness = ty.intInfo(self.target.*).signedness; |
| 1275 | | try self.genIntMulDivOpMir(switch (signedness) { |
| 1276 | | .signed => .imul, |
| 1277 | | .unsigned => .mul, |
| 1278 | | }, ty, signedness, lhs, rhs); |
| 1279 | | break :result MCValue{ .register = .rax }; |
| 1280 | | }; |
| 1281 | | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1282 | | } |
| 1283 | | |
| 1284 | 1236 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1285 | 1237 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1286 | 1238 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| ... | ... | @@ -1308,7 +1260,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1308 | 1260 | try self.spillCompareFlagsIfOccupied(); |
| 1309 | 1261 | self.compare_flags_inst = inst; |
| 1310 | 1262 | |
| 1311 | | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1263 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); |
| 1312 | 1264 | const result: MCValue = switch (int_info.signedness) { |
| 1313 | 1265 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1314 | 1266 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | ... | @@ -1340,7 +1292,7 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1340 | 1292 | try self.spillCompareFlagsIfOccupied(); |
| 1341 | 1293 | self.compare_flags_inst = inst; |
| 1342 | 1294 | |
| 1343 | | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs); |
| 1295 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); |
| 1344 | 1296 | const result: MCValue = switch (int_info.signedness) { |
| 1345 | 1297 | .signed => .{ .register_overflow_signed = partial.register }, |
| 1346 | 1298 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| ... | ... | @@ -1373,34 +1325,17 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1373 | 1325 | return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); |
| 1374 | 1326 | } |
| 1375 | 1327 | |
| 1328 | try self.spillCompareFlagsIfOccupied(); |
| 1329 | |
| 1376 | 1330 | if (math.isPowerOfTwo(int_info.bits)) { |
| 1377 | | try self.spillCompareFlagsIfOccupied(); |
| 1378 | 1331 | self.compare_flags_inst = inst; |
| 1379 | | |
| 1380 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1381 | | try self.register_manager.getReg(.rax, inst); |
| 1382 | | try self.register_manager.getReg(.rdx, null); |
| 1383 | | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1384 | | defer for (reg_locks) |reg| { |
| 1385 | | self.register_manager.unlockReg(reg); |
| 1332 | const partial = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, true); |
| 1333 | break :result switch (int_info.signedness) { |
| 1334 | .signed => MCValue{ .register_overflow_signed = partial.register }, |
| 1335 | .unsigned => MCValue{ .register_overflow_unsigned = partial.register }, |
| 1386 | 1336 | }; |
| 1387 | | |
| 1388 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1389 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1390 | | |
| 1391 | | try self.genIntMulDivOpMir(switch (int_info.signedness) { |
| 1392 | | .signed => .imul, |
| 1393 | | .unsigned => .mul, |
| 1394 | | }, ty, int_info.signedness, lhs, rhs); |
| 1395 | | |
| 1396 | | const result: MCValue = switch (int_info.signedness) { |
| 1397 | | .signed => .{ .register_overflow_signed = .rax }, |
| 1398 | | .unsigned => .{ .register_overflow_unsigned = .rax }, |
| 1399 | | }; |
| 1400 | | break :result result; |
| 1401 | 1337 | } |
| 1402 | 1338 | |
| 1403 | | try self.spillCompareFlagsIfOccupied(); |
| 1404 | 1339 | self.compare_flags_inst = null; |
| 1405 | 1340 | |
| 1406 | 1341 | const dst_reg: Register = dst_reg: { |
| ... | ... | @@ -1437,20 +1372,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1437 | 1372 | break :dst_reg dst_reg; |
| 1438 | 1373 | }, |
| 1439 | 1374 | .unsigned => { |
| 1440 | | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 1441 | | try self.register_manager.getReg(.rax, null); |
| 1442 | | try self.register_manager.getReg(.rdx, null); |
| 1443 | | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 1444 | | defer for (reg_locks) |reg| { |
| 1445 | | self.register_manager.unlockReg(reg); |
| 1446 | | }; |
| 1447 | | |
| 1448 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1449 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1450 | | |
| 1451 | | try self.genIntMulDivOpMir(.mul, ty, .unsigned, lhs, rhs); |
| 1452 | | |
| 1453 | | break :dst_reg registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))); |
| 1375 | const dst_mcv = try self.genBinOp(inst, bin_op.lhs, bin_op.rhs, false); |
| 1376 | break :dst_reg dst_mcv.register; |
| 1454 | 1377 | }, |
| 1455 | 1378 | } |
| 1456 | 1379 | }; |
| ... | ... | @@ -3291,6 +3214,7 @@ fn genBinOp( |
| 3291 | 3214 | inst: Air.Inst.Index, |
| 3292 | 3215 | op_lhs: Air.Inst.Ref, |
| 3293 | 3216 | op_rhs: Air.Inst.Ref, |
| 3217 | track: bool, |
| 3294 | 3218 | ) !MCValue { |
| 3295 | 3219 | const tag = self.air.instructions.items(.tag)[inst]; |
| 3296 | 3220 | const is_commutative: bool = switch (tag) { |
| ... | ... | @@ -3309,6 +3233,8 @@ fn genBinOp( |
| 3309 | 3233 | .subwrap, |
| 3310 | 3234 | .sub_with_overflow, |
| 3311 | 3235 | .mul, |
| 3236 | .mulwrap, |
| 3237 | .mul_with_overflow, |
| 3312 | 3238 | .shl, |
| 3313 | 3239 | .shr, |
| 3314 | 3240 | .ptr_add, |
| ... | ... | @@ -3320,6 +3246,43 @@ fn genBinOp( |
| 3320 | 3246 | const dst_ty = self.air.typeOf(op_lhs); |
| 3321 | 3247 | const src_ty = self.air.typeOf(op_rhs); |
| 3322 | 3248 | |
| 3249 | if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) { |
| 3250 | return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()}); |
| 3251 | } |
| 3252 | if (dst_ty.abiSize(self.target.*) > 8) { |
| 3253 | return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()}); |
| 3254 | } |
| 3255 | |
| 3256 | switch (tag) { |
| 3257 | .mul, |
| 3258 | .mulwrap, |
| 3259 | .mul_with_overflow, |
| 3260 | => { |
| 3261 | // Spill .rax and .rdx upfront to ensure we don't spill the operands too late. |
| 3262 | try self.register_manager.getReg(.rax, if (track) inst else null); |
| 3263 | try self.register_manager.getReg(.rdx, null); |
| 3264 | const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx }); |
| 3265 | defer for (reg_locks) |reg| { |
| 3266 | self.register_manager.unlockReg(reg); |
| 3267 | }; |
| 3268 | |
| 3269 | const lhs = try self.resolveInst(op_lhs); |
| 3270 | const rhs = try self.resolveInst(op_rhs); |
| 3271 | |
| 3272 | const int_info = dst_ty.intInfo(self.target.*); |
| 3273 | try self.genIntMulDivOpMir(switch (int_info.signedness) { |
| 3274 | .signed => .imul, |
| 3275 | .unsigned => .mul, |
| 3276 | }, dst_ty, int_info.signedness, lhs, rhs); |
| 3277 | |
| 3278 | return switch (int_info.signedness) { |
| 3279 | .signed => MCValue{ .register = .rax }, |
| 3280 | .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) }, |
| 3281 | }; |
| 3282 | }, |
| 3283 | else => {}, |
| 3284 | } |
| 3285 | |
| 3323 | 3286 | const lhs = try self.resolveInst(op_lhs); |
| 3324 | 3287 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| 3325 | 3288 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | ... | @@ -3343,7 +3306,11 @@ fn genBinOp( |
| 3343 | 3306 | flipped = true; |
| 3344 | 3307 | break :blk rhs; |
| 3345 | 3308 | } |
| 3346 | | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 3309 | if (track) { |
| 3310 | break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs); |
| 3311 | } else { |
| 3312 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) }; |
| 3313 | } |
| 3347 | 3314 | }; |
| 3348 | 3315 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { |
| 3349 | 3316 | .register => |reg| self.register_manager.lockReg(reg), |