[llvm] [InstCombine] Create new instructions instead of in-place operand replacement (PR #115988)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 28 09:02:14 PDT 2026


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/115988

>From 7c8f342eb4e8106851ba5b8bb59743c183503abb Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 13 Nov 2024 11:49:16 +0800
Subject: [PATCH 01/12] [InstCombine] Add pre-commit tests. NFC.

---
 llvm/test/Transforms/InstCombine/minmax-fold.ll | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll
index a982225370620..1dd4c5c56fcdf 100644
--- a/llvm/test/Transforms/InstCombine/minmax-fold.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll
@@ -1842,3 +1842,14 @@ define i32 @test_umin_or_neg1_nuw(i32 %x, i32 range(i32 1, 0) %w) {
   %r = select i1 %cmp, i32 %x, i32 %sub
   ret i32 %r
 }
+
+; Make sure that poison-generating/UB-implying parameters are swapped.
+
+define i32 @umax_commute_operand_drop_attrs(i32 %x) {
+; CHECK-LABEL: @umax_commute_operand_drop_attrs(
+; CHECK-NEXT:    [[RET:%.*]] = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 noundef range(i32 -10, -8) [[X:%.*]], i32 -10)
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+  %ret = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 noundef range(i32 -10, -8) -10, i32 %x)
+  ret i32 %ret
+}

>From 5ce8f2e729316824ab9d701d0ad794008c9b2181 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 13 Nov 2024 12:35:41 +0800
Subject: [PATCH 02/12] [InstCombine] Drop poison-generating/UB-implying param
 attrs after changing operands

---
 llvm/include/llvm/IR/InstrTypes.h             |   3 +
 .../Transforms/InstCombine/InstCombiner.h     |   8 ++
 llvm/lib/IR/Instructions.cpp                  |  11 ++
 .../InstCombine/InstCombineCalls.cpp          | 100 ++++++++----------
 .../Transforms/InstCombine/minmax-fold.ll     |   2 +-
 5 files changed, 70 insertions(+), 54 deletions(-)

diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 5f7df6a4eb6f8..41955adba789d 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -1803,6 +1803,9 @@ class CallBase : public Instruction {
            paramHasAttr(ArgNo, Attribute::DereferenceableOrNull);
   }
 
+  /// Drop parameter attributes that may cause this instruction to cause UB.
+  void dropPoisonGeneratingAndUBImplyingParamAttrs(unsigned ArgNo);
+
   /// Determine if there are is an inalloca argument. Only the last argument can
   /// have the inalloca attribute.
   bool hasInAllocaArgument() const {
diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 8f9c586066298..79ca12e80b2ef 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -451,6 +451,14 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
     return &I;
   }
 
+  /// Replace operand of a call-like instruction and add old operand to the
+  /// worklist. Also drop poison generating and UB implying parameter
+  /// attributes.
+  Instruction *replaceArgOperand(CallBase &I, unsigned OpNum, Value *V) {
+    I.dropPoisonGeneratingAndUBImplyingParamAttrs(OpNum);
+    return replaceOperand(I, OpNum, V);
+  }
+
   /// Replace use and add the previously used value to the worklist.
   void replaceUse(Use &U, Value *NewValue) {
     Value *OldOp = U;
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index faa046729aff6..0e8f1f1f3975c 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -16,6 +16,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/IR/AttributeMask.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constant.h"
@@ -330,6 +331,16 @@ unsigned CallBase::getNumSubclassExtraOperandsDynamic() const {
   return cast<CallBrInst>(this)->getNumIndirectDests() + 1;
 }
 
+void CallBase::dropPoisonGeneratingAndUBImplyingParamAttrs(unsigned ArgNo) {
+  AttributeMask AM = AttributeFuncs::getUBImplyingAttributes();
+  // TODO: Add a helper AttributeFuncs::getPoisonGeneratingAttributes
+  AM.addAttribute(Attribute::NoFPClass);
+  AM.addAttribute(Attribute::Range);
+  AM.addAttribute(Attribute::Alignment);
+  AM.addAttribute(Attribute::NonNull);
+  removeParamAttrs(ArgNo, AM);
+}
+
 bool CallBase::isIndirectCall() const {
   const Value *V = getCalledOperand();
   if (isa<Function>(V) || isa<Constant>(V))
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index ce9e4b836a56e..34991cfbb1a08 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -349,7 +349,7 @@ Instruction *InstCombinerImpl::simplifyMaskedStore(IntrinsicInst &II) {
   APInt PoisonElts(DemandedElts.getBitWidth(), 0);
   if (Value *V = SimplifyDemandedVectorElts(II.getOperand(0), DemandedElts,
                                             PoisonElts))
-    return replaceOperand(II, 0, V);
+    return replaceArgOperand(II, 0, V);
 
   return nullptr;
 }
@@ -432,10 +432,10 @@ Instruction *InstCombinerImpl::simplifyMaskedScatter(IntrinsicInst &II) {
   APInt PoisonElts(DemandedElts.getBitWidth(), 0);
   if (Value *V = SimplifyDemandedVectorElts(II.getOperand(0), DemandedElts,
                                             PoisonElts))
-    return replaceOperand(II, 0, V);
+    return replaceArgOperand(II, 0, V);
   if (Value *V = SimplifyDemandedVectorElts(II.getOperand(1), DemandedElts,
                                             PoisonElts))
-    return replaceOperand(II, 1, V);
+    return replaceArgOperand(II, 1, V);
 
   return nullptr;
 }
@@ -517,11 +517,11 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
   if (IsTZ) {
     // cttz(-x) -> cttz(x)
     if (match(Op0, m_Neg(m_Value(X))))
-      return IC.replaceOperand(II, 0, X);
+      return IC.replaceArgOperand(II, 0, X);
 
     // cttz(-x & x) -> cttz(x)
     if (match(Op0, m_c_And(m_Neg(m_Value(X)), m_Deferred(X))))
-      return IC.replaceOperand(II, 0, X);
+      return IC.replaceArgOperand(II, 0, X);
 
     // cttz(sext(x)) -> cttz(zext(x))
     if (match(Op0, m_OneUse(m_SExt(m_Value(X))))) {
@@ -545,10 +545,10 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
     Value *Y;
     SelectPatternFlavor SPF = matchSelectPattern(Op0, X, Y).Flavor;
     if (SPF == SPF_ABS || SPF == SPF_NABS)
-      return IC.replaceOperand(II, 0, X);
+      return IC.replaceArgOperand(II, 0, X);
 
     if (match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X))))
-      return IC.replaceOperand(II, 0, X);
+      return IC.replaceArgOperand(II, 0, X);
 
     // cttz(shl(%const, %val), 1) --> add(cttz(%const, 1), %val)
     if (match(Op0, m_Shl(m_ImmConstant(C), m_Value(X))) &&
@@ -665,13 +665,13 @@ static Instruction *foldCtpop(IntrinsicInst &II, InstCombinerImpl &IC) {
   // ctpop(bitreverse(x)) -> ctpop(x)
   // ctpop(bswap(x)) -> ctpop(x)
   if (match(Op0, m_BitReverse(m_Value(X))) || match(Op0, m_BSwap(m_Value(X))))
-    return IC.replaceOperand(II, 0, X);
+    return IC.replaceArgOperand(II, 0, X);
 
   // ctpop(rot(x)) -> ctpop(x)
   if ((match(Op0, m_FShl(m_Value(X), m_Value(Y), m_Value())) ||
        match(Op0, m_FShr(m_Value(X), m_Value(Y), m_Value()))) &&
       X == Y)
-    return IC.replaceOperand(II, 0, X);
+    return IC.replaceArgOperand(II, 0, X);
 
   // ctpop(x | -x) -> bitwidth - cttz(x, false)
   if (Op0->hasOneUse() &&
@@ -923,6 +923,8 @@ static CallInst *canonicalizeConstantArg0ToArg1(CallInst &Call) {
   if (isa<Constant>(Arg0) && !isa<Constant>(Arg1)) {
     Call.setArgOperand(0, Arg1);
     Call.setArgOperand(1, Arg0);
+    Call.dropPoisonGeneratingAndUBImplyingParamAttrs(0);
+    Call.dropPoisonGeneratingAndUBImplyingParamAttrs(1);
     return &Call;
   }
   return nullptr;
@@ -1067,13 +1069,13 @@ Instruction *InstCombinerImpl::foldIntrinsicIsFPClass(IntrinsicInst &II) {
     // is.fpclass (fneg x), mask -> is.fpclass x, (fneg mask)
 
     II.setArgOperand(1, ConstantInt::get(Src1->getType(), fneg(Mask)));
-    return replaceOperand(II, 0, FNegSrc);
+    return replaceArgOperand(II, 0, FNegSrc);
   }
 
   Value *FAbsSrc;
   if (match(Src0, m_FAbs(m_Value(FAbsSrc)))) {
     II.setArgOperand(1, ConstantInt::get(Src1->getType(), inverse_fabs(Mask)));
-    return replaceOperand(II, 0, FAbsSrc);
+    return replaceArgOperand(II, 0, FAbsSrc);
   }
 
   if ((OrderedMask == fcInf || OrderedInvertedMask == fcInf) &&
@@ -2023,8 +2025,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
   if (II->isCommutative()) {
     if (auto Pair = matchSymmetricPair(II->getOperand(0), II->getOperand(1))) {
-      replaceOperand(*II, 0, Pair->first);
-      replaceOperand(*II, 1, Pair->second);
+      replaceArgOperand(*II, 0, Pair->first);
+      replaceArgOperand(*II, 1, Pair->second);
       return II;
     }
 
@@ -2062,10 +2064,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (match(IIOperand, m_Neg(m_Value(X)))) {
       if (cast<Instruction>(IIOperand)->hasNoSignedWrap() || IntMinIsPoison)
         replaceOperand(*II, 1, Builder.getTrue());
-      return replaceOperand(*II, 0, X);
+      return replaceArgOperand(*II, 0, X);
     }
     if (match(IIOperand, m_c_Select(m_Neg(m_Value(X)), m_Deferred(X))))
-      return replaceOperand(*II, 0, X);
+      return replaceArgOperand(*II, 0, X);
 
     Value *Y;
     // abs(a * abs(b)) -> abs(a * b)
@@ -2075,7 +2077,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       bool NSW =
           cast<Instruction>(IIOperand)->hasNoSignedWrap() && IntMinIsPoison;
       auto *XY = NSW ? Builder.CreateNSWMul(X, Y) : Builder.CreateMul(X, Y);
-      return replaceOperand(*II, 0, XY);
+      return replaceArgOperand(*II, 0, XY);
     }
 
     if (std::optional<bool> Known =
@@ -2517,7 +2519,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
             match(II->getArgOperand(0), m_FAbs(m_Value(X))) ||
             match(II->getArgOperand(0),
                   m_Intrinsic<Intrinsic::copysign>(m_Value(X), m_Value())))
-          return replaceOperand(*II, 0, X);
+          return replaceArgOperand(*II, 0, X);
       }
     }
     if (ConstantFP *Base = dyn_cast<ConstantFP>(II->getArgOperand(0))) {
@@ -2560,7 +2562,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       if (!ModuloC)
         return nullptr;
       if (ModuloC != ShAmtC)
-        return replaceOperand(*II, 2, ModuloC);
+        return replaceArgOperand(*II, 2, ModuloC);
 
       assert(match(ConstantFoldCompareInstOperands(ICmpInst::ICMP_UGT, WidthC,
                                                    ShAmtC, DL),
@@ -2713,8 +2715,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       // TODO: If InnerMask == Op1, we could copy attributes from inner
       // callsite -> outer callsite.
       Value *NewMask = Builder.CreateAnd(II->getArgOperand(1), InnerMask);
-      replaceOperand(CI, 0, InnerPtr);
-      replaceOperand(CI, 1, NewMask);
+      replaceArgOperand(CI, 0, InnerPtr);
+      replaceArgOperand(CI, 1, NewMask);
       Changed = true;
     }
 
@@ -3026,8 +3028,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     Value *A, *B;
     if (match(II->getArgOperand(0), m_FNeg(m_Value(A))) &&
         match(II->getArgOperand(1), m_FNeg(m_Value(B)))) {
-      replaceOperand(*II, 0, A);
-      replaceOperand(*II, 1, B);
+      replaceArgOperand(*II, 0, A);
+      replaceArgOperand(*II, 1, B);
       return II;
     }
 
@@ -3062,8 +3064,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (ElementCount::isKnownGT(NegatedCount, OtherCount) &&
         ElementCount::isKnownLT(OtherCount, RetCount)) {
       Value *InverseOtherOp = Builder.CreateFNeg(OtherOp);
-      replaceOperand(*II, NegatedOpArg, OpNotNeg);
-      replaceOperand(*II, OtherOpArg, InverseOtherOp);
+      replaceArgOperand(*II, NegatedOpArg, OpNotNeg);
+      replaceArgOperand(*II, OtherOpArg, InverseOtherOp);
       return II;
     }
     // (-A) * B -> -(A * B), if it is cheaper to negate the result
@@ -3092,16 +3094,16 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     Value *Src2 = II->getArgOperand(2);
     Value *X, *Y;
     if (match(Src0, m_FNeg(m_Value(X))) && match(Src1, m_FNeg(m_Value(Y)))) {
-      replaceOperand(*II, 0, X);
-      replaceOperand(*II, 1, Y);
+      replaceArgOperand(*II, 0, X);
+      replaceArgOperand(*II, 1, Y);
       return II;
     }
 
     // fma fabs(x), fabs(x), z -> fma x, x, z
     if (match(Src0, m_FAbs(m_Value(X))) &&
         match(Src1, m_FAbs(m_Specific(X)))) {
-      replaceOperand(*II, 0, X);
-      replaceOperand(*II, 1, X);
+      replaceArgOperand(*II, 0, X);
+      replaceArgOperand(*II, 1, X);
       return II;
     }
 
@@ -3157,14 +3159,15 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (match(Mag, m_APFloat(MagC)) && MagC->isNegative()) {
       APFloat PosMagC = *MagC;
       PosMagC.clearSign();
-      return replaceOperand(*II, 0, ConstantFP::get(Mag->getType(), PosMagC));
+      return replaceArgOperand(*II, 0,
+                               ConstantFP::get(Mag->getType(), PosMagC));
     }
 
     // Peek through changes of magnitude's sign-bit. This call rewrites those:
     // copysign (fabs X), Sign --> copysign X, Sign
     // copysign (fneg X), Sign --> copysign X, Sign
     if (match(Mag, m_FAbs(m_Value(X))) || match(Mag, m_FNeg(m_Value(X))))
-      return replaceOperand(*II, 0, X);
+      return replaceArgOperand(*II, 0, X);
 
     // copysign(floor(fabs(X)), X) --> copysign(trunc(X), X)
     // copysign ignores the sign bit of its magnitude argument (implicit fabs),
@@ -3220,10 +3223,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       }
       // fabs (select Cond, -FVal, FVal) --> fabs FVal
       if (match(TVal, m_FNeg(m_Specific(FVal))))
-        return replaceOperand(*II, 0, FVal);
+        return replaceArgOperand(*II, 0, FVal);
       // fabs (select Cond, TVal, -TVal) --> fabs TVal
       if (match(FVal, m_FNeg(m_Specific(TVal))))
-        return replaceOperand(*II, 0, TVal);
+        return replaceArgOperand(*II, 0, TVal);
     }
 
     Value *Magnitude, *Sign;
@@ -3262,7 +3265,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       // f(fabs(x)) --> f(x)
       // f(copysign(x, y)) --> f(x)
       // for f in {cos, cosh}
-      return replaceOperand(*II, 0, X);
+      return replaceArgOperand(*II, 0, X);
     }
     break;
   }
@@ -3328,8 +3331,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         Value *NewExp =
             Builder.CreateBinaryIntrinsic(Intrinsic::sadd_sat, InnerExp, Exp);
         II->setArgOperand(1, NewExp);
+        II->dropPoisonGeneratingAndUBImplyingParamAttrs(1);
         II->setFastMathFlags(InnerFlags); // Or the inner flags.
-        return replaceOperand(*II, 0, InnerSrc);
+        return replaceArgOperand(*II, 0, InnerSrc);
       }
     }
 
