[llvm] [VectorCombine][AArch64] Fix reverse uses of deinterleave (PR #216308)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 14 05:14:54 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-vectorizers

@llvm/pr-subscribers-llvm-transforms

Author: Kamlesh Kumar (kamleshbhalui)

<details>
<summary>Changes</summary>

Fold a reversed deinterleave with reversed field order to a vector reverse.
i.e. interleaveN(reverse(deinterleaveN(X)[N-1]), ...,reverse(deinterleaveN(X)[0])) --> reverse(X).
           
This is always profitable if interleave store cancels interleave load.

---

Patch is 22.66 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/216308.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Vectorize/VectorCombine.cpp (+62) 
- (added) llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll (+280) 


``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 9eeeef16c7bd3..3aa4a1ca104d2 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -155,6 +155,7 @@ class VectorCombine {
   bool foldEquivalentReductionCmp(Instruction &I);
   bool foldReduceAddCmpZero(Instruction &I);
   bool foldSelectShuffle(Instruction &I, bool FromReduction = false);
+  bool foldInterleaveOfReversedDeinterleave(Instruction &I);
   bool foldInterleaveIntrinsics(Instruction &I);
   bool foldDeinterleaveIntrinsics(Instruction &I);
   bool foldBitcastOfVPLoad(Instruction &I);
@@ -5905,6 +5906,65 @@ bool VectorCombine::foldInsExtVectorToShuffle(Instruction &I) {
   return true;
 }
 
+/// Fold a reversed deinterleave with reversed field order to a vector reverse.
+/// i.e.
+/// interleaveN(reverse(deinterleaveN(X)[N-1]), ...,
+///             reverse(deinterleaveN(X)[0])) --> reverse(X).
+bool VectorCombine::foldInterleaveOfReversedDeinterleave(Instruction &I) {
+  auto *II = dyn_cast<IntrinsicInst>(&I);
+  if (!II)
+    return false;
+  unsigned Factor = getInterleaveIntrinsicFactor(II->getIntrinsicID());
+  if (!Factor)
+    return false;
+
+  IntrinsicInst *Deinterleave = nullptr;
+  for (unsigned Idx = 0; Idx != Factor; ++Idx) {
+    Value *Op = II->getArgOperand(Idx);
+    // Every reverse must feed only this interleave, otherwise
+    // it's not profitable to fold.
+    if (!Op->hasOneUse())
+      return false;
+
+    Value *Reversed = nullptr;
+    if (auto *Shuffle = dyn_cast<ShuffleVectorInst>(Op)) {
+      ArrayRef<int> Mask = Shuffle->getShuffleMask();
+      if (!Shuffle->isReverse() ||
+          !llvm::all_of(Mask, [NumElts = static_cast<int>(Mask.size())](
+                                  int MaskElt) { return MaskElt < NumElts; }))
+        return false;
+      Reversed = Shuffle->getOperand(0);
+    } else if (!match(Op, m_Intrinsic<Intrinsic::vector_reverse>(
+                              m_Value(Reversed)))) {
+      return false;
+    }
+
+    auto *Extract = dyn_cast<ExtractValueInst>(Reversed);
+    if (!Extract || !Extract->hasOneUse() || Extract->getNumIndices() != 1 ||
+        *Extract->idx_begin() != (Factor - Idx - 1))
+      return false;
+    auto *CurrentDeinterleave =
+        dyn_cast<IntrinsicInst>(Extract->getAggregateOperand());
+    if (!CurrentDeinterleave)
+      return false;
+    if (CurrentDeinterleave->getIntrinsicID() !=
+            Intrinsic::getDeinterleaveIntrinsicID(Factor) ||
+        (Deinterleave && Deinterleave != CurrentDeinterleave))
+      return false;
+
+    Deinterleave = CurrentDeinterleave;
+  }
+
+  if (!Deinterleave->hasNUses(Factor))
+    return false;
+
+  Value *Input = Deinterleave->getArgOperand(0);
+  Value *Reverse = Builder.CreateIntrinsic(Intrinsic::vector_reverse,
+                                           {Input->getType()}, {Input});
+  replaceValue(I, *Reverse);
+  return true;
+}
+
 /// If we're interleaving 2 constant splats, for instance `<vscale x 8 x i32>
 /// <splat of 666>` and `<vscale x 8 x i32> <splat of 777>`, we can create a
 /// larger splat `<vscale x 8 x i64> <splat of ((777 << 32) | 666)>` first
@@ -6551,6 +6611,8 @@ bool VectorCombine::run() {
         return true;
       if (scalarizeVPIntrinsic(I))
         return true;
+      if (foldInterleaveOfReversedDeinterleave(I))
+        return true;
       if (foldInterleaveIntrinsics(I))
         return true;
       if (foldBitcastOfVPLoad(I))
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll b/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll
new file mode 100644
index 0000000000000..106b1cf5e0c16
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/AArch64/interleave-reverse-deinterleave.ll
@@ -0,0 +1,280 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -mtriple=aarch64-linux-gnu -passes=vector-combine -S %s | FileCheck %s
+
+define <24 x i16> @reverse_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @reverse_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.reverse.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <8 x i16> %e1, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r2 = shufflevector <8 x i16> %e2, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r2, <8 x i16> %r1, <8 x i16> %r0)
+  ret <24 x i16> %interleave
+}
+
+define <24 x i16> @reverse_intrinsic_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @reverse_intrinsic_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.reverse.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e0)
+  %r1 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e1)
+  %r2 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e2)
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r2, <8 x i16> %r1, <8 x i16> %r0)
+  ret <24 x i16> %interleave
+}
+
+define <vscale x 24 x i16> @reverse_intrinsic_interleave3_scalable(<vscale x 24 x i16> %x) {
+; CHECK-LABEL: define <vscale x 24 x i16> @reverse_intrinsic_interleave3_scalable(
+; CHECK-SAME: <vscale x 24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <vscale x 24 x i16> @llvm.vector.reverse.nxv24i16(<vscale x 24 x i16> [[X]])
+; CHECK-NEXT:    ret <vscale x 24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } @llvm.vector.deinterleave3(<vscale x 24 x i16> %x)
+  %e0 = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <vscale x 8 x i16>, <vscale x 8 x i16>, <vscale x 8 x i16> } %deinterleave, 2
+  %r0 = call <vscale x 8 x i16> @llvm.vector.reverse(<vscale x 8 x i16> %e0)
+  %r1 = call <vscale x 8 x i16> @llvm.vector.reverse(<vscale x 8 x i16> %e1)
+  %r2 = call <vscale x 8 x i16> @llvm.vector.reverse(<vscale x 8 x i16> %e2)
+  %interleave = call <vscale x 24 x i16> @llvm.vector.interleave3(<vscale x 8 x i16> %r2, <vscale x 8 x i16> %r1, <vscale x 8 x i16> %r0)
+  ret <vscale x 24 x i16> %interleave
+}
+
+define <24 x i16> @group_reverse_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @group_reverse_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[E2:%.*]] = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 2
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <8 x i16> [[E1]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R2:%.*]] = shufflevector <8 x i16> [[E2]], <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.interleave3.v24i16(<8 x i16> [[R0]], <8 x i16> [[R1]], <8 x i16> [[R2]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <8 x i16> %e1, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r2 = shufflevector <8 x i16> %e2, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r0, <8 x i16> %r1, <8 x i16> %r2)
+  ret <24 x i16> %interleave
+}
+
+define <6 x i16> @reverse_second_operand_interleave2(<6 x i16> %x) {
+; CHECK-LABEL: define <6 x i16> @reverse_second_operand_interleave2(
+; CHECK-SAME: <6 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2.v6i16(<6 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <3 x i16>, <3 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <3 x i16> [[E0]], <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <3 x i16> [[E1]], <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <6 x i16> @llvm.vector.interleave2.v6i16(<3 x i16> [[R1]], <3 x i16> [[R0]])
+; CHECK-NEXT:    ret <6 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2(<6 x i16> %x)
+  %e0 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 1
+  %r0 = shufflevector <3 x i16> %e0, <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+  %r1 = shufflevector <3 x i16> %e1, <3 x i16> zeroinitializer, <3 x i32> <i32 5, i32 4, i32 3>
+  %interleave = call <6 x i16> @llvm.vector.interleave2(<3 x i16> %r1, <3 x i16> %r0)
+  ret <6 x i16> %interleave
+}
+
+define <6 x i16> @reverse_poison_mask_interleave2(<6 x i16> %x) {
+; CHECK-LABEL: define <6 x i16> @reverse_poison_mask_interleave2(
+; CHECK-SAME: <6 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <6 x i16> @llvm.vector.reverse.v6i16(<6 x i16> [[X]])
+; CHECK-NEXT:    ret <6 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <3 x i16>, <3 x i16> } @llvm.vector.deinterleave2(<6 x i16> %x)
+  %e0 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <3 x i16>, <3 x i16> } %deinterleave, 1
+  %r0 = shufflevector <3 x i16> %e0, <3 x i16> poison, <3 x i32> <i32 2, i32 poison, i32 0>
+  %r1 = shufflevector <3 x i16> %e1, <3 x i16> poison, <3 x i32> <i32 2, i32 1, i32 poison>
+  %interleave = call <6 x i16> @llvm.vector.interleave2(<3 x i16> %r1, <3 x i16> %r0)
+  ret <6 x i16> %interleave
+}
+
+define <16 x i16> @reverse_interleave4(<16 x i16> %x) {
+; CHECK-LABEL: define <16 x i16> @reverse_interleave4(
+; CHECK-SAME: <16 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <16 x i16> @llvm.vector.reverse.v16i16(<16 x i16> [[X]])
+; CHECK-NEXT:    ret <16 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.vector.deinterleave4(<16 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 2
+  %e3 = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %deinterleave, 3
+  %r0 = shufflevector <4 x i16> %e0, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <4 x i16> %e1, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r2 = shufflevector <4 x i16> %e2, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r3 = shufflevector <4 x i16> %e3, <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <16 x i16> @llvm.vector.interleave4(<4 x i16> %r3, <4 x i16> %r2, <4 x i16> %r1, <4 x i16> %r0)
+  ret <16 x i16> %interleave
+}
+
+define <24 x i16> @mixed_reverse_interleave3(<24 x i16> %x) {
+; CHECK-LABEL: define <24 x i16> @mixed_reverse_interleave3(
+; CHECK-SAME: <24 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <24 x i16> @llvm.vector.reverse.v24i16(<24 x i16> [[X]])
+; CHECK-NEXT:    ret <24 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave3(<24 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+  %e2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = call <8 x i16> @llvm.vector.reverse(<8 x i16> %e1)
+  %r2 = shufflevector <8 x i16> %e2, <8 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <24 x i16> @llvm.vector.interleave3(<8 x i16> %r2, <8 x i16> %r1, <8 x i16> %r0)
+  ret <24 x i16> %interleave
+}
+
+define <8 x i16> @narrowing_shuffle_interleave2(<16 x i16> %x) {
+; CHECK-LABEL: define <8 x i16> @narrowing_shuffle_interleave2(
+; CHECK-SAME: <16 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.vector.deinterleave2.v16i16(<16 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <8 x i16>, <8 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <8 x i16> [[E0]], <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <8 x i16> [[E1]], <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <8 x i16> @llvm.vector.interleave2.v8i16(<4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <8 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <8 x i16>, <8 x i16> } @llvm.vector.deinterleave2(<16 x i16> %x)
+  %e0 = extractvalue { <8 x i16>, <8 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <8 x i16>, <8 x i16> } %deinterleave, 1
+  %r0 = shufflevector <8 x i16> %e0, <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <8 x i16> %e1, <8 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <8 x i16> @llvm.vector.interleave2(<4 x i16> %r1, <4 x i16> %r0)
+  ret <8 x i16> %interleave
+}
+
+define <16 x i16> @widening_shuffle_interleave2(<8 x i16> %x) {
+; CHECK-LABEL: define <16 x i16> @widening_shuffle_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = shufflevector <4 x i16> [[E0]], <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[R1:%.*]] = shufflevector <4 x i16> [[E1]], <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <16 x i16> @llvm.vector.interleave2.v16i16(<8 x i16> [[R1]], <8 x i16> [[R0]])
+; CHECK-NEXT:    ret <16 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 1
+  %r0 = shufflevector <4 x i16> %e0, <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %r1 = shufflevector <4 x i16> %e1, <4 x i16> poison, <8 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
+  %interleave = call <16 x i16> @llvm.vector.interleave2(<8 x i16> %r1, <8 x i16> %r0)
+  ret <16 x i16> %interleave
+}
+
+define <8 x i16> @multi_use_reverse_interleave2(<8 x i16> %x) {
+; CHECK-LABEL: define <8 x i16> @multi_use_reverse_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[R0:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E1]])
+; CHECK-NEXT:    call void (...) @llvm.fake.use(<4 x i16> [[R0]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <8 x i16> @llvm.vector.interleave2.v8i16(<4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <8 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 1
+  %r0 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e0)
+  %r1 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e1)
+  call void (...) @llvm.fake.use(<4 x i16> %r0)
+  %interleave = call <8 x i16> @llvm.vector.interleave2(<4 x i16> %r1, <4 x i16> %r0)
+  ret <8 x i16> %interleave
+}
+
+define <8 x i16> @extra_extract_use_interleave2(<8 x i16> %x) {
+; CHECK-LABEL: define <8 x i16> @extra_extract_use_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]]) {
+; CHECK-NEXT:    [[DEINTERLEAVE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[E0:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    [[E1:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 1
+; CHECK-NEXT:    [[EXTRA:%.*]] = extractvalue { <4 x i16>, <4 x i16> } [[DEINTERLEAVE]], 0
+; CHECK-NEXT:    call void (...) @llvm.fake.use(<4 x i16> [[EXTRA]])
+; CHECK-NEXT:    [[R0:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E0]])
+; CHECK-NEXT:    [[R1:%.*]] = call <4 x i16> @llvm.vector.reverse.v4i16(<4 x i16> [[E1]])
+; CHECK-NEXT:    [[INTERLEAVE:%.*]] = call <8 x i16> @llvm.vector.interleave2.v8i16(<4 x i16> [[R1]], <4 x i16> [[R0]])
+; CHECK-NEXT:    ret <8 x i16> [[INTERLEAVE]]
+;
+  %deinterleave = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2(<8 x i16> %x)
+  %e0 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  %e1 = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 1
+  %extra = extractvalue { <4 x i16>, <4 x i16> } %deinterleave, 0
+  call void (...) @llvm.fake.use(<4 x i16> %extra)
+  %r0 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e0)
+  %r1 = call <4 x i16> @llvm.vector.reverse(<4 x i16> %e1)
+  %interleave = call <8 x i16> @llvm.vector.interleave2(<4 x i16> %r1, <4 x i16> %r0)
+  ret <8 x i16> %interleave
+}
+
+define <8 x i16> @two_deinterleaves_interleave2(<8 x i16> %x, <8 x i16> %y) {
+; CHECK-LABEL: define <8 x i16> @two_deinterleaves_interleave2(
+; CHECK-SAME: <8 x i16> [[X:%.*]], <8 x i16> [[Y:%.*]]) {
+; CHECK-NEXT:    [[D0:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[X]])
+; CHECK-NEXT:    [[D1:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.vector.deinterleave2.v8i16(<8 x i16> [[Y]])...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list