[llvm] a809862 - [IR] Teach `drop/hasPoisonGeneratingAnnotations()` about `abs`, `ctlz` and `cttz` (#175941)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 14 16:02:02 PST 2026


Author: Nathan Corbyn
Date: 2026-01-15T00:01:58Z
New Revision: a8098629bce2decd4b52aebaf179cbc480603dd2

URL: https://github.com/llvm/llvm-project/commit/a8098629bce2decd4b52aebaf179cbc480603dd2
DIFF: https://github.com/llvm/llvm-project/commit/a8098629bce2decd4b52aebaf179cbc480603dd2.diff

LOG: [IR] Teach `drop/hasPoisonGeneratingAnnotations()` about `abs`, `ctlz` and `cttz` (#175941)

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/lib/IR/Instruction.cpp
    llvm/lib/IR/Operator.cpp
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ece8425aef698..171952120fc40 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7573,9 +7573,8 @@ static bool canCreateUndefOrPoison(const Operator *Op, UndefPoisonKind Kind,
       case Intrinsic::ctlz:
       case Intrinsic::cttz:
       case Intrinsic::abs:
-        if (cast<ConstantInt>(II->getArgOperand(1))->isNullValue())
-          return false;
-        break;
+        // We're not considering flags so it is safe to just return false.
+        return false;
       case Intrinsic::sshl_sat:
       case Intrinsic::ushl_sat:
         if (!includesPoison(Kind) ||

diff  --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 7682c28e23b33..3c35c656dca84 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -473,6 +473,19 @@ void Instruction::dropPoisonGeneratingFlags() {
   case Instruction::ICmp:
     cast<ICmpInst>(this)->setSameSign(false);
     break;
+
+  case Instruction::Call: {
+    if (auto *II = dyn_cast<IntrinsicInst>(this)) {
+      switch (II->getIntrinsicID()) {
+      case Intrinsic::ctlz:
+      case Intrinsic::cttz:
+      case Intrinsic::abs:
+        II->setOperand(1, ConstantInt::getFalse(getContext()));
+        break;
+      }
+    }
+    break;
+  }
   }
 
   if (isa<FPMathOperator>(this)) {

diff  --git a/llvm/lib/IR/Operator.cpp b/llvm/lib/IR/Operator.cpp
index c3e54a0fc0c7e..bd92a32142ebc 100644
--- a/llvm/lib/IR/Operator.cpp
+++ b/llvm/lib/IR/Operator.cpp
@@ -14,6 +14,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/GetElementPtrTypeIterator.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
 
 #include "ConstantsContext.h"
 
@@ -53,6 +54,16 @@ bool Operator::hasPoisonGeneratingFlags() const {
     return false;
   case Instruction::ICmp:
     return cast<ICmpInst>(this)->hasSameSign();
+  case Instruction::Call:
+    if (auto *II = dyn_cast<IntrinsicInst>(this)) {
+      switch (II->getIntrinsicID()) {
+      case Intrinsic::ctlz:
+      case Intrinsic::cttz:
+      case Intrinsic::abs:
+        return cast<ConstantInt>(II->getArgOperand(1))->isOneValue();
+      }
+    }
+    [[fallthrough]];
   default:
     if (const auto *FP = dyn_cast<FPMathOperator>(this))
       return FP->hasNoNaNs() || FP->hasNoInfs();

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 1f415ffa8eed2..d4604e05de688 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1396,9 +1396,6 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal,
   // sizeof in bits of 'Count'.
   unsigned SizeOfInBits = Count->getType()->getScalarSizeInBits();
   if (match(ValueOnZero, m_SpecificInt(SizeOfInBits))) {
-    // Explicitly clear the 'is_zero_poison' flag. It's always valid to go from
-    // true to false on this flag, so we can replace it for all users.
-    II->setArgOperand(1, ConstantInt::getFalse(II->getContext()));
     // A range annotation on the intrinsic may no longer be valid.
     II->dropPoisonGeneratingAnnotations();
     IC.addToWorklist(II);
@@ -3885,8 +3882,6 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder,
 
   // Drop range attributes and re-infer them in the next iteration.
   cast<Instruction>(Ctlz)->dropPoisonGeneratingAnnotations();
-  // Set is_zero_poison to false and re-infer them in the next iteration.
-  cast<Instruction>(Ctlz)->setOperand(1, Builder.getFalse());
   IC.addToWorklist(cast<Instruction>(Ctlz));
   Value *Neg = Builder.CreateNeg(Ctlz);
   Value *Masked =

diff  --git a/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll b/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll
index 3cab09c2876bf..fa464d80f3d2b 100644
--- a/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll
@@ -3,9 +3,9 @@
 
 define i32 @ctlz_true_freeze(i32 %arg) {
 ; CHECK-LABEL: @ctlz_true_freeze(
-; CHECK-NEXT:    [[CALL:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[ARG:%.*]], i1 true)
-; CHECK-NEXT:    [[FREEZE:%.*]] = freeze i32 [[CALL]]
-; CHECK-NEXT:    ret i32 [[FREEZE]]
+; CHECK-NEXT:    [[FREEZE:%.*]] = freeze i32 [[CALL:%.*]]
+; CHECK-NEXT:    [[CALL1:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[FREEZE]], i1 false)
+; CHECK-NEXT:    ret i32 [[CALL1]]
 ;
   %call = call i32 @llvm.ctlz.i32(i32 %arg, i1 true)
   %freeze = freeze i32 %call
@@ -35,9 +35,9 @@ define i32 @ctlz_true_noundef_freeze(i32 %arg) {
 
 define i32 @cttz_true_freeze(i32 %arg) {
 ; CHECK-LABEL: @cttz_true_freeze(
-; CHECK-NEXT:    [[CALL:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[ARG:%.*]], i1 true)
-; CHECK-NEXT:    [[FREEZE:%.*]] = freeze i32 [[CALL]]
-; CHECK-NEXT:    ret i32 [[FREEZE]]
+; CHECK-NEXT:    [[FREEZE:%.*]] = freeze i32 [[CALL:%.*]]
+; CHECK-NEXT:    [[CALL1:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[FREEZE]], i1 false)
+; CHECK-NEXT:    ret i32 [[CALL1]]
 ;
   %call = call i32 @llvm.cttz.i32(i32 %arg, i1 true)
   %freeze = freeze i32 %call
@@ -89,9 +89,9 @@ define i32 @freeze_cttz_false(i32 %arg) {
 
 define i32 @abs_true_i32(i32 %arg) {
 ; CHECK-LABEL: @abs_true_i32(
-; CHECK-NEXT:    [[CALL:%.*]] = call i32 @llvm.abs.i32(i32 [[ARG:%.*]], i1 true)
-; CHECK-NEXT:    [[FREEZE:%.*]] = freeze i32 [[CALL]]
-; CHECK-NEXT:    ret i32 [[FREEZE]]
+; CHECK-NEXT:    [[FREEZE:%.*]] = freeze i32 [[CALL:%.*]]
+; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @llvm.abs.i32(i32 [[FREEZE]], i1 false)
+; CHECK-NEXT:    ret i32 [[CALL1]]
 ;
   %call = call i32 @llvm.abs.i32(i32 %arg, i1 true)
   %freeze = freeze i32 %call


        


More information about the llvm-commits mailing list