[llvm] [InstSimplify] Expose simplifyIntrinsic (NFC) (PR #202577)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 03:57:16 PDT 2026


https://github.com/artagnon created https://github.com/llvm/llvm-project/pull/202577

With the objective of using it in the constant-folder.

>From ac7e19d3c373c785d0973f42a3e44bd33c8c81d7 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Tue, 9 Jun 2026 11:43:39 +0100
Subject: [PATCH] [InstSimplify] Expose simplifyIntrinsic (NFC)

With the objective of using it in the constant-folder.
---
 .../llvm/Analysis/InstructionSimplify.h       |  16 +-
 llvm/lib/Analysis/InstructionSimplify.cpp     | 205 ++++++++----------
 2 files changed, 108 insertions(+), 113 deletions(-)

diff --git a/llvm/include/llvm/Analysis/InstructionSimplify.h b/llvm/include/llvm/Analysis/InstructionSimplify.h
index 14941a3cdba45..50090c4d587bf 100644
--- a/llvm/include/llvm/Analysis/InstructionSimplify.h
+++ b/llvm/include/llvm/Analysis/InstructionSimplify.h
@@ -194,16 +194,24 @@ LLVM_ABI Value *simplifyExtractElementInst(Value *Vec, Value *Idx,
 LLVM_ABI Value *simplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
                                  const SimplifyQuery &Q);
 
+/// Given operands for a unary intrinsic, fold the result or return null.
+LLVM_ABI Value *simplifyUnaryIntrinsic(Intrinsic::ID IID, Value *Op0,
+                                       FastMathFlags FMF,
+                                       const SimplifyQuery &Q);
+
 /// Given operands for a binary intrinsic, fold the result or return null.
 LLVM_ABI Value *simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
                                         Value *Op0, Value *Op1,
                                         FastMathFlags FMF,
                                         const SimplifyQuery &Q);
 
-/// Given operands for a unary intrinsic, fold the result or return null.
-LLVM_ABI Value *simplifyUnaryIntrinsic(Intrinsic::ID IID, Value *Op0,
-                                       FastMathFlags FMF,
-                                       const SimplifyQuery &Q);
+/// Given operands for an intrinsic, fold the result or return null.
+LLVM_ABI Value *
+simplifyIntrinsic(Intrinsic::ID IID, Type *ReturnType, ArrayRef<Value *> Args,
+                  FastMathFlags FMF, const SimplifyQuery &Q,
+                  fp::ExceptionBehavior ExBehavior = fp::ebIgnore,
+                  RoundingMode Rounding = RoundingMode::NearestTiesToEven,
+                  ConstantRange VScaleRange = ConstantRange::getFull(64));
 
 /// Given operands for a ShuffleVectorInst, fold the result or return null.
 /// See class ShuffleVectorInst for a description of the mask representation.
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 81debece796b1..b78628ce1b283 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -7219,27 +7219,24 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
   return nullptr;
 }
 
-static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
-                                ArrayRef<Value *> Args,
-                                const SimplifyQuery &Q) {
-  // Operand bundles should not be in Args.
-  assert(Call->arg_size() == Args.size());
+Value *llvm::simplifyIntrinsic(Intrinsic::ID IID, Type *ReturnType,
+                               ArrayRef<Value *> Args, FastMathFlags FMF,
+                               const SimplifyQuery &Q,
+                               fp::ExceptionBehavior ExBehavior,
+                               RoundingMode Rounding,
+                               ConstantRange VScaleRange) {
   unsigned NumOperands = Args.size();
-  Function *F = cast<Function>(Callee);
-  Intrinsic::ID IID = F->getIntrinsicID();
-
   if (IID != Intrinsic::not_intrinsic && intrinsicPropagatesPoison(IID) &&
       any_of(Args, IsaPred<PoisonValue>))
-    return PoisonValue::get(F->getReturnType());
+    return PoisonValue::get(ReturnType);
+
   // Most of the intrinsics with no operands have some kind of side effect.
   // Don't simplify.
   if (!NumOperands) {
     switch (IID) {
     case Intrinsic::vscale: {
-      Type *RetTy = F->getReturnType();
-      ConstantRange CR = getVScaleRange(Call->getFunction(), 64);
-      if (const APInt *C = CR.getSingleElement())
-        return ConstantInt::get(RetTy, C->getZExtValue());
+      if (const APInt *C = VScaleRange.getSingleElement())
+        return ConstantInt::get(ReturnType, C->getZExtValue());
       return nullptr;
     }
     default:
@@ -7248,15 +7245,37 @@ static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
   }
 
   if (NumOperands == 1)
-    return simplifyUnaryIntrinsic(IID, Args[0], Call->getFastMathFlagsOrNone(),
-                                  Q);
+    return simplifyUnaryIntrinsic(IID, Args[0], FMF, Q);
 
   if (NumOperands == 2)
-    return simplifyBinaryIntrinsic(IID, F->getReturnType(), Args[0], Args[1],
-                                   Call->getFastMathFlagsOrNone(), Q);
+    return simplifyBinaryIntrinsic(IID, ReturnType, Args[0], Args[1], FMF, Q);
 
   // Handle intrinsics with 3 or more arguments.
   switch (IID) {
+  case Intrinsic::vector_splice_left:
+  case Intrinsic::vector_splice_right: {
+    Value *Offset = Args[2];
+    auto *Ty = cast<VectorType>(ReturnType);
+    if (Q.isUndefValue(Offset))
+      return PoisonValue::get(Ty);
+
+    unsigned BitWidth = Offset->getType()->getScalarSizeInBits();
+    ConstantRange NumElts(
+        APInt(BitWidth, Ty->getElementCount().getKnownMinValue()));
+    if (Ty->isScalableTy())
+      NumElts = NumElts.multiply(VScaleRange.zextOrTrunc(BitWidth));
+
+    // If we know Offset > NumElts, simplify to poison.
+    ConstantRange CR = computeConstantRangeIncludingKnownBits(Offset, false, Q);
+    if (CR.getUnsignedMin().ugt(NumElts.getUnsignedMax()))
+      return PoisonValue::get(Ty);
+
+    // splice.left(a, b, 0) --> a, splice.right(a, b, 0) --> b
+    if (CR.isSingleElement() && CR.getSingleElement()->isZero())
+      return IID == Intrinsic::vector_splice_left ? Args[0] : Args[1];
+
+    return nullptr;
+  }
   case Intrinsic::masked_load:
   case Intrinsic::masked_gather: {
     Value *MaskArg = Args[1];
@@ -7273,7 +7292,7 @@ static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
 
     // If both operands are undef, the result is undef.
     if (Q.isUndefValue(Op0) && Q.isUndefValue(Op1))
-      return UndefValue::get(F->getReturnType());
+      return UndefValue::get(ReturnType);
 
     // If shift amount is undef, assume it is zero.
     if (Q.isUndefValue(ShAmtArg))
@@ -7299,34 +7318,25 @@ static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
 
     // Rotating zero by anything is zero.
     if (match(Op0, m_Zero()) && match(Op1, m_Zero()))
-      return ConstantInt::getNullValue(F->getReturnType());
+      return ConstantInt::getNullValue(ReturnType);
 
     // Rotating -1 by anything is -1.
     if (match(Op0, m_AllOnes()) && match(Op1, m_AllOnes()))
-      return ConstantInt::getAllOnesValue(F->getReturnType());
+      return ConstantInt::getAllOnesValue(ReturnType);
 
     return nullptr;
   }
-  case Intrinsic::experimental_constrained_fma: {
-    auto *FPI = cast<ConstrainedFPIntrinsic>(Call);
-    if (Value *V = simplifyFPOp(Args, {}, Q, *FPI->getExceptionBehavior(),
-                                *FPI->getRoundingMode()))
-      return V;
-    return nullptr;
-  }
+  case Intrinsic::experimental_constrained_fma:
+    return simplifyFPOp(Args, {}, Q, ExBehavior, Rounding);
   case Intrinsic::fma:
-  case Intrinsic::fmuladd: {
-    if (Value *V = simplifyFPOp(Args, {}, Q, fp::ebIgnore,
-                                RoundingMode::NearestTiesToEven))
-      return V;
-    return nullptr;
-  }
+  case Intrinsic::fmuladd:
+    return simplifyFPOp(Args, {}, Q, fp::ebIgnore,
+                        RoundingMode::NearestTiesToEven);
   case Intrinsic::smul_fix:
   case Intrinsic::smul_fix_sat: {
     Value *Op0 = Args[0];
     Value *Op1 = Args[1];
     Value *Op2 = Args[2];
-    Type *ReturnType = F->getReturnType();
 
     // Canonicalize constant operand as Op1 (ConstantFolding handles the case
     // when both Op0 and Op1 are constant so we do not care about that special
@@ -7355,7 +7365,6 @@ static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
     Value *Vec = Args[0];
     Value *SubVec = Args[1];
     Value *Idx = Args[2];
-    Type *ReturnType = F->getReturnType();
 
     // (insert_vector Y, (extract_vector X, 0), 0) -> X
     // where: Y is X, or Y is undef
@@ -7369,62 +7378,46 @@ static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
 
     return nullptr;
   }
-  case Intrinsic::vector_splice_left:
-  case Intrinsic::vector_splice_right: {
-    Value *Offset = Args[2];
-    auto *Ty = cast<VectorType>(F->getReturnType());
-    if (Q.isUndefValue(Offset))
-      return PoisonValue::get(Ty);
-
-    unsigned BitWidth = Offset->getType()->getScalarSizeInBits();
-    ConstantRange NumElts(
-        APInt(BitWidth, Ty->getElementCount().getKnownMinValue()));
-    if (Ty->isScalableTy())
-      NumElts = NumElts.multiply(getVScaleRange(Call->getFunction(), BitWidth));
-
-    // If we know Offset > NumElts, simplify to poison.
-    ConstantRange CR = computeConstantRangeIncludingKnownBits(Offset, false, Q);
-    if (CR.getUnsignedMin().ugt(NumElts.getUnsignedMax()))
-      return PoisonValue::get(Ty);
+  case Intrinsic::experimental_constrained_fadd:
+    return simplifyFAddInst(Args[0], Args[1], FMF, Q, ExBehavior, Rounding);
+  case Intrinsic::experimental_constrained_fsub:
+    return simplifyFSubInst(Args[0], Args[1], FMF, Q, ExBehavior, Rounding);
+  case Intrinsic::experimental_constrained_fmul:
+    return simplifyFMulInst(Args[0], Args[1], FMF, Q, ExBehavior, Rounding);
+  case Intrinsic::experimental_constrained_fdiv:
+    return simplifyFDivInst(Args[0], Args[1], FMF, Q, ExBehavior, Rounding);
+  case Intrinsic::experimental_constrained_frem:
+    return simplifyFRemInst(Args[0], Args[1], FMF, Q, ExBehavior, Rounding);
+  case Intrinsic::experimental_constrained_ldexp:
+    return simplifyLdexp(Args[0], Args[1], Q, true);
+  case Intrinsic::experimental_vp_reverse: {
+    Value *Vec = Args[0];
+    Value *EVL = Args[2];
 
-    // splice.left(a, b, 0) --> a, splice.right(a, b, 0) --> b
-    if (CR.isSingleElement() && CR.getSingleElement()->isZero())
-      return IID == Intrinsic::vector_splice_left ? Args[0] : Args[1];
+    Value *X;
+    // vp.reverse(vp.reverse(X)) == X (mask doesn't matter)
+    if (match(Vec, m_Intrinsic<Intrinsic::experimental_vp_reverse>(
+                       m_Value(X), m_Value(), m_Specific(EVL))))
+      return X;
 
+    // vp.reverse(splat(X)) -> splat(X) (regardless of mask and EVL)
+    if (isSplatValue(Vec))
+      return Vec;
     return nullptr;
   }
-  case Intrinsic::experimental_constrained_fadd: {
-    auto *FPI = cast<ConstrainedFPIntrinsic>(Call);
-    return simplifyFAddInst(Args[0], Args[1], FPI->getFastMathFlags(), Q,
-                            *FPI->getExceptionBehavior(),
-                            *FPI->getRoundingMode());
-  }
-  case Intrinsic::experimental_constrained_fsub: {
-    auto *FPI = cast<ConstrainedFPIntrinsic>(Call);
-    return simplifyFSubInst(Args[0], Args[1], FPI->getFastMathFlags(), Q,
-                            *FPI->getExceptionBehavior(),
-                            *FPI->getRoundingMode());
-  }
-  case Intrinsic::experimental_constrained_fmul: {
-    auto *FPI = cast<ConstrainedFPIntrinsic>(Call);
-    return simplifyFMulInst(Args[0], Args[1], FPI->getFastMathFlags(), Q,
-                            *FPI->getExceptionBehavior(),
-                            *FPI->getRoundingMode());
-  }
-  case Intrinsic::experimental_constrained_fdiv: {
-    auto *FPI = cast<ConstrainedFPIntrinsic>(Call);
-    return simplifyFDivInst(Args[0], Args[1], FPI->getFastMathFlags(), Q,
-                            *FPI->getExceptionBehavior(),
-                            *FPI->getRoundingMode());
-  }
-  case Intrinsic::experimental_constrained_frem: {
-    auto *FPI = cast<ConstrainedFPIntrinsic>(Call);
-    return simplifyFRemInst(Args[0], Args[1], FPI->getFastMathFlags(), Q,
-                            *FPI->getExceptionBehavior(),
-                            *FPI->getRoundingMode());
+  default:
+    return nullptr;
   }
-  case Intrinsic::experimental_constrained_ldexp:
-    return simplifyLdexp(Args[0], Args[1], Q, true);
+}
+
+static Value *simplifyIntrinsic(CallBase *Call, ArrayRef<Value *> Args,
+                                const SimplifyQuery &Q) {
+  // Operand bundles should not be in Args.
+  assert(Call->arg_size() == Args.size());
+  Intrinsic::ID IID = Call->getCalledFunction()->getIntrinsicID();
+  Type *ReturnType = Call->getCalledFunction()->getReturnType();
+
+  switch (IID) {
   case Intrinsic::experimental_gc_relocate: {
     GCRelocateInst &GCR = *cast<GCRelocateInst>(Call);
     Value *DerivedPtr = GCR.getDerivedPtr();
@@ -7446,30 +7439,24 @@ static Value *simplifyIntrinsic(CallBase *Call, Value *Callee,
     }
     return nullptr;
   }
-  case Intrinsic::experimental_vp_reverse: {
-    Value *Vec = Call->getArgOperand(0);
-    Value *EVL = Call->getArgOperand(2);
-
-    Value *X;
-    // vp.reverse(vp.reverse(X)) == X (mask doesn't matter)
-    if (match(Vec, m_Intrinsic<Intrinsic::experimental_vp_reverse>(
-                       m_Value(X), m_Value(), m_Specific(EVL))))
-      return X;
-
-    // vp.reverse(splat(X)) -> splat(X) (regardless of mask and EVL)
-    if (isSplatValue(Vec))
-      return Vec;
-    return nullptr;
+  default: {
+    // Use the default FP environment if none is found.
+    fp::ExceptionBehavior ExBehavior = fp::ebIgnore;
+    RoundingMode Rounding = RoundingMode::NearestTiesToEven;
+    if (auto *Constrained = dyn_cast<ConstrainedFPIntrinsic>(Call)) {
+      ExBehavior = Constrained->getExceptionBehavior().value_or(ExBehavior);
+      Rounding = Constrained->getRoundingMode().value_or(Rounding);
+    }
+    return simplifyIntrinsic(IID, ReturnType, Args,
+                             Call->getFastMathFlagsOrNone(), Q, ExBehavior,
+                             Rounding, getVScaleRange(Call->getFunction(), 64));
   }
-  default:
-    return nullptr;
   }
 }
 
-static Value *tryConstantFoldCall(CallBase *Call, Value *Callee,
-                                  ArrayRef<Value *> Args,
+static Value *tryConstantFoldCall(CallBase *Call, ArrayRef<Value *> Args,
                                   const SimplifyQuery &Q) {
-  auto *F = dyn_cast<Function>(Callee);
+  auto *F = Call->getCalledFunction();
   if (!F || !canConstantFoldCallTo(Call, F))
     return nullptr;
 
@@ -7503,12 +7490,12 @@ Value *llvm::simplifyCall(CallBase *Call, Value *Callee, ArrayRef<Value *> Args,
   if (isa<UndefValue>(Callee) || isa<ConstantPointerNull>(Callee))
     return PoisonValue::get(Call->getType());
 
-  if (Value *V = tryConstantFoldCall(Call, Callee, Args, Q))
+  if (Value *V = tryConstantFoldCall(Call, Args, Q))
     return V;
 
   auto *F = dyn_cast<Function>(Callee);
   if (F && F->isIntrinsic())
-    if (Value *Ret = simplifyIntrinsic(Call, Callee, Args, Q))
+    if (Value *Ret = ::simplifyIntrinsic(Call, Args, Q))
       return Ret;
 
   return nullptr;
@@ -7517,9 +7504,9 @@ Value *llvm::simplifyCall(CallBase *Call, Value *Callee, ArrayRef<Value *> Args,
 Value *llvm::simplifyConstrainedFPCall(CallBase *Call, const SimplifyQuery &Q) {
   assert(isa<ConstrainedFPIntrinsic>(Call));
   SmallVector<Value *, 4> Args(Call->args());
-  if (Value *V = tryConstantFoldCall(Call, Call->getCalledOperand(), Args, Q))
+  if (Value *V = tryConstantFoldCall(Call, Args, Q))
     return V;
-  if (Value *Ret = simplifyIntrinsic(Call, Call->getCalledOperand(), Args, Q))
+  if (Value *Ret = ::simplifyIntrinsic(Call, Args, Q))
     return Ret;
   return nullptr;
 }



More information about the llvm-commits mailing list