[llvm] [RISCV] Eliminate redundant VSLIDEDOWN_VL/VSLIDEUP_VL pairs (PR #223863)

Min-Yih Hsu via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 09:55:18 PDT 2026


================
@@ -22265,6 +22265,85 @@ static SDValue performVECTOR_INTERLEAVECombine(SDNode *N, SelectionDAG &DAG) {
   return DAG.getMergeValues(Operands, DL);
 }
 
+static SDValue performVSlideUpDownCombine(SDNode *N, SelectionDAG &DAG,
+                                          const RISCVSubtarget &Subtarget) {
+  unsigned Opcode = N->getOpcode();
+  assert(Opcode == RISCVISD::VSLIDEUP_VL || Opcode == RISCVISD::VSLIDEDOWN_VL);
+
+  // Trivial case.
+  if (N->getOperand(1)->isUndef())
+    return N->getOperand(0);
+
+  SDValue SlideDown = N->getOperand(1);
+  SDValue SlideUpOffset = N->getOperand(2);
+  SDValue SlideUpMask = N->getOperand(3);
+  SDValue SlideUpVL = N->getOperand(4);
+
+  // Given this pattern
+  // ```
+  //   %down = RISCVISD::VSLIDEDOWN_VL undef, %val, %offset, %mask, %vl0
+  // %up = RISCVISD::VSLIDEUP_VL %val, %down, %offset, %mask, %vl1
+  // ```
+  // We can simplify it with `%val`, as it's doing redundant shifting.
+  if (Opcode != RISCVISD::VSLIDEUP_VL ||
+      SlideDown.getOpcode() != RISCVISD::VSLIDEDOWN_VL)
+    return SDValue();
+
+  SDValue SlideDownPassthru = SlideDown->getOperand(0);
+  SDValue SlideDownVal = SlideDown->getOperand(1);
+  SDValue SlideDownOffset = SlideDown->getOperand(2);
+  SDValue SlideDownMask = SlideDown->getOperand(3);
+  SDValue SlideDownVL = SlideDown->getOperand(4);
+  if (!SlideDownPassthru.isUndef() || SlideDownVal != N->getOperand(0) ||
+      SlideDownOffset != SlideUpOffset)
+    return SDValue();
+
+  auto isVLMax = [](SDValue VL) {
+    return (isa<RegisterSDNode>(VL) &&
+            cast<RegisterSDNode>(VL)->getReg() == RISCV::X0) ||
+           isAllOnesConstant(VL);
+  };
+
+  // Check VLs.
+  // First, we need to worry about the zeros shifted into VSLIDEDOWN_VL. In this
+  // scenario, the worst case would be %vl0 = VLMAX, as %down is guaranteed to
+  // have those zeros. Our goal here is to ensure elements from %down that are
+  // actually inserted into %up are not those zeros. The number of %down that
+  // are actually inserted would be `%vl1 - %offset`, and the number of non-zero
+  // elements from %down would be `VLMAX - %offset`. Therefore, the invariant
+  // would be
+  // `%vl1 - %offset <= VLMAX - %offset` ---> `%vl1 <= VLMAX`
+  // Thus, we will never read those zeros that are shifted in by VSLIDEDOWN_VL.
+  // Second, we don't want slideup to read pass the result produced by
+  // slidedown. So the condition for this case would be `%vl0 + %offset >=
+  // %vl1`.
+  if (!isVLMax(SlideDownVL)) {
+    KnownBits DownVLKB = DAG.computeKnownBits(SlideDownVL);
+    KnownBits UpVLKB = DAG.computeKnownBits(SlideUpVL);
+    KnownBits OffsetKB = DAG.computeKnownBits(SlideDownOffset);
+    if (!KnownBits::uge(KnownBits::add(DownVLKB, OffsetKB, /*NSW=*/false,
+                                       /*NUW=*/true),
+                        UpVLKB)
+             .value_or(false))
+      return SDValue();
+  }
+
+  // Check Masks.
+  auto isAllSetMask = [&](SDValue V, SDValue VL) -> bool {
+    using namespace SDPatternMatch;
+    SDValue VMSet;
+    return sd_match(V, m_Node(RISCVISD::VMSET_VL, m_Value(VMSet))) &&
+           (isVLMax(VMSet) || KnownBits::uge(DAG.computeKnownBits(VMSet),
+                                             DAG.computeKnownBits(VL))
+                                  .value_or(false));
----------------
mshockwave wrote:

It's now fixed.

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


More information about the llvm-commits mailing list