aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
diff options
context:
space:
mode:
authorDavid Green <david.green@arm.com>2024-09-18 09:38:28 +0100
committerGitHub <noreply@github.com>2024-09-18 09:38:28 +0100
commit112aac4e8961b9626bb84f36deeaa5a674f03f5a (patch)
tree9f16f417df98f1bd91143a9acbc983d7be2be61f /llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
parentd2d947b7e24679e0d1710a4f31dc0c8c9ee7c0b7 (diff)
downloadllvm-112aac4e8961b9626bb84f36deeaa5a674f03f5a.zip
llvm-112aac4e8961b9626bb84f36deeaa5a674f03f5a.tar.gz
llvm-112aac4e8961b9626bb84f36deeaa5a674f03f5a.tar.bz2
[InstCombine] Fold fmod to frem if we know it does not set errno. (#107912)
fmod will be folded to frem in clang under -fno-math-errno and can be constant folded in llvm if the operands are known. It can be relatively common to have fp code that handles special values before doing some calculation: ``` if (isnan(f)) return handlenan; if (isinf(f)) return handleinf; .. fmod(f, 2.0) ``` This patch enables the folding of fmod to frem in instcombine if the first parameter is not inf and the second is not zero. Other combinations do not set errno. The same transform is performed for fmod with the nnan flag, which implies the input is known to not be inf/zero.
Diffstat (limited to 'llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp33
1 files changed, 33 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 917f818..4933b5b 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -2796,6 +2796,35 @@ Value *LibCallSimplifier::optimizeSqrt(CallInst *CI, IRBuilderBase &B) {
return copyFlags(*CI, FabsCall);
}
+Value *LibCallSimplifier::optimizeFMod(CallInst *CI, IRBuilderBase &B) {
+ SimplifyQuery SQ(DL, TLI, DT, AC, CI, true, true, DC);
+
+ // fmod(x,y) can set errno if y == 0 or x == +/-inf, and returns Nan in those
+ // case. If we know those do not happen, then we can convert the fmod into
+ // frem.
+ bool IsNoNan = CI->hasNoNaNs();
+ if (!IsNoNan) {
+ KnownFPClass Known0 = computeKnownFPClass(CI->getOperand(0), fcInf,
+ /*Depth=*/0, SQ);
+ if (Known0.isKnownNeverInfinity()) {
+ KnownFPClass Known1 =
+ computeKnownFPClass(CI->getOperand(1), fcZero | fcSubnormal,
+ /*Depth=*/0, SQ);
+ Function *F = CI->getParent()->getParent();
+ if (Known1.isKnownNeverLogicalZero(*F, CI->getType()))
+ IsNoNan = true;
+ }
+ }
+
+ if (IsNoNan) {
+ Value *FRem = B.CreateFRemFMF(CI->getOperand(0), CI->getOperand(1), CI);
+ if (auto *FRemI = dyn_cast<Instruction>(FRem))
+ FRemI->setHasNoNaNs(true);
+ substituteInParent(CI, FRem);
+ }
+ return nullptr;
+}
+
Value *LibCallSimplifier::optimizeTrigInversionPairs(CallInst *CI,
IRBuilderBase &B) {
Module *M = CI->getModule();
@@ -3945,6 +3974,10 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
case LibFunc_sqrt:
case LibFunc_sqrtl:
return optimizeSqrt(CI, Builder);
+ case LibFunc_fmod:
+ case LibFunc_fmodf:
+ case LibFunc_fmodl:
+ return optimizeFMod(CI, Builder);
case LibFunc_logf:
case LibFunc_log:
case LibFunc_logl: