Skip to content

Commit 414710c

Browse files
authored
[SLP] Fix isCommutative to check uses of the original instruction instead of the converted instruction. (#143094)
1 parent dc72b91 commit 414710c

File tree

2 files changed

+64
-6
lines changed

2 files changed

+64
-6
lines changed

llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -511,15 +511,25 @@ static bool isSplat(ArrayRef<Value *> VL) {
511511
}
512512

513513
/// \returns True if \p I is commutative, handles CmpInst and BinaryOperator.
514-
static bool isCommutative(Instruction *I) {
514+
/// For BinaryOperator, it also checks if \p InstWithUses is used in specific
515+
/// patterns that make it effectively commutative (like equality comparisons
516+
/// with zero).
517+
/// In most cases, users should not call this function directly (since \p I and
518+
/// \p InstWithUses are the same). However, when analyzing interchangeable
519+
/// instructions, we need to use the converted opcode along with the original
520+
/// uses.
521+
/// \param I The instruction to check for commutativity
522+
/// \param InstWithUses The instruction whose uses are analyzed for special
523+
/// patterns
524+
static bool isCommutative(Instruction *I, Instruction *InstWithUses) {
515525
if (auto *Cmp = dyn_cast<CmpInst>(I))
516526
return Cmp->isCommutative();
517527
if (auto *BO = dyn_cast<BinaryOperator>(I))
518528
return BO->isCommutative() ||
519529
(BO->getOpcode() == Instruction::Sub &&
520-
!BO->hasNUsesOrMore(UsesLimit) &&
530+
!InstWithUses->hasNUsesOrMore(UsesLimit) &&
521531
all_of(
522-
BO->uses(),
532+
InstWithUses->uses(),
523533
[](const Use &U) {
524534
// Commutative, if icmp eq/ne sub, 0
525535
CmpPredicate Pred;
@@ -536,14 +546,24 @@ static bool isCommutative(Instruction *I) {
536546
Flag->isOne());
537547
})) ||
538548
(BO->getOpcode() == Instruction::FSub &&
539-
!BO->hasNUsesOrMore(UsesLimit) &&
540-
all_of(BO->uses(), [](const Use &U) {
549+
!InstWithUses->hasNUsesOrMore(UsesLimit) &&
550+
all_of(InstWithUses->uses(), [](const Use &U) {
541551
return match(U.getUser(),
542552
m_Intrinsic<Intrinsic::fabs>(m_Specific(U.get())));
543553
}));
544554
return I->isCommutative();
545555
}
546556

557+
/// This is a helper function to check whether \p I is commutative.
558+
/// This is a convenience wrapper that calls the two-parameter version of
559+
/// isCommutative with the same instruction for both parameters. This is
560+
/// the common case where the instruction being checked for commutativity
561+
/// is the same as the instruction whose uses are analyzed for special
562+
/// patterns (see the two-parameter version above for details).
563+
/// \param I The instruction to check for commutativity
564+
/// \returns true if the instruction is commutative, false otherwise
565+
static bool isCommutative(Instruction *I) { return isCommutative(I, I); }
566+
547567
template <typename T>
548568
static std::optional<unsigned> getInsertExtractIndex(const Value *Inst,
549569
unsigned Offset) {
@@ -2898,7 +2918,11 @@ class BoUpSLP {
28982918
continue;
28992919
}
29002920
auto [SelectedOp, Ops] = convertTo(cast<Instruction>(V), S);
2901-
bool IsInverseOperation = !isCommutative(SelectedOp);
2921+
// We cannot check commutativity by the converted instruction
2922+
// (SelectedOp) because isCommutative also examines def-use
2923+
// relationships.
2924+
bool IsInverseOperation =
2925+
!isCommutative(SelectedOp, cast<Instruction>(V));
29022926
for (unsigned OpIdx : seq<unsigned>(ArgSize)) {
29032927
bool APO = (OpIdx == 0) ? false : IsInverseOperation;
29042928
OpsVec[OpIdx][Lane] = {Operands[OpIdx][Lane], APO, false};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -passes=slp-vectorizer -S %s | FileCheck %s
3+
4+
define i16 @check_isCommutative_with_the_original_source() {
5+
; CHECK-LABEL: @check_isCommutative_with_the_original_source(
6+
; CHECK-NEXT: entry:
7+
; CHECK-NEXT: [[COND3:%.*]] = select i1 true, i16 1, i16 0
8+
; CHECK-NEXT: ret i16 [[COND3]]
9+
;
10+
entry:
11+
%sub = sub i16 0, -1
12+
%cmp = icmp eq i16 %sub, 1
13+
14+
%sub1 = sub i16 0, -1
15+
%cmp2 = icmp eq i16 %sub1, 1
16+
%cond3 = select i1 %cmp2, i16 1, i16 0
17+
18+
%sub5 = sub nsw i16 0, 0
19+
%cmp6 = icmp eq i16 %sub5, 0
20+
%cmp9 = icmp eq i16 %sub5, 0
21+
22+
%sub12 = sub nsw i16 0, 0
23+
%cmp13 = icmp eq i16 %sub12, 0
24+
25+
%sub16 = sub nsw i16 0, 0
26+
%cmp17 = icmp eq i16 %sub16, 0
27+
28+
%sub20 = sub nsw i16 0, 0
29+
%cmp21 = icmp eq i16 %sub20, 0
30+
%cmp24 = icmp eq i16 %sub20, 0
31+
32+
ret i16 %cond3
33+
}
34+

0 commit comments

Comments
 (0)