@@ -1351,48 +1351,52 @@ static bool areCFlagsAccessedBetweenInstrs(
1351
1351
return false ;
1352
1352
}
1353
1353
1354
- // / optimizePTestInstr - Attempt to remove a ptest of a predicate-generating
1355
- // / operation which could set the flags in an identical manner
1356
- bool AArch64InstrInfo::optimizePTestInstr (
1357
- MachineInstr *PTest, unsigned MaskReg, unsigned PredReg,
1358
- const MachineRegisterInfo *MRI) const {
1359
- auto *Mask = MRI->getUniqueVRegDef (MaskReg);
1360
- auto *Pred = MRI->getUniqueVRegDef (PredReg);
1361
- auto NewOp = Pred->getOpcode ();
1362
- bool OpChanged = false ;
1363
-
1354
+ std::pair<bool , unsigned >
1355
+ AArch64InstrInfo::canRemovePTestInstr (MachineInstr *PTest, MachineInstr *Mask,
1356
+ MachineInstr *Pred,
1357
+ const MachineRegisterInfo *MRI) const {
1364
1358
unsigned MaskOpcode = Mask->getOpcode ();
1365
1359
unsigned PredOpcode = Pred->getOpcode ();
1366
1360
bool PredIsPTestLike = isPTestLikeOpcode (PredOpcode);
1367
1361
bool PredIsWhileLike = isWhileOpcode (PredOpcode);
1368
1362
1369
- if (isPTrueOpcode (MaskOpcode) && (PredIsPTestLike || PredIsWhileLike) &&
1370
- getElementSizeForOpcode (MaskOpcode) ==
1371
- getElementSizeForOpcode (PredOpcode) &&
1372
- Mask->getOperand (1 ).getImm () == 31 ) {
1363
+ if (PredIsWhileLike) {
1364
+ // For PTEST(PG, PG), PTEST is redundant when PG is the result of a WHILEcc
1365
+ // instruction and the condition is "any" since WHILcc does an implicit
1366
+ // PTEST(ALL, PG) check and PG is always a subset of ALL.
1367
+ if ((Mask == Pred) && PTest->getOpcode () == AArch64::PTEST_PP_ANY)
1368
+ return {true , 0 };
1369
+
1373
1370
// For PTEST(PTRUE_ALL, WHILE), if the element size matches, the PTEST is
1374
1371
// redundant since WHILE performs an implicit PTEST with an all active
1375
- // mask. Must be an all active predicate of matching element size.
1372
+ // mask.
1373
+ if (isPTrueOpcode (MaskOpcode) && Mask->getOperand (1 ).getImm () == 31 &&
1374
+ getElementSizeForOpcode (MaskOpcode) ==
1375
+ getElementSizeForOpcode (PredOpcode))
1376
+ return {true , 0 };
1377
+
1378
+ return {false , 0 };
1379
+ }
1380
+
1381
+ if (PredIsPTestLike) {
1382
+ // For PTEST(PG, PG), PTEST is redundant when PG is the result of an
1383
+ // instruction that sets the flags as PTEST would and the condition is
1384
+ // "any" since PG is always a subset of the governing predicate of the
1385
+ // ptest-like instruction.
1386
+ if ((Mask == Pred) && PTest->getOpcode () == AArch64::PTEST_PP_ANY)
1387
+ return {true , 0 };
1376
1388
1377
1389
// For PTEST(PTRUE_ALL, PTEST_LIKE), the PTEST is redundant if the
1378
- // PTEST_LIKE instruction uses the same all active mask and the element
1379
- // size matches. If the PTEST has a condition of any then it is always
1380
- // redundant.
1381
- if (PredIsPTestLike) {
1390
+ // the element size matches and either the PTEST_LIKE instruction uses
1391
+ // the same all active mask or the condition is "any".
1392
+ if (isPTrueOpcode (MaskOpcode) && Mask->getOperand (1 ).getImm () == 31 &&
1393
+ getElementSizeForOpcode (MaskOpcode) ==
1394
+ getElementSizeForOpcode (PredOpcode)) {
1382
1395
auto PTestLikeMask = MRI->getUniqueVRegDef (Pred->getOperand (1 ).getReg ());
1383
- if (Mask != PTestLikeMask && PTest->getOpcode () ! = AArch64::PTEST_PP_ANY)
1384
- return false ;
1396
+ if (Mask == PTestLikeMask || PTest->getOpcode () = = AArch64::PTEST_PP_ANY)
1397
+ return { true , 0 } ;
1385
1398
}
1386
1399
1387
- // Fallthough to simply remove the PTEST.
1388
- } else if ((Mask == Pred) && (PredIsPTestLike || PredIsWhileLike) &&
1389
- PTest->getOpcode () == AArch64::PTEST_PP_ANY) {
1390
- // For PTEST(PG, PG), PTEST is redundant when PG is the result of an
1391
- // instruction that sets the flags as PTEST would. This is only valid when
1392
- // the condition is any.
1393
-
1394
- // Fallthough to simply remove the PTEST.
1395
- } else if (PredIsPTestLike) {
1396
1400
// For PTEST(PG, PTEST_LIKE(PG, ...)), the PTEST is redundant since the
1397
1401
// flags are set based on the same mask 'PG', but PTEST_LIKE must operate
1398
1402
// on 8-bit predicates like the PTEST. Otherwise, for instructions like
@@ -1417,55 +1421,65 @@ bool AArch64InstrInfo::optimizePTestInstr(
1417
1421
// identical regardless of element size.
1418
1422
auto PTestLikeMask = MRI->getUniqueVRegDef (Pred->getOperand (1 ).getReg ());
1419
1423
uint64_t PredElementSize = getElementSizeForOpcode (PredOpcode);
1420
- if ((Mask != PTestLikeMask) ||
1421
- (PredElementSize != AArch64::ElementSizeB &&
1422
- PTest->getOpcode () != AArch64::PTEST_PP_ANY))
1423
- return false ;
1424
+ if (Mask == PTestLikeMask && (PredElementSize == AArch64::ElementSizeB ||
1425
+ PTest->getOpcode () == AArch64::PTEST_PP_ANY))
1426
+ return {true , 0 };
1424
1427
1425
- // Fallthough to simply remove the PTEST.
1426
- } else {
1427
- // If OP in PTEST(PG, OP(PG, ...)) has a flag-setting variant change the
1428
- // opcode so the PTEST becomes redundant.
1429
- switch (PredOpcode) {
1430
- case AArch64::AND_PPzPP:
1431
- case AArch64::BIC_PPzPP:
1432
- case AArch64::EOR_PPzPP:
1433
- case AArch64::NAND_PPzPP:
1434
- case AArch64::NOR_PPzPP:
1435
- case AArch64::ORN_PPzPP:
1436
- case AArch64::ORR_PPzPP:
1437
- case AArch64::BRKA_PPzP:
1438
- case AArch64::BRKPA_PPzPP:
1439
- case AArch64::BRKB_PPzP:
1440
- case AArch64::BRKPB_PPzPP:
1441
- case AArch64::RDFFR_PPz: {
1442
- // Check to see if our mask is the same. If not the resulting flag bits
1443
- // may be different and we can't remove the ptest.
1444
- auto *PredMask = MRI->getUniqueVRegDef (Pred->getOperand (1 ).getReg ());
1445
- if (Mask != PredMask)
1446
- return false ;
1447
- break ;
1448
- }
1449
- case AArch64::BRKN_PPzP: {
1450
- // BRKN uses an all active implicit mask to set flags unlike the other
1451
- // flag-setting instructions.
1452
- // PTEST(PTRUE_B(31), BRKN(PG, A, B)) -> BRKNS(PG, A, B).
1453
- if ((MaskOpcode != AArch64::PTRUE_B) ||
1454
- (Mask->getOperand (1 ).getImm () != 31 ))
1455
- return false ;
1456
- break ;
1457
- }
1458
- case AArch64::PTRUE_B:
1459
- // PTEST(OP=PTRUE_B(A), OP) -> PTRUES_B(A)
1460
- break ;
1461
- default :
1462
- // Bail out if we don't recognize the input
1463
- return false ;
1464
- }
1428
+ return {false , 0 };
1429
+ }
1465
1430
1466
- NewOp = convertToFlagSettingOpc (PredOpcode);
1467
- OpChanged = true ;
1431
+ // If OP in PTEST(PG, OP(PG, ...)) has a flag-setting variant change the
1432
+ // opcode so the PTEST becomes redundant.
1433
+ switch (PredOpcode) {
1434
+ case AArch64::AND_PPzPP:
1435
+ case AArch64::BIC_PPzPP:
1436
+ case AArch64::EOR_PPzPP:
1437
+ case AArch64::NAND_PPzPP:
1438
+ case AArch64::NOR_PPzPP:
1439
+ case AArch64::ORN_PPzPP:
1440
+ case AArch64::ORR_PPzPP:
1441
+ case AArch64::BRKA_PPzP:
1442
+ case AArch64::BRKPA_PPzPP:
1443
+ case AArch64::BRKB_PPzP:
1444
+ case AArch64::BRKPB_PPzPP:
1445
+ case AArch64::RDFFR_PPz: {
1446
+ // Check to see if our mask is the same. If not the resulting flag bits
1447
+ // may be different and we can't remove the ptest.
1448
+ auto *PredMask = MRI->getUniqueVRegDef (Pred->getOperand (1 ).getReg ());
1449
+ if (Mask != PredMask)
1450
+ return {false , 0 };
1451
+ break ;
1468
1452
}
1453
+ case AArch64::BRKN_PPzP: {
1454
+ // BRKN uses an all active implicit mask to set flags unlike the other
1455
+ // flag-setting instructions.
1456
+ // PTEST(PTRUE_B(31), BRKN(PG, A, B)) -> BRKNS(PG, A, B).
1457
+ if ((MaskOpcode != AArch64::PTRUE_B) ||
1458
+ (Mask->getOperand (1 ).getImm () != 31 ))
1459
+ return {false , 0 };
1460
+ break ;
1461
+ }
1462
+ case AArch64::PTRUE_B:
1463
+ // PTEST(OP=PTRUE_B(A), OP) -> PTRUES_B(A)
1464
+ break ;
1465
+ default :
1466
+ // Bail out if we don't recognize the input
1467
+ return {false , 0 };
1468
+ }
1469
+
1470
+ return {true , convertToFlagSettingOpc (PredOpcode)};
1471
+ }
1472
+
1473
+ // / optimizePTestInstr - Attempt to remove a ptest of a predicate-generating
1474
+ // / operation which could set the flags in an identical manner
1475
+ bool AArch64InstrInfo::optimizePTestInstr (
1476
+ MachineInstr *PTest, unsigned MaskReg, unsigned PredReg,
1477
+ const MachineRegisterInfo *MRI) const {
1478
+ auto *Mask = MRI->getUniqueVRegDef (MaskReg);
1479
+ auto *Pred = MRI->getUniqueVRegDef (PredReg);
1480
+ auto [canRemove, NewOp] = canRemovePTestInstr (PTest, Mask, Pred, MRI);
1481
+ if (!canRemove)
1482
+ return false ;
1469
1483
1470
1484
const TargetRegisterInfo *TRI = &getRegisterInfo ();
1471
1485
@@ -1478,9 +1492,9 @@ bool AArch64InstrInfo::optimizePTestInstr(
1478
1492
// as they are prior to PTEST. Sometimes this requires the tested PTEST
1479
1493
// operand to be replaced with an equivalent instruction that also sets the
1480
1494
// flags.
1481
- Pred->setDesc (get (NewOp));
1482
1495
PTest->eraseFromParent ();
1483
- if (OpChanged) {
1496
+ if (NewOp) {
1497
+ Pred->setDesc (get (NewOp));
1484
1498
bool succeeded = UpdateOperandRegClass (*Pred);
1485
1499
(void )succeeded;
1486
1500
assert (succeeded && " Operands have incompatible register classes!" );
0 commit comments