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

In https://github.com/llvm/llvm-project/commit/899336735aeb2b41a48b6ac2c895da5e0f22dbf0, there seems to be an uncovered correctness issue in the handling of boolean select chains involving poison. 

Consider the following scalar IR:

```llvm
%op1 = select i1 %a, i1 true, i1 poison
%op2 = select i1 %b, i1 true, i1 poison
%res = select i1 %op1, i1 true, i1 %op2
ret i1 %res
```

Semantically, this code is safe:
if `%a` is true, `%op1` is true, and `%res` immediately becomes true.
In this case, the value of `%op2` (and the poison on its false branch) is never observed.

After the current transformation, this pattern is rewritten by grouping `%op1` and `%op2` into a vector and lowering the logic to a `llvm.vector.reduce.or`. This transformation eagerly evaluates all vector lanes.

As a result, if `%op2` is poison, the reduction observes that poison and produces a poison result, even when `%op1` is true. This introduces poison in cases where the original scalar code would have produced a well-defined true.

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

cc @alexey-bataev 



Fix patch:
commit d9ce80db7aaa985160276aa59a405e5f47fd7354
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Sun Dec 28 11:20:42 2025 -0800

    [SLP]FIx order of bool logical ops, if the right op is used in the first reduction operarion
    
    If the LHS of the first reduction op is not a first operand, but RHS is,
    and RHS is the second operand of the first reductoin op, still need to
    emit RHS as a second reduction operand, though without freeze of the
    LHS operand
    
    https://alive2.llvm.org/ce/z/2_JLBu
    
    Fixes #173784

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 6e05fcfe421c..a7b41631594d 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -25024,13 +25024,21 @@ public:
                                         getRdxOperand(RedOp1, 0) == LHS ||
                                         isGuaranteedNotToBePoison(LHS, AC)))
             return;
+          bool NeedFreeze = LHS != VectorizedTree;
           if (isBoolLogicOp(RedOp2) && ((!InitStep && RHS == VectorizedTree) ||
                                         getRdxOperand(RedOp2, 0) == RHS ||
                                         isGuaranteedNotToBePoison(RHS, AC))) {
-            std::swap(LHS, RHS);
-            return;
+            if ((InitStep || RHS != VectorizedTree) &&
+                getRdxOperand(RedOp2, 0) == RHS &&
+                (!isBoolLogicOp(RedOp1) ||
+                 getRdxOperand(RedOp1, 1) == RedOp2)) {
+              NeedFreeze = false;
+            } else {
+              std::swap(LHS, RHS);
+              return;
+            }
           }
-          if (LHS != VectorizedTree)
+          if (NeedFreeze)
             LHS = Builder.CreateFreeze(LHS);
         };
     // Finish the reduction.


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/boolean-op-with-poisons.ll
commands: opt -S --passes=slp-vectorizer < %s
tests: test_name: test_explicit_poison_leaves
test_body: define i1 @test_explicit_poison_leaves(i1 %a, i1 %b) {
  %op1 = select i1 %a, i1 true, i1 poison
  %op2 = select i1 %b, i1 true, i1 poison
  %res = select i1 %op1, i1 true, i1 %op2
  ret i1 %res
}