[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{};
----------------
lukel97 wrote:
Is the idea behind using std::array that you might extend this to further factors later?
https://github.com/llvm/llvm-project/pull/192121
More information about the llvm-commits
mailing list