diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h index 2e7a0ec29ed999..2d3d2ada6183a7 100644 --- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -206,6 +206,7 @@ class LibCallSimplifier { Value *optimizeFMinFMax(CallInst *CI, IRBuilderBase &B); Value *optimizeLog(CallInst *CI, IRBuilderBase &B); Value *optimizeSqrt(CallInst *CI, IRBuilderBase &B); + Value *optimizeFMod(CallInst *CI, IRBuilderBase &B); Value *mergeSqrtToExp(CallInst *CI, IRBuilderBase &B); Value *optimizeSinCosPi(CallInst *CI, bool IsSin, IRBuilderBase &B); Value *optimizeTrigInversionPairs(CallInst *CI, IRBuilderBase &B); diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 917f81863cf673..4933b5bf60eea8 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(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: diff --git a/llvm/test/Transforms/InstCombine/fmod.ll b/llvm/test/Transforms/InstCombine/fmod.ll index c021d27e95fa5e..10cff189b8dfca 100644 --- a/llvm/test/Transforms/InstCombine/fmod.ll +++ b/llvm/test/Transforms/InstCombine/fmod.ll @@ -9,7 +9,7 @@ define float @test_inf_const(float %f) { ; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq float [[ABS]], 0x7FF0000000000000 ; CHECK-NEXT: br i1 [[ISINF]], label [[RETURN:%.*]], label [[IF_END:%.*]] ; CHECK: if.end: -; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float [[F]], float 2.000000e+00) +; CHECK-NEXT: [[CALL:%.*]] = frem nnan float [[F]], 2.000000e+00 ; CHECK-NEXT: ret float [[CALL]] ; CHECK: return: ; CHECK-NEXT: ret float 0.000000e+00 @@ -34,7 +34,7 @@ define float @test_const_zero(float %f) { ; CHECK-NEXT: [[ISZERO:%.*]] = fcmp oeq float [[F]], 0.000000e+00 ; CHECK-NEXT: br i1 [[ISZERO]], label [[RETURN:%.*]], label [[IF_END:%.*]] ; CHECK: if.end: -; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float 2.000000e+00, float [[F]]) +; CHECK-NEXT: [[CALL:%.*]] = frem nnan float 2.000000e+00, [[F]] ; CHECK-NEXT: ret float [[CALL]] ; CHECK: return: ; CHECK-NEXT: ret float 0.000000e+00 @@ -67,11 +67,11 @@ define float @test_noinf_nozero(float nofpclass(inf) %f, float nofpclass(zero) % ; CHECK-LABEL: define float @test_noinf_nozero( ; CHECK-SAME: float nofpclass(inf) [[F:%.*]], float nofpclass(zero) [[G:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan float @fmodf(float [[F]], float [[G]]) +; CHECK-NEXT: [[CALL:%.*]] = frem nnan float [[F]], [[G]] ; CHECK-NEXT: ret float [[CALL]] ; entry: - %call = tail call nnan float @fmodf(float %f, float %g) + %call = tail call float @fmodf(float %f, float %g) ret float %call } @@ -79,7 +79,7 @@ define double @test_double(double nofpclass(inf) %f, double nofpclass(zero) %g) ; CHECK-LABEL: define double @test_double( ; CHECK-SAME: double nofpclass(inf) [[F:%.*]], double nofpclass(zero) [[G:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = tail call double @fmod(double [[F]], double [[G]]) +; CHECK-NEXT: [[CALL:%.*]] = frem nnan double [[F]], [[G]] ; CHECK-NEXT: ret double [[CALL]] ; entry: @@ -91,7 +91,7 @@ define fp128 @test_fp128(fp128 nofpclass(inf) %f, fp128 nofpclass(zero) %g) { ; CHECK-LABEL: define fp128 @test_fp128( ; CHECK-SAME: fp128 nofpclass(inf) [[F:%.*]], fp128 nofpclass(zero) [[G:%.*]]) { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = tail call fp128 @fmodl(fp128 [[F]], fp128 [[G]]) +; CHECK-NEXT: [[CALL:%.*]] = frem nnan fp128 [[F]], [[G]] ; CHECK-NEXT: ret fp128 [[CALL]] ; entry: @@ -103,11 +103,11 @@ define float @test_noinf_nozero_dazpreservesign(float nofpclass(inf) %f, float n ; CHECK-LABEL: define float @test_noinf_nozero_dazpreservesign( ; CHECK-SAME: float nofpclass(inf) [[F:%.*]], float nofpclass(zero) [[G:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan float @fmodf(float [[F]], float [[G]]) +; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float [[F]], float [[G]]) ; CHECK-NEXT: ret float [[CALL]] ; entry: - %call = tail call nnan float @fmodf(float %f, float %g) + %call = tail call float @fmodf(float %f, float %g) ret float %call } @@ -115,7 +115,19 @@ define float @test_noinf_nozero_dazdynamic(float nofpclass(inf) %f, float nofpcl ; CHECK-LABEL: define float @test_noinf_nozero_dazdynamic( ; CHECK-SAME: float nofpclass(inf) [[F:%.*]], float nofpclass(zero) [[G:%.*]]) #[[ATTR1:[0-9]+]] { ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan float @fmodf(float [[F]], float [[G]]) +; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float [[F]], float [[G]]) +; CHECK-NEXT: ret float [[CALL]] +; +entry: + %call = tail call float @fmodf(float %f, float %g) + ret float %call +} + +define float @test_nnan(float %f, float %g) { +; CHECK-LABEL: define float @test_nnan( +; CHECK-SAME: float [[F:%.*]], float [[G:%.*]]) { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = frem nnan float [[F]], [[G]] ; CHECK-NEXT: ret float [[CALL]] ; entry: