Skip to content

Commit 617ae10

Browse files
[AArch64] Refactor redundant PTEST optimisations (NFC)
1 parent c04687f commit 617ae10

File tree

2 files changed

+95
-78
lines changed

2 files changed

+95
-78
lines changed

llvm/lib/Target/AArch64/AArch64InstrInfo.cpp

Lines changed: 92 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,48 +1351,52 @@ static bool areCFlagsAccessedBetweenInstrs(
13511351
return false;
13521352
}
13531353

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 {
13641358
unsigned MaskOpcode = Mask->getOpcode();
13651359
unsigned PredOpcode = Pred->getOpcode();
13661360
bool PredIsPTestLike = isPTestLikeOpcode(PredOpcode);
13671361
bool PredIsWhileLike = isWhileOpcode(PredOpcode);
13681362

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+
13731370
// For PTEST(PTRUE_ALL, WHILE), if the element size matches, the PTEST is
13741371
// 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};
13761388

13771389
// 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)) {
13821395
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};
13851398
}
13861399

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) {
13961400
// For PTEST(PG, PTEST_LIKE(PG, ...)), the PTEST is redundant since the
13971401
// flags are set based on the same mask 'PG', but PTEST_LIKE must operate
13981402
// on 8-bit predicates like the PTEST. Otherwise, for instructions like
@@ -1417,55 +1421,65 @@ bool AArch64InstrInfo::optimizePTestInstr(
14171421
// identical regardless of element size.
14181422
auto PTestLikeMask = MRI->getUniqueVRegDef(Pred->getOperand(1).getReg());
14191423
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};
14241427

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+
}
14651430

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;
14681452
}
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;
14691483

14701484
const TargetRegisterInfo *TRI = &getRegisterInfo();
14711485

@@ -1478,9 +1492,9 @@ bool AArch64InstrInfo::optimizePTestInstr(
14781492
// as they are prior to PTEST. Sometimes this requires the tested PTEST
14791493
// operand to be replaced with an equivalent instruction that also sets the
14801494
// flags.
1481-
Pred->setDesc(get(NewOp));
14821495
PTest->eraseFromParent();
1483-
if (OpChanged) {
1496+
if (NewOp) {
1497+
Pred->setDesc(get(NewOp));
14841498
bool succeeded = UpdateOperandRegClass(*Pred);
14851499
(void)succeeded;
14861500
assert(succeeded && "Operands have incompatible register classes!");

llvm/lib/Target/AArch64/AArch64InstrInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,9 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
432432
bool optimizePTestInstr(MachineInstr *PTest, unsigned MaskReg,
433433
unsigned PredReg,
434434
const MachineRegisterInfo *MRI) const;
435+
std::pair<bool, unsigned>
436+
canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
437+
MachineInstr *Pred, const MachineRegisterInfo *MRI) const;
435438
};
436439

437440
struct UsedNZCV {

0 commit comments

Comments
 (0)