Skip to content

Commit 2a6ad7f

Browse files
committed
Constant fold nextafter and nexttoward
1 parent 0fef7b8 commit 2a6ad7f

File tree

5 files changed

+127
-85
lines changed

5 files changed

+127
-85
lines changed

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2008,7 +2008,9 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
20082008
Name == "log10f" || Name == "logb" || Name == "logbf" ||
20092009
Name == "log1p" || Name == "log1pf";
20102010
case 'n':
2011-
return Name == "nearbyint" || Name == "nearbyintf";
2011+
return Name == "nearbyint" || Name == "nearbyintf" || Name == "nextafter" ||
2012+
Name == "nextafterf" || Name == "nexttoward" ||
2013+
Name == "nexttowardf";
20122014
case 'p':
20132015
return Name == "pow" || Name == "powf";
20142016
case 'r':
@@ -3174,6 +3176,52 @@ static Constant *evaluateCompare(const APFloat &Op1, const APFloat &Op2,
31743176
return nullptr;
31753177
}
31763178

3179+
/// Returns the first NaN in the operand list if it exists, preserving the NaN
3180+
/// payload if possible. Returns nullptr if no NaNs are in the list.
3181+
static Constant *TryConstantFoldNaN(ArrayRef<APFloat> Operands,
3182+
const Type *RetTy) {
3183+
assert(RetTy != nullptr);
3184+
for (const APFloat &Op : Operands) {
3185+
if (Op.isNaN()) {
3186+
bool Unused;
3187+
APFloat Ret(Op);
3188+
Ret.convert(RetTy->getFltSemantics(), detail::rmNearestTiesToEven,
3189+
&Unused);
3190+
return ConstantFP::get(RetTy->getContext(), Ret);
3191+
}
3192+
}
3193+
return nullptr;
3194+
}
3195+
3196+
static Constant *ConstantFoldNextToward(const APFloat &Op0, const APFloat &Op1,
3197+
const Type *RetTy,
3198+
bool *WouldSetErrno) {
3199+
assert(RetTy != nullptr);
3200+
*WouldSetErrno = false;
3201+
3202+
Constant *RetNaN = TryConstantFoldNaN({Op0, Op1}, RetTy);
3203+
if (RetNaN != nullptr) {
3204+
return RetNaN;
3205+
}
3206+
3207+
// Recall that the second argument of nexttoward is always a long double,
3208+
// so we may need to widen the first argument for comparisons to be valid.
3209+
bool LosesInfo;
3210+
APFloat WideOp0(Op0);
3211+
WideOp0.convert(Op1.getSemantics(), detail::rmNearestTiesToEven, &LosesInfo);
3212+
assert(!LosesInfo && "Unexpected lossy conversion to long double");
3213+
3214+
if (WideOp0 == Op1)
3215+
return ConstantFP::get(RetTy->getContext(), Op0);
3216+
3217+
APFloat Next(Op0);
3218+
Next.next(/*nextDown=*/WideOp0 > Op1);
3219+
const bool DidOverflow = !Op0.isInfinity() && Next.isInfinity();
3220+
*WouldSetErrno = Next.isZero() || Next.isDenormal() || DidOverflow;
3221+
3222+
return ConstantFP::get(RetTy->getContext(), Next);
3223+
}
3224+
31773225
static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
31783226
ArrayRef<Constant *> Operands,
31793227
const TargetLibraryInfo *TLI) {
@@ -3233,6 +3281,14 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
32333281
if (TLI->has(Func))
32343282
return ConstantFoldBinaryFP(atan2, Op1V, Op2V, Ty);
32353283
break;
3284+
case LibFunc_nextafter:
3285+
case LibFunc_nextafterf:
3286+
case LibFunc_nexttoward:
3287+
case LibFunc_nexttowardf:
3288+
if (TLI->has(Func)) {
3289+
bool Unused;
3290+
return ConstantFoldNextToward(Op1V, Op2V, Ty, &Unused);
3291+
}
32363292
}
32373293

32383294
return nullptr;
@@ -4685,6 +4741,16 @@ bool llvm::isMathLibCallNoop(const CallBase *Call,
46854741
// may occur, so allow for that possibility.
46864742
return !Op0.isZero() || !Op1.isZero();
46874743

4744+
case LibFunc_nextafter:
4745+
case LibFunc_nextafterf:
4746+
case LibFunc_nextafterl:
4747+
case LibFunc_nexttoward:
4748+
case LibFunc_nexttowardf:
4749+
case LibFunc_nexttowardl: {
4750+
bool WouldSetErrno;
4751+
ConstantFoldNextToward(Op0, Op1, F->getReturnType(), &WouldSetErrno);
4752+
return !WouldSetErrno;
4753+
}
46884754
default:
46894755
break;
46904756
}

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

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,62 +8,55 @@ attributes #0 = { willreturn memory(errnomem: write) }
88

