aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp')
-rw-r--r--llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp60
1 files changed, 43 insertions, 17 deletions
diff --git a/llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp b/llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp
index 74fe0cdd1ea7..9911f33371c6 100644
--- a/llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp
+++ b/llvm/lib/Target/AArch64/SVEIntrinsicOpts.cpp
@@ -37,7 +37,7 @@
using namespace llvm;
using namespace llvm::PatternMatch;
-#define DEBUG_TYPE "sve-intrinsic-opts"
+#define DEBUG_TYPE "aarch64-sve-intrinsic-opts"
namespace llvm {
void initializeSVEIntrinsicOptsPass(PassRegistry &);
@@ -160,7 +160,7 @@ bool SVEIntrinsicOpts::optimizePTest(IntrinsicInst *I) {
I->eraseFromParent();
if (Op1->use_empty())
Op1->eraseFromParent();
- if (Op2->use_empty())
+ if (Op1 != Op2 && Op2->use_empty())
Op2->eraseFromParent();
return true;
@@ -177,22 +177,50 @@ bool SVEIntrinsicOpts::optimizeConvertFromSVBool(IntrinsicInst *I) {
if (isa<PHINode>(I->getArgOperand(0)))
return processPhiNode(I);
- // If we have a reinterpret intrinsic I of type A which is converting from
- // another reinterpret Y of type B, and the source type of Y is A, then we can
- // elide away both reinterprets if there are no other users of Y.
- auto *Y = isReinterpretToSVBool(I->getArgOperand(0));
- if (!Y)
- return false;
+ SmallVector<Instruction *, 32> CandidatesForRemoval;
+ Value *Cursor = I->getOperand(0), *EarliestReplacement = nullptr;
+
+ const auto *IVTy = cast<VectorType>(I->getType());
+
+ // Walk the chain of conversions.
+ while (Cursor) {
+ // If the type of the cursor has fewer lanes than the final result, zeroing
+ // must take place, which breaks the equivalence chain.
+ const auto *CursorVTy = cast<VectorType>(Cursor->getType());
+ if (CursorVTy->getElementCount().getKnownMinValue() <
+ IVTy->getElementCount().getKnownMinValue())
+ break;
+
+ // If the cursor has the same type as I, it is a viable replacement.
+ if (Cursor->getType() == IVTy)
+ EarliestReplacement = Cursor;
+
+ auto *IntrinsicCursor = dyn_cast<IntrinsicInst>(Cursor);
- Value *SourceVal = Y->getArgOperand(0);
- if (I->getType() != SourceVal->getType())
+ // If this is not an SVE conversion intrinsic, this is the end of the chain.
+ if (!IntrinsicCursor || !(IntrinsicCursor->getIntrinsicID() ==
+ Intrinsic::aarch64_sve_convert_to_svbool ||
+ IntrinsicCursor->getIntrinsicID() ==
+ Intrinsic::aarch64_sve_convert_from_svbool))
+ break;
+
+ CandidatesForRemoval.insert(CandidatesForRemoval.begin(), IntrinsicCursor);
+ Cursor = IntrinsicCursor->getOperand(0);
+ }
+
+ // If no viable replacement in the conversion chain was found, there is
+ // nothing to do.
+ if (!EarliestReplacement)
return false;
- I->replaceAllUsesWith(SourceVal);
+ I->replaceAllUsesWith(EarliestReplacement);
I->eraseFromParent();
- if (Y->use_empty())
- Y->eraseFromParent();
+ while (!CandidatesForRemoval.empty()) {
+ Instruction *Candidate = CandidatesForRemoval.pop_back_val();
+ if (Candidate->use_empty())
+ Candidate->eraseFromParent();
+ }
return true;
}
@@ -248,10 +276,8 @@ bool SVEIntrinsicOpts::runOnModule(Module &M) {
case Intrinsic::aarch64_sve_ptest_any:
case Intrinsic::aarch64_sve_ptest_first:
case Intrinsic::aarch64_sve_ptest_last:
- for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
- auto *Inst = dyn_cast<Instruction>(*I++);
- Functions.insert(Inst->getFunction());
- }
+ for (User *U : F.users())
+ Functions.insert(cast<Instruction>(U)->getFunction());
break;
default:
break;