Skip to content

Commit 9fc5d57

Browse files
committed
[ConstantFolding] Fold nextafter/nextafterf/nexttoward/nexttowardf
1 parent b7e922a commit 9fc5d57

File tree

6 files changed

+180
-4
lines changed

6 files changed

+180
-4
lines changed

llvm/include/llvm/ADT/APFloat.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,16 @@ class APFloat : public APFloatBase {
11491149
/// \param Semantics - type float semantics
11501150
LLVM_ABI static APFloat getAllOnesValue(const fltSemantics &Semantics);
11511151

1152+
APFloat getExtended(const fltSemantics &Sem) const {
1153+
assert(isRepresentableBy(this->getSemantics(), Sem) &&
1154+
"Target semantics will lose information.");
1155+
APFloat Val(*this);
1156+
bool LosesInfo;
1157+
Val.convert(Sem, rmNearestTiesToEven, &LosesInfo);
1158+
assert(!LosesInfo);
1159+
return Val;
1160+
}
1161+
11521162
/// Returns true if the given semantics has actual significand.
11531163
///
11541164
/// \param Sem - type float semantics

llvm/include/llvm/Analysis/TargetLibraryInfo.def

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,6 +1951,36 @@ TLI_DEFINE_ENUM_INTERNAL(nearbyintl)
19511951
TLI_DEFINE_STRING_INTERNAL("nearbyintl")
19521952
TLI_DEFINE_SIG_INTERNAL(LDbl, LDbl)
19531953

1954+
/// double nextafter(double x, double y);
1955+
TLI_DEFINE_ENUM_INTERNAL(nextafter)
1956+
TLI_DEFINE_STRING_INTERNAL("nextafter")
1957+
TLI_DEFINE_SIG_INTERNAL(Dbl, Dbl, Dbl)
1958+
1959+
/// float nextafterf(float x, float y);
1960+
TLI_DEFINE_ENUM_INTERNAL(nextafterf)
1961+
TLI_DEFINE_STRING_INTERNAL("nextafterf")
1962+
TLI_DEFINE_SIG_INTERNAL(Flt, Flt, Flt)
1963+
1964+
/// long double nextafterl(long double x, long double y);
1965+
TLI_DEFINE_ENUM_INTERNAL(nextafterl)
1966+
TLI_DEFINE_STRING_INTERNAL("nextafterl")
1967+
TLI_DEFINE_SIG_INTERNAL(LDbl, LDbl, LDbl)
1968+
1969+
/// double nexttoward(double x, long double y);
1970+
TLI_DEFINE_ENUM_INTERNAL(nexttoward)
1971+
TLI_DEFINE_STRING_INTERNAL("nexttoward")
1972+
TLI_DEFINE_SIG_INTERNAL(Dbl, Dbl, LDbl)
1973+
1974+
/// float nexttowardf(float x, long double y);
1975+
TLI_DEFINE_ENUM_INTERNAL(nexttowardf)
1976+
TLI_DEFINE_STRING_INTERNAL("nexttowardf")
1977+
TLI_DEFINE_SIG_INTERNAL(Flt, Flt, LDbl)
1978+
1979+
/// long double nexttowardl(long double x, long double y);
1980+
TLI_DEFINE_ENUM_INTERNAL(nexttowardl)
1981+
TLI_DEFINE_STRING_INTERNAL("nexttowardl")
1982+
TLI_DEFINE_SIG_INTERNAL(LDbl, LDbl, LDbl)
1983+
19541984
/// uint32_t ntohl(uint32_t netlong);
19551985
TLI_DEFINE_ENUM_INTERNAL(ntohl)
19561986
TLI_DEFINE_STRING_INTERNAL("ntohl")

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1996,7 +1996,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
19961996
Name == "log10f" || Name == "logb" || Name == "logbf" ||
19971997
Name == "log1p" || Name == "log1pf";
19981998
case 'n':
1999-
return Name == "nearbyint" || Name == "nearbyintf";
1999+
return Name == "nearbyint" || Name == "nearbyintf" || "nextafter" ||
2000+
"nextafterf" || "nexttoward" || "nexttowardf";
20002001
case 'p':
20012002
return Name == "pow" || Name == "powf";
20022003
case 'r':
@@ -3221,6 +3222,17 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
32213222
if (TLI->has(Func))
32223223
return ConstantFoldBinaryFP(atan2, Op1V, Op2V, Ty);
32233224
break;
3225+
case LibFunc_nextafter:
3226+
case LibFunc_nextafterf:
3227+
case LibFunc_nexttoward:
3228+
case LibFunc_nexttowardf:
3229+
if (TLI->has(Func)) {
3230+
APFloat Next(Op1V);
3231+
bool ShouldGoDown = Op1V.getExtended(APFloat::IEEEquad()) >
3232+
Op2V.getExtended(APFloat::IEEEquad());
3233+
Next.next(ShouldGoDown);
3234+
return GetConstantFoldFPValue(Next.convertToDouble(), Ty);
3235+
}
32243236
}
32253237

