[llvm] [RISCV] Lower disjoint shuffle of shuffles to MERGE-GATHER sequence (PR #178095)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 29 02:42:50 PST 2026


================
@@ -5439,6 +5439,113 @@ static SDValue lowerVECTOR_SHUFFLEAsVSlideup(const SDLoc &DL, MVT VT,
   return convertFromScalableVector(VT, Res, DAG, Subtarget);
 }
 
+// A shuffle of shuffles where:
+// - the first level of shuffles both only used data from a single input
+// - the final output doesn't use data from the same lane of both operands
+// This can be lowered to a MERGE followed by a GATHER
+static SDValue lowerVECTOR_SHUFFLEAsMergeGather(const SDLoc &DL, MVT VT,
+                                                SDValue V1, SDValue V2,
+                                                ArrayRef<int> Mask,
+                                                const RISCVSubtarget &Subtarget,
+                                                SelectionDAG &DAG) {
+  if (V1.getOpcode() != ISD::VECTOR_SHUFFLE ||
+      V2.getOpcode() != ISD::VECTOR_SHUFFLE)
+    return SDValue();
+
+  if (!V1.hasOneUse() || !V2.hasOneUse())
+    return SDValue();
+
+  // Can just be reduced into a single gather operation
+  if (V1.getOperand(0) == V2.getOperand(0))
+    return SDValue();
+
+  unsigned NumElts = VT.getVectorNumElements();
+  auto *SVN1 = cast<ShuffleVectorSDNode>(V1.getNode());
+  auto *SVN2 = cast<ShuffleVectorSDNode>(V2.getNode());
+  auto V1Mask = SVN1->getMask();
+  auto V2Mask = SVN2->getMask();
+  // 0: Not set, 1: Set by V1, 2: Set by V2
+  SmallVector<unsigned> ShuffleLaneUses(NumElts, 0);
+  for (unsigned Idx : seq<unsigned>(NumElts)) {
+    int Lane = Mask[Idx];
+    // Don't assign if poison
+    if (Lane == -1)
+      continue;
+    unsigned OpNum;
+    int OrigLane;
+    if ((unsigned)Lane < NumElts) {
+      OpNum = 1;
+      OrigLane = V1Mask[Lane];
+    } else {
+      OpNum = 2;
+      OrigLane = V2Mask[Lane - NumElts];
+    }
+    if (OrigLane == -1)
+      continue;
+    // Don't handle if shuffling from a second operand
+    if ((unsigned)OrigLane >= NumElts)
+      return SDValue();
+
+    const unsigned CurrLaneSrc = ShuffleLaneUses[OrigLane];
+    // Can't use the same lane from both operands in the merge
+    if (CurrLaneSrc != 0 && CurrLaneSrc != OpNum)
+      return SDValue();
+    ShuffleLaneUses[OrigLane] = OpNum;
+  }
+
+  MVT ContainerVT = getContainerForFixedLengthVector(DAG, VT, Subtarget);
+  auto [TrueMask, VL] = getDefaultVLOps(VT, ContainerVT, DL, DAG, Subtarget);
+
+  // Create the mask for the initial merge
+  auto XLenVT = Subtarget.getXLenVT();
----------------
lukel97 wrote:

Nit 
```suggestion
  MVT XLenVT = Subtarget.getXLenVT();
```

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


More information about the llvm-commits mailing list