Skip to content

Commit e94017f

Browse files
committed
Add constantfolding for nextafter/nexttoward
1 parent 0065b07 commit e94017f

File tree

6 files changed

+127
-108
lines changed

6 files changed

+127
-108
lines changed

llvm/include/llvm/ADT/APFloat.h

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

1152+
/// Returns a copy of this APFloat with the requested semantics.
1153+
/// The requested semantics should be equal to or stronger
1154+
/// than the semantics of the current instance.
1155+
APFloat getPromoted(const fltSemantics &Sem) const {
1156+
assert(isRepresentableBy(this->getSemantics(), Sem) &&
1157+
"Target semantics will lose information.");
1158+
APFloat Val(*this);
1159+
bool LosesInfo;
1160+
Val.convert(Sem, rmNearestTiesToEven, &LosesInfo);
1161+
assert(!LosesInfo);
1162+
return Val;
1163+
}
1164+
11521165
/// Returns true if the given semantics has actual significand.
11531166
///
11541167
/// \param Sem - type float semantics

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1996,7 +1996,9 @@ 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" || Name == "nextafter" ||
2000+
Name == "nextafterf" || Name == "nexttoward" ||
2001+
Name == "nexttowardf";
20002002
case 'p':
20012003
return Name == "pow" || Name == "powf";
20022004
case 'r':
@@ -3221,6 +3223,26 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
32213223
if (TLI->has(Func))
32223224
return ConstantFoldBinaryFP(atan2, Op1V, Op2V, Ty);
32233225
break;
3226+
case LibFunc_nextafter:
3227+
case LibFunc_nextafterf:
3228+
case LibFunc_nexttoward:
3229+
case LibFunc_nexttowardf:
3230+
if (TLI->has(Func)) {
3231+
if (Op1V.isNaN() || Op2V.isNaN()) {
3232+
return ConstantFP::get(Ty->getContext(),
3233+
APFloat::getNaN(Ty->getFltSemantics()));
3234+
}
3235+
3236+
APFloat PromotedOp1V = Op1V.getPromoted(APFloat::IEEEquad());
3237+
APFloat PromotedOp2V = Op2V.getPromoted(APFloat::IEEEquad());
3238+
if (PromotedOp1V == PromotedOp2V) {
3239+
return ConstantFP::get(Ty->getContext(), Op1V);
3240+
}
3241+
3242+
APFloat Next(Op1V);
3243+
Next.next(/*nextDown=*/PromotedOp1V > PromotedOp2V);
3244+
return ConstantFP::get(Ty->getContext(), Next);
3245+
}
32243246
}
32253247

32263248
return nullptr;
@@ -4655,6 +4677,22 @@ bool llvm::isMathLibCallNoop(const CallBase *Call,
46554677
// may occur, so allow for that possibility.
46564678
return !Op0.isZero() || !Op1.isZero();
46574679

4680+
case LibFunc_nextafter:
4681+
case LibFunc_nextafterf:
4682+
case LibFunc_nextafterl:
4683+
case LibFunc_nexttoward:
4684+
case LibFunc_nexttowardf:
4685+
case LibFunc_nexttowardl: {
4686+
APFloat PromotedOp0 = Op0.getPromoted(APFloat::IEEEquad());
4687+
APFloat PromotedOp1 = Op1.getPromoted(APFloat::IEEEquad());
4688+
if (PromotedOp0 == PromotedOp1)
4689+
return true;
4690+
4691+
APFloat Next(Op0);
4692+
Next.next(/*nextDown=*/PromotedOp0 > PromotedOp1);
4693+
bool DidOverflow = Op0.isLargest() && Next.isInfinity();
4694+
return !Next.isZero() && !Next.isDenormal() && !DidOverflow;
4695+
}
46584696
default:
46594697
break;
46604698
}

llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,28 @@ attributes #0 = { willreturn memory(errnomem: write) }
1212

1313
define double @nextafter_can_constant_fold_up_direction() {
1414
; CHECK-LABEL: define double @nextafter_can_constant_fold_up_direction() {
15-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 2.000000e+00)
16-
; CHECK-NEXT: ret double [[NEXT]]
15+
; CHECK-NEXT: ret double 0x3FF0000000000001
1716
;
1817
%next = call double @nextafter(double noundef 1.0, double noundef 2.0)
1918
ret double %next
2019
}
2120
define double @nextafter_can_constant_fold_down_direction() {
2221
; CHECK-LABEL: define double @nextafter_can_constant_fold_down_direction() {
23-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 0.000000e+00)
24-
; CHECK-NEXT: ret double [[NEXT]]
22+
; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF
2523
;
2624
%next = call double @nextafter(double noundef 1.0, double noundef 0.0)
2725
ret double %next
2826
}
2927
define double @nextafter_can_constant_fold_equal_args() {
3028
; CHECK-LABEL: define double @nextafter_can_constant_fold_equal_args() {
31-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 1.000000e+00)
32-
; CHECK-NEXT: ret double [[NEXT]]
29+
; CHECK-NEXT: ret double 1.000000e+00
3330
;
3431
%next = call double @nextafter(double noundef 1.0, double noundef 1.0)
3532
ret double %next
3633
}
3734
define double @nextafter_can_constant_fold_with_nan_arg() {
3835
; CHECK-LABEL: define double @nextafter_can_constant_fold_with_nan_arg() {
39-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 1.000000e+00, double 0x7FF8000000000000)
40-
; CHECK-NEXT: ret double [[NEXT]]
36+
; CHECK-NEXT: ret double 0x7FF8000000000000
4137
;
4238
%arg = load double, double* @dbl_nan
4339
%next = call double @nextafter(double 1.0, double %arg)
@@ -46,7 +42,7 @@ define double @nextafter_can_constant_fold_with_nan_arg() {
4642
define double @nextafter_not_marked_dead_on_pos_overflow () {
4743
; CHECK-LABEL: define double @nextafter_not_marked_dead_on_pos_overflow() {
4844
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0x7FEFFFFFFFFFFFFF, double 0x7FF0000000000000)
49-
; CHECK-NEXT: ret double [[NEXT]]
45+
; CHECK-NEXT: ret double 0x7FF0000000000000
5046
;
5147
%arg1 = load double, double* @dbl_pos_max
5248
%arg2 = load double, double* @dbl_pos_infinity
@@ -56,7 +52,7 @@ define double @nextafter_not_marked_dead_on_pos_overflow () {
5652
define double @nextafter_not_marked_dead_on_neg_overflow() {
5753
; CHECK-LABEL: define double @nextafter_not_marked_dead_on_neg_overflow() {
5854
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0xFFEFFFFFFFFFFFFF, double 0xFFF0000000000000)
59-
; CHECK-NEXT: ret double [[NEXT]]
55+
; CHECK-NEXT: ret double 0xFFF0000000000000
6056
;
6157
%arg1 = load double, double* @dbl_neg_max
6258
%arg2 = load double, double* @dbl_neg_infinity
@@ -66,7 +62,7 @@ define double @nextafter_not_marked_dead_on_neg_overflow() {
6662
define double @nextafter_not_marked_dead_on_zero_from_above() {
6763
; CHECK-LABEL: define double @nextafter_not_marked_dead_on_zero_from_above() {
6864
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0.000000e+00)
69-
; CHECK-NEXT: ret double [[NEXT]]
65+
; CHECK-NEXT: ret double 0.000000e+00
7066
;
7167
%arg = load double, double* @dbl_pos_min_subnormal
7268
%next = call double @nextafter(double %arg, double 0.0)
@@ -75,7 +71,7 @@ define double @nextafter_not_marked_dead_on_zero_from_above() {
7571
define double @nextafter_not_marked_dead_on_zero_from_below() {
7672
; CHECK-LABEL: define double @nextafter_not_marked_dead_on_zero_from_below() {
7773
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double -4.940660e-324, double 0.000000e+00)
78-
; CHECK-NEXT: ret double [[NEXT]]
74+
; CHECK-NEXT: ret double -0.000000e+00
7975
;
8076
%arg = load double, double* @dbl_neg_min_subnormal
8177
%next = call double @nextafter(double %arg, double 0.0)
@@ -84,7 +80,7 @@ define double @nextafter_not_marked_dead_on_zero_from_below() {
8480
define double @nextafter_not_marked_dead_on_subnormal() {
8581
; CHECK-LABEL: define double @nextafter_not_marked_dead_on_subnormal() {
8682
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0x7FF0000000000000)
87-
; CHECK-NEXT: ret double [[NEXT]]
83+
; CHECK-NEXT: ret double 9.881310e-324
8884
;
8985
%subnormal = load double, double* @dbl_pos_min_subnormal
9086
%infinity = load double, double* @dbl_pos_infinity
@@ -98,32 +94,28 @@ define double @nextafter_not_marked_dead_on_subnormal() {
9894

9995
define float @nextafterf_can_constant_fold_up_direction() {
10096
; CHECK-LABEL: define float @nextafterf_can_constant_fold_up_direction() {
101-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 2.000000e+00)
102-
; CHECK-NEXT: ret float [[NEXT]]
97+
; CHECK-NEXT: ret float 0x3FF0000020000000
10398
;
10499
%next = call float @nextafterf(float noundef 1.0, float noundef 2.0)
105100
ret float %next
106101
}
107102
define float @nextafterf_can_constant_fold_down_direction() {
108103
; CHECK-LABEL: define float @nextafterf_can_constant_fold_down_direction() {
109-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 0.000000e+00)
110-
; CHECK-NEXT: ret float [[NEXT]]
104+
; CHECK-NEXT: ret float 0x3FEFFFFFE0000000
111105
;
112106
%next = call float @nextafterf(float noundef 1.0, float noundef 0.0)
113107
ret float %next
114108
}
115109
define float @nextafterf_can_constant_fold_equal_args() {
116110
; CHECK-LABEL: define float @nextafterf_can_constant_fold_equal_args() {
117-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 1.000000e+00)
118-
; CHECK-NEXT: ret float [[NEXT]]
111+
; CHECK-NEXT: ret float 1.000000e+00
119112
;
120113
%next = call float @nextafterf(float noundef 1.0, float noundef 1.0)
121114
ret float %next
122115
}
123116
define float @nextafterf_can_constant_fold_with_nan_arg() {
124117
; CHECK-LABEL: define float @nextafterf_can_constant_fold_with_nan_arg() {
125-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 1.000000e+00, float 0x7FF8000000000000)
126-
; CHECK-NEXT: ret float [[NEXT]]
118+
; CHECK-NEXT: ret float 0x7FF8000000000000
127119
;
128120
%arg = load float, float* @flt_nan
129121
%next = call float @nextafterf(float 1.0, float %arg)
@@ -132,7 +124,7 @@ define float @nextafterf_can_constant_fold_with_nan_arg() {
132124
define float @nextafterf_not_marked_dead_on_pos_overflow() {
133125
; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_pos_overflow() {
134126
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x47EFFFFFE0000000, float 0x7FF0000000000000)
135-
; CHECK-NEXT: ret float [[NEXT]]
127+
; CHECK-NEXT: ret float 0x7FF0000000000000
136128
;
137129
%arg1 = load float, float* @flt_pos_max
138130
%arg2 = load float, float* @flt_pos_infinity
@@ -142,7 +134,7 @@ define float @nextafterf_not_marked_dead_on_pos_overflow() {
142134
define float @nextafterf_not_marked_dead_on_neg_overflow() {
143135
; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_neg_overflow() {
144136
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xC7EFFFFFE0000000, float 0xFFF0000000000000)
145-
; CHECK-NEXT: ret float [[NEXT]]
137+
; CHECK-NEXT: ret float 0xFFF0000000000000
146138
;
147139
%arg1 = load float, float* @flt_neg_max
148140
%arg2 = load float, float* @flt_neg_infinity
@@ -152,7 +144,7 @@ define float @nextafterf_not_marked_dead_on_neg_overflow() {
152144
define float @nextafterf_not_marked_dead_on_zero_from_above() {
153145
; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_zero_from_above() {
154146
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0.000000e+00)
155-
; CHECK-NEXT: ret float [[NEXT]]
147+
; CHECK-NEXT: ret float 0.000000e+00
156148
;
157149
%arg = load float, float* @flt_pos_min_subnormal
158150
%next = call float @nextafterf(float %arg, float 0.0)
@@ -161,7 +153,7 @@ define float @nextafterf_not_marked_dead_on_zero_from_above() {
161153
define float @nextafterf_not_marked_dead_on_zero_from_below() {
162154
; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_zero_from_below() {
163155
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xB6A0000000000000, float 0.000000e+00)
164-
; CHECK-NEXT: ret float [[NEXT]]
156+
; CHECK-NEXT: ret float -0.000000e+00
165157
;
166158
%arg = load float, float* @flt_neg_min_subnormal
167159
%next = call float @nextafterf(float %arg, float 0.0)
@@ -170,7 +162,7 @@ define float @nextafterf_not_marked_dead_on_zero_from_below() {
170162
define float @nextafterf_not_marked_dead_on_subnormal() {
171163
; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_subnormal() {
172164
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0x7FF0000000000000)
173-
; CHECK-NEXT: ret float [[NEXT]]
165+
; CHECK-NEXT: ret float 0x36B0000000000000
174166
;
175167
%subnormal = load float, float* @flt_pos_min_subnormal
176168
%infinity = load float, float* @flt_pos_infinity

0 commit comments

Comments
 (0)