32263238
return nullptr;
@@ -4655,6 +4667,34 @@ bool llvm::isMathLibCallNoop(const CallBase *Call,
46554667
// may occur, so allow for that possibility.
46564668
return !Op0.isZero() || !Op1.isZero();
46574669

4670+
case LibFunc_nextafter:
4671+
case LibFunc_nextafterf:
4672+
case LibFunc_nextafterl:
4673+
case LibFunc_nexttoward:
4674+
case LibFunc_nexttowardf:
4675+
case LibFunc_nexttowardl: {
4676+
APFloat Extended0 = Op0.getExtended(APFloat::IEEEquad());
4677+
APFloat Extended1 = Op1.getExtended(APFloat::IEEEquad());
4678+
if (Extended0 == Extended1)
4679+
return true;
4680+
4681+
bool NextGoesDown = Extended0 > Extended1;
4682+
if (Op0.isLargest()) {
4683+
if (Op0.isNegative() && NextGoesDown)
4684+
return false;
4685+
if (!Op0.isNegative() && !NextGoesDown)
4686+
return false;
4687+
}
4688+
4689+
if (Op0.isSmallest() || Op0.isSmallestNormalized()) {
4690+
if (Op0.isNegative() && !NextGoesDown)
4691+
return false;
4692+
if (!Op0.isNegative() && NextGoesDown)
4693+
return false;
4694+
}
4695+
4696+
return true;
4697+
}
46584698
default:
46594699
break;
46604700
}

