Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp: foldBitCeil
isSafeToRemoveBitCeilSelect
Issue title: instcombine removes a select, making code more poisonous
Labels: miscompilation
llvm:instcombine
Reported by: regehr

https://alive2.llvm.org/ce/z/c__jy8

this function:
```llvm
define i32 @f(i32 %0) {
  %2 = sub nuw 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) }
```

is getting rewritten to not have the select, but the select was blocking a poison value. the bad thing happens when -1 is passed as an argument, see the Alive link for a detailed execution trace

```llvm
define i32 @f(i32 %0) {
  %2 = sub nuw i32 -2, %0
  %3 = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 %2, i1 false)
  %4 = sub nsw i32 0, %3
  %5 = and i32 %4, 31
  %6 = shl nuw i32 1, %5
  ret i32 %6
}

; 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) }
```

cc @nunoplopes 


Fix patch:
commit b5f4210e9f51f938ae517f219f04f9ab431a2684
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Mon May 13 14:27:59 2024 +0800

    [InstCombine] Drop nuw flag when CtlzOp is a sub nuw (#91776)
    
    See the following case:
    ```
    define i32 @src1(i32 %x) {
      %dec = sub nuw i32 -2, %x
      %ctlz = tail call i32 @llvm.ctlz.i32(i32 %dec, i1 false)
      %sub = sub nsw i32 32, %ctlz
      %shl = shl i32 1, %sub
      %ugt = icmp ult i32 %x, -2
      %sel = select i1 %ugt, i32 %shl, i32 1
      ret i32 %sel
    }
    
    define i32 @tgt1(i32 %x) {
      %dec = sub nuw i32 -2, %x
      %ctlz = tail call i32 @llvm.ctlz.i32(i32 %dec, i1 false)
      %sub = sub nsw i32 32, %ctlz
      %and = and i32 %sub, 31
      %shl = shl nuw i32 1, %and
      ret i32 %shl
    }
    ```
    `nuw` in `%dec` should be dropped after the select instruction is
    eliminated.
    
    Alive2: https://alive2.llvm.org/ce/z/7S9529
    
    Fixes https://github.com/llvm/llvm-project/issues/91691.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index ee090e012508..a3ddb402bf66 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3343,7 +3343,8 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
 // pattern.
 static bool isSafeToRemoveBitCeilSelect(ICmpInst::Predicate Pred, Value *Cond0,
                                         const APInt *Cond1, Value *CtlzOp,
-                                        unsigned BitWidth) {
+                                        unsigned BitWidth,
+                                        bool &ShouldDropNUW) {
   // The challenge in recognizing std::bit_ceil(X) is that the operand is used
   // for the CTLZ proper and select condition, each possibly with some
   // operation like add and sub.
@@ -3366,6 +3367,8 @@ static bool isSafeToRemoveBitCeilSelect(ICmpInst::Predicate Pred, Value *Cond0,
   ConstantRange CR = ConstantRange::makeExactICmpRegion(
       CmpInst::getInversePredicate(Pred), *Cond1);
 
+  ShouldDropNUW = false;
+
   // Match the operation that's used to compute CtlzOp from CommonAncestor.  If
   // CtlzOp == CommonAncestor, return true as no operation is needed.  If a
   // match is found, execute the operation on CR, update CR, and return true.
@@ -3379,6 +3382,7 @@ static bool isSafeToRemoveBitCeilSelect(ICmpInst::Predicate Pred, Value *Cond0,
       return true;
     }
     if (match(CtlzOp, m_Sub(m_APInt(C), m_Specific(CommonAncestor)))) {
+      ShouldDropNUW = true;
       CR = ConstantRange(*C).sub(CR);
       return true;
     }
@@ -3448,14 +3452,20 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
     Pred = CmpInst::getInversePredicate(Pred);
   }
 
+  bool ShouldDropNUW;
+
   if (!match(FalseVal, m_One()) ||
       !match(TrueVal,
              m_OneUse(m_Shl(m_One(), m_OneUse(m_Sub(m_SpecificInt(BitWidth),
                                                     m_Value(Ctlz)))))) ||
       !match(Ctlz, m_Intrinsic<Intrinsic::ctlz>(m_Value(CtlzOp), m_Zero())) ||
-      !isSafeToRemoveBitCeilSelect(Pred, Cond0, Cond1, CtlzOp, BitWidth))
+      !isSafeToRemoveBitCeilSelect(Pred, Cond0, Cond1, CtlzOp, BitWidth,
+                                   ShouldDropNUW))
     return nullptr;
 
+  if (ShouldDropNUW)
+    cast<Instruction>(CtlzOp)->setHasNoUnsignedWrap(false);
+
   // Build 1 << (-CTLZ & (BitWidth-1)).  The negation likely corresponds to a
   // single hardware instruction as opposed to BitWidth - CTLZ, where BitWidth
   // is an integer constant.  Masking with BitWidth-1 comes free on some


Regression tests:
file: llvm/test/Transforms/InstCombine/bit_ceil.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: pr91691
test_body: define i32 @pr91691(i32 %0) {
  %2 = sub nuw 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) }

test_name: bit_ceil_v4i32
test_body: define <4 x i32> @bit_ceil_v4i32(<4 x i32> %x) {
  %dec = add <4 x i32> %x, splat (i32 -1)
  %ctlz = tail call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %dec, i1 false)
  %sub = sub <4 x i32> splat (i32 32), %ctlz
  %shl = shl <4 x i32> splat (i32 1), %sub
  %ugt = icmp ugt <4 x i32> %x, splat (i32 1)
  %sel = select <4 x i1> %ugt, <4 x i32> %shl, <4 x i32> splat (i32 1)
  ret <4 x i32> %sel
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <4 x i32> @llvm.ctlz.v4i32(<4 x 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) }