99
define double @nextafter_up_direction() {
1010
; CHECK-LABEL: define double @nextafter_up_direction() {
11-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 1.000000e+00, double 2.000000e+00)
12-
; CHECK-NEXT: ret double [[NEXT]]
11+
; CHECK-NEXT: ret double 0x3FF0000000000001
1312
;
1413
%next = call double @nextafter(double 1.0, double 2.0)
1514
ret double %next
1615
}
1716

1817
define float @nextafterf_up_direction() {
1918
; CHECK-LABEL: define float @nextafterf_up_direction() {
20-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 1.000000e+00, float 2.000000e+00)
21-
; CHECK-NEXT: ret float [[NEXT]]
19+
; CHECK-NEXT: ret float 0x3FF0000020000000
2220
;
2321
%next = call float @nextafterf(float 1.0, float 2.0)
2422
ret float %next
2523
}
2624

2725
define double @nextafter_down_direction() {
2826
; CHECK-LABEL: define double @nextafter_down_direction() {
29-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 1.000000e+00, double 0.000000e+00)
30-
; CHECK-NEXT: ret double [[NEXT]]
27+
; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF
3128
;
3229
%next = call double @nextafter(double 1.0, double 0.0)
3330
ret double %next
3431
}
3532

3633
define float @nextafterf_down_direction() {
3734
; CHECK-LABEL: define float @nextafterf_down_direction() {
38-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 1.000000e+00, float 0.000000e+00)
39-
; CHECK-NEXT: ret float [[NEXT]]
35+
; CHECK-NEXT: ret float 0x3FEFFFFFE0000000
4036
;
4137
%next = call float @nextafterf(float 1.0, float 0.0)
4238
ret float %next
4339
}
4440

4541
define double @nextafter_equal_args() {
4642
; CHECK-LABEL: define double @nextafter_equal_args() {
47-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 1.000000e+00, double 1.000000e+00)
48-
; CHECK-NEXT: ret double [[NEXT]]
43+
; CHECK-NEXT: ret double 1.000000e+00
4944
;
5045
%next = call double @nextafter(double 1.0, double 1.0)
5146
ret double %next
5247
}
5348

5449
define float @nextafterf_equal_args() {
5550
; CHECK-LABEL: define float @nextafterf_equal_args() {
56-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 1.000000e+00, float 1.000000e+00)
57-
; CHECK-NEXT: ret float [[NEXT]]
51+
; CHECK-NEXT: ret float 1.000000e+00
5852
;
5953
%next = call float @nextafterf(float 1.0, float 1.0)
6054
ret float %next
6155
}
6256

6357
define double @nextafter_nan_with_payload() {
6458
; CHECK-LABEL: define double @nextafter_nan_with_payload() {
65-
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0x7FF8000000000001, double 1.000000e+00)
66-
; CHECK-NEXT: ret double [[NEXT]]
59+
; CHECK-NEXT: ret double 0x7FF8000000000001
6760
;
6861
%nan = load double, double* @dbl_nan
6962
%tmp1 = bitcast double %nan to i64
@@ -76,8 +69,7 @@ define double @nextafter_nan_with_payload() {
7669

7770
define float @nextafterf_nan_with_payload() {
7871
; CHECK-LABEL: define float @nextafterf_nan_with_payload() {
79-
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x7FF8000020000000, float 1.000000e+00)
80-
; CHECK-NEXT: ret float [[NEXT]]
72+
; CHECK-NEXT: ret float 0x7FF8000020000000
8173
;
8274
%nan = load float, float* @flt_nan
8375
%tmp1 = bitcast float %nan to i32
@@ -90,7 +82,7 @@ define float @nextafterf_nan_with_payload() {
9082
define double @nextafter_pos_overflow () {
9183
; CHECK-LABEL: define double @nextafter_pos_overflow() {
9284
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0x7FEFFFFFFFFFFFFF, double 0x7FF0000000000000)
93-
; CHECK-NEXT: ret double [[NEXT]]
85+
; CHECK-NEXT: ret double 0x7FF0000000000000
9486
;
9587
%arg1 = load double, double* @dbl_pos_max
9688
%arg2 = load double, double* @dbl_pos_infinity
@@ -101,7 +93,7 @@ define double @nextafter_pos_overflow () {
10193
define float @nextafterf_pos_overflow() {
10294
; CHECK-LABEL: define float @nextafterf_pos_overflow() {
10395
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x47EFFFFFE0000000, float 0x7FF0000000000000)
104-
; CHECK-NEXT: ret float [[NEXT]]
96+
; CHECK-NEXT: ret float 0x7FF0000000000000
10597
;
10698
%arg1 = load float, float* @flt_pos_max
10799
%arg2 = load float, float* @flt_pos_infinity
@@ -112,7 +104,7 @@ define float @nextafterf_pos_overflow() {
112104
define double @nextafter_neg_overflow() {
113105
; CHECK-LABEL: define double @nextafter_neg_overflow() {
114106
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0xFFEFFFFFFFFFFFFF, double 0xFFF0000000000000)
115-
; CHECK-NEXT: ret double [[NEXT]]
107+
; CHECK-NEXT: ret double 0xFFF0000000000000
116108
;
117109
%arg1 = load double, double* @dbl_neg_max
118110
%arg2 = load double, double* @dbl_neg_infinity
@@ -123,7 +115,7 @@ define double @nextafter_neg_overflow() {
123115
define float @nextafterf_neg_overflow() {
124116
; CHECK-LABEL: define float @nextafterf_neg_overflow() {
125117
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xC7EFFFFFE0000000, float 0xFFF0000000000000)
126-
; CHECK-NEXT: ret float [[NEXT]]
118+
; CHECK-NEXT: ret float 0xFFF0000000000000
127119
;
128120
%arg1 = load float, float* @flt_neg_max
129121
%arg2 = load float, float* @flt_neg_infinity
@@ -134,7 +126,7 @@ define float @nextafterf_neg_overflow() {
134126
define double @nextafter_zero_from_above() {
135127
; CHECK-LABEL: define double @nextafter_zero_from_above() {
136128
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0.000000e+00)
137-
; CHECK-NEXT: ret double [[NEXT]]
129+
; CHECK-NEXT: ret double 0.000000e+00
138130
;
139131
%arg = load double, double* @dbl_pos_min_subnormal
140132
%next = call double @nextafter(double %arg, double 0.0)
@@ -144,7 +136,7 @@ define double @nextafter_zero_from_above() {
144136
define float @nextafterf_zero_from_above() {
145137
; CHECK-LABEL: define float @nextafterf_zero_from_above() {
146138
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0.000000e+00)
147-
; CHECK-NEXT: ret float [[NEXT]]
139+
; CHECK-NEXT: ret float 0.000000e+00
148140
;
149141
%arg = load float, float* @flt_pos_min_subnormal
150142
%next = call float @nextafterf(float %arg, float 0.0)
@@ -154,7 +146,7 @@ define float @nextafterf_zero_from_above() {
154146
define double @nextafter_zero_from_below() {
155147
; CHECK-LABEL: define double @nextafter_zero_from_below() {
156148
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double -4.940660e-324, double 0.000000e+00)
157-
; CHECK-NEXT: ret double [[NEXT]]
149+
; CHECK-NEXT: ret double -0.000000e+00
158150
;
159151
%arg = load double, double* @dbl_neg_min_subnormal
160152
%next = call double @nextafter(double %arg, double 0.0)
@@ -164,7 +156,7 @@ define double @nextafter_zero_from_below() {
164156
define float @nextafterf_zero_from_below() {
165157
; CHECK-LABEL: define float @nextafterf_zero_from_below() {
166158
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xB6A0000000000000, float 0.000000e+00)
167-
; CHECK-NEXT: ret float [[NEXT]]
159+
; CHECK-NEXT: ret float -0.000000e+00
168160
;
169161
%arg = load float, float* @flt_neg_min_subnormal
170162
%next = call float @nextafterf(float %arg, float 0.0)
@@ -174,7 +166,7 @@ define float @nextafterf_zero_from_below() {
174166
define double @nextafter_subnormal() {
175167
; CHECK-LABEL: define double @nextafter_subnormal() {
176168
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0x7FF0000000000000)
177-
; CHECK-NEXT: ret double [[NEXT]]
169+
; CHECK-NEXT: ret double 9.881310e-324
178170
;
179171
%subnormal = load double, double* @dbl_pos_min_subnormal
180172
%infinity = load double, double* @dbl_pos_infinity
@@ -185,7 +177,7 @@ define double @nextafter_subnormal() {
185177
define float @nextafterf_subnormal() {
186178
; CHECK-LABEL: define float @nextafterf_subnormal() {
187179
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0x7FF0000000000000)
188-
; CHECK-NEXT: ret float [[NEXT]]
180+
; CHECK-NEXT: ret float 0x36B0000000000000
189181
;
190182
%subnormal = load float, float* @flt_pos_min_subnormal
191183
%infinity = load float, float* @flt_pos_infinity
@@ -214,7 +206,7 @@ define double @nextafterf_poison() {
214206
define double @nextafter_subnormal_readnone() {
215207
; CHECK-LABEL: define double @nextafter_subnormal_readnone() {
216208
; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0x7FF0000000000000) #[[ATTR1:[0-9]+]]
217-
; CHECK-NEXT: ret double [[NEXT]]
209+
; CHECK-NEXT: ret double 9.881310e-324
218210
;
219211
%subnormal = load double, double* @dbl_pos_min_subnormal
220212
%infinity = load double, double* @dbl_pos_infinity
@@ -225,7 +217,7 @@ define double @nextafter_subnormal_readnone() {
225217
define float @nextafterf_subnormal_readnone() {
226218
; CHECK-LABEL: define float @nextafterf_subnormal_readnone() {
227219
; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0x7FF0000000000000) #[[ATTR1]]
228-
; CHECK-NEXT: ret float [[NEXT]]
220+
; CHECK-NEXT: ret float 0x36B0000000000000
229221
;
230222
%subnormal = load float, float* @flt_pos_min_subnormal
231223
%infinity = load float, float* @flt_pos_infinity

0 commit comments

Comments
 (0)