@@ -4098,11 +4102,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     Value *Arg = II->getArgOperand(0);
     Value *Vect;
 
-    if (Value *NewOp =
-            simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-      replaceUse(II->getOperandUse(0), NewOp);
-      return II;
-    }
+    if (Value *NewOp = simplifyReductionOperand(Arg, /*CanReorderLanes=*/true))
+      return replaceArgOperand(*II, 0, NewOp);
 
     if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
       if (auto *FTy = dyn_cast<FixedVectorType>(Vect->getType()))
@@ -4138,8 +4139,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        replaceUse(II->getOperandUse(0), NewOp);
-        return II;
+        return replaceArgOperand(*II, 0, NewOp);
       }
 
       // vector.reduce.add.vNiM(splat(%x)) -> mul(%x, N)
@@ -4184,10 +4184,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       Value *Vect;
 
       if (Value *NewOp =
-              simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        replaceUse(II->getOperandUse(0), NewOp);
-        return II;
-      }
+              simplifyReductionOperand(Arg, /*CanReorderLanes=*/true))
+        return replaceArgOperand(*II, 0, NewOp);
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
         if (auto *VTy = dyn_cast<VectorType>(Vect->getType()))
@@ -4208,8 +4206,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        replaceUse(II->getOperandUse(0), NewOp);
-        return II;
+        return replaceArgOperand(*II, 0, NewOp);
       }
 
       // vector_reduce_mul(zext(<n x i1>)), or
@@ -4250,8 +4247,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        replaceUse(II->getOperandUse(0), NewOp);
-        return II;
+        return replaceArgOperand(*II, 0, NewOp);
       }
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
@@ -4292,8 +4288,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        replaceUse(II->getOperandUse(0), NewOp);
-        return II;
+        return replaceArgOperand(*II, 0, NewOp);
       }
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
@@ -4327,8 +4322,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
                                 : 0;
     Value *Arg = II->getArgOperand(ArgIdx);
     if (Value *NewOp = simplifyReductionOperand(Arg, CanReorderLanes)) {
-      replaceUse(II->getOperandUse(ArgIdx), NewOp);
-      return nullptr;
+      return replaceArgOperand(*II, ArgIdx, NewOp);
     }
     break;
   }
diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll
index 1dd4c5c56fcdf..2cfa0296890ca 100644
--- a/llvm/test/Transforms/InstCombine/minmax-fold.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll
@@ -1847,7 +1847,7 @@ define i32 @test_umin_or_neg1_nuw(i32 %x, i32 range(i32 1, 0) %w) {
 
 define i32 @umax_commute_operand_drop_attrs(i32 %x) {
 ; CHECK-LABEL: @umax_commute_operand_drop_attrs(
-; CHECK-NEXT:    [[RET:%.*]] = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 noundef range(i32 -10, -8) [[X:%.*]], i32 -10)
+; CHECK-NEXT:    [[RET:%.*]] = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 [[X:%.*]], i32 -10)
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %ret = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 noundef range(i32 -10, -8) -10, i32 %x)

