Skip to content

Commit 112aac4

Browse files
authored
[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.
1 parent d2d947b commit 112aac4

File tree

3 files changed

+55
-9
lines changed

3 files changed

+55
-9
lines changed

llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ class LibCallSimplifier {
206206
Value *optimizeFMinFMax(CallInst *CI, IRBuilderBase &B);
207207
Value *optimizeLog(CallInst *CI, IRBuilderBase &B);
208208
Value *optimizeSqrt(CallInst *CI, IRBuilderBase &B);
209+
Value *optimizeFMod(CallInst *CI, IRBuilderBase &B);
209210
Value *mergeSqrtToExp(CallInst *CI, IRBuilderBase &B);
210211
Value *optimizeSinCosPi(CallInst *CI, bool IsSin, IRBuilderBase &B);
211212
Value *optimizeTrigInversionPairs(CallInst *CI, IRBuilderBase &B);

llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2796,6 +2796,35 @@ Value *LibCallSimplifier::optimizeSqrt(CallInst *CI, IRBuilderBase &B) {
27962796
return copyFlags(*CI, FabsCall);
27972797
}
27982798

2799+
Value *LibCallSimplifier::optimizeFMod(CallInst *CI, IRBuilderBase &B) {
2800+
SimplifyQuery SQ(DL, TLI, DT, AC, CI, true, true, DC);
2801+
2802+
// fmod(x,y) can set errno if y == 0 or x == +/-inf, and returns Nan in those
2803+
// case. If we know those do not happen, then we can convert the fmod into
2804+
// frem.
2805+
bool IsNoNan = CI->hasNoNaNs();
2806+
if (!IsNoNan) {
2807+
KnownFPClass Known0 = computeKnownFPClass(CI->getOperand(0), fcInf,
2808+
/*Depth=*/0, SQ);
2809+
if (Known0.isKnownNeverInfinity()) {
2810+
KnownFPClass Known1 =
2811+
computeKnownFPClass(CI->getOperand(1), fcZero | fcSubnormal,
2812+
/*Depth=*/0, SQ);
2813+
Function *F = CI->getParent()->getParent();
2814+
if (Known1.isKnownNeverLogicalZero(*F, CI->getType()))
2815+
IsNoNan = true;
2816+
}
2817+
}
2818+
2819+
if (IsNoNan) {
2820+
Value *FRem = B.CreateFRemFMF(CI->getOperand(0), CI->getOperand(1), CI);
2821+
if (auto *FRemI = dyn_cast<Instruction>(FRem))
2822+
FRemI->setHasNoNaNs(true);
2823+
substituteInParent(CI, FRem);
2824+
}
2825+
return nullptr;
2826+
}
2827+
27992828
Value *LibCallSimplifier::optimizeTrigInversionPairs(CallInst *CI,
28002829
IRBuilderBase &B) {
28012830
Module *M = CI->getModule();
@@ -3945,6 +3974,10 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
39453974
case LibFunc_sqrt:
39463975
case LibFunc_sqrtl:
39473976
return optimizeSqrt(CI, Builder);
3977+
case LibFunc_fmod:
3978+
case LibFunc_fmodf:
3979+
case LibFunc_fmodl:
3980+
return optimizeFMod(CI, Builder);
39483981
case LibFunc_logf:
39493982
case LibFunc_log:
39503983
case LibFunc_logl:

llvm/test/Transforms/InstCombine/fmod.ll

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ define float @test_inf_const(float %f) {
99
; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq float [[ABS]], 0x7FF0000000000000
1010
; CHECK-NEXT: br i1 [[ISINF]], label [[RETURN:%.*]], label [[IF_END:%.*]]
1111
; CHECK: if.end:
12-
; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float [[F]], float 2.000000e+00)
12+
; CHECK-NEXT: [[CALL:%.*]] = frem nnan float [[F]], 2.000000e+00
1313
; CHECK-NEXT: ret float [[CALL]]
1414
; CHECK: return:
1515
; CHECK-NEXT: ret float 0.000000e+00
@@ -34,7 +34,7 @@ define float @test_const_zero(float %f) {
3434
; CHECK-NEXT: [[ISZERO:%.*]] = fcmp oeq float [[F]], 0.000000e+00
3535
; CHECK-NEXT: br i1 [[ISZERO]], label [[RETURN:%.*]], label [[IF_END:%.*]]
3636
; CHECK: if.end:
37-
; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float 2.000000e+00, float [[F]])
37+
; CHECK-NEXT: [[CALL:%.*]] = frem nnan float 2.000000e+00, [[F]]
3838
; CHECK-NEXT: ret float [[CALL]]
3939
; CHECK: return:
4040
; CHECK-NEXT: ret float 0.000000e+00
@@ -67,19 +67,19 @@ define float @test_noinf_nozero(float nofpclass(inf) %f, float nofpclass(zero) %
6767
; CHECK-LABEL: define float @test_noinf_nozero(
6868
; CHECK-SAME: float nofpclass(inf) [[F:%.*]], float nofpclass(zero) [[G:%.*]]) {
6969
; CHECK-NEXT: entry:
70-
; CHECK-NEXT: [[CALL:%.*]] = tail call nnan float @fmodf(float [[F]], float [[G]])
70+
; CHECK-NEXT: [[CALL:%.*]] = frem nnan float [[F]], [[G]]
7171
; CHECK-NEXT: ret float [[CALL]]
7272
;
7373
entry:
74-
%call = tail call nnan float @fmodf(float %f, float %g)
74+
%call = tail call float @fmodf(float %f, float %g)
7575
ret float %call
7676
}
7777

7878
define double @test_double(double nofpclass(inf) %f, double nofpclass(zero) %g) {
7979
; CHECK-LABEL: define double @test_double(
8080
; CHECK-SAME: double nofpclass(inf) [[F:%.*]], double nofpclass(zero) [[G:%.*]]) {
8181
; CHECK-NEXT: entry:
82-
; CHECK-NEXT: [[CALL:%.*]] = tail call double @fmod(double [[F]], double [[G]])
82+
; CHECK-NEXT: [[CALL:%.*]] = frem nnan double [[F]], [[G]]
8383
; CHECK-NEXT: ret double [[CALL]]
8484
;
8585
entry:
@@ -91,7 +91,7 @@ define fp128 @test_fp128(fp128 nofpclass(inf) %f, fp128 nofpclass(zero) %g) {
9191
; CHECK-LABEL: define fp128 @test_fp128(
9292
; CHECK-SAME: fp128 nofpclass(inf) [[F:%.*]], fp128 nofpclass(zero) [[G:%.*]]) {
9393
; CHECK-NEXT: entry:
94-
; CHECK-NEXT: [[CALL:%.*]] = tail call fp128 @fmodl(fp128 [[F]], fp128 [[G]])
94+
; CHECK-NEXT: [[CALL:%.*]] = frem nnan fp128 [[F]], [[G]]
9595
; CHECK-NEXT: ret fp128 [[CALL]]
9696
;
9797
entry:
@@ -103,19 +103,31 @@ define float @test_noinf_nozero_dazpreservesign(float nofpclass(inf) %f, float n
103103
; CHECK-LABEL: define float @test_noinf_nozero_dazpreservesign(
104104
; CHECK-SAME: float nofpclass(inf) [[F:%.*]], float nofpclass(zero) [[G:%.*]]) #[[ATTR0:[0-9]+]] {
105105
; CHECK-NEXT: entry:
106-
; CHECK-NEXT: [[CALL:%.*]] = tail call nnan float @fmodf(float [[F]], float [[G]])
106+
; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float [[F]], float [[G]])
107107
; CHECK-NEXT: ret float [[CALL]]
108108
;
109109
entry:
110-
%call = tail call nnan float @fmodf(float %f, float %g)
110+
%call = tail call float @fmodf(float %f, float %g)
111111
ret float %call
112112
}
113113

114114
define float @test_noinf_nozero_dazdynamic(float nofpclass(inf) %f, float nofpclass(zero) %g) "denormal-fp-math"="dynamic,dynamic" {
115115
; CHECK-LABEL: define float @test_noinf_nozero_dazdynamic(
116116
; CHECK-SAME: float nofpclass(inf) [[F:%.*]], float nofpclass(zero) [[G:%.*]]) #[[ATTR1:[0-9]+]] {
117117
; CHECK-NEXT: entry:
118-
; CHECK-NEXT: [[CALL:%.*]] = tail call nnan float @fmodf(float [[F]], float [[G]])
118+
; CHECK-NEXT: [[CALL:%.*]] = tail call float @fmodf(float [[F]], float [[G]])
119+
; CHECK-NEXT: ret float [[CALL]]
120+
;
121+
entry:
122+
%call = tail call float @fmodf(float %f, float %g)
123+
ret float %call
124+
}
125+
126+
define float @test_nnan(float %f, float %g) {
127+
; CHECK-LABEL: define float @test_nnan(
128+
; CHECK-SAME: float [[F:%.*]], float [[G:%.*]]) {
129+
; CHECK-NEXT: entry:
130+
; CHECK-NEXT: [[CALL:%.*]] = frem nnan float [[F]], [[G]]
119131
; CHECK-NEXT: ret float [[CALL]]
120132
;
121133
entry:

0 commit comments

Comments
 (0)