[llvm] [SLP] Fix misvectorization in commutative to non-commutative conversion (PR #185230)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Mar 7 13:39:02 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: tudinhh (tudinhh)
<details>
<summary>Changes</summary>
**Summary**
Fixes a miscompilation where commutative operations (e.g., or, and, mul) with a left-hand side constant were incorrectly transformed into non-commutative operations (e.g., shl, sub).
**The Problem**
In BinOpSameOpcodeHelper::getOperand, when a constant is at Pos == 0, the helper was failing to swap operand order for new non-commutative target opcodes. This resulted in inverted logic, such as transforming `or 0, %x` into `shl 0, %x` (resulting in 0) instead of the correct `%x << 0`.
**The Fix**
The existing logic only protected the Sub opcode. This patch generalizes the fix to all non-commutative instructions by using !Instruction::isCommutative(ToOpcode). This ensures that for any directional operation, the variable is correctly placed on the LHS and the constant on the RHS.
**Changes**
SLPVectorizer.cpp: Replaced the specific Sub check with a general isCommutative check.
Regression Test: Added lhs-constant-non-cummutative.ll to cover shl, sub, and ashr targets.
Fixes #<!-- -->185186
---
Full diff: https://github.com/llvm/llvm-project/pull/185230.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp (+4-6)
- (added) llvm/test/Transforms/SLPVectorizer/X86/lhs-constant-non-cummutative.ll (+39)
``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 631af61e2cfba..df7885e31741e 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -1132,13 +1132,11 @@ class BinOpSameOpcodeHelper {
break;
}
Value *LHS = I->getOperand(1 - Pos);
- // constant + x cannot be -constant - x
- // instead, it should be x - -constant
- if (Pos == 1 ||
- ((FromOpcode == Instruction::Add || FromOpcode == Instruction::Or ||
- FromOpcode == Instruction::Xor) &&
- ToOpcode == Instruction::Sub))
+ // If the target opcode is non-commutative (e.g., shl, sub),
+ // force the variable to the left and the constant to the right.
+ if (Pos == 1 || !Instruction::isCommutative(ToOpcode))
return SmallVector<Value *>({LHS, RHS});
+
return SmallVector<Value *>({RHS, LHS});
}
};
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/lhs-constant-non-cummutative.ll b/llvm/test/Transforms/SLPVectorizer/X86/lhs-constant-non-cummutative.ll
new file mode 100644
index 0000000000000..5a33d5f5bac5b
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/lhs-constant-non-cummutative.ll
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S --passes=slp-vectorizer -slp-threshold=-50 -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+define void @or_lhs_to_shl(ptr %p, ptr %s) {
+; CHECK-LABEL: define void @or_lhs_to_shl(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[S:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr [[P]], align 2
+; CHECK-NEXT: [[TMP1:%.*]] = shl <4 x i16> [[TMP0]], <i16 1, i16 2, i16 3, i16 0>
+; CHECK-NEXT: store <4 x i16> [[TMP1]], ptr [[S]], align 2
+; CHECK-NEXT: ret void
+;
+entry:
+ %p1 = getelementptr i16, ptr %p, i64 1
+ %p2 = getelementptr i16, ptr %p, i64 2
+ %p3 = getelementptr i16, ptr %p, i64 3
+
+ %l0 = load i16, ptr %p, align 2
+ %l1 = load i16, ptr %p1, align 2
+ %l2 = load i16, ptr %p2, align 2
+ %l3 = load i16, ptr %p3, align 2
+
+ ; 3 shl instructions force the vectorizer to choose shl as the target
+ %op0 = shl i16 %l0, 1
+ %op1 = shl i16 %l1, 2
+ %op2 = shl i16 %l2, 3
+ %op3 = or i16 0, %l3 ; The buggy instruction
+
+ %s1 = getelementptr i16, ptr %s, i64 1
+ %s2 = getelementptr i16, ptr %s, i64 2
+ %s3 = getelementptr i16, ptr %s, i64 3
+
+ store i16 %op0, ptr %s, align 2
+ store i16 %op1, ptr %s1, align 2
+ store i16 %op2, ptr %s2, align 2
+ store i16 %op3, ptr %s3, align 2
+
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/185230
More information about the llvm-commits
mailing list