[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