[llvm] a25c7d7 - ValueTracking: Extract isKnownIntegral out of AMDGPU (#177912)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 26 10:55:18 PST 2026
Author: Matt Arsenault
Date: 2026-01-26T19:55:14+01:00
New Revision: a25c7d7ade5b80cad61562c9f78be4071201ac26
URL: https://github.com/llvm/llvm-project/commit/a25c7d7ade5b80cad61562c9f78be4071201ac26
DIFF: https://github.com/llvm/llvm-project/commit/a25c7d7ade5b80cad61562c9f78be4071201ac26.diff
LOG: ValueTracking: Extract isKnownIntegral out of AMDGPU (#177912)
Also do some basic conversions to use SimplifyQuery and add tests to
show assume works in a new context.
Added:
Modified:
llvm/include/llvm/Analysis/ValueTracking.h
llvm/lib/Analysis/ValueTracking.cpp
llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-pow.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 2ce49c558b241..1cd88fd89aea2 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -329,6 +329,11 @@ LLVM_ABI bool canIgnoreSignBitOfZero(const Use &U);
/// the value is NaN.
LLVM_ABI bool canIgnoreSignBitOfNaN(const Use &U);
+/// Return true if the floating-point value \p V is known to be an integer
+/// value.
+LLVM_ABI bool isKnownIntegral(const Value *V, const SimplifyQuery &SQ,
+ FastMathFlags FMF);
+
/// If the specified value can be set by repeating the same byte in memory,
/// return the i8 value that it is represented with. This is true for all i8
/// values obviously, but is also true for i32 0, i32 -1, i16 0xF0F0, double
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b84919d89388d..9c4027dfced17 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -6229,6 +6229,73 @@ bool llvm::canIgnoreSignBitOfNaN(const Use &U) {
}
}
+bool llvm::isKnownIntegral(const Value *V, const SimplifyQuery &SQ,
+ FastMathFlags FMF) {
+ if (isa<PoisonValue>(V))
+ return true;
+ if (isa<UndefValue>(V))
+ return false;
+
+ if (const ConstantFP *CF = dyn_cast<ConstantFP>(V))
+ return CF->getValueAPF().isInteger();
+
+ auto *VFVTy = dyn_cast<FixedVectorType>(V->getType());
+ const Constant *CV = dyn_cast<Constant>(V);
+ if (VFVTy && CV) {
+ unsigned NumElts = VFVTy->getNumElements();
+ for (unsigned i = 0; i != NumElts; ++i) {
+ Constant *Elt = CV->getAggregateElement(i);
+ if (!Elt)
+ return false;
+ if (isa<PoisonValue>(Elt))
+ continue;
+
+ const ConstantFP *CFP = dyn_cast<ConstantFP>(Elt);
+ if (!CFP || !CFP->getValue().isInteger())
+ return false;
+ }
+
+ return true;
+ }
+
+ const Instruction *I = dyn_cast<Instruction>(V);
+ if (!I)
+ return false;
+
+ switch (I->getOpcode()) {
+ case Instruction::SIToFP:
+ case Instruction::UIToFP:
+ // TODO: Could check nofpclass(inf) on incoming argument
+ if (FMF.noInfs())
+ return true;
+
+ // Need to check int size cannot produce infinity, which computeKnownFPClass
+ // knows how to do already.
+ return isKnownNeverInfinity(I, SQ);
+ case Instruction::Call: {
+ const CallInst *CI = cast<CallInst>(I);
+ switch (CI->getIntrinsicID()) {
+ case Intrinsic::trunc:
+ case Intrinsic::floor:
+ case Intrinsic::ceil:
+ case Intrinsic::rint:
+ case Intrinsic::nearbyint:
+ case Intrinsic::round:
+ case Intrinsic::roundeven:
+ return (FMF.noInfs() && FMF.noNaNs()) || isKnownNeverInfOrNaN(I, SQ);
+ default:
+ break;
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
Value *llvm::isBytewiseValue(Value *V, const DataLayout &DL) {
// All byte-wide stores are splatable, even of arbitrary variables.
diff --git a/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp b/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
index c5c19d9d572b7..4a553beb63bb1 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
@@ -47,9 +47,7 @@ namespace llvm {
class AMDGPULibCalls {
private:
- const TargetLibraryInfo *TLInfo = nullptr;
- AssumptionCache *AC = nullptr;
- DominatorTree *DT = nullptr;
+ SimplifyQuery SQ;
using FuncInfo = llvm::AMDGPULibFunc;
@@ -129,11 +127,10 @@ class AMDGPULibCalls {
}
public:
- AMDGPULibCalls() = default;
+ AMDGPULibCalls(Function &F, FunctionAnalysisManager &FAM);
bool fold(CallInst *CI);
- void initFunction(Function &F, FunctionAnalysisManager &FAM);
void initNativeFuncs();
// Replace a normal math function call with that native version
@@ -422,11 +419,11 @@ bool AMDGPULibCalls::canIncreasePrecisionOfConstantFold(
return FPOp->isFast();
}
-void AMDGPULibCalls::initFunction(Function &F, FunctionAnalysisManager &FAM) {
- AC = &FAM.getResult<AssumptionAnalysis>(F);
- TLInfo = &FAM.getResult<TargetLibraryAnalysis>(F);
- DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
-}
+AMDGPULibCalls::AMDGPULibCalls(Function &F, FunctionAnalysisManager &FAM)
+ : SQ(F.getParent()->getDataLayout(),
+ &FAM.getResult<TargetLibraryAnalysis>(F),
+ FAM.getCachedResult<DominatorTreeAnalysis>(F),
+ &FAM.getResult<AssumptionAnalysis>(F)) {}
bool AMDGPULibCalls::useNativeFunc(const StringRef F) const {
return AllNative || llvm::is_contained(UseNative, F);
@@ -563,74 +560,6 @@ bool AMDGPULibCalls::fold_read_write_pipe(CallInst *CI, IRBuilder<> &B,
return true;
}
-static bool isKnownIntegral(const Value *V, const DataLayout &DL,
- FastMathFlags FMF) {
- if (isa<PoisonValue>(V))
- return true;
- if (isa<UndefValue>(V))
- return false;
-
- if (const ConstantFP *CF = dyn_cast<ConstantFP>(V))
- return CF->getValueAPF().isInteger();
-
- auto *VFVTy = dyn_cast<FixedVectorType>(V->getType());
- const Constant *CV = dyn_cast<Constant>(V);
- if (VFVTy && CV) {
- unsigned NumElts = VFVTy->getNumElements();
- for (unsigned i = 0; i != NumElts; ++i) {
- Constant *Elt = CV->getAggregateElement(i);
- if (!Elt)
- return false;
- if (isa<PoisonValue>(Elt))
- continue;
-
- const ConstantFP *CFP = dyn_cast<ConstantFP>(Elt);
- if (!CFP || !CFP->getValue().isInteger())
- return false;
- }
-
- return true;
- }
-
- const Instruction *I = dyn_cast<Instruction>(V);
- if (!I)
- return false;
-
- switch (I->getOpcode()) {
- case Instruction::SIToFP:
- case Instruction::UIToFP:
- // TODO: Could check nofpclass(inf) on incoming argument
- if (FMF.noInfs())
- return true;
-
- // Need to check int size cannot produce infinity, which computeKnownFPClass
- // knows how to do already.
- return isKnownNeverInfinity(I, SimplifyQuery(DL));
- case Instruction::Call: {
- const CallInst *CI = cast<CallInst>(I);
- switch (CI->getIntrinsicID()) {
- case Intrinsic::trunc:
- case Intrinsic::floor:
- case Intrinsic::ceil:
- case Intrinsic::rint:
- case Intrinsic::nearbyint:
- case Intrinsic::round:
- case Intrinsic::roundeven:
- return (FMF.noInfs() && FMF.noNaNs()) ||
- isKnownNeverInfOrNaN(I, SimplifyQuery(DL));
- default:
- break;
- }
-
- break;
- }
- default:
- break;
- }
-
- return false;
-}
-
// This function returns false if no change; return true otherwise.
bool AMDGPULibCalls::fold(CallInst *CI) {
Function *Callee = CI->getCalledFunction();
@@ -753,16 +682,14 @@ bool AMDGPULibCalls::fold(CallInst *CI) {
// pow(x, y) -> powr(x, y) for x >= -0.0
// TODO: Account for flags on current call
- if (PowrFunc &&
- cannotBeOrderedLessThanZero(
- FPOp->getOperand(0),
- SimplifyQuery(M->getDataLayout(), TLInfo, DT, AC, Call))) {
+ if (PowrFunc && cannotBeOrderedLessThanZero(
+ FPOp->getOperand(0), SQ.getWithInstruction(Call))) {
Call->setCalledFunction(PowrFunc);
return fold_pow(FPOp, B, PowrInfo) || true;
}
// pow(x, y) -> pown(x, y) for known integral y
- if (isKnownIntegral(FPOp->getOperand(1), M->getDataLayout(),
+ if (isKnownIntegral(FPOp->getOperand(1), SQ.getWithInstruction(CI),
FPOp->getFastMathFlags())) {
FunctionType *PownType = getPownType(CI->getFunctionType());
AMDGPULibFunc PownInfo(AMDGPULibFunc::EI_POWN, PownType, true);
@@ -1084,7 +1011,8 @@ bool AMDGPULibCalls::fold_pow(FPMathOperator *FPOp, IRBuilder<> &B,
if (needcopysign && (FInfo.getId() == AMDGPULibFunc::EI_POW)) {
// We cannot handle corner cases for a general pow() function, give up
// unless y is a constant integral value. Then proceed as if it were pown.
- if (!isKnownIntegral(opr1, M->getDataLayout(), FPOp->getFastMathFlags()))
+ if (!isKnownIntegral(opr1, SQ.getWithInstruction(cast<Instruction>(FPOp)),
+ FPOp->getFastMathFlags()))
return false;
}
@@ -1699,9 +1627,8 @@ bool AMDGPULibCalls::evaluateCall(CallInst *aCI, const FuncInfo &FInfo) {
PreservedAnalyses AMDGPUSimplifyLibCallsPass::run(Function &F,
FunctionAnalysisManager &AM) {
- AMDGPULibCalls Simplifier;
+ AMDGPULibCalls Simplifier(F, AM);
Simplifier.initNativeFuncs();
- Simplifier.initFunction(F, AM);
bool Changed = false;
@@ -1728,9 +1655,8 @@ PreservedAnalyses AMDGPUUseNativeCallsPass::run(Function &F,
if (UseNative.empty())
return PreservedAnalyses::all();
- AMDGPULibCalls Simplifier;
+ AMDGPULibCalls Simplifier(F, AM);
Simplifier.initNativeFuncs();
- Simplifier.initFunction(F, AM);
bool Changed = false;
for (auto &BB : F) {
diff --git a/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-pow.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-pow.ll
index 091e5a67799a9..113531571757c 100644
--- a/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-pow.ll
+++ b/llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-pow.ll
@@ -2645,6 +2645,44 @@ define float @test_pow_f32__y_known_integral_nearbyint(float %x, float nofpclass
ret float %pow
}
+define float @test_pow_f32__y_known_integral_nearbyint_assume(float %x, float %y.arg) {
+; CHECK-LABEL: define float @test_pow_f32__y_known_integral_nearbyint_assume
+; CHECK-SAME: (float [[X:%.*]], float [[Y_ARG:%.*]]) {
+; CHECK-NEXT: [[Y:%.*]] = call float @llvm.nearbyint.f32(float [[Y_ARG]])
+; CHECK-NEXT: [[Y_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y]])
+; CHECK-NEXT: [[Y_IS_FINITE:%.*]] = fcmp one float [[Y_FABS]], 0x7FF0000000000000
+; CHECK-NEXT: call void @llvm.assume(i1 [[Y_IS_FINITE]])
+; CHECK-NEXT: [[TMP1:%.*]] = fptosi float [[Y]] to i32
+; CHECK-NEXT: [[POW:%.*]] = tail call float @_Z4pownfi(float [[X]], i32 [[TMP1]])
+; CHECK-NEXT: ret float [[POW]]
+;
+ %y = call float @llvm.nearbyint.f32(float %y.arg)
+ %y.fabs = call float @llvm.fabs.f32(float %y)
+ %y.is.finite = fcmp one float %y.fabs, 0x7FF0000000000000
+ call void @llvm.assume(i1 %y.is.finite)
+ %pow = tail call float @_Z3powff(float %x, float %y)
+ ret float %pow
+}
+
+define float @test_pow_f32__y_known_integral_nearbyint_assume_arg_input(float %x, float %y.arg) {
+; CHECK-LABEL: define float @test_pow_f32__y_known_integral_nearbyint_assume_arg_input
+; CHECK-SAME: (float [[X:%.*]], float [[Y_ARG:%.*]]) {
+; CHECK-NEXT: [[Y_ARG_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y_ARG]])
+; CHECK-NEXT: [[IS_FINITE:%.*]] = fcmp one float [[Y_ARG_FABS]], 0x7FF0000000000000
+; CHECK-NEXT: call void @llvm.assume(i1 [[IS_FINITE]])
+; CHECK-NEXT: [[Y:%.*]] = call float @llvm.nearbyint.f32(float [[Y_ARG]])
+; CHECK-NEXT: [[TMP1:%.*]] = fptosi float [[Y]] to i32
+; CHECK-NEXT: [[POW:%.*]] = tail call float @_Z4pownfi(float [[X]], i32 [[TMP1]])
+; CHECK-NEXT: ret float [[POW]]
+;
+ %y.arg.fabs = call float @llvm.fabs.f32(float %y.arg)
+ %is.finite = fcmp one float %y.arg.fabs, 0x7FF0000000000000
+ call void @llvm.assume(i1 %is.finite)
+ %y = call float @llvm.nearbyint.f32(float %y.arg)
+ %pow = tail call float @_Z3powff(float %x, float %y)
+ ret float %pow
+}
+
define float @test_pow_f32__y_known_integral_round(float %x, float nofpclass(inf nan) %y.arg) {
; CHECK-LABEL: define float @test_pow_f32__y_known_integral_round
; CHECK-SAME: (float [[X:%.*]], float nofpclass(nan inf) [[Y_ARG:%.*]]) {
More information about the llvm-commits
mailing list