[llvm] [VectorCombine] Check call targets when folding deinterleave/interleave pairs (PR #219116)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 22:33:05 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Oscar Priego (Opriego)
<details>
<summary>Changes</summary>
`foldDeinterleaveInterleavePair` uses `Instruction::isSameOperationAs` to
determine whether operations on deinterleaved chains can be widened into a
single operation.
For call instructions, `isSameOperationAs` compares the instruction opcode,
types, operand counts/types, and special state, but does not compare the call
target. As a result, same-signature intrinsics such as `llvm.smax` and
`llvm.smin` could be considered equivalent and incorrectly folded into a
single wide intrinsic.
Require call instructions participating in this fold to have the same called
operand.
This preserves the existing behavior for non-call instructions and identical
intrinsics while preventing folds across different called operations.
Regression coverage includes:
- `smax` + `smin`, which must not fold
- `smax` + `smax`, which must continue folding
Fixes #<!-- -->218162.
Tests:
- `ninja -C ~/LinuxDev/upstream/llvm-build opt`
- `llvm-lit -v llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll`
- `git diff --check`
---
Full diff: https://github.com/llvm/llvm-project/pull/219116.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Vectorize/VectorCombine.cpp (+9-2)
- (modified) llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll (+35)
``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index d19894d57c058..7da3121a35998 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -6153,8 +6153,15 @@ bool VectorCombine::foldDeinterleaveInterleavePair(Instruction &I) {
unsigned ChainOperand = CurrentUses.front()->getOperandNo();
if (any_of(CurrentUses, [&](Use *U) {
auto *Inst = cast<Instruction>(U->getUser());
- return Inst != FirstInst && (U->getOperandNo() != ChainOperand ||
- !FirstInst->isSameOperationAs(Inst));
+ if (Inst == FirstInst)
+ return false;
+ if (U->getOperandNo() != ChainOperand ||
+ !FirstInst->isSameOperationAs(Inst))
+ return true;
+ // isSameOperationAs does not compare call targets.
+ auto *FirstCB = dyn_cast<CallBase>(FirstInst);
+ return FirstCB && FirstCB->getCalledOperand() !=
+ cast<CallBase>(Inst)->getCalledOperand();
}))
return false;
diff --git a/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll b/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll
index e3c542e900fe0..75388509185f6 100644
--- a/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll
+++ b/llvm/test/Transforms/VectorCombine/deinterleave-interleave-pairs.ll
@@ -712,6 +712,41 @@ else:
ret <vscale x 16 x i16> zeroinitializer
}
+define <4 x i16> @deinterleave2_same_intrinsic_interleave2(<4 x i16> %v) {
+; CHECK-LABEL: define <4 x i16> @deinterleave2_same_intrinsic_interleave2(
+; CHECK-SAME: <4 x i16> [[V:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call <4 x i16> @llvm.smax.v4i16(<4 x i16> [[V]], <4 x i16> splat (i16 3))
+; CHECK-NEXT: ret <4 x i16> [[R]]
+;
+ %d = call { <2 x i16>, <2 x i16> } @llvm.vector.deinterleave2.v4i16(<4 x i16> %v)
+ %f0 = extractvalue { <2 x i16>, <2 x i16> } %d, 0
+ %f1 = extractvalue { <2 x i16>, <2 x i16> } %d, 1
+ %u0 = call <2 x i16> @llvm.smax.v2i16(<2 x i16> %f0, <2 x i16> splat (i16 3))
+ %u1 = call <2 x i16> @llvm.smax.v2i16(<2 x i16> %f1, <2 x i16> splat (i16 3))
+ %r = call <4 x i16> @llvm.vector.interleave2.v4i16(<2 x i16> %u0, <2 x i16> %u1)
+ ret <4 x i16> %r
+}
+
+define <4 x i16> @negative_deinterleave2_different_intrinsics_interleave2(<4 x i16> %v) {
+; CHECK-LABEL: define <4 x i16> @negative_deinterleave2_different_intrinsics_interleave2(
+; CHECK-SAME: <4 x i16> [[V:%.*]]) {
+; CHECK-NEXT: [[D:%.*]] = call { <2 x i16>, <2 x i16> } @llvm.vector.deinterleave2.v4i16(<4 x i16> [[V]])
+; CHECK-NEXT: [[F0:%.*]] = extractvalue { <2 x i16>, <2 x i16> } [[D]], 0
+; CHECK-NEXT: [[F1:%.*]] = extractvalue { <2 x i16>, <2 x i16> } [[D]], 1
+; CHECK-NEXT: [[U0:%.*]] = call <2 x i16> @llvm.smax.v2i16(<2 x i16> [[F0]], <2 x i16> splat (i16 3))
+; CHECK-NEXT: [[U1:%.*]] = call <2 x i16> @llvm.smin.v2i16(<2 x i16> [[F1]], <2 x i16> splat (i16 3))
+; CHECK-NEXT: [[R:%.*]] = call <4 x i16> @llvm.vector.interleave2.v4i16(<2 x i16> [[U0]], <2 x i16> [[U1]])
+; CHECK-NEXT: ret <4 x i16> [[R]]
+;
+ %d = call { <2 x i16>, <2 x i16> } @llvm.vector.deinterleave2.v4i16(<4 x i16> %v)
+ %f0 = extractvalue { <2 x i16>, <2 x i16> } %d, 0
+ %f1 = extractvalue { <2 x i16>, <2 x i16> } %d, 1
+ %u0 = call <2 x i16> @llvm.smax.v2i16(<2 x i16> %f0, <2 x i16> splat (i16 3))
+ %u1 = call <2 x i16> @llvm.smin.v2i16(<2 x i16> %f1, <2 x i16> splat (i16 3))
+ %r = call <4 x i16> @llvm.vector.interleave2.v4i16(<2 x i16> %u0, <2 x i16> %u1)
+ ret <4 x i16> %r
+}
+
!0 = !{!"function_entry_count", i64 1000}
!1 = !{!"branch_weights", i32 2, i32 3}
``````````
</details>
https://github.com/llvm/llvm-project/pull/219116
More information about the llvm-commits
mailing list