| ... | @@ -1311,18 +1311,15 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1311,18 +1311,15 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1311 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1311 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1312 | const result = if (self.liveness.isUnused(inst)) .dead else result: { | 1312 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1313 | const ty = self.air.typeOf(bin_op.lhs); | 1313 | const ty = self.air.typeOf(bin_op.lhs); |
| 1314 | | 1314 | const abi_size = ty.abiSize(self.target.*); |
| 1315 | switch (ty.zigTypeTag()) { | 1315 | switch (ty.zigTypeTag()) { |
| 1316 | .Vector => return self.fail("TODO implement add_with_overflow for Vector type", .{}), | 1316 | .Vector => return self.fail("TODO implement add_with_overflow for Vector type", .{}), |
| 1317 | .Int => { | 1317 | .Int => { |
| 1318 | const int_info = ty.intInfo(self.target.*); | 1318 | if (abi_size > 8) { |
| 1319 | | | |
| 1320 | if (int_info.bits > 64) { | | |
| 1321 | return self.fail("TODO implement add_with_overflow for Ints larger than 64bits", .{}); | 1319 | return self.fail("TODO implement add_with_overflow for Ints larger than 64bits", .{}); |
| 1322 | } | 1320 | } |
| 1323 | | 1321 | |
| 1324 | try self.spillCompareFlagsIfOccupied(); | 1322 | try self.spillCompareFlagsIfOccupied(); |
| 1325 | self.compare_flags_inst = inst; | | |
| 1326 | | 1323 | |
| 1327 | const lhs = try self.resolveInst(bin_op.lhs); | 1324 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1328 | const rhs = try self.resolveInst(bin_op.rhs); | 1325 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | @@ -1333,11 +1330,30 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1333,11 +1330,30 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1333 | else => unreachable, | 1330 | else => unreachable, |
| 1334 | }; | 1331 | }; |
| 1335 | const partial = try self.genBinOp(base_tag, null, lhs, rhs, ty, ty); | 1332 | const partial = try self.genBinOp(base_tag, null, lhs, rhs, ty, ty); |
| 1336 | const result: MCValue = switch (int_info.signedness) { | 1333 | |
| 1337 | .signed => .{ .register_overflow_signed = partial.register }, | 1334 | const int_info = ty.intInfo(self.target.*); |
| 1338 | .unsigned => .{ .register_overflow_unsigned = partial.register }, | 1335 | |
| 1339 | }; | 1336 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { |
| 1340 | break :result result; | 1337 | self.compare_flags_inst = inst; |
| | 1338 | |
| | 1339 | const result: MCValue = switch (int_info.signedness) { |
| | 1340 | .signed => .{ .register_overflow_signed = partial.register }, |
| | 1341 | .unsigned => .{ .register_overflow_unsigned = partial.register }, |
| | 1342 | }; |
| | 1343 | break :result result; |
| | 1344 | } |
| | 1345 | |
| | 1346 | self.compare_flags_inst = null; |
| | 1347 | |
| | 1348 | const tuple_ty = self.air.typeOfIndex(inst); |
| | 1349 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| | 1350 | const tuple_align = tuple_ty.abiAlignment(self.target.*); |
| | 1351 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); |
| | 1352 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); |
| | 1353 | |
| | 1354 | try self.genSetStackTruncatedOverflowCompare(ty, stack_offset, overflow_bit_offset, partial.register); |
| | 1355 | |
| | 1356 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1341 | }, | 1357 | }, |
| 1342 | else => unreachable, | 1358 | else => unreachable, |
| 1343 | } | 1359 | } |
| ... | @@ -1346,6 +1362,75 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1346,6 +1362,75 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1346 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1362 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1347 | } | 1363 | } |
| 1348 | | 1364 | |
| | 1365 | fn genSetStackTruncatedOverflowCompare( |
| | 1366 | self: *Self, |
| | 1367 | ty: Type, |
| | 1368 | stack_offset: i32, |
| | 1369 | overflow_bit_offset: i32, |
| | 1370 | reg: Register, |
| | 1371 | ) !void { |
| | 1372 | const reg_lock = self.register_manager.lockReg(reg); |
| | 1373 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 1374 | |
| | 1375 | const int_info = ty.intInfo(self.target.*); |
| | 1376 | const extended_ty = switch (int_info.signedness) { |
| | 1377 | .signed => Type.isize, |
| | 1378 | .unsigned => ty, |
| | 1379 | }; |
| | 1380 | |
| | 1381 | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }); |
| | 1382 | const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); |
| | 1383 | defer for (temp_regs_locks) |rreg| { |
| | 1384 | self.register_manager.unlockReg(rreg); |
| | 1385 | }; |
| | 1386 | |
| | 1387 | const overflow_reg = temp_regs[0]; |
| | 1388 | const flags: u2 = switch (int_info.signedness) { |
| | 1389 | .signed => 0b00, |
| | 1390 | .unsigned => 0b10, |
| | 1391 | }; |
| | 1392 | _ = try self.addInst(.{ |
| | 1393 | .tag = .cond_set_byte_overflow, |
| | 1394 | .ops = (Mir.Ops{ |
| | 1395 | .reg1 = overflow_reg.to8(), |
| | 1396 | .flags = flags, |
| | 1397 | }).encode(), |
| | 1398 | .data = undefined, |
| | 1399 | }); |
| | 1400 | |
| | 1401 | const scratch_reg = temp_regs[1]; |
| | 1402 | try self.genSetReg(extended_ty, scratch_reg, .{ .register = reg }); |
| | 1403 | try self.truncateRegister(ty, scratch_reg); |
| | 1404 | try self.genBinOpMir( |
| | 1405 | .cmp, |
| | 1406 | extended_ty, |
| | 1407 | .{ .register = reg }, |
| | 1408 | .{ .register = scratch_reg }, |
| | 1409 | ); |
| | 1410 | |
| | 1411 | const eq_reg = temp_regs[2]; |
| | 1412 | _ = try self.addInst(.{ |
| | 1413 | .tag = .cond_set_byte_eq_ne, |
| | 1414 | .ops = (Mir.Ops{ |
| | 1415 | .reg1 = eq_reg.to8(), |
| | 1416 | .flags = 0b00, |
| | 1417 | }).encode(), |
| | 1418 | .data = undefined, |
| | 1419 | }); |
| | 1420 | |
| | 1421 | try self.genBinOpMir( |
| | 1422 | .@"or", |
| | 1423 | Type.u8, |
| | 1424 | .{ .register = overflow_reg }, |
| | 1425 | .{ .register = eq_reg }, |
| | 1426 | ); |
| | 1427 | |
| | 1428 | try self.genSetStack(ty, stack_offset, .{ .register = scratch_reg }, .{}); |
| | 1429 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ |
| | 1430 | .register = overflow_reg.to8(), |
| | 1431 | }, .{}); |
| | 1432 | } |
| | 1433 | |
| 1349 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 1434 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1350 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1435 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1351 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1436 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | @@ -1355,17 +1440,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1355,17 +1440,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1355 | } | 1440 | } |
| 1356 | | 1441 | |
| 1357 | const ty = self.air.typeOf(bin_op.lhs); | 1442 | const ty = self.air.typeOf(bin_op.lhs); |
| | 1443 | const abi_size = ty.abiSize(self.target.*); |
| 1358 | const result: MCValue = result: { | 1444 | const result: MCValue = result: { |
| 1359 | switch (ty.zigTypeTag()) { | 1445 | switch (ty.zigTypeTag()) { |
| 1360 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), | 1446 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 1361 | .Int => { | 1447 | .Int => { |
| 1362 | const int_info = ty.intInfo(self.target.*); | 1448 | if (abi_size > 8) { |
| 1363 | | | |
| 1364 | if (int_info.bits > 64) { | | |
| 1365 | return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); | 1449 | return self.fail("TODO implement mul_with_overflow for Ints larger than 64bits", .{}); |
| 1366 | } | 1450 | } |
| 1367 | | 1451 | |
| 1368 | if (math.isPowerOfTwo(int_info.bits)) { | 1452 | const int_info = ty.intInfo(self.target.*); |
| | 1453 | |
| | 1454 | if (math.isPowerOfTwo(int_info.bits) and int_info.bits >= 8) { |
| 1369 | try self.spillCompareFlagsIfOccupied(); | 1455 | try self.spillCompareFlagsIfOccupied(); |
| 1370 | self.compare_flags_inst = inst; | 1456 | self.compare_flags_inst = inst; |
| 1371 | | 1457 | |
| ... | @@ -1428,71 +1514,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1428,71 +1514,14 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1428 | }, | 1514 | }, |
| 1429 | } | 1515 | } |
| 1430 | }; | 1516 | }; |
| 1431 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | | |
| 1432 | defer self.register_manager.unlockReg(dst_reg_lock); | | |
| 1433 | | 1517 | |
| 1434 | const tuple_ty = self.air.typeOfIndex(inst); | 1518 | const tuple_ty = self.air.typeOfIndex(inst); |
| 1435 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 1519 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); |
| 1436 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 1520 | const tuple_align = tuple_ty.abiAlignment(self.target.*); |
| 1437 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); | 1521 | const overflow_bit_offset = @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)); |
| 1438 | | | |
| 1439 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); | 1522 | const stack_offset = @intCast(i32, try self.allocMem(inst, tuple_size, tuple_align)); |
| 1440 | const extended_ty = switch (int_info.signedness) { | | |
| 1441 | .signed => Type.isize, | | |
| 1442 | .unsigned => ty, | | |
| 1443 | }; | | |
| 1444 | | | |
| 1445 | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }); | | |
| 1446 | const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); | | |
| 1447 | defer for (temp_regs_locks) |reg| { | | |
| 1448 | self.register_manager.unlockReg(reg); | | |
| 1449 | }; | | |
| 1450 | | | |
| 1451 | const overflow_reg = temp_regs[0]; | | |
| 1452 | const flags: u2 = switch (int_info.signedness) { | | |
| 1453 | .signed => 0b00, | | |
| 1454 | .unsigned => 0b10, | | |
| 1455 | }; | | |
| 1456 | _ = try self.addInst(.{ | | |
| 1457 | .tag = .cond_set_byte_overflow, | | |
| 1458 | .ops = (Mir.Ops{ | | |
| 1459 | .reg1 = overflow_reg.to8(), | | |
| 1460 | .flags = flags, | | |
| 1461 | }).encode(), | | |
| 1462 | .data = undefined, | | |
| 1463 | }); | | |
| 1464 | | | |
| 1465 | const scratch_reg = temp_regs[1]; | | |
| 1466 | try self.genSetReg(extended_ty, scratch_reg, .{ .register = dst_reg }); | | |
| 1467 | try self.truncateRegister(ty, scratch_reg); | | |
| 1468 | try self.genBinOpMir( | | |
| 1469 | .cmp, | | |
| 1470 | extended_ty, | | |
| 1471 | .{ .register = dst_reg }, | | |
| 1472 | .{ .register = scratch_reg }, | | |
| 1473 | ); | | |
| 1474 | | | |
| 1475 | const eq_reg = temp_regs[2]; | | |
| 1476 | _ = try self.addInst(.{ | | |
| 1477 | .tag = .cond_set_byte_eq_ne, | | |
| 1478 | .ops = (Mir.Ops{ | | |
| 1479 | .reg1 = eq_reg.to8(), | | |
| 1480 | .flags = 0b00, | | |
| 1481 | }).encode(), | | |
| 1482 | .data = undefined, | | |
| 1483 | }); | | |
| 1484 | | | |
| 1485 | try self.genBinOpMir( | | |
| 1486 | .@"or", | | |
| 1487 | Type.u8, | | |
| 1488 | .{ .register = overflow_reg }, | | |
| 1489 | .{ .register = eq_reg }, | | |
| 1490 | ); | | |
| 1491 | | 1523 | |
| 1492 | try self.genSetStack(ty, stack_offset, .{ .register = scratch_reg }, .{}); | 1524 | try self.genSetStackTruncatedOverflowCompare(ty, stack_offset, overflow_bit_offset, dst_reg); |
| 1493 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ | | |
| 1494 | .register = overflow_reg.to8(), | | |
| 1495 | }, .{}); | | |
| 1496 | | 1525 | |
| 1497 | break :result MCValue{ .stack_offset = stack_offset }; | 1526 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1498 | }, | 1527 | }, |