Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp: InstCombinerImpl::visitSelectInst
foldBitCeil
Issue title: [InstCombine] `range` attribute should be dropped in `foldBitCeil`
Labels: miscompilation
llvm:instcombine
Reported by: dtcxzyw

Reproducer: https://alive2.llvm.org/ce/z/NQTmkh (Please use latest alive2 with https://github.com/AliveToolkit/alive2/pull/1097)
```
define i32 @src(i32 %x) {
  %ctlz = call range(i32 1, 33) i32 @llvm.ctlz.i32(i32 %x, i1 false)
  %sub = sub i32 32, %ctlz
  %shl = shl i32 1, %sub
  %dec = add i32 %x, -1
  %ult = icmp ult i32 %dec, -2
  %sel = select i1 %ult, i32 %shl, i32 1
  ret i32 %sel
}

define i32 @tgt(i32 %x) {
  %ctlz = call range(i32 1, 33) i32 @llvm.ctlz.i32(i32 %x, i1 false)
  %1 = sub nsw i32 0, %ctlz
  %2 = and i32 %1, 31
  %sel = shl nuw i32 1, %2
  ret i32 %sel
}
```
```
----------------------------------------
define i32 @src(i32 %x) {
#0:
  %ctlz = ctlz i32 %x, 0
  %#range_0_%ctlz = !range i32 %ctlz, i32 1, i32 33
  %sub = sub i32 32, %#range_0_%ctlz
  %shl = shl i32 1, %sub
  %dec = add i32 %x, 4294967295
  %ult = icmp ult i32 %dec, 4294967294
  %sel = select i1 %ult, i32 %shl, i32 1
  ret i32 %sel
}
=>
define i32 @tgt(i32 %x) {
#0:
  %ctlz = ctlz i32 %x, 0
  %#range_0_%ctlz = !range i32 %ctlz, i32 1, i32 33
  %#1 = sub nsw i32 0, %#range_0_%ctlz
  %#2 = and i32 %#1, 31
  %sel = shl nuw i32 1, %#2
  ret i32 %sel
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
i32 %x = #xffffffff (4294967295, -1)

Source:
i32 %ctlz = #x00000000 (0)
i32 %#range_0_%ctlz = poison
i32 %sub = poison
i32 %shl = poison
i32 %dec = #xfffffffe (4294967294, -2)
i1 %ult = #x0 (0)
i32 %sel = #x00000001 (1)

Target:
i32 %ctlz = #x00000000 (0)
i32 %#range_0_%ctlz = poison
i32 %#1 = poison
i32 %#2 = poison
i32 %sel = poison
Source value: #x00000001 (1)
Target value: poison
```



Fix patch:
commit 2c094ac761912eea0d7e8ccb140bc647b5378bdf
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Wed Nov 20 21:15:26 2024 +0800

    [InstCombine] Drop range attributes in `foldBitCeil` (#116641)
    
    Closes https://github.com/llvm/llvm-project/issues/112076

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 28dbca027037..2526ce7704ab 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3466,7 +3466,8 @@ static bool isSafeToRemoveBitCeilSelect(ICmpInst::Predicate Pred, Value *Cond0,
 // Note that the select is optimized away while the shift count is masked with
 // 31.  We handle some variations of the input operand like std::bit_ceil(X +
 // 1).
-static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
+static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder,
+                                InstCombinerImpl &IC) {
   Type *SelType = SI.getType();
   unsigned BitWidth = SelType->getScalarSizeInBits();
 
@@ -3501,6 +3502,10 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
   // single hardware instruction as opposed to BitWidth - CTLZ, where BitWidth
   // is an integer constant.  Masking with BitWidth-1 comes free on some
   // hardware as part of the shift instruction.
+
+  // Drop range attributes and re-infer them in the next iteration.
+  cast<Instruction>(Ctlz)->dropPoisonGeneratingAnnotations();
+  IC.addToWorklist(cast<Instruction>(Ctlz));
   Value *Neg = Builder.CreateNeg(Ctlz);
   Value *Masked =
       Builder.CreateAnd(Neg, ConstantInt::get(SelType, BitWidth - 1));
@@ -4148,7 +4153,7 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   if (sinkNotIntoOtherHandOfLogicalOp(SI))
     return &SI;
 
-  if (Instruction *I = foldBitCeil(SI, Builder))
+  if (Instruction *I = foldBitCeil(SI, Builder, *this))
     return I;
 
   if (Instruction *I = foldSelectToCmp(SI))


Regression tests:
file: llvm/test/Transforms/InstCombine/bit_ceil.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: test_drop_range_attr
test_body: define i32 @test_drop_range_attr(i32 %x) {
  %ctlz = call range(i32 1, 33) i32 @llvm.ctlz.i32(i32 %x, i1 false)
  %sub = sub i32 32, %ctlz
  %shl = shl i32 1, %sub
  %dec = add i32 %x, -1
  %ult = icmp ult i32 %dec, -2
  %sel = select i1 %ult, i32 %shl, i32 1
  ret i32 %sel
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.ctlz.i32(i32, i1 immarg) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

test_name: pr91691_keep_nsw
test_body: define i32 @pr91691_keep_nsw(i32 %0) {
  %2 = sub nsw i32 -2, %0
  %3 = tail call i32 @llvm.ctlz.i32(i32 %2, i1 false)
  %4 = sub i32 32, %3
  %5 = shl i32 1, %4
  %6 = icmp ult i32 %0, -2
  %7 = select i1 %6, i32 %5, i32 1
  ret i32 %7
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.ctlz.i32(i32, i1 immarg) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }