Skip to content

Commit a21d5d3

Browse files
[AArch64] Refactor redundant PTEST optimisations (NFC)
1 parent 80a9f39 commit a21d5d3

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
@@ -1354,48 +1354,52 @@ static bool areCFlagsAccessedBetweenInstrs(
13541354
return false;
13551355
}
13561356

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

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

13801392
// 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)) {
13851398
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};
13881401
}
13891402

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) {
13991403
// For PTEST(PG, PTEST_LIKE(PG, ...)), the PTEST is redundant since the
14001404
// flags are set based on the same mask 'PG', but PTEST_LIKE must operate
14011405
// on 8-bit predicates like the PTEST. Otherwise, for instructions like
@@ -1420,55 +1424,65 @@ bool AArch64InstrInfo::optimizePTestInstr(
14201424
// identical regardless of element size.
14211425
auto PTestLikeMask = MRI->getUniqueVRegDef(Pred->getOperand(1).getReg());
14221426
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};
14271430

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

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;
14711455
}
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;
14721486

14731487
const TargetRegisterInfo *TRI = &getRegisterInfo();
14741488

@@ -1481,9 +1495,9 @@ bool AArch64InstrInfo::optimizePTestInstr(
14811495
// as they are prior to PTEST. Sometimes this requires the tested PTEST
14821496
// operand to be replaced with an equivalent instruction that also sets the
14831497
// flags.
1484-
Pred->setDesc(get(NewOp));
14851498
PTest->eraseFromParent();
1486-
if (OpChanged) {
1499+
if (NewOp) {
1500+
Pred->setDesc(get(NewOp));
14871501
bool succeeded = UpdateOperandRegClass(*Pred);
14881502
(void)succeeded;
14891503
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
@@ -572,6 +572,9 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
572572
bool optimizePTestInstr(MachineInstr *PTest, unsigned MaskReg,
573573
unsigned PredReg,
574574
const MachineRegisterInfo *MRI) const;
575+
std::pair<bool, unsigned>
576+
canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
577+
MachineInstr *Pred, const MachineRegisterInfo *MRI) const;
575578
};
576579

577580
struct UsedNZCV {

0 commit comments

Comments
 (0)