[llvm] [InstSimplify] Expose simplifyIntrinsic (NFC) (PR #202577)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 05:51:15 PDT 2026
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/202577
>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 1/2] [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;
}
>From 672439eeaaba7834a48044e05961e4af06395a99 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Tue, 9 Jun 2026 13:43:31 +0100
Subject: [PATCH 2/2] [InstSimplify] Reorder, use CxtF in place of VScaleRange
---
.../llvm/Analysis/InstructionSimplify.h | 2 +-
llvm/lib/Analysis/InstructionSimplify.cpp | 58 ++++++++++---------
2 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/llvm/include/llvm/Analysis/InstructionSimplify.h b/llvm/include/llvm/Analysis/InstructionSimplify.h
index 50090c4d587bf..4ebb190af798f 100644
--- a/llvm/include/llvm/Analysis/InstructionSimplify.h
+++ b/llvm/include/llvm/Analysis/InstructionSimplify.h
@@ -211,7 +211,7 @@ 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));
+ Function *CtxF = nullptr);
/// 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 b78628ce1b283..755e69a393960 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -7223,8 +7223,7 @@ Value *llvm::simplifyIntrinsic(Intrinsic::ID IID, Type *ReturnType,
ArrayRef<Value *> Args, FastMathFlags FMF,
const SimplifyQuery &Q,
fp::ExceptionBehavior ExBehavior,
- RoundingMode Rounding,
- ConstantRange VScaleRange) {
+ RoundingMode Rounding, Function *CxtF) {
unsigned NumOperands = Args.size();
if (IID != Intrinsic::not_intrinsic && intrinsicPropagatesPoison(IID) &&
any_of(Args, IsaPred<PoisonValue>))
@@ -7235,7 +7234,9 @@ Value *llvm::simplifyIntrinsic(Intrinsic::ID IID, Type *ReturnType,
if (!NumOperands) {
switch (IID) {
case Intrinsic::vscale: {
- if (const APInt *C = VScaleRange.getSingleElement())
+ ConstantRange CR =
+ CxtF ? getVScaleRange(CxtF, 64) : ConstantRange::getFull(64);
+ if (const APInt *C = CR.getSingleElement())
return ConstantInt::get(ReturnType, C->getZExtValue());
return nullptr;
}
@@ -7252,30 +7253,6 @@ Value *llvm::simplifyIntrinsic(Intrinsic::ID IID, Type *ReturnType,
// 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];
@@ -7378,6 +7355,31 @@ Value *llvm::simplifyIntrinsic(Intrinsic::ID IID, Type *ReturnType,
return nullptr;
}
+ 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(CxtF ? getVScaleRange(CxtF, BitWidth)
+ : ConstantRange::getFull(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::experimental_constrained_fadd:
return simplifyFAddInst(Args[0], Args[1], FMF, Q, ExBehavior, Rounding);
case Intrinsic::experimental_constrained_fsub:
@@ -7449,7 +7451,7 @@ static Value *simplifyIntrinsic(CallBase *Call, ArrayRef<Value *> Args,
}
return simplifyIntrinsic(IID, ReturnType, Args,
Call->getFastMathFlagsOrNone(), Q, ExBehavior,
- Rounding, getVScaleRange(Call->getFunction(), 64));
+ Rounding, Call->getFunction());
}
}
}
More information about the llvm-commits
mailing list