>From bc201b5e5cc18b8747b80391bbe26d69b4f3e00b Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 15 Nov 2024 11:35:34 +0800
Subject: [PATCH 03/12] [InstCombine] Swap parameter attributes in
 `canonicalizeConstantArg0ToArg1`

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 11 +++++++++--
 llvm/test/Transforms/InstCombine/minmax-fold.ll      |  2 +-
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 34991cfbb1a08..2f758abceb5cc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -923,8 +923,15 @@ static CallInst *canonicalizeConstantArg0ToArg1(CallInst &Call) {
   if (isa<Constant>(Arg0) && !isa<Constant>(Arg1)) {
     Call.setArgOperand(0, Arg1);
     Call.setArgOperand(1, Arg0);
-    Call.dropPoisonGeneratingAndUBImplyingParamAttrs(0);
-    Call.dropPoisonGeneratingAndUBImplyingParamAttrs(1);
+    auto CallAttr = Call.getAttributes();
+    auto LHSAttr = CallAttr.getParamAttrs(0);
+    auto RHSAttr = CallAttr.getParamAttrs(1);
+    LLVMContext &Ctx = Call.getContext();
+    Call.setAttributes(
+        CallAttr.removeAttributesAtIndex(Ctx, 0)
+            .removeAttributesAtIndex(Ctx, 1)
+            .addParamAttributes(Ctx, 0, AttrBuilder(Ctx, RHSAttr))
+            .addParamAttributes(Ctx, 1, AttrBuilder(Ctx, LHSAttr)));
     return &Call;
   }
   return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll
index 2cfa0296890ca..049d3153ff51c 100644
--- a/llvm/test/Transforms/InstCombine/minmax-fold.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll
@@ -1847,7 +1847,7 @@ define i32 @test_umin_or_neg1_nuw(i32 %x, i32 range(i32 1, 0) %w) {
 
 define i32 @umax_commute_operand_drop_attrs(i32 %x) {
 ; CHECK-LABEL: @umax_commute_operand_drop_attrs(
-; CHECK-NEXT:    [[RET:%.*]] = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 [[X:%.*]], i32 -10)
+; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 noundef range(i32 -10, -8) -10)
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %ret = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 noundef range(i32 -10, -8) -10, i32 %x)

>From d86d4cc571ce4c6b5d46586fea2dc7ea57a4c843 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 15 Nov 2024 11:42:20 +0800
Subject: [PATCH 04/12] [InstCombine] Add more tests. NFC.

---
 llvm/test/Transforms/InstCombine/abs-intrinsic.ll | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
index 96dfbe4730d0e..f93d0b366ef11 100644
--- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
@@ -227,6 +227,16 @@ define i32 @abs_of_neg(i32 %x) {
   ret i32 %b
 }
 
+define i32 @abs_of_neg_range(i32 %x) {
+; CHECK-LABEL: @abs_of_neg_range(
+; CHECK-NEXT:    [[B:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
+; CHECK-NEXT:    ret i32 [[B]]
+;
+  %a = sub i32 0, %x
+  %b = call i32 @llvm.abs.i32(i32 range(i32 -10, 0) %a, i1 false)
+  ret i32 %b
+}
+
 define <4 x i32> @abs_of_neg_vec(<4 x i32> %x) {
 ; CHECK-LABEL: @abs_of_neg_vec(
 ; CHECK-NEXT:    [[B:%.*]] = call <4 x i32> @llvm.abs.v4i32(<4 x i32> [[X:%.*]], i1 true)

>From 8eac0bc37d3f4143f6a635336a8b45462a0dfa7c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 28 Jun 2026 16:56:13 +0800
Subject: [PATCH 05/12] [InstCombine] Fix regression.

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 2f758abceb5cc..57fdc3f305fc0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -349,7 +349,7 @@ Instruction *InstCombinerImpl::simplifyMaskedStore(IntrinsicInst &II) {
   APInt PoisonElts(DemandedElts.getBitWidth(), 0);
   if (Value *V = SimplifyDemandedVectorElts(II.getOperand(0), DemandedElts,
                                             PoisonElts))
-    return replaceArgOperand(II, 0, V);
+    return replaceOperand(II, 0, V);
 
   return nullptr;
 }
@@ -432,10 +432,10 @@ Instruction *InstCombinerImpl::simplifyMaskedScatter(IntrinsicInst &II) {
   APInt PoisonElts(DemandedElts.getBitWidth(), 0);
   if (Value *V = SimplifyDemandedVectorElts(II.getOperand(0), DemandedElts,
                                             PoisonElts))
-    return replaceArgOperand(II, 0, V);
+    return replaceOperand(II, 0, V);
   if (Value *V = SimplifyDemandedVectorElts(II.getOperand(1), DemandedElts,
                                             PoisonElts))
-    return replaceArgOperand(II, 1, V);
+    return replaceOperand(II, 1, V);
 
   return nullptr;
 }

>From 6367a416c8c412319ac2f457201c3d8e5f443f97 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 28 Jun 2026 19:58:07 +0800
Subject: [PATCH 06/12] [InstCombine] Avoid in-place modification

---
 llvm/include/llvm/IR/InstrTypes.h             |   3 -
 .../Transforms/InstCombine/InstCombiner.h     |   8 --
 llvm/lib/IR/Instructions.cpp                  |  10 --
 .../InstCombine/InstCombineCalls.cpp          | 132 +++++++++---------
 llvm/test/Transforms/InstCombine/bit_ceil.ll  |   2 +-
 .../InstCombine/ctpop-bswap-bitreverse.ll     |   8 +-
 llvm/test/Transforms/InstCombine/ctpop.ll     |   4 +-
 llvm/test/Transforms/InstCombine/cttz-abs.ll  |  14 +-
 .../Transforms/InstCombine/cttz-negative.ll   |   4 +-
 .../InstCombine/hyperbolic-functions.ll       |   2 +-
 .../test/Transforms/InstCombine/intrinsics.ll |  16 +--
 .../test/Transforms/InstCombine/is_fpclass.ll |   6 +-
 llvm/test/Transforms/InstCombine/powi.ll      |   6 +-
 13 files changed, 96 insertions(+), 119 deletions(-)

diff --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 41955adba789d..5f7df6a4eb6f8 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -1803,9 +1803,6 @@ class CallBase : public Instruction {
            paramHasAttr(ArgNo, Attribute::DereferenceableOrNull);
   }
 
-  /// Drop parameter attributes that may cause this instruction to cause UB.
-  void dropPoisonGeneratingAndUBImplyingParamAttrs(unsigned ArgNo);
-
   /// Determine if there are is an inalloca argument. Only the last argument can
   /// have the inalloca attribute.
   bool hasInAllocaArgument() const {
diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 79ca12e80b2ef..8f9c586066298 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -451,14 +451,6 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
     return &I;
   }
 
-  /// Replace operand of a call-like instruction and add old operand to the
-  /// worklist. Also drop poison generating and UB implying parameter
-  /// attributes.
-  Instruction *replaceArgOperand(CallBase &I, unsigned OpNum, Value *V) {
-    I.dropPoisonGeneratingAndUBImplyingParamAttrs(OpNum);
-    return replaceOperand(I, OpNum, V);
-  }
-
   /// Replace use and add the previously used value to the worklist.
   void replaceUse(Use &U, Value *NewValue) {
     Value *OldOp = U;
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 0e8f1f1f3975c..413abb9a39e62 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -331,16 +331,6 @@ unsigned CallBase::getNumSubclassExtraOperandsDynamic() const {
   return cast<CallBrInst>(this)->getNumIndirectDests() + 1;
 }
 
-void CallBase::dropPoisonGeneratingAndUBImplyingParamAttrs(unsigned ArgNo) {
-  AttributeMask AM = AttributeFuncs::getUBImplyingAttributes();
-  // TODO: Add a helper AttributeFuncs::getPoisonGeneratingAttributes
-  AM.addAttribute(Attribute::NoFPClass);
-  AM.addAttribute(Attribute::Range);
-  AM.addAttribute(Attribute::Alignment);
-  AM.addAttribute(Attribute::NonNull);
-  removeParamAttrs(ArgNo, AM);
-}
-
 bool CallBase::isIndirectCall() const {
   const Value *V = getCalledOperand();
   if (isa<Function>(V) || isa<Constant>(V))
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 57fdc3f305fc0..9dc2ab187e5e4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -507,21 +507,20 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
 
   // If ctlz/cttz is only used as a shift amount, set is_zero_poison to true.
   if (II.hasOneUse() && match(Op1, m_Zero()) &&
-      match(II.user_back(), m_Shift(m_Value(), m_Specific(&II)))) {
-    II.dropUBImplyingAttrsAndMetadata();
-    return IC.replaceOperand(II, 1, IC.Builder.getTrue());
-  }
+      match(II.user_back(), m_Shift(m_Value(), m_Specific(&II))))
+    return CallInst::Create(II.getCalledFunction(),
+                            {Op0, IC.Builder.getTrue()});
 
   Constant *C;
 
   if (IsTZ) {
     // cttz(-x) -> cttz(x)
     if (match(Op0, m_Neg(m_Value(X))))
-      return IC.replaceArgOperand(II, 0, X);
+      return CallInst::Create(II.getCalledFunction(), {X, Op1});
 
     // cttz(-x & x) -> cttz(x)
     if (match(Op0, m_c_And(m_Neg(m_Value(X)), m_Deferred(X))))
-      return IC.replaceArgOperand(II, 0, X);
+      return CallInst::Create(II.getCalledFunction(), {X, Op1});
 
     // cttz(sext(x)) -> cttz(zext(x))
     if (match(Op0, m_OneUse(m_SExt(m_Value(X))))) {
@@ -545,10 +544,10 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
     Value *Y;
     SelectPatternFlavor SPF = matchSelectPattern(Op0, X, Y).Flavor;
     if (SPF == SPF_ABS || SPF == SPF_NABS)
-      return IC.replaceArgOperand(II, 0, X);
+      return CallInst::Create(II.getCalledFunction(), {X, Op1});
 
     if (match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X))))
-      return IC.replaceArgOperand(II, 0, X);
+      return CallInst::Create(II.getCalledFunction(), {X, Op1});
 
     // cttz(shl(%const, %val), 1) --> add(cttz(%const, 1), %val)
     if (match(Op0, m_Shl(m_ImmConstant(C), m_Value(X))) &&
@@ -638,7 +637,8 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
   if (!Known.One.isZero() ||
       isKnownNonZero(Op0, IC.getSimplifyQuery().getWithInstruction(&II))) {
     if (!match(II.getArgOperand(1), m_One()))
-      return IC.replaceOperand(II, 1, IC.Builder.getTrue());
+      return CallInst::Create(II.getCalledFunction(),
+                              {Op0, IC.Builder.getTrue()});
   }
 
   // Add range attribute since known bits can't completely reflect what we know.
@@ -665,13 +665,13 @@ static Instruction *foldCtpop(IntrinsicInst &II, InstCombinerImpl &IC) {
   // ctpop(bitreverse(x)) -> ctpop(x)
   // ctpop(bswap(x)) -> ctpop(x)
   if (match(Op0, m_BitReverse(m_Value(X))) || match(Op0, m_BSwap(m_Value(X))))
-    return IC.replaceArgOperand(II, 0, X);
+    return CallInst::Create(II.getCalledFunction(), X);
 
   // ctpop(rot(x)) -> ctpop(x)
   if ((match(Op0, m_FShl(m_Value(X), m_Value(Y), m_Value())) ||
        match(Op0, m_FShr(m_Value(X), m_Value(Y), m_Value()))) &&
       X == Y)
-    return IC.replaceArgOperand(II, 0, X);
+    return CallInst::Create(II.getCalledFunction(), X);
 
   // ctpop(x | -x) -> bitwidth - cttz(x, false)
   if (Op0->hasOneUse() &&
@@ -1072,18 +1072,17 @@ Instruction *InstCombinerImpl::foldIntrinsicIsFPClass(IntrinsicInst &II) {
       II.getFunction()->getAttributes().hasFnAttr(Attribute::StrictFP);
 
   Value *FNegSrc;
-  if (match(Src0, m_FNeg(m_Value(FNegSrc)))) {
-    // is.fpclass (fneg x), mask -> is.fpclass x, (fneg mask)
-
-    II.setArgOperand(1, ConstantInt::get(Src1->getType(), fneg(Mask)));
-    return replaceArgOperand(II, 0, FNegSrc);
-  }
+  // is.fpclass (fneg x), mask -> is.fpclass x, (fneg mask)
+  if (match(Src0, m_FNeg(m_Value(FNegSrc))))
+    return CallInst::Create(
+        II.getCalledFunction(),
+        {FNegSrc, ConstantInt::get(Src1->getType(), fneg(Mask))});
 
   Value *FAbsSrc;
-  if (match(Src0, m_FAbs(m_Value(FAbsSrc)))) {
-    II.setArgOperand(1, ConstantInt::get(Src1->getType(), inverse_fabs(Mask)));
-    return replaceArgOperand(II, 0, FAbsSrc);
-  }
+  if (match(Src0, m_FAbs(m_Value(FAbsSrc))))
+    return CallInst::Create(
+        II.getCalledFunction(),
+        {FAbsSrc, ConstantInt::get(Src1->getType(), inverse_fabs(Mask))});
 
   if ((OrderedMask == fcInf || OrderedInvertedMask == fcInf) &&
       (IsOrdered || IsUnordered) && !IsStrict) {
@@ -2032,8 +2031,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
   if (II->isCommutative()) {
     if (auto Pair = matchSymmetricPair(II->getOperand(0), II->getOperand(1))) {
-      replaceArgOperand(*II, 0, Pair->first);
-      replaceArgOperand(*II, 1, Pair->second);
+      replaceOperand(*II, 0, Pair->first);
+      replaceOperand(*II, 1, Pair->second);
+      II->dropPoisonGeneratingAnnotations();
       return II;
     }
 
@@ -2068,13 +2068,16 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
     // abs(-x) -> abs(x)
     Value *X;
-    if (match(IIOperand, m_Neg(m_Value(X)))) {
-      if (cast<Instruction>(IIOperand)->hasNoSignedWrap() || IntMinIsPoison)
-        replaceOperand(*II, 1, Builder.getTrue());
-      return replaceArgOperand(*II, 0, X);
-    }
+    if (match(IIOperand, m_Neg(m_Value(X))))
+      return CallInst::Create(
+          II->getCalledFunction(),
+          {X,
+           Builder.getInt1(IntMinIsPoison ||
+                           cast<Instruction>(IIOperand)->hasNoSignedWrap())});
+
     if (match(IIOperand, m_c_Select(m_Neg(m_Value(X)), m_Deferred(X))))
-      return replaceArgOperand(*II, 0, X);
+      return CallInst::Create(II->getCalledFunction(),
+                              {X, II->getArgOperand(1)});
 
     Value *Y;
     // abs(a * abs(b)) -> abs(a * b)
@@ -2084,7 +2087,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       bool NSW =
           cast<Instruction>(IIOperand)->hasNoSignedWrap() && IntMinIsPoison;
       auto *XY = NSW ? Builder.CreateNSWMul(X, Y) : Builder.CreateMul(X, Y);
-      return replaceArgOperand(*II, 0, XY);
+      return CallInst::Create(II->getCalledFunction(),
+                              {XY, II->getArgOperand(1)});
     }
 
     if (std::optional<bool> Known =
@@ -2526,7 +2530,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
             match(II->getArgOperand(0), m_FAbs(m_Value(X))) ||
             match(II->getArgOperand(0),
                   m_Intrinsic<Intrinsic::copysign>(m_Value(X), m_Value())))
-          return replaceArgOperand(*II, 0, X);
+          return CallInst::Create(II->getCalledFunction(), {X, Power});
       }
     }
     if (ConstantFP *Base = dyn_cast<ConstantFP>(II->getArgOperand(0))) {
@@ -2569,7 +2573,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       if (!ModuloC)
         return nullptr;
       if (ModuloC != ShAmtC)
-        return replaceArgOperand(*II, 2, ModuloC);
+        return CallInst::Create(II->getCalledFunction(), {Op0, Op1, ModuloC});
 
       assert(match(ConstantFoldCompareInstOperands(ICmpInst::ICMP_UGT, WidthC,
                                                    ShAmtC, DL),
@@ -2722,8 +2726,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       // TODO: If InnerMask == Op1, we could copy attributes from inner
       // callsite -> outer callsite.
       Value *NewMask = Builder.CreateAnd(II->getArgOperand(1), InnerMask);
-      replaceArgOperand(CI, 0, InnerPtr);
-      replaceArgOperand(CI, 1, NewMask);
+      replaceOperand(CI, 0, InnerPtr);
+      replaceOperand(CI, 1, NewMask);
       Changed = true;
     }
 
@@ -3035,8 +3039,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     Value *A, *B;
     if (match(II->getArgOperand(0), m_FNeg(m_Value(A))) &&
         match(II->getArgOperand(1), m_FNeg(m_Value(B)))) {
-      replaceArgOperand(*II, 0, A);
-      replaceArgOperand(*II, 1, B);
+      replaceOperand(*II, 0, A);
+      replaceOperand(*II, 1, B);
       return II;
     }
 
@@ -3071,8 +3075,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (ElementCount::isKnownGT(NegatedCount, OtherCount) &&
         ElementCount::isKnownLT(OtherCount, RetCount)) {
       Value *InverseOtherOp = Builder.CreateFNeg(OtherOp);
-      replaceArgOperand(*II, NegatedOpArg, OpNotNeg);
-      replaceArgOperand(*II, OtherOpArg, InverseOtherOp);
+      replaceOperand(*II, NegatedOpArg, OpNotNeg);
+      replaceOperand(*II, OtherOpArg, InverseOtherOp);
       return II;
     }
     // (-A) * B -> -(A * B), if it is cheaper to negate the result
@@ -3100,19 +3104,14 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     Value *Src1 = II->getArgOperand(1);
     Value *Src2 = II->getArgOperand(2);
     Value *X, *Y;
-    if (match(Src0, m_FNeg(m_Value(X))) && match(Src1, m_FNeg(m_Value(Y)))) {
-      replaceArgOperand(*II, 0, X);
-      replaceArgOperand(*II, 1, Y);
-      return II;
-    }
+    if (match(Src0, m_FNeg(m_Value(X))) && match(Src1, m_FNeg(m_Value(Y))))
+      return replaceInstUsesWith(
+          *II, Builder.CreateIntrinsic(IID, II->getType(), {X, Y, Src2}, II));
 
     // fma fabs(x), fabs(x), z -> fma x, x, z
-    if (match(Src0, m_FAbs(m_Value(X))) &&
-        match(Src1, m_FAbs(m_Specific(X)))) {
-      replaceArgOperand(*II, 0, X);
-      replaceArgOperand(*II, 1, X);
-      return II;
-    }
+    if (match(Src0, m_FAbs(m_Value(X))) && match(Src1, m_FAbs(m_Specific(X))))
+      return replaceInstUsesWith(
+          *II, Builder.CreateIntrinsic(IID, II->getType(), {X, X, Src2}, II));
 
     // Try to simplify the underlying FMul. We can only apply simplifications
     // that do not require rounding.
@@ -3166,15 +3165,16 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (match(Mag, m_APFloat(MagC)) && MagC->isNegative()) {
       APFloat PosMagC = *MagC;
       PosMagC.clearSign();
-      return replaceArgOperand(*II, 0,
-                               ConstantFP::get(Mag->getType(), PosMagC));
+      return replaceInstUsesWith(
+          *II, Builder.CreateCopySign(ConstantFP::get(Mag->getType(), PosMagC),
+                                      Sign, II));
     }
 
     // Peek through changes of magnitude's sign-bit. This call rewrites those:
     // copysign (fabs X), Sign --> copysign X, Sign
     // copysign (fneg X), Sign --> copysign X, Sign
     if (match(Mag, m_FAbs(m_Value(X))) || match(Mag, m_FNeg(m_Value(X))))
-      return replaceArgOperand(*II, 0, X);
+      return replaceInstUsesWith(*II, Builder.CreateCopySign(X, Sign, II));
 
     // copysign(floor(fabs(X)), X) --> copysign(trunc(X), X)
     // copysign ignores the sign bit of its magnitude argument (implicit fabs),
@@ -3185,7 +3185,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     if (match(Mag, m_Intrinsic<Intrinsic::floor>(m_FAbs(m_Value(FAbsArg)))) &&
         FAbsArg == Sign) {
       Value *Trunc = Builder.CreateUnaryIntrinsic(Intrinsic::trunc, Sign, II);
-      return replaceOperand(*II, 0, Trunc);
+      return replaceInstUsesWith(*II, Builder.CreateCopySign(Trunc, Sign, II));
     }
 
     Type *SignEltTy = Sign->getType()->getScalarType();
@@ -3230,10 +3230,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       }
       // fabs (select Cond, -FVal, FVal) --> fabs FVal
       if (match(TVal, m_FNeg(m_Specific(FVal))))
-        return replaceArgOperand(*II, 0, FVal);
+        return replaceInstUsesWith(*II, Builder.CreateFAbs(FVal, II));
       // fabs (select Cond, TVal, -TVal) --> fabs TVal
       if (match(FVal, m_FNeg(m_Specific(TVal))))
-        return replaceArgOperand(*II, 0, TVal);
+        return replaceInstUsesWith(*II, Builder.CreateFAbs(TVal, II));
     }
 
     Value *Magnitude, *Sign;
@@ -3272,7 +3272,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       // f(fabs(x)) --> f(x)
       // f(copysign(x, y)) --> f(x)
       // for f in {cos, cosh}
-      return replaceArgOperand(*II, 0, X);
+      return replaceInstUsesWith(*II, Builder.CreateUnaryIntrinsic(IID, X, II));
     }
     break;
   }
@@ -3337,10 +3337,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
            signBitMustBeTheSame(Exp, InnerExp, SQ.getWithInstruction(II)))) {
         Value *NewExp =
             Builder.CreateBinaryIntrinsic(Intrinsic::sadd_sat, InnerExp, Exp);
-        II->setArgOperand(1, NewExp);
-        II->dropPoisonGeneratingAndUBImplyingParamAttrs(1);
-        II->setFastMathFlags(InnerFlags); // Or the inner flags.
-        return replaceArgOperand(*II, 0, InnerSrc);
+        return replaceInstUsesWith(
+            *II, Builder.CreateLdexp(InnerSrc, NewExp, FMF | InnerFlags));
       }
     }
 
@@ -4110,7 +4108,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     Value *Vect;
 
     if (Value *NewOp = simplifyReductionOperand(Arg, /*CanReorderLanes=*/true))
-      return replaceArgOperand(*II, 0, NewOp);
+      return replaceOperand(*II, 0, NewOp);
 
     if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
       if (auto *FTy = dyn_cast<FixedVectorType>(Vect->getType()))
@@ -4146,7 +4144,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceArgOperand(*II, 0, NewOp);
+        return replaceOperand(*II, 0, NewOp);
       }
 
       // vector.reduce.add.vNiM(splat(%x)) -> mul(%x, N)
@@ -4192,7 +4190,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true))
-        return replaceArgOperand(*II, 0, NewOp);
+        return replaceOperand(*II, 0, NewOp);
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
         if (auto *VTy = dyn_cast<VectorType>(Vect->getType()))
@@ -4213,7 +4211,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceArgOperand(*II, 0, NewOp);
+        return replaceOperand(*II, 0, NewOp);
       }
 
       // vector_reduce_mul(zext(<n x i1>)), or
