[llvm] [RISCV] Recognize VLA shift pairs from shuffle masks (PR #127710)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 19 20:29:26 PST 2025


================
@@ -5651,6 +5695,73 @@ static SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG,
     return getWideningInterleave(EvenV, OddV, DL, DAG, Subtarget);
   }
 
+  // Recognize a pattern which can handled via a pair of vslideup/vslidedown
+  // instructions (in any combination) with masking on the second instruction.
+  // Avoid matching bit rotates as slide pairs.  This is a performance
+  // heuristic, not a functional check.
+  // TODO: Generalize this slightly to allow single instruction cases, and
+  // prune the logic above which is mostly covered by this already.
+  std::pair<int, int> SrcInfo[2];
+  unsigned RotateAmt;
+  MVT RotateVT;
+  if (isMaskedSlidePair(Mask, SrcInfo) &&
+      !isLegalBitRotate(Mask, VT, Subtarget, RotateVT, RotateAmt)) {
+    SDValue Sources[2];
+    auto GetSourceFor = [&](const std::pair<int, int> &Info) {
+      int SrcIdx = Info.first;
+      assert(SrcIdx == 0 || SrcIdx == 1);
+      SDValue &Src = Sources[SrcIdx];
+      if (!Src) {
+        SDValue SrcV = SrcIdx == 0 ? V1 : V2;
+        Src = convertToScalableVector(ContainerVT, SrcV, DAG, Subtarget);
+      }
+      return Src;
+    };
+    auto GetSlide = [&](const std::pair<int, int> &Src, SDValue Mask,
+                        SDValue Passthru) {
+      SDValue SrcV = GetSourceFor(Src);
+      int SlideAmt = Src.second;
+      if (SlideAmt == 0) {
+        // Should never be second operation
+        assert(Mask == TrueMask);
+        return SrcV;
+      }
+      if (SlideAmt < 0)
+        return getVSlidedown(DAG, Subtarget, DL, ContainerVT, Passthru, SrcV,
+                             DAG.getConstant(-SlideAmt, DL, XLenVT), Mask, VL,
+                             RISCVVType::TAIL_AGNOSTIC);
+      return getVSlideup(DAG, Subtarget, DL, ContainerVT, Passthru, SrcV,
+                         DAG.getConstant(SlideAmt, DL, XLenVT), Mask, VL,
+                         RISCVVType::TAIL_AGNOSTIC);
+    };
+
+    // Build the mask.  Note that vslideup unconditionally preserves elements
+    // below the slide amount in the destination, and thus those elements are
+    // undefined in the mask.  If the mask ends up all true (or undef), it
+    // will be folded away by general logic.
+    SmallVector<SDValue> MaskVals;
+    for (unsigned i = 0; i != Mask.size(); ++i) {
+      int M = Mask[i];
+      if (M < 0 || (SrcInfo[1].second > 0 && i < (unsigned)SrcInfo[1].second)) {
+        MaskVals.push_back(DAG.getUNDEF(XLenVT));
+        continue;
+      }
+      int Src = M >= (int)NumElts;
+      int Diff = (int)i - (M % NumElts);
+      bool C = Src == SrcInfo[1].first && Diff == SrcInfo[1].second;
+      MaskVals.push_back(DAG.getConstant(C, DL, XLenVT));
----------------
lukel97 wrote:

Just to check my understanding, at this point we'll also have the invariant `C || Src == SrcInfo[0].first && Diff == SrcInfo[0].second`? Is that worth an assert

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


More information about the llvm-commits mailing list