Bug type: miscompilation
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: tryToReduce
Issue title: [SLP] Incorrect poison propagation when vectorizing boolean select chains
Labels: miscompilation
llvm:SLPVectorizer
Reported by: cardigan1008

In https://github.com/llvm/llvm-project/commit/889215a30ed60474e573f9632d1fa362dfa1b04e, there is still an uncovered correctness issue in SLP vectorization of boolean select chains involving poison, specifically when an intermediate reduction node is used in mixed positions within the same reduction tree.

Consider the following IR:

```llvm
%i1 = select i1 %p, i1 true, i1 false
%safe   = select i1 %f, i1 %i1, i1 false
%unsafe = select i1 %i1, i1 true, i1 false
%res    = select i1 %safe, i1 %unsafe, i1 false
ret i1 %res
```

If `%f` is false, `%safe` evaluates to false, and `%res` immediately becomes false. 
In this case, `%unsafe` is never observed, and the poison carried by `%i1` is correctly suppressed by the scalar semantics. 

However, after the current SLP transformation, `%safe` and `%unsafe` are combined into a single boolean reduction tree.
The intermediate value `%i1` is treated as a reduction operand and participates directly in the vectorized reduction logic. 

Because `%i1` is used as a condition operand in `%unsafe`, the current logic assumes that `%i1` is poison-propagating and therefore skips inserting a freeze.
This classification ignores the fact that `%i1` is also used as a value operand in `%safe`, where poison is semantically suppressed by a dominating constant false.

Alive2 proof: https://alive2.llvm.org/ce/z/qPCjs6

Exposed from https://github.com/llvm/llvm-project/commit/889215a30ed60474e573f9632d1fa362dfa1b04e, cc @alexey-bataev 


Fix patch:
commit ab450597dad2bc8f92376da2c230d9604fc8afc1
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Sun Dec 28 13:31:04 2025 -0800

    [SLP]Do not swap RHS, if it is used in bool op, used as a second operand in a reduction
    
    If the RHS operand is used as a first operand in the bool reduction op,
    used as a second operand in the reduction ops, still need to use this
    RHS as RHS, not as LHS
    
    https://alive2.llvm.org/ce/z/pmc2YJ
    
    Fixes #173796

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index a7b41631594d..0bf90209df9c 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -25028,10 +25028,18 @@ public:
           if (isBoolLogicOp(RedOp2) && ((!InitStep && RHS == VectorizedTree) ||
                                         getRdxOperand(RedOp2, 0) == RHS ||
                                         isGuaranteedNotToBePoison(RHS, AC))) {
+            // If RedOp2 was used as a second operand - do not swap.
             if ((InitStep || RHS != VectorizedTree) &&
                 getRdxOperand(RedOp2, 0) == RHS &&
-                (!isBoolLogicOp(RedOp1) ||
-                 getRdxOperand(RedOp1, 1) == RedOp2)) {
+                ((isBoolLogicOp(RedOp1) &&
+                  getRdxOperand(RedOp1, 1) == RedOp2) ||
+                 any_of(ReductionOps, [&](ArrayRef<Value *> Ops) {
+                   return any_of(Ops, [&](Value *Op) {
+                     auto *OpI = dyn_cast<Instruction>(Op);
+                     return OpI && isBoolLogicOp(OpI) &&
+                            getRdxOperand(OpI, 1) == RedOp2;
+                   });
+                 }))) {
               NeedFreeze = false;
             } else {
               std::swap(LHS, RHS);


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/test_intermediate_dual_use.ll
commands: opt -S --passes=slp-vectorizer < %s
tests: test_name: test_intermediate_dual_use
test_body: define i1 @test_intermediate_dual_use(<4 x i32> %x) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %p_val = extractelement <4 x i32> %x, i32 -1
  %leaf_p = icmp eq i32 %p_val, 0
  %leaf_f = icmp ugt i32 %x0, -1
  %i1 = select i1 %leaf_p, i1 true, i1 false
  %safe = select i1 %leaf_f, i1 %i1, i1 false
  %unsafe = select i1 %i1, i1 true, i1 false
  %res = select i1 %safe, i1 %unsafe, i1 false
  ret i1 %res
}