@@ -4254,7 +4252,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceArgOperand(*II, 0, NewOp);
+        return replaceOperand(*II, 0, NewOp);
       }
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
@@ -4295,7 +4293,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceArgOperand(*II, 0, NewOp);
+        return replaceOperand(*II, 0, NewOp);
       }
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
@@ -4329,7 +4327,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
                                 : 0;
     Value *Arg = II->getArgOperand(ArgIdx);
     if (Value *NewOp = simplifyReductionOperand(Arg, CanReorderLanes)) {
-      return replaceArgOperand(*II, ArgIdx, NewOp);
+      return replaceOperand(*II, ArgIdx, NewOp);
     }
     break;
   }
diff --git a/llvm/test/Transforms/InstCombine/bit_ceil.ll b/llvm/test/Transforms/InstCombine/bit_ceil.ll
index edf1c176ff12c..4017c41acbdd7 100644
--- a/llvm/test/Transforms/InstCombine/bit_ceil.ll
+++ b/llvm/test/Transforms/InstCombine/bit_ceil.ll
@@ -380,7 +380,7 @@ define i32 @bit_ceil_plus_nuw(i32 %x) {
 ; CHECK-LABEL: @bit_ceil_plus_nuw(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[X:%.*]], 1
-; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[SUB]], i1 false)
+; CHECK-NEXT:    [[CTLZ:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[SUB]], i1 false)
 ; CHECK-NEXT:    [[TMP0:%.*]] = sub nsw i32 0, [[CTLZ]]
 ; CHECK-NEXT:    [[SUB2:%.*]] = and i32 [[TMP0]], 31
 ; CHECK-NEXT:    [[SHL:%.*]] = shl nuw i32 1, [[SUB2]]
