Bug type: miscompilation
Component: IndVarSimplify
Bug location: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp: IndVarSimplify::canonicalizeExitCondition
Issue title: [IndVarSimplify] samesign flag should be dropped after narrowing
Labels: miscompilation
llvm:transforms
Reported by: dtcxzyw

Found with https://github.com/dtcxzyw/llvm-ub-aware-interpreter.
Reproducer: https://alive2.llvm.org/ce/z/fcnvLv
```
; bin/opt -passes=indvars test.ll -S
define i8 @test(i1 %cond, i32 range(i32 0, 32) %x) {
entry:
  br i1 %cond, label %for.body, label %else

else:
  %call1 = call i8 @callee()
  br label %exit

for.body:
  %call2 = call i8 @callee()
  %ext = zext i8 %call2 to i32
  %cond2 = icmp samesign ugt i32 %x, %ext
  br i1 %cond2, label %for.body, label %exit

exit:
  %res = phi i8 [ %call1, %else ], [ %call2, %for.body ]
  ret i8 %res
}
```
```

----------------------------------------
declare i8 @callee()

define i8 @test(i1 %cond, i32 %x) {
init:
  %#range_0_%x = !range i32 %x, i32 0, i32 32
  br label %entry

entry:
  br i1 %cond, label %for.body, label %else

else:
  %call1 = call i8 @callee()
  br label %exit

for.body:
  %call2 = call i8 @callee()
  %ext = zext i8 %call2 to i32
  %cond2 = icmp samesign ugt i32 %#range_0_%x, %ext
  br i1 %cond2, label %for.body, label %exit

exit:
  %res = phi i8 [ %call1, %else ], [ %call2, %for.body ]
  ret i8 %res
}
=>
declare i8 @callee()

define i8 @test(i1 %cond, i32 %x) {
init:
  %#range_0_%x = !range i32 %x, i32 0, i32 32
  br label %entry

entry:
  br i1 %cond, label %for.body.preheader, label %else

else:
  %call1 = call i8 @callee()
  br label %exit

for.body.preheader:
  %#0 = trunc i32 %#range_0_%x to i8
  br label %for.body

for.body:
  %call2 = call i8 @callee()
  %cond2 = icmp samesign ugt i8 %#0, %call2
  br i1 %cond2, label %for.body, label %exit.loopexit

exit.loopexit:
  %call2.lcssa = phi i8 [ %call2, %for.body ]
  br label %exit

exit:
  %res = phi i8 [ %call1, %else ], [ %call2.lcssa, %exit.loopexit ]
  ret i8 %res
}
Transformation doesn't verify!

ERROR: Source is more defined than target

Example:
i1 %cond = #x1 (1)
i32 %x = #x00000000 (0)

Source:
i32 %#range_0_%x = #x00000000 (0)
  >> Jump to %entry
  >> Jump to %for.body
i8 %call2 = #x80 (128, -128)
i32 %ext = #x00000080 (128)
i1 %cond2 = #x0 (0)
  >> Jump to %exit
i8 %res = #x80 (128, -128)

SOURCE MEMORY STATE
===================
NON-LOCAL BLOCKS:
Block 0 >	size: 0	align: 1	alloc type: 0	alive: false	address: 0
Block 1 >	size: 4	align: 1	alloc type: 0	alive: true	address: 1

Target:
i32 %#range_0_%x = #x00000000 (0)
  >> Jump to %entry
  >> Jump to %for.body.preheader
i8 %#0 = #x00 (0)
  >> Jump to %for.body
i8 %call2 = #x80 (128, -128)
i1 %cond2 = poison
UB triggered on br


Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```


Fix patch:
commit 40a647fc7dc6048c92e2d580b61f5feca0785980
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Fri Nov 15 09:15:37 2024 +0800

    [IndVarSimplify] Drop samesign flags after narrowing compares (#116263)
    
    Samesign flag cannot be preserved after narrowing the compare since the
    position of the sign bit is changed.
    
    Closes https://github.com/llvm/llvm-project/issues/116249.

diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 2b2d516a7079..8a3e0bc3eb97 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1530,6 +1530,8 @@ bool IndVarSimplify::canonicalizeExitCondition(Loop *L) {
           L->getLoopPreheader()->getTerminator()->getIterator());
       ICmp->setOperand(Swapped ? 1 : 0, LHSOp);
       ICmp->setOperand(Swapped ? 0 : 1, NewRHS);
+      // Samesign flag cannot be preserved after narrowing the compare.
+      ICmp->setSameSign(false);
       if (LHS->use_empty())
         DeadInsts.push_back(LHS);
     };


Regression tests:
file: llvm/test/Transforms/IndVarSimplify/finite-exit-comparisons.ll
commands: opt -passes=indvars -S < %s -indvars-predicate-loops=0
tests: test_name: test_drop_icmp_samesign
test_body: target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"

define i8 @test_drop_icmp_samesign(i1 %cond, i32 range(i32 0, 32) %x) {
entry:
  br i1 %cond, label %for.body, label %else

else:                                             ; preds = %entry
  %call1 = call i8 @callee()
  br label %exit

for.body:                                         ; preds = %for.body, %entry
  %call2 = call i8 @callee()
  %ext = zext i8 %call2 to i32
  %cond2 = icmp samesign ugt i32 %x, %ext
  br i1 %cond2, label %for.body, label %exit

exit:                                             ; preds = %for.body, %else
  %res = phi i8 [ %call1, %else ], [ %call2, %for.body ]
  ret i8 %res
}

declare i8 @callee()