[llvm] [VectorCombine] Add support for zext/sext/trunc to shuffleToIdentity (PR #92696)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Mon May 20 01:46:14 PDT 2024


https://github.com/artagnon commented:

Hi,

I did a partial review of the existing code, and my suggestions are along the lines of the following diff. I think it would be nice if you could improve the existing code as an NFC patch before landing this patch.

```diff
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 8573a8adf53b..52830d7ed462 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1686,7 +1686,7 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
       int M = SV->getMaskValue(Lane);
       if (M < 0)
         return {nullptr, PoisonMaskElem};
-      else if (M < (int)NumElts) {
+      if (static_cast<unsigned>(M) < NumElts) {
         V = SV->getOperand(0);
         Lane = M;
       } else {
@@ -1700,12 +1700,12 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
   auto GenerateInstLaneVectorFromOperand =
       [&LookThroughShuffles](ArrayRef<InstLane> Item, int Op) {
         SmallVector<InstLane> NItem;
-        for (InstLane V : Item) {
-          NItem.emplace_back(
-              !V.first
-                  ? InstLane{nullptr, PoisonMaskElem}
-                  : LookThroughShuffles(
-                        cast<Instruction>(V.first)->getOperand(Op), V.second));
+        for (InstLane IL : Item) {
+          auto [V, Lane] = IL;
+          // The caller is responsible for ensuring that this is always an Instruction.
+          auto *I = cast<Instruction>(V);
+          InstLane ToInsert = V ? LookThroughShuffles(I->getOperand(Op), Lane) : IL;
+          NItem.emplace_back(ToInsert);
         }
         return NItem;
       };
@@ -1721,57 +1721,66 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {

   while (!Worklist.empty()) {
     SmallVector<InstLane> Item = Worklist.pop_back_val();
-    if (++NumVisited > MaxInstrsToScan)
+    if (NumVisited++ > MaxInstrsToScan)
       return false;

+    auto [FrontV, FrontLane] = Item.front();
+
     // If we found an undef first lane then bail out to keep things simple.
-    if (!Item[0].first)
+    if (!FrontV)
       return false;

     // Look for an identity value.
-    if (Item[0].second == 0 && Item[0].first->getType() == Ty &&
-        all_of(drop_begin(enumerate(Item)), [&](const auto &E) {
-          return !E.value().first || (E.value().first == Item[0].first &&
-                                      E.value().second == (int)E.index());
+    if (!FrontLane && FrontV->getType() == Ty &&
+        all_of(drop_begin(enumerate(Item)), [Item](const auto &I) {
+          auto [FrontV, _] = Item.front();
+          auto [Idx, E] = I;
+          auto [V, Lane] = E;
+          return !V || (V == FrontV && Lane == (int)Idx);
         })) {
-      IdentityLeafs.insert(Item[0].first);
+      IdentityLeafs.insert(FrontV);
       continue;
     }
+
     // Look for a splat value.
-    if (all_of(drop_begin(Item), [&](InstLane &IL) {
-          return !IL.first ||
-                 (IL.first == Item[0].first && IL.second == Item[0].second);
+    if (all_of(drop_begin(Item), [Item](InstLane &IL) {
+          auto [FrontV, FrontLane] = Item.front();
+          auto [V, Lane] = IL;
+          return !V ||
+                 (V == FrontV && Lane == FrontLane);
         })) {
-      SplatLeafs.insert(Item[0].first);
+      SplatLeafs.insert(FrontV);
       continue;
     }

     // We need each element to be the same type of value, and check that each
     // element has a single use.
-    if (!all_of(drop_begin(Item), [&](InstLane IL) {
-          if (!IL.first)
+    if (!all_of(drop_begin(Item), [Item](InstLane IL) {
+          auto [FrontV, _] = Item.front();
+          auto [V, _Lane] = IL;
+          if (!V)
             return true;
-          if (auto *I = dyn_cast<Instruction>(IL.first); I && !I->hasOneUse())
+          if (auto *I = dyn_cast<Instruction>(V); I && !I->hasOneUse())
             return false;
-          if (IL.first->getValueID() != Item[0].first->getValueID())
+          if (V->getValueID() != FrontV->getValueID())
             return false;
-          if (isa<CallInst>(IL.first) && !isa<IntrinsicInst>(IL.first))
+          if (isa<CallInst>(V) && !isa<IntrinsicInst>(V))
             return false;
-          auto *II = dyn_cast<IntrinsicInst>(IL.first);
+          auto *II = dyn_cast<IntrinsicInst>(V);
           return !II ||
-                 (isa<IntrinsicInst>(Item[0].first) &&
+                 (isa<IntrinsicInst>(FrontV) &&
                   II->getIntrinsicID() ==
-                      cast<IntrinsicInst>(Item[0].first)->getIntrinsicID());
+                      cast<IntrinsicInst>(FrontV)->getIntrinsicID());
         }))
       return false;

     // Check the operator is one that we support. We exclude div/rem in case
     // they hit UB from poison lanes.
-    if (isa<BinaryOperator>(Item[0].first) &&
-        !cast<BinaryOperator>(Item[0].first)->isIntDivRem()) {
+    if (isa<BinaryOperator>(FrontV) &&
+        !cast<BinaryOperator>(FrontV)->isIntDivRem()) {
       Worklist.push_back(GenerateInstLaneVectorFromOperand(Item, 0));
       Worklist.push_back(GenerateInstLaneVectorFromOperand(Item, 1));
-    } else if (isa<UnaryOperator>(Item[0].first)) {
+    } else if (isa<UnaryOperator>(FrontV)) {
       Worklist.push_back(GenerateInstLaneVectorFromOperand(Item, 0));
     } else {
       return false;
@@ -1790,7 +1799,7 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
       return Item[0].first;
     }
     if (SplatLeafs.contains(Item[0].first)) {
-      if (auto ILI = dyn_cast<Instruction>(Item[0].first))
+      if (auto *ILI = dyn_cast<Instruction>(Item[0].first))
         Builder.SetInsertPoint(*ILI->getInsertionPointAfterDef());
       else if (isa<Argument>(Item[0].first))
         Builder.SetInsertPointPastAllocas(I.getParent()->getParent());
@@ -1803,7 +1812,7 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
     for (unsigned Idx = 0, E = I->getNumOperands(); Idx < E; Idx++)
       Ops[Idx] = Generate(GenerateInstLaneVectorFromOperand(Item, Idx));
     Builder.SetInsertPoint(I);
-    if (auto BI = dyn_cast<BinaryOperator>(I))
+    if (auto *BI = dyn_cast<BinaryOperator>(I))
       return Builder.CreateBinOp((Instruction::BinaryOps)BI->getOpcode(),
                                  Ops[0], Ops[1]);
     assert(isa<UnaryInstruction>(I) &&
--
2.45.1
```

https://github.com/llvm/llvm-project/pull/92696


More information about the llvm-commits mailing list