@@ -1184,6 +1184,7 @@ bool AArch64InstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
11841184 break ;
11851185 case AArch64::PTEST_PP:
11861186 case AArch64::PTEST_PP_ANY:
1187+ case AArch64::PTEST_PP_FIRST:
11871188 SrcReg = MI.getOperand (0 ).getReg ();
11881189 SrcReg2 = MI.getOperand (1 ).getReg ();
11891190 // Not sure about the mask and value for now...
@@ -1355,12 +1356,25 @@ static bool areCFlagsAccessedBetweenInstrs(
13551356 return false ;
13561357}
13571358
1358- std::optional<unsigned >
1359+ std::optional<std::pair< unsigned , MachineInstr *> >
13591360AArch64InstrInfo::canRemovePTestInstr (MachineInstr *PTest, MachineInstr *Mask,
13601361 MachineInstr *Pred,
13611362 const MachineRegisterInfo *MRI) const {
13621363 unsigned MaskOpcode = Mask->getOpcode ();
13631364 unsigned PredOpcode = Pred->getOpcode ();
1365+
1366+ // Handle a COPY from the LSB of the results of paired WHILEcc instruction.
1367+ if ((PredOpcode == TargetOpcode::COPY &&
1368+ Pred->getOperand (1 ).getSubReg () == AArch64::psub0) ||
1369+ // Handle unpack of the LSB of the result of a WHILEcc instruction.
1370+ PredOpcode == AArch64::PUNPKLO_PP) {
1371+ MachineInstr *MI = MRI->getUniqueVRegDef (Pred->getOperand (1 ).getReg ());
1372+ if (MI && isWhileOpcode (MI->getOpcode ())) {
1373+ Pred = MI;
1374+ PredOpcode = MI->getOpcode ();
1375+ }
1376+ }
1377+
13641378 bool PredIsPTestLike = isPTestLikeOpcode (PredOpcode);
13651379 bool PredIsWhileLike = isWhileOpcode (PredOpcode);
13661380
@@ -1369,15 +1383,16 @@ AArch64InstrInfo::canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
13691383 // instruction and the condition is "any" since WHILcc does an implicit
13701384 // PTEST(ALL, PG) check and PG is always a subset of ALL.
13711385 if ((Mask == Pred) && PTest->getOpcode () == AArch64::PTEST_PP_ANY)
1372- return PredOpcode;
1386+ return std::make_pair ( PredOpcode, Pred) ;
13731387
1374- // For PTEST(PTRUE_ALL, WHILE), if the element size matches, the PTEST is
1375- // redundant since WHILE performs an implicit PTEST with an all active
1376- // mask .
1388+ // For PTEST(PTRUE_ALL, WHILE), since WHILE performs an implicit PTEST
1389+ // with an all active mask, the PTEST is redundant if ether the element
1390+ // size matches or the PTEST condition is "first" .
13771391 if (isPTrueOpcode (MaskOpcode) && Mask->getOperand (1 ).getImm () == 31 &&
1378- getElementSizeForOpcode (MaskOpcode) ==
1379- getElementSizeForOpcode (PredOpcode))
1380- return PredOpcode;
1392+ (PTest->getOpcode () == AArch64::PTEST_PP_FIRST ||
1393+ getElementSizeForOpcode (MaskOpcode) ==
1394+ getElementSizeForOpcode (PredOpcode)))
1395+ return std::make_pair (PredOpcode, Pred);
13811396
13821397 return {};
13831398 }
@@ -1388,7 +1403,7 @@ AArch64InstrInfo::canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
13881403 // "any" since PG is always a subset of the governing predicate of the
13891404 // ptest-like instruction.
13901405 if ((Mask == Pred) && PTest->getOpcode () == AArch64::PTEST_PP_ANY)
1391- return PredOpcode;
1406+ return std::make_pair ( PredOpcode, Pred) ;
13921407
13931408 // For PTEST(PTRUE_ALL, PTEST_LIKE), the PTEST is redundant if the
13941409 // the element size matches and either the PTEST_LIKE instruction uses
@@ -1398,7 +1413,7 @@ AArch64InstrInfo::canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
13981413 getElementSizeForOpcode (PredOpcode)) {
13991414 auto PTestLikeMask = MRI->getUniqueVRegDef (Pred->getOperand (1 ).getReg ());
14001415 if (Mask == PTestLikeMask || PTest->getOpcode () == AArch64::PTEST_PP_ANY)
1401- return PredOpcode;
1416+ return std::make_pair ( PredOpcode, Pred) ;
14021417 }
14031418
14041419 // For PTEST(PG, PTEST_LIKE(PG, ...)), the PTEST is redundant since the
@@ -1427,7 +1442,7 @@ AArch64InstrInfo::canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
14271442 uint64_t PredElementSize = getElementSizeForOpcode (PredOpcode);
14281443 if (Mask == PTestLikeMask && (PredElementSize == AArch64::ElementSizeB ||
14291444 PTest->getOpcode () == AArch64::PTEST_PP_ANY))
1430- return PredOpcode;
1445+ return std::make_pair ( PredOpcode, Pred) ;
14311446
14321447 return {};
14331448 }
@@ -1471,7 +1486,7 @@ AArch64InstrInfo::canRemovePTestInstr(MachineInstr *PTest, MachineInstr *Mask,
14711486 return {};
14721487 }
14731488
1474- return convertToFlagSettingOpc (PredOpcode);
1489+ return std::make_pair ( convertToFlagSettingOpc (PredOpcode), Pred );
14751490}
14761491
14771492// / optimizePTestInstr - Attempt to remove a ptest of a predicate-generating
@@ -1481,10 +1496,12 @@ bool AArch64InstrInfo::optimizePTestInstr(
14811496 const MachineRegisterInfo *MRI) const {
14821497 auto *Mask = MRI->getUniqueVRegDef (MaskReg);
14831498 auto *Pred = MRI->getUniqueVRegDef (PredReg);
1499+ unsigned NewOp;
14841500 unsigned PredOpcode = Pred->getOpcode ();
1485- auto NewOp = canRemovePTestInstr (PTest, Mask, Pred, MRI);
1486- if (!NewOp )
1501+ auto canRemove = canRemovePTestInstr (PTest, Mask, Pred, MRI);
1502+ if (!canRemove )
14871503 return false ;
1504+ std::tie (NewOp, Pred) = *canRemove;
14881505
14891506 const TargetRegisterInfo *TRI = &getRegisterInfo ();
14901507
@@ -1498,8 +1515,8 @@ bool AArch64InstrInfo::optimizePTestInstr(
14981515 // operand to be replaced with an equivalent instruction that also sets the
14991516 // flags.
15001517 PTest->eraseFromParent ();
1501- if (* NewOp != PredOpcode) {
1502- Pred->setDesc (get (* NewOp));
1518+ if (NewOp != PredOpcode) {
1519+ Pred->setDesc (get (NewOp));
15031520 bool succeeded = UpdateOperandRegClass (*Pred);
15041521 (void )succeeded;
15051522 assert (succeeded && " Operands have incompatible register classes!" );
@@ -1560,7 +1577,8 @@ bool AArch64InstrInfo::optimizeCompareInstr(
15601577 }
15611578
15621579 if (CmpInstr.getOpcode () == AArch64::PTEST_PP ||
1563- CmpInstr.getOpcode () == AArch64::PTEST_PP_ANY)
1580+ CmpInstr.getOpcode () == AArch64::PTEST_PP_ANY ||
1581+ CmpInstr.getOpcode () == AArch64::PTEST_PP_FIRST)
15641582 return optimizePTestInstr (&CmpInstr, SrcReg, SrcReg2, MRI);
15651583
15661584 if (SrcReg2 != 0 )
0 commit comments