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