Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp: InstCombinerImpl::foldAndOrOfICmps
Issue title: [InstCombine] `samesign` flag should be dropped in `foldAndOrOfICmpsWithConstEq`
Labels: miscompilation
llvm:instcombine
Reported by: dtcxzyw

Reproducer:
```
; bin/opt -passes=instcombine test.ll -S
define i1 @src(i8 %x, i8 %y) {
  %cmp = icmp sgt i8 %x, %y
  %cmpeq = icmp samesign ne i8 %x, 0
  %r = select i1 %cmp, i1 true, i1 %cmpeq
  ret i1 %r
}
```
```
define i1 @tgt(i8 %x, i8 %y) {
  %cmpeq = icmp samesign ne i8 %x, 0
  %1 = icmp slt i8 %y, 0
  %r = or i1 %cmpeq, %1
  ret i1 %r
}
```
```
----------------------------------------
define i1 @src(i8 %x, i8 %y) {
#0:
  %cmp = icmp sgt i8 %x, %y
  %cmpeq = icmp samesign ne i8 %x, 0
  %r = select i1 %cmp, i1 1, i1 %cmpeq
  ret i1 %r
}
=>
define i1 @tgt(i8 %x, i8 %y) {
#0:
  %cmpeq = icmp samesign ne i8 %x, 0
  %#1 = icmp slt i8 %y, 0
  %r = or i1 %cmpeq, %#1
  ret i1 %r
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
i8 %x = #x81 (129, -127)
i8 %y = #x80 (128, -128)

Source:
i1 %cmp = #x1 (1)
i1 %cmpeq = poison
i1 %r = #x1 (1)

Target:
i1 %cmpeq = poison
i1 %#1 = #x1 (1)
i1 %r = poison
Source value: #x1 (1)
Target value: poison
```



Fix patch:
commit 3bf2295ee0ebd1eafe66ca15dff44bdb31e6198a
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Wed Oct 16 16:24:44 2024 +0800

    [InstCombine] Drop `samesign` flag in `foldAndOrOfICmpsWithConstEq` (#112489)
    
    In
    https://github.com/llvm/llvm-project/commit/5dbfca30c1a672cd0c5089df2b4fdd171436643a
    we assume that RHS is poison implies LHS is also poison. It doesn't hold
    after introducing samesign flag.
    
    This patch drops the `samesign` flag on RHS if the original expression
    is a logical and/or.
    
    Closes #112467.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 64bee4ab974e..c8407e8ba5ab 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3369,8 +3369,14 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
   // We can convert this case to bitwise and, because both operands are used
   // on the LHS, and as such poison from both will propagate.
   if (Value *V = foldAndOrOfICmpsWithConstEq(RHS, LHS, IsAnd,
-                                             /*IsLogical*/ false, Builder, Q))
+                                             /*IsLogical=*/false, Builder, Q)) {
+    // If RHS is still used, we should drop samesign flag.
+    if (IsLogical && RHS->hasSameSign() && !RHS->use_empty()) {
+      RHS->setSameSign(false);
+      addToWorklist(RHS);
+    }
     return V;
+  }
 
   if (Value *V = foldIsPowerOf2OrZero(LHS, RHS, IsAnd, Builder, *this))
     return V;


Regression tests:
file: llvm/test/Transforms/InstCombine/and-or-icmp-min-max.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: sge_and_max_commute
test_body: define i1 @sge_and_max_commute(i8 %x, i8 %y) {
  %cmp = icmp sge i8 %x, %y
  %cmpeq = icmp eq i8 %x, 127
  %r = and i1 %cmpeq, %cmp
  ret i1 %r
}

test_name: sge_and_max_logical
test_body: define i1 @sge_and_max_logical(i8 %x, i8 %y) {
  %cmp = icmp sge i8 %x, %y
  %cmpeq = icmp eq i8 %x, 127
  %r = select i1 %cmp, i1 %cmpeq, i1 false
  ret i1 %r
}

test_name: sge_and_max_logical_samesign
test_body: define i1 @sge_and_max_logical_samesign(i8 %x, i8 %y) {
  %cmp = icmp sge i8 %x, %y
  %cmpeq = icmp samesign eq i8 %x, 127
  %r = select i1 %cmp, i1 %cmpeq, i1 false
  ret i1 %r
}

file: llvm/test/Transforms/InstCombine/and-or-icmp-nullptr.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: sgt_and_min_logical_samesign
test_body: define i1 @sgt_and_min_logical_samesign(ptr %x, ptr %y) {
  %cmp = icmp sgt ptr %x, %y
  %cmpeq = icmp samesign eq ptr %x, null
  %r = select i1 %cmp, i1 %cmpeq, i1 false
  ret i1 %r
}

test_name: sgt_and_min_logical
test_body: define i1 @sgt_and_min_logical(ptr %x, ptr %y) {
  %cmp = icmp sgt ptr %x, %y
  %cmpeq = icmp eq ptr %x, null
  %r = select i1 %cmp, i1 %cmpeq, i1 false
  ret i1 %r
}

test_name: sle_or_not_min
test_body: define i1 @sle_or_not_min(ptr %x, ptr %y) {
  %cmp = icmp sle ptr %x, %y
  %cmpeq = icmp ne ptr %x, null
  %r = or i1 %cmp, %cmpeq
  ret i1 %r
}