[llvm] [VectorCombine] Fold deinterleave2 with smaller effective element size (PR #192121)

Luke Lau via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 18 03:08:52 PDT 2026


================
@@ -5531,6 +5532,138 @@ bool VectorCombine::foldInterleaveIntrinsics(Instruction &I) {
   return true;
 }
 
+bool VectorCombine::foldDeinterleaveIntrinsics(Instruction &I) {
+  using namespace PatternMatch;
+  Value *DeinterleavedVal;
+  if (!match(&I, m_Deinterleave2(m_Value(DeinterleavedVal))))
+    return false;
+
+  // Given this sequence:
+  // ```
+  // %d = llvm.vector.deinterleave2 <vscale x 16 x i32> %v
+  // %f0 = extractvalue { <vscale x 8 x i32>, <vscale x 8 x i32> } %d, 0
+  // %f1 = extractvalue { <vscale x 8 x i32>, <vscale x 8 x i32> } %d, 1
+  //
+  // %low0 = and <vscale x 8 x i32> %f0, splat (i32 65535)
+  // %low1 = shl <vscale x 8 x i32> %f1, splat (i32 16)
+  // %merge0 = or disjoint <vscale x 8 x i32> %low0, %low1
+  //
+  // %high0 = and <vscale x 8 x i32> %f1, splat (i32 -65536)
+  // %high1 = lshr <vscale x 8 x i32> %f0, splat (i32 16)
+  // %merge1 = or disjoint <vscale x 8 x i32> %high0, %high1
+  // ```
+  // It is actually just de-interleaving a 16-bit vector with double the
+  // vector length. More generally speaking, it's de-interleaving on a vector
+  // with half the element width as the original vector.
+  //
+  // Therefore, we can turn it into:
+  // ```
+  // %narrow.v = bitcast <vscale x 16 x i32> %v to <vscale x 32 x i16>
+  // %d = llvm.vector.deinterleave2 <vscale x 32 x i16> %narrow.v
+  // %f0 = extractvalue { <vscale x 16 x i16>, <vscale x 16 x i16> } %d, 0
+  // %f1 = extractvalue { <vscale x 16 x i16>, <vscale x 16 x i16> } %d, 1
+  //
+  // %merge0 = bitcast <vscale x 16 x i16> %f0 to <vscale x 8 x i32>
+  // %merge1 = bitcast <vscale x 16 x i16> %f1 to <vscale x 8 x i32>
+  // ```
+  VectorType *VecTy = cast<VectorType>(DeinterleavedVal->getType());
+  IntegerType *ElementTy = dyn_cast<IntegerType>(VecTy->getElementType());
+  if (!ElementTy)
+    return false;
+  unsigned ElementWidth = ElementTy->getBitWidth();
+  assert(isPowerOf2_32(ElementWidth));
+  unsigned HalfElementWidth = ElementWidth / 2;
+  APInt LoMask(ElementWidth, 0);
+  LoMask.setLowBits(HalfElementWidth);
+  APInt HiMask(ElementWidth, 0);
+  HiMask.setHighBits(HalfElementWidth);
+
+  if (!I.hasNUses(2))
+    return false;
+  std::array<ExtractValueInst *, 2> OrigFields{};
+  for (User *Usr : I.users()) {
+    auto *E = dyn_cast<ExtractValueInst>(Usr);
+    // The detinerleave result can only be used by extractions.
+    if (!E || E->getNumIndices() != 1)
+      return false;
+    unsigned Idx = *E->idx_begin();
+    // A single field cannot be extracted more than once.
+    if (Idx >= 2 || OrigFields[Idx] || !E->hasNUses(2))
+      return false;
+    OrigFields[Idx] = E;
+  }
+
+  // Find the OR (merge instruction) first.
+  SmallVector<PossiblyDisjointInst *, 2> MergeInsts;
+  for (auto *FieldUsr : OrigFields[0]->users()) {
+    if (!FieldUsr->hasOneUse())
+      return false;
+    auto *Merge = dyn_cast<PossiblyDisjointInst>(*FieldUsr->user_begin());
+    if (!Merge)
+      return false;
+    MergeInsts.push_back(Merge);
+  }
+  assert(MergeInsts.size() == 2);
+
+  // Pattern match bottom-up from the merge instructions.
+  auto MatchMerge = [&](void) -> bool {
+    return match(MergeInsts[0],
+                 m_c_Or(m_And(m_Specific(OrigFields[0]), m_SpecificInt(LoMask)),
+                        m_Shl(m_Specific(OrigFields[1]),
+                              m_SpecificInt(HalfElementWidth)))) &&
+           match(MergeInsts[1],
+                 m_c_Or(m_And(m_Specific(OrigFields[1]), m_SpecificInt(HiMask)),
+                        m_LShr(m_Specific(OrigFields[0]),
+                               m_SpecificInt(HalfElementWidth))));
+  };
+  if (!MatchMerge()) {
+    std::swap(MergeInsts[0], MergeInsts[1]);
+    if (!MatchMerge())
+      return false;
+  }
+
+  // Profitibility check.
----------------
lukel97 wrote:

Nit

```suggestion
  // Profitability check. 
```


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


More information about the llvm-commits mailing list