Bug type: miscompilation
Component: SLPVectorizer
Bug location: llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp: tryToReduce
Issue title: wrong folding of `select`s in slp-vectorizer
Labels: miscompilation
llvm:SLPVectorizer
Reported by: bongjunj

Alive2 report: https://alive2.llvm.org/ce/z/jEopx9

```llvm
----------------------------------------
define i1 @logical_and_icmp_diff_preds.2(<4 x i32> %x) {
#0:
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %s1 = select i1 %#1, i1 %c1, i1 0
  %s2 = select i1 %s1, i1 %c3, i1 0
  %s3 = select i1 %s2, i1 %c3, i1 0
  ret i1 %s3
}
=>
define i1 @logical_and_icmp_diff_preds.2(<4 x i32> %x) {
#0:
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %op.rdx = select i1 %c3, i1 %c1, i1 0
  %op.rdx1 = select i1 %op.rdx, i1 %#1, i1 0
  ret i1 %op.rdx1
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
<4 x i32> %x = < #x00000000 (0), #x00000000 (0), #x00000000 (0), #xffffffff (4294967295, -1) >

Source:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %s1 = #x0 (0)
i1 %s2 = #x0 (0)
i1 %s3 = #x0 (0)

Target:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %op.rdx = poison
i1 %op.rdx1 = poison
Source value: #x0 (0)
Target value: poison

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```

Comments: author: nunoplopes
body: Alive2 is still not happy with the fix:
```llvm
define i1 @test(<4 x i32> %x) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %s1 = select i1 %#1, i1 %c1, i1 0
  %s2 = select i1 %s1, i1 %c3, i1 0
  %s3 = select i1 %s2, i1 %c3, i1 0
  ret i1 %s3
}
=>
define i1 @test(<4 x i32> %x) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 4294967295
  %x3 = extractelement <4 x i32> %x, i32 3
  %#1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c3 = icmp slt i32 %x3, 0
  %#2 = freeze i1 %c3
  %op.rdx = select i1 %#2, i1 %c1, i1 0
  %op.rdx1 = select i1 %op.rdx, i1 %#1, i1 0
  ret i1 %op.rdx1
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
<4 x i32> %x = < #x00000000 (0), poison, poison, #xffffffff (4294967295, -1) >

Source:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %s1 = #x0 (0)
i1 %s2 = #x0 (0)
i1 %s3 = #x0 (0)

Target:
i32 %x0 = #x00000000 (0)
i32 %x1 = poison
i32 %x3 = #xffffffff (4294967295, -1)
i1 %#1 = #x0 (0)
i1 %c1 = poison
i1 %c3 = #x1 (1)
i1 %#2 = #x1 (1)
i1 %op.rdx = poison
i1 %op.rdx1 = poison
Source value: #x0 (0)
Target value: poison
```

Fix patch:
commit 889215a30ed60474e573f9632d1fa362dfa1b04e
Author: Alexey Bataev <a.bataev@outlook.com>
Date:   Thu Dec 26 05:09:51 2024 -0800

    [SLP]Followup fix for the poisonous logical op in reductions
    
    If the VectorizedTree still may generate poisonous value, but it is not
    the original operand of the reduction op, need to check if Res still the
    operand, to generate correct code.
    
    Fixes #114905

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 57f3016fbe1e..e9fc89fa242a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -19821,21 +19821,21 @@ public:
         Builder.SetCurrentDebugLocation(
             cast<Instruction>(ReductionOps.front().front())->getDebugLoc());
         if (AnyBoolLogicOp) {
-
-          if (auto It = ReducedValsToOps.find(VectorizedTree);
-              It == ReducedValsToOps.end() ||
+          auto It = ReducedValsToOps.find(VectorizedTree);
+          auto It1 = ReducedValsToOps.find(Res);
+          if ((It == ReducedValsToOps.end() && It1 == ReducedValsToOps.end()) ||
               isGuaranteedNotToBePoison(VectorizedTree, AC) ||
-              any_of(It->getSecond(), [&](Instruction *I) {
-                return isBoolLogicOp(I) &&
-                       getRdxOperand(I, 0) == VectorizedTree;
-              })) {
+              (It != ReducedValsToOps.end() &&
+               any_of(It->getSecond(), [&](Instruction *I) {
+                 return isBoolLogicOp(I) &&
+                        getRdxOperand(I, 0) == VectorizedTree;
+               }))) {
             ;
-          } else if (auto It = ReducedValsToOps.find(Res);
-                     It == ReducedValsToOps.end() ||
-                     isGuaranteedNotToBePoison(Res, AC) ||
-                     any_of(It->getSecond(), [&](Instruction *I) {
+          } else if (isGuaranteedNotToBePoison(Res, AC) ||
+                     (It1 != ReducedValsToOps.end() &&
+                     any_of(It1->getSecond(), [&](Instruction *I) {
                        return isBoolLogicOp(I) && getRdxOperand(I, 0) == Res;
-                     })) {
+                     }))) {
             std::swap(VectorizedTree, Res);
           } else {
             VectorizedTree = Builder.CreateFreeze(VectorizedTree);


Regression tests:
file: llvm/test/Transforms/SLPVectorizer/X86/reduction-logical.ll
commands: opt < %s -passes=slp-vectorizer -mtriple=x86_64--                 -S
opt < %s -passes=slp-vectorizer -mtriple=x86_64-- -mattr=avx512vl -S
tests: test_name: logical_or_icmp_extra_op
test_body: define i1 @logical_or_icmp_extra_op(<4 x i32> %x, <4 x i32> %y, i1 %c) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 1
  %x2 = extractelement <4 x i32> %x, i32 2
  %x3 = extractelement <4 x i32> %x, i32 3
  %y0 = extractelement <4 x i32> %y, i32 0
  %y1 = extractelement <4 x i32> %y, i32 1
  %y2 = extractelement <4 x i32> %y, i32 2
  %y3 = extractelement <4 x i32> %y, i32 3
  %d0 = icmp slt i32 %x0, %y0
  %d1 = icmp slt i32 %x1, %y1
  %d2 = icmp slt i32 %x2, %y2
  %d3 = icmp slt i32 %x3, %y3
  %s3 = select i1 %c, i1 true, i1 %c
  %s4 = select i1 %s3, i1 true, i1 %d0
  %s5 = select i1 %s4, i1 true, i1 %d1
  %s6 = select i1 %s5, i1 true, i1 %d2
  %s7 = select i1 %s6, i1 true, i1 %d3
  ret i1 %s7
}

test_name: logical_and_icmp_extra_op
test_body: define i1 @logical_and_icmp_extra_op(<4 x i32> %x, <4 x i32> %y, i1 %c) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 1
  %x2 = extractelement <4 x i32> %x, i32 2
  %x3 = extractelement <4 x i32> %x, i32 3
  %y0 = extractelement <4 x i32> %y, i32 0
  %y1 = extractelement <4 x i32> %y, i32 1
  %y2 = extractelement <4 x i32> %y, i32 2
  %y3 = extractelement <4 x i32> %y, i32 3
  %d0 = icmp slt i32 %x0, %y0
  %d1 = icmp slt i32 %x1, %y1
  %d2 = icmp slt i32 %x2, %y2
  %d3 = icmp slt i32 %x3, %y3
  %s3 = select i1 %c, i1 %c, i1 false
  %s4 = select i1 %s3, i1 %d0, i1 false
  %s5 = select i1 %s4, i1 %d1, i1 false
  %s6 = select i1 %s5, i1 %d2, i1 false
  %s7 = select i1 %s6, i1 %d3, i1 false
  ret i1 %s7
}

file: llvm/test/Transforms/SLPVectorizer/logical-ops-poisonous-repeated.ll
commands: opt -S --passes=slp-vectorizer < %s
tests: test_name: test
test_body: define i1 @test(<4 x i32> %x) {
  %x0 = extractelement <4 x i32> %x, i32 0
  %x1 = extractelement <4 x i32> %x, i32 -1
  %x2 = extractelement <4 x i32> %x, i32 2
  %x3 = extractelement <4 x i32> %x, i32 3
  %1 = icmp ugt i32 %x0, 0
  %c1 = icmp slt i32 %x1, 0
  %c2 = icmp sgt i32 %x2, 0
  %c3 = icmp slt i32 %x3, 0
  %s1 = select i1 %1, i1 %c1, i1 false
  %s2 = select i1 %s1, i1 %c3, i1 false
  %s3 = select i1 %s2, i1 %c3, i1 false
  ret i1 %s3
}