llvm/lib/Analysis/TargetLibraryInfo.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ static void initializeLibCalls(TargetLibraryInfoImpl &TLI, const Triple &T,
388388
TLI.setAvailableWithName(LibFunc_logbf, "_logbf");
389389
else
390390
TLI.setUnavailable(LibFunc_logbf);
391+
TLI.setUnavailable(LibFunc_nextafter);
392+
TLI.setUnavailable(LibFunc_nextafterf);
393+
TLI.setUnavailable(LibFunc_nexttoward);
394+
TLI.setUnavailable(LibFunc_nexttowardf);
391395
TLI.setUnavailable(LibFunc_rint);
392396
TLI.setUnavailable(LibFunc_rintf);
393397
TLI.setUnavailable(LibFunc_round);
@@ -418,6 +422,8 @@ static void initializeLibCalls(TargetLibraryInfoImpl &TLI, const Triple &T,
418422
TLI.setUnavailable(LibFunc_logbl);
419423
TLI.setUnavailable(LibFunc_ilogbl);
420424
TLI.setUnavailable(LibFunc_nearbyintl);
425+
TLI.setUnavailable(LibFunc_nextafterl);
426+
TLI.setUnavailable(LibFunc_nexttowardl);
421427
TLI.setUnavailable(LibFunc_rintl);
422428
TLI.setUnavailable(LibFunc_roundl);
423429
TLI.setUnavailable(LibFunc_scalblnl);

llvm/lib/Transforms/Utils/BuildLibCalls.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,13 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
12831283
case LibFunc_ilogbl:
12841284
case LibFunc_logf:
12851285
case LibFunc_logl:
1286+
case LibFunc_nearbyint:
1287+
case LibFunc_nearbyintf:
1288+
case LibFunc_nearbyintl:
1289+
case LibFunc_nextafter:
1290+
case LibFunc_nextafterf:
1291+
case LibFunc_nexttoward:
1292+
case LibFunc_nexttowardf:
12861293
case LibFunc_pow:
12871294
case LibFunc_powf:
12881295
case LibFunc_powl:
@@ -1352,9 +1359,6 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
13521359
case LibFunc_fminl:
13531360
case LibFunc_labs:
13541361
case LibFunc_llabs:
1355-
case LibFunc_nearbyint:
1356-
case LibFunc_nearbyintf:
1357-
case LibFunc_nearbyintl:
13581362
case LibFunc_toascii:
13591363
case LibFunc_trunc:
13601364
case LibFunc_truncf:
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
2+
; RUN: opt -passes=inferattrs,instcombine -S < %s | FileCheck %s
3+
4+
declare double @nextafter(double noundef, double noundef)
5+
declare float @nextafterf(float noundef, float noundef)
6+
declare double @nexttoward(double noundef, fp128 noundef)
7+
declare float @nexttowardf(float noundef, fp128 noundef)
8+
9+
; ==================
10+
; nextafter tests
11+
; ==================
12+
13+
;define float @nextafter_can_constant_fold_up_direction() {}
14+
;define float @nextafter_can_constant_fold_down_direction() {}
15+
;define float @nextafter_can_constant_fold_with_atleast_one_nan_arg() {}
16+
;define float @nextafter_can_constant_fold_with_both_args_pos_infinite() {}
17+
;define float @nextafter_can_constant_fold_with_both_args_neg_infinite() {}
18+
;define float @nextafter_no_constant_fold_on_overflow () {}
19+
;define float @nextafter_no_constant_fold_on_underflow() {}
20+
;define float @nextafter_no_constant_fold_on_zero_from_above() {}
21+
;define float @nextafter_no_constant_fold_on_zero_from_below() {}
22+
;define float @nextafter_no_constant_fold_on_crossing_subnormal_boundary_from_above() {}
23+
;define float @nextafter_no_constant_fold_on_crossing_subnormal_boundary_from_below() {}
24+
25+
; ==================
26+
; nextafterf tests
27+
; ==================
28+
29+
define float @nextafterf_can_constant_fold_up_direction() {
30+
; CHECK-LABEL: define float @nextafterf_can_constant_fold_up_direction() {
31+
; CHECK-NEXT: ret float 0x3FF0000020000000
32+
;
33+
%next = call float @nextafterf(float noundef 1.0, float noundef 2.0)
34+
ret float %next
35+
}
36+
37+
;define float @nextafterf_can_constant_fold_down_direction() {}
38+
;define float @nextafterf_can_constant_fold_with_atleast_one_nan_arg() {}
39+
;define float @nextafterf_can_constant_fold_with_both_args_pos_infinite() {}
40+
;define float @nextafterf_can_constant_fold_with_both_args_neg_infinite() {}
41+
;
42+
define float @nextafterf_no_constant_fold_on_overflow() {
43+
; CHECK-LABEL: define float @nextafterf_no_constant_fold_on_overflow() {
44+
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 0x47EFFFFFE0000000, float noundef 0x7FF0000000000000)
45+
; CHECK-NEXT: ret float 0x7FF0000000000000
46+
;
47+
%next = call float @nextafterf(float noundef 0x47EFFFFFE0000000, float noundef 0x7FF0000000000000)
48+
ret float %next
49+
}
50+
;define float @nextafterf_no_constant_fold_on_underflow() {}
51+
;define float @nextafterf_no_constant_fold_on_zero_from_above() {}
52+
;define float @nextafterf_no_constant_fold_on_zero_from_below() {}
53+
;define float @nextafterf_no_constant_fold_on_crossing_subnormal_boundary_from_above() {}
54+
;define float @nextafterf_no_constant_fold_on_crossing_subnormal_boundary_from_below() {}
55+
56+
; ==================
57+
; nexttoward tests
58+
; ==================
59+
60+
;define float @nexttoward_can_constant_fold_up_direction() {}
61+
;define float @nexttoward_can_constant_fold_down_direction() {}
62+
;define float @nexttoward_can_constant_fold_with_atleast_one_nan_arg() {}
63+
;define float @nexttoward_can_constant_fold_with_both_args_pos_infinite() {}
64+
;define float @nexttoward_can_constant_fold_with_both_args_neg_infinite() {}
65+
;define float @nexttoward_no_constant_fold_on_overflow () {}
66+
;define float @nexttoward_no_constant_fold_on_underflow() {}
67+
;define float @nexttoward_no_constant_fold_on_zero_from_above() {}
68+
;define float @nexttoward_no_constant_fold_on_zero_from_below() {}
69+
;define float @nexttoward_no_constant_fold_on_crossing_subnormal_boundary_from_above() {}
70+
;define float @nexttoward_no_constant_fold_on_crossing_subnormal_boundary_from_below() {}
71+
72+
; ==================
73+
; nexttowardf tests
74+
; ==================
75+
76+
;define float @nexttowardf_can_constant_fold_up_direction() {}
77+
;define float @nexttowardf_can_constant_fold_down_direction() {}
78+
;define float @nexttowardf_can_constant_fold_with_atleast_one_nan_arg() {}
79+
;define float @nexttowardf_can_constant_fold_with_both_args_pos_infinite() {}
80+
;define float @nexttowardf_can_constant_fold_with_both_args_neg_infinite() {}
81+
;define float @nexttowardf_no_constant_fold_on_overflow () {}
82+
;define float @nexttowardf_no_constant_fold_on_underflow() {}
83+
;define float @nexttowardf_no_constant_fold_on_zero_from_above() {}
84+
;define float @nexttowardf_no_constant_fold_on_zero_from_below() {}
85+
;define float @nexttowardf_no_constant_fold_on_crossing_subnormal_boundary_from_above() {}
86+
;define float @nexttowardf_no_constant_fold_on_crossing_subnormal_boundary_from_below() {}

0 commit comments

Comments
 (0)