diff --git a/llvm/test/Transforms/InstCombine/ctpop-bswap-bitreverse.ll b/llvm/test/Transforms/InstCombine/ctpop-bswap-bitreverse.ll
index 7e4050873dc92..32791fe186c33 100644
--- a/llvm/test/Transforms/InstCombine/ctpop-bswap-bitreverse.ll
+++ b/llvm/test/Transforms/InstCombine/ctpop-bswap-bitreverse.ll
@@ -3,7 +3,7 @@
 
 define i32 @ctpop_bitreverse(i32 %x) {
 ; CHECK-LABEL: @ctpop_bitreverse(
-; CHECK-NEXT:    [[B:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X:%.*]])
 ; CHECK-NEXT:    ret i32 [[B]]
 ;
   %a = tail call i32 @llvm.bitreverse.i32(i32 %x)
@@ -13,7 +13,7 @@ define i32 @ctpop_bitreverse(i32 %x) {
 
 define <2 x i64> @ctpop_bitreverse_vec(<2 x i64> %x) {
 ; CHECK-LABEL: @ctpop_bitreverse_vec(
-; CHECK-NEXT:    [[B:%.*]] = tail call range(i64 0, 65) <2 x i64> @llvm.ctpop.v2i64(<2 x i64> [[X:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call range(i64 0, 65) <2 x i64> @llvm.ctpop.v2i64(<2 x i64> [[X:%.*]])
 ; CHECK-NEXT:    ret <2 x i64> [[B]]
 ;
   %a = tail call <2 x i64> @llvm.bitreverse.v2i64(<2 x i64> %x)
@@ -23,7 +23,7 @@ define <2 x i64> @ctpop_bitreverse_vec(<2 x i64> %x) {
 
 define i32 @ctpop_bswap(i32 %x) {
 ; CHECK-LABEL: @ctpop_bswap(
-; CHECK-NEXT:    [[B:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X:%.*]])
 ; CHECK-NEXT:    ret i32 [[B]]
 ;
   %a = tail call i32 @llvm.bswap.i32(i32 %x)
@@ -33,7 +33,7 @@ define i32 @ctpop_bswap(i32 %x) {
 
 define <2 x i64> @ctpop_bswap_vec(<2 x i64> %x) {
 ; CHECK-LABEL: @ctpop_bswap_vec(
-; CHECK-NEXT:    [[B:%.*]] = tail call range(i64 0, 65) <2 x i64> @llvm.ctpop.v2i64(<2 x i64> [[X:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call range(i64 0, 65) <2 x i64> @llvm.ctpop.v2i64(<2 x i64> [[X:%.*]])
 ; CHECK-NEXT:    ret <2 x i64> [[B]]
 ;
   %a = tail call <2 x i64> @llvm.bswap.v2i64(<2 x i64> %x)
diff --git a/llvm/test/Transforms/InstCombine/ctpop.ll b/llvm/test/Transforms/InstCombine/ctpop.ll
index 217a3c308a2dd..e3a6a2ad594ee 100644
--- a/llvm/test/Transforms/InstCombine/ctpop.ll
+++ b/llvm/test/Transforms/InstCombine/ctpop.ll
@@ -265,7 +265,7 @@ define <2 x i32> @ctpop_add_no_common_bits_vec_use2(<2 x i32> %a, <2 x i32> %b,
 
 define i8 @ctpop_rotate_left(i8 %a, i8 %amt)  {
 ; CHECK-LABEL: @ctpop_rotate_left(
-; CHECK-NEXT:    [[RES:%.*]] = tail call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[A:%.*]])
+; CHECK-NEXT:    [[RES:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[A:%.*]])
 ; CHECK-NEXT:    ret i8 [[RES]]
 ;
   %rotl = tail call i8 @llvm.fshl.i8(i8 %a, i8 %a, i8 %amt)
@@ -275,7 +275,7 @@ define i8 @ctpop_rotate_left(i8 %a, i8 %amt)  {
 
 define i8 @ctpop_rotate_right(i8 %a, i8 %amt)  {
 ; CHECK-LABEL: @ctpop_rotate_right(
-; CHECK-NEXT:    [[RES:%.*]] = tail call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[A:%.*]])
+; CHECK-NEXT:    [[RES:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[A:%.*]])
 ; CHECK-NEXT:    ret i8 [[RES]]
 ;
   %rotr = tail call i8 @llvm.fshr.i8(i8 %a, i8 %a, i8 %amt)
diff --git a/llvm/test/Transforms/InstCombine/cttz-abs.ll b/llvm/test/Transforms/InstCombine/cttz-abs.ll
index 9d3b6168e710b..69dfc5dd0dc19 100644
--- a/llvm/test/Transforms/InstCombine/cttz-abs.ll
+++ b/llvm/test/Transforms/InstCombine/cttz-abs.ll
@@ -3,7 +3,7 @@
 
 define i32 @cttz_abs(i32 %x) {
 ; CHECK-LABEL: @cttz_abs(
-; CHECK-NEXT:    [[R:%.*]] = tail call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
+; CHECK-NEXT:    [[R:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %c = icmp slt i32 %x, 0
@@ -29,7 +29,7 @@ define i32 @cttz_abs2(i32 %x) {
 ; CHECK-LABEL: @cttz_abs2(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[X:%.*]], 0
 ; CHECK-NEXT:    call void @use_cond(i1 [[C]])
-; CHECK-NEXT:    [[R:%.*]] = tail call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
+; CHECK-NEXT:    [[R:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %c = icmp sgt i32 %x, 0
@@ -44,7 +44,7 @@ define i32 @cttz_abs3(i32 %x) {
 ; CHECK-LABEL: @cttz_abs3(
 ; CHECK-NEXT:    [[C:%.*]] = icmp sgt i32 [[X:%.*]], -1
 ; CHECK-NEXT:    call void @use_cond(i1 [[C]])
-; CHECK-NEXT:    [[R:%.*]] = tail call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
+; CHECK-NEXT:    [[R:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %c = icmp sgt i32 %x, -1
@@ -57,7 +57,7 @@ define i32 @cttz_abs3(i32 %x) {
 
 define i32 @cttz_abs4(i32 %x) {
 ; CHECK-LABEL: @cttz_abs4(
-; CHECK-NEXT:    [[R:%.*]] = tail call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
+; CHECK-NEXT:    [[R:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %c = icmp slt i32 %x, 1
@@ -69,7 +69,7 @@ define i32 @cttz_abs4(i32 %x) {
 
 define i32 @cttz_nabs(i32 %x) {
 ; CHECK-LABEL: @cttz_nabs(
-; CHECK-NEXT:    [[R:%.*]] = tail call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[R:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 false)
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %c = icmp slt i32 %x, 0
@@ -107,7 +107,7 @@ define i32 @cttz_abs_multiuse(i32 %x) {
 ; CHECK-LABEL: @cttz_abs_multiuse(
 ; CHECK-NEXT:    [[D:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
 ; CHECK-NEXT:    call void @use_abs(i32 [[D]])
-; CHECK-NEXT:    [[R:%.*]] = tail call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
+; CHECK-NEXT:    [[R:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %c = icmp slt i32 %x, 1
@@ -123,7 +123,7 @@ define i32 @cttz_nabs_multiuse(i32 %x) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 false)
 ; CHECK-NEXT:    [[D:%.*]] = sub i32 0, [[TMP1]]
 ; CHECK-NEXT:    call void @use_abs(i32 [[D]])
-; CHECK-NEXT:    [[R:%.*]] = tail call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
+; CHECK-NEXT:    [[R:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X]], i1 true)
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %c = icmp slt i32 %x, 1
diff --git a/llvm/test/Transforms/InstCombine/cttz-negative.ll b/llvm/test/Transforms/InstCombine/cttz-negative.ll
index 6f812e420935d..5c6cf553dd91f 100644
--- a/llvm/test/Transforms/InstCombine/cttz-negative.ll
+++ b/llvm/test/Transforms/InstCombine/cttz-negative.ll
@@ -26,7 +26,7 @@ define i32 @cttz_neg_value_multiuse(i32 %x) {
 
 define i64 @cttz_neg_value_64(i64 %x) {
 ; CHECK-LABEL: @cttz_neg_value_64(
-; CHECK-NEXT:    [[B:%.*]] = tail call range(i64 0, 65) i64 @llvm.cttz.i64(i64 [[X:%.*]], i1 true)
+; CHECK-NEXT:    [[B:%.*]] = call range(i64 0, 65) i64 @llvm.cttz.i64(i64 [[X:%.*]], i1 true)
 ; CHECK-NEXT:    ret i64 [[B]]
 ;
   %a = sub i64 0, %x
@@ -36,7 +36,7 @@ define i64 @cttz_neg_value_64(i64 %x) {
 
 define i64 @cttz_neg_value2_64(i64 %x) {
 ; CHECK-LABEL: @cttz_neg_value2_64(
-; CHECK-NEXT:    [[B:%.*]] = tail call range(i64 0, 65) i64 @llvm.cttz.i64(i64 [[X:%.*]], i1 false)
+; CHECK-NEXT:    [[B:%.*]] = call range(i64 0, 65) i64 @llvm.cttz.i64(i64 [[X:%.*]], i1 false)
 ; CHECK-NEXT:    ret i64 [[B]]
 ;
   %a = sub i64 0, %x
diff --git a/llvm/test/Transforms/InstCombine/hyperbolic-functions.ll b/llvm/test/Transforms/InstCombine/hyperbolic-functions.ll
index 6cf689a982dd0..279d2775af8ea 100644
--- a/llvm/test/Transforms/InstCombine/hyperbolic-functions.ll
+++ b/llvm/test/Transforms/InstCombine/hyperbolic-functions.ll
@@ -4,7 +4,7 @@
 define double @fneg_cosh(double noundef %x) {
 ; CHECK-LABEL: @fneg_cosh(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[RET:%.*]] = tail call nnan double @llvm.cosh.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[RET:%.*]] = call nnan double @llvm.cosh.f64(double [[X:%.*]])
 ; CHECK-NEXT:    ret double [[RET]]
 ;
 entry:
diff --git a/llvm/test/Transforms/InstCombine/intrinsics.ll b/llvm/test/Transforms/InstCombine/intrinsics.ll
index 9dceb419215e5..8610912e8127c 100644
--- a/llvm/test/Transforms/InstCombine/intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/intrinsics.ll
@@ -139,7 +139,7 @@ define <vscale x 1 x i1> @cttz_knownbits_scalable_vec(<vscale x 1 x i32> %arg) {
 define i32 @cttz_knownbits2(i32 %arg) {
 ; CHECK-LABEL: @cttz_knownbits2(
 ; CHECK-NEXT:    [[OR:%.*]] = or i32 [[ARG:%.*]], 4
-; CHECK-NEXT:    [[CNT:%.*]] = call range(i32 0, 3) i32 @llvm.cttz.i32(i32 [[OR]], i1 true) #[[ATTR2:[0-9]+]]
+; CHECK-NEXT:    [[CNT:%.*]] = call range(i32 0, 3) i32 @llvm.cttz.i32(i32 [[OR]], i1 true) #[[ATTR3:[0-9]+]]
 ; CHECK-NEXT:    ret i32 [[CNT]]
 ;
   %or = or i32 %arg, 4
@@ -150,7 +150,7 @@ define i32 @cttz_knownbits2(i32 %arg) {
 define <2 x i32> @cttz_knownbits2_vec(<2 x i32> %arg) {
 ; CHECK-LABEL: @cttz_knownbits2_vec(
 ; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[ARG:%.*]], splat (i32 4)
-; CHECK-NEXT:    [[CNT:%.*]] = call range(i32 0, 3) <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[OR]], i1 true) #[[ATTR2]]
+; CHECK-NEXT:    [[CNT:%.*]] = call range(i32 0, 3) <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[OR]], i1 true) #[[ATTR3]]
 ; CHECK-NEXT:    ret <2 x i32> [[CNT]]
 ;
   %or = or <2 x i32> %arg, <i32 4, i32 4>
@@ -256,7 +256,7 @@ define <2 x i1> @ctlz_knownbits_vec(<2 x i8> %arg) {
 define i8 @ctlz_knownbits2(i8 %arg) {
 ; CHECK-LABEL: @ctlz_knownbits2(
 ; CHECK-NEXT:    [[OR:%.*]] = or i8 [[ARG:%.*]], 32
-; CHECK-NEXT:    [[CNT:%.*]] = call range(i8 0, 3) i8 @llvm.ctlz.i8(i8 [[OR]], i1 true) #[[ATTR2]]
+; CHECK-NEXT:    [[CNT:%.*]] = call range(i8 0, 3) i8 @llvm.ctlz.i8(i8 [[OR]], i1 true) #[[ATTR3]]
 ; CHECK-NEXT:    ret i8 [[CNT]]
 ;
   %or = or i8 %arg, 32
@@ -267,7 +267,7 @@ define i8 @ctlz_knownbits2(i8 %arg) {
 define <2 x i8> @ctlz_knownbits2_vec(<2 x i8> %arg) {
 ; CHECK-LABEL: @ctlz_knownbits2_vec(
 ; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[ARG:%.*]], splat (i8 32)
-; CHECK-NEXT:    [[CNT:%.*]] = call range(i8 0, 3) <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[OR]], i1 true) #[[ATTR2]]
+; CHECK-NEXT:    [[CNT:%.*]] = call range(i8 0, 3) <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[OR]], i1 true) #[[ATTR3]]
 ; CHECK-NEXT:    ret <2 x i8> [[CNT]]
 ;
   %or = or <2 x i8> %arg, <i8 32, i8 32>
@@ -314,7 +314,7 @@ define <2 x i32> @ctlz_poison_vec(<2 x i32> %Value) {
 define i32 @ctlz_no_zero(i32 %a) {
 ; CHECK-LABEL: @ctlz_no_zero(
 ; CHECK-NEXT:    [[OR:%.*]] = or i32 [[A:%.*]], 8
-; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 29) i32 @llvm.ctlz.i32(i32 [[OR]], i1 true)
+; CHECK-NEXT:    [[CTLZ:%.*]] = call range(i32 0, 29) i32 @llvm.ctlz.i32(i32 [[OR]], i1 true)
 ; CHECK-NEXT:    ret i32 [[CTLZ]]
 ;
   %or = or i32 %a, 8
@@ -325,7 +325,7 @@ define i32 @ctlz_no_zero(i32 %a) {
 define <2 x i32> @ctlz_no_zero_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @ctlz_no_zero_vec(
 ; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[A:%.*]], splat (i32 8)
-; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 29) <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[OR]], i1 true)
+; CHECK-NEXT:    [[CTLZ:%.*]] = call range(i32 0, 29) <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[OR]], i1 true)
 ; CHECK-NEXT:    ret <2 x i32> [[CTLZ]]
 ;
   %or = or <2 x i32> %a, <i32 8, i32 8>
@@ -352,7 +352,7 @@ define <2 x i32> @cttz_poison_vec(<2 x i32> %Value) {
 define i32 @cttz_no_zero(i32 %a) {
 ; CHECK-LABEL: @cttz_no_zero(
 ; CHECK-NEXT:    [[OR:%.*]] = or i32 [[A:%.*]], 8
-; CHECK-NEXT:    [[CTTZ:%.*]] = tail call range(i32 0, 4) i32 @llvm.cttz.i32(i32 [[OR]], i1 true)
+; CHECK-NEXT:    [[CTTZ:%.*]] = call range(i32 0, 4) i32 @llvm.cttz.i32(i32 [[OR]], i1 true)
 ; CHECK-NEXT:    ret i32 [[CTTZ]]
 ;
   %or = or i32 %a, 8
@@ -363,7 +363,7 @@ define i32 @cttz_no_zero(i32 %a) {
 define <2 x i32> @cttz_no_zero_vec(<2 x i32> %a) {
 ; CHECK-LABEL: @cttz_no_zero_vec(
 ; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[A:%.*]], splat (i32 8)
-; CHECK-NEXT:    [[CTTZ:%.*]] = tail call range(i32 0, 4) <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[OR]], i1 true)
+; CHECK-NEXT:    [[CTTZ:%.*]] = call range(i32 0, 4) <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[OR]], i1 true)
 ; CHECK-NEXT:    ret <2 x i32> [[CTTZ]]
 ;
   %or = or <2 x i32> %a, <i32 8, i32 8>
diff --git a/llvm/test/Transforms/InstCombine/is_fpclass.ll b/llvm/test/Transforms/InstCombine/is_fpclass.ll
index a4f7a43adf1e5..62b456a6e81a2 100644
--- a/llvm/test/Transforms/InstCombine/is_fpclass.ll
+++ b/llvm/test/Transforms/InstCombine/is_fpclass.ll
@@ -1743,7 +1743,7 @@ define i1 @test_class_fneg_posinf_negnormal_possubnormal_negzero_nan(float %arg)
 ; -> ninf|pnormal|negsubnormal|pzero|snan
 define i1 @test_class_fneg_posinf_negnormal_possubnormal_negzero_snan_strictfp(float %arg) strictfp {
 ; CHECK-LABEL: @test_class_fneg_posinf_negnormal_possubnormal_negzero_snan_strictfp(
-; CHECK-NEXT:    [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 341) #[[ATTR0]]
+; CHECK-NEXT:    [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 341)
 ; CHECK-NEXT:    ret i1 [[CLASS]]
 ;
   %fneg = fneg float %arg
@@ -2075,7 +2075,7 @@ define i1 @test_class_fabs_posinf_negnormal_possubnormal_negzero_nan(float %arg)
 ; -> pinf|psubnormal|snan
 define i1 @test_class_fabs_posinf_negnormal_possubnormal_negzero_snan_strictfp(float %arg) strictfp {
 ; CHECK-LABEL: @test_class_fabs_posinf_negnormal_possubnormal_negzero_snan_strictfp(
-; CHECK-NEXT:    [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 661) #[[ATTR0]]
+; CHECK-NEXT:    [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 661)
 ; CHECK-NEXT:    ret i1 [[CLASS]]
 ;
   %fabs = call float @llvm.fabs.f32(float %arg) strictfp
@@ -2406,7 +2406,7 @@ define i1 @test_class_fneg_fabs_posinf_negnormal_possubnormal_negzero_nan(float
 ; strictfp doesn't matter
 define i1 @test_class_fneg_fabs_posinf_negnormal_possubnormal_negzero_snan_strictfp(float %arg) strictfp {
 ; CHECK-LABEL: @test_class_fneg_fabs_posinf_negnormal_possubnormal_negzero_snan_strictfp(
-; CHECK-NEXT:    [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 361) #[[ATTR0]]
+; CHECK-NEXT:    [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 361)
 ; CHECK-NEXT:    ret i1 [[CLASS]]
 ;
   %fabs = call float @llvm.fabs.f32(float %arg) strictfp
diff --git a/llvm/test/Transforms/InstCombine/powi.ll b/llvm/test/Transforms/InstCombine/powi.ll
index 2059e94e0e371..e106ccad909b9 100644
--- a/llvm/test/Transforms/InstCombine/powi.ll
+++ b/llvm/test/Transforms/InstCombine/powi.ll
@@ -11,7 +11,7 @@ declare void @use(double)
 define double @powi_fneg_even_int(double %x) {
 ; CHECK-LABEL: @powi_fneg_even_int(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[R:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 4)
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 4)
 ; CHECK-NEXT:    ret double [[R]]
 ;
 entry:
@@ -23,7 +23,7 @@ entry:
 define double @powi_fabs_even_int(double %x) {
 ; CHECK-LABEL: @powi_fabs_even_int(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[R:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 4)
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 4)
 ; CHECK-NEXT:    ret double [[R]]
 ;
 entry:
@@ -35,7 +35,7 @@ entry:
 define double @powi_copysign_even_int(double %x, double %y) {
 ; CHECK-LABEL: @powi_copysign_even_int(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[R:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 4)
+; CHECK-NEXT:    [[R:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 4)
 ; CHECK-NEXT:    ret double [[R]]
 ;
 entry:

>From 7d48df1b27be3f23b500cc31bcdce886777215c8 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 28 Jun 2026 20:01:22 +0800
Subject: [PATCH 07/12] [InstCombine] Add more tests. NFC.

---
 .../Transforms/InstCombine/minmax-of-minmax.ll    | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll b/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
index e04e3c146924b..e2256630e2f62 100644
--- a/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
@@ -288,3 +288,18 @@ define i32 @umin_of_umin_umax_wrong_operand2(i32 %x, i32 %y, i32 %z) {
   %r = select i1 %cmp3, i32 %min, i32 %max
   ret i32 %r
 }
+
+; Make sure that the range attribute is dropped.
+
+define i32 @umax_of_umax_umin_drop_range(i32 %x, i32 %y) {
+; CHECK-LABEL: @umax_of_umax_umin_drop_range(
+; CHECK-NEXT:    [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
+; CHECK-NEXT:    ret i32 [[MAX]]
+;
+  %cmp1 = icmp ugt i32 %x, %y
+  %min = select i1 %cmp1, i32 %y, i32 %x
+  %cmp2 = icmp ugt i32 %x, %y
+  %max = select i1 %cmp2, i32 %x, i32 %y
+  %r = call i32 @llvm.umax.i32(i32 range(i32 0, 4) %min, i32 range(i32 4, 8) %max)
+  ret i32 %r
+}

>From bd7674e92b443423b04cdfe45b222345b2fcc0d6 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 28 Jun 2026 20:02:34 +0800
Subject: [PATCH 08/12] [IR] Drop unused includes

---
 llvm/lib/IR/Instructions.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 413abb9a39e62..faa046729aff6 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -16,7 +16,6 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
-#include "llvm/IR/AttributeMask.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constant.h"

>From fef4c03e8754b3f3418bce9bca62f65e681f4f31 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 28 Jun 2026 23:39:45 +0800
Subject: [PATCH 09/12] [InstCombine] Address review comments.

---
 llvm/include/llvm/IR/Attributes.h             |  6 +--
 .../InstCombine/InstCombineCalls.cpp          | 44 ++++++++++++-------
 .../Transforms/InstCombine/minmax-fold.ll     |  6 +--
 3 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 833f2a033a067..3387649850ed5 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -579,9 +579,6 @@ class AttributeList {
 
   static AttributeList getImpl(LLVMContext &C, ArrayRef<AttributeSet> AttrSets);
 
-  AttributeList setAttributesAtIndex(LLVMContext &C, unsigned Index,
-                                     AttributeSet Attrs) const;
-
 public:
   AttributeList() = default;
 
@@ -604,6 +601,9 @@ class AttributeList {
   LLVM_ABI static AttributeList get(LLVMContext &C, unsigned Index,
                                     const AttrBuilder &B);
 
+  AttributeList setAttributesAtIndex(LLVMContext &C, unsigned Index,
+                                     AttributeSet Attrs) const;
+
   // TODO: remove non-AtIndex versions of these methods.
   /// Add an attribute to the attribute set at the given index.
   /// Returns a new list because attribute lists are immutable.
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 9dc2ab187e5e4..091b449b19f72 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -923,15 +923,15 @@ static CallInst *canonicalizeConstantArg0ToArg1(CallInst &Call) {
   if (isa<Constant>(Arg0) && !isa<Constant>(Arg1)) {
     Call.setArgOperand(0, Arg1);
     Call.setArgOperand(1, Arg0);
-    auto CallAttr = Call.getAttributes();
-    auto LHSAttr = CallAttr.getParamAttrs(0);
-    auto RHSAttr = CallAttr.getParamAttrs(1);
+    AttributeList CallAttr = Call.getAttributes();
+    AttributeSet LHSAttr = CallAttr.getParamAttrs(0);
+    AttributeSet RHSAttr = CallAttr.getParamAttrs(1);
     LLVMContext &Ctx = Call.getContext();
-    Call.setAttributes(
-        CallAttr.removeAttributesAtIndex(Ctx, 0)
-            .removeAttributesAtIndex(Ctx, 1)
-            .addParamAttributes(Ctx, 0, AttrBuilder(Ctx, RHSAttr))
-            .addParamAttributes(Ctx, 1, AttrBuilder(Ctx, LHSAttr)));
+    Call.setAttributes(CallAttr
+                           .setAttributesAtIndex(
+                               Ctx, AttributeList::FirstArgIndex + 0, RHSAttr)
+                           .setAttributesAtIndex(
+                               Ctx, AttributeList::FirstArgIndex + 1, LHSAttr));
     return &Call;
   }
   return nullptr;
@@ -4107,8 +4107,11 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
     Value *Arg = II->getArgOperand(0);
     Value *Vect;
 
-    if (Value *NewOp = simplifyReductionOperand(Arg, /*CanReorderLanes=*/true))
-      return replaceOperand(*II, 0, NewOp);
+    if (Value *NewOp =
+            simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
+      replaceUse(II->getOperandUse(0), NewOp);
+      return II;
+    }
 
     if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
       if (auto *FTy = dyn_cast<FixedVectorType>(Vect->getType()))
@@ -4144,7 +4147,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceOperand(*II, 0, NewOp);
+        replaceUse(II->getOperandUse(0), NewOp);
+        return II;
       }
 
       // vector.reduce.add.vNiM(splat(%x)) -> mul(%x, N)
@@ -4189,8 +4193,10 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       Value *Vect;
 
       if (Value *NewOp =
-              simplifyReductionOperand(Arg, /*CanReorderLanes=*/true))
-        return replaceOperand(*II, 0, NewOp);
+              simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
+        replaceUse(II->getOperandUse(0), NewOp);
+        return II;
+      }
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
         if (auto *VTy = dyn_cast<VectorType>(Vect->getType()))
@@ -4211,7 +4217,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceOperand(*II, 0, NewOp);
+        replaceUse(II->getOperandUse(0), NewOp);
+        return II;
       }
 
       // vector_reduce_mul(zext(<n x i1>)), or
@@ -4252,7 +4259,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceOperand(*II, 0, NewOp);
+        replaceUse(II->getOperandUse(0), NewOp);
+        return II;
       }
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
@@ -4293,7 +4301,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
 
       if (Value *NewOp =
               simplifyReductionOperand(Arg, /*CanReorderLanes=*/true)) {
-        return replaceOperand(*II, 0, NewOp);
+        replaceUse(II->getOperandUse(0), NewOp);
+        return II;
       }
 
       if (match(Arg, m_ZExtOrSExtOrSelf(m_Value(Vect)))) {
@@ -4327,7 +4336,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
                                 : 0;
     Value *Arg = II->getArgOperand(ArgIdx);
     if (Value *NewOp = simplifyReductionOperand(Arg, CanReorderLanes)) {
-      return replaceOperand(*II, ArgIdx, NewOp);
+      replaceUse(II->getOperandUse(ArgIdx), NewOp);
+      return nullptr;
     }
     break;
   }
diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll
index 049d3153ff51c..3234ed5055f80 100644
--- a/llvm/test/Transforms/InstCombine/minmax-fold.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll
@@ -1845,9 +1845,9 @@ define i32 @test_umin_or_neg1_nuw(i32 %x, i32 range(i32 1, 0) %w) {
 
 ; Make sure that poison-generating/UB-implying parameters are swapped.
 
-define i32 @umax_commute_operand_drop_attrs(i32 %x) {
-; CHECK-LABEL: @umax_commute_operand_drop_attrs(
-; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 noundef range(i32 -10, -8) -10)
+define i32 @umax_commute_operand_swap_attrs(i32 %x) {
+; CHECK-LABEL: @umax_commute_operand_swap_attrs(
+; CHECK-NEXT:    [[RET:%.*]] = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 [[X:%.*]], i32 noundef range(i32 -10, -8) -10)
 ; CHECK-NEXT:    ret i32 [[RET]]
 ;
   %ret = call range(i32 -10, 0) i32 @llvm.umax.i32(i32 noundef range(i32 -10, -8) -10, i32 %x)

>From c27d88cd51aaa73536cfff069e32697a2a65ccca Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 28 Jun 2026 23:45:58 +0800
Subject: [PATCH 10/12] [InstCombine] Add pre-commit tests. NFC.

---
 .../test/Transforms/InstCombine/minmax-of-minmax.ll | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll b/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
index e2256630e2f62..d55824362728a 100644
--- a/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
@@ -303,3 +303,16 @@ define i32 @umax_of_umax_umin_drop_range(i32 %x, i32 %y) {
   %r = call i32 @llvm.umax.i32(i32 range(i32 0, 4) %min, i32 range(i32 4, 8) %max)
   ret i32 %r
 }
+
+; Make sure that the noundef attribute is dropped.
+
+define i32 @umax_of_symmetric_drop_noundef(i1 %cond, i32 %x, i32 %y) {
+; CHECK-LABEL: @umax_of_symmetric_drop_noundef(
+; CHECK-NEXT:    [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 noundef [[Y:%.*]], i32 [[X:%.*]])
+; CHECK-NEXT:    ret i32 [[MAX]]
+;
+  %sel1 = select i1 %cond, i32 %y, i32 %x
+  %sel2 = select i1 %cond, i32 %x, i32 %y
+  %r = call i32 @llvm.umax.i32(i32 noundef %sel1, i32 %sel2)
+  ret i32 %r
+}

>From ec211d2342ff939a3eb98b264ee27a58796a6f83 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 29 Jun 2026 00:01:05 +0800
Subject: [PATCH 11/12] [InstCombine] Drop noundef

---
 llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 1 +
 llvm/test/Transforms/InstCombine/minmax-of-minmax.ll | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 091b449b19f72..0c2d11fab4f43 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2034,6 +2034,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       replaceOperand(*II, 0, Pair->first);
       replaceOperand(*II, 1, Pair->second);
       II->dropPoisonGeneratingAnnotations();
+      II->dropUBImplyingAttrsAndMetadata();
       return II;
     }
 
diff --git a/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll b/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
index d55824362728a..56ba1cf5e9e1f 100644
--- a/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-of-minmax.ll
@@ -308,7 +308,7 @@ define i32 @umax_of_umax_umin_drop_range(i32 %x, i32 %y) {
 
 define i32 @umax_of_symmetric_drop_noundef(i1 %cond, i32 %x, i32 %y) {
 ; CHECK-LABEL: @umax_of_symmetric_drop_noundef(
-; CHECK-NEXT:    [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 noundef [[Y:%.*]], i32 [[X:%.*]])
+; CHECK-NEXT:    [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[Y:%.*]], i32 [[X:%.*]])
 ; CHECK-NEXT:    ret i32 [[MAX]]
 ;
   %sel1 = select i1 %cond, i32 %y, i32 %x

>From e89cf83d3b081152f87edaa3403e6d77c7c6a2cf Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 29 Jun 2026 00:01:46 +0800
Subject: [PATCH 12/12] [IR] Add LLVM_ABI

---
 llvm/include/llvm/IR/Attributes.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 3387649850ed5..049f699b2980b 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -601,8 +601,10 @@ class AttributeList {
   LLVM_ABI static AttributeList get(LLVMContext &C, unsigned Index,
                                     const AttrBuilder &B);
 
-  AttributeList setAttributesAtIndex(LLVMContext &C, unsigned Index,
-                                     AttributeSet Attrs) const;
+  /// Set the attribute set at the given index.
+  /// Returns a new list because attribute lists are immutable.
+  [[nodiscard]] LLVM_ABI AttributeList setAttributesAtIndex(
+      LLVMContext &C, unsigned Index, AttributeSet Attrs) const;
 
   // TODO: remove non-AtIndex versions of these methods.
   /// Add an attribute to the attribute set at the given index.



More information about the llvm-commits mailing list