[llvm] ff125ae - [ConstantFolding] Constant fold nextafter and nexttoward (#168794)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 23 06:46:47 PDT 2026
Author: Sayan Sivakumaran
Date: 2026-04-23T14:46:41+01:00
New Revision: ff125ae1bae7c815c9ee77fd9d65a2de41234725
URL: https://github.com/llvm/llvm-project/commit/ff125ae1bae7c815c9ee77fd9d65a2de41234725
DIFF: https://github.com/llvm/llvm-project/commit/ff125ae1bae7c815c9ee77fd9d65a2de41234725.diff
LOG: [ConstantFolding] Constant fold nextafter and nexttoward (#168794)
Closes #74368.
This patch enables us to constant fold `nextafter` and `nexttoward` as
long as we know that `errno` won't be written. In the latter case, we
should keep the function call so the programmer can observe the side
effect.
Added:
llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll
llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll
llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll
llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll
Modified:
llvm/lib/Analysis/ConstantFolding.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 982d8b9059aa7..b14471de744b1 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -2127,7 +2127,9 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
Name == "log10f" || Name == "logb" || Name == "logbf" ||
Name == "log1p" || Name == "log1pf";
case 'n':
- return Name == "nearbyint" || Name == "nearbyintf";
+ return Name == "nearbyint" || Name == "nearbyintf" || Name == "nextafter" ||
+ Name == "nextafterf" || Name == "nexttoward" ||
+ Name == "nexttowardf";
case 'p':
return Name == "pow" || Name == "powf";
case 'r':
@@ -3292,6 +3294,45 @@ static Constant *evaluateCompare(const APFloat &Op1, const APFloat &Op2,
return nullptr;
}
+static Constant *ConstantFoldNextToward(const APFloat &Op0, const APFloat &Op1,
+ const Type *RetTy) {
+ assert(RetTy != nullptr);
+ bool LosesInfo;
+
+ if (Op1.isSignaling())
+ return nullptr;
+ if (Op1.isNaN()) {
+ APFloat Ret(Op1);
+ Ret.convert(RetTy->getFltSemantics(), detail::rmNearestTiesToEven,
+ &LosesInfo);
+ return ConstantFP::get(RetTy->getContext(), Ret);
+ }
+
+ // Recall that the second argument of nexttoward is always a long double,
+ // so we may need to promote the first argument for comparisons to be valid.
+ APFloat PromotedOp0(Op0);
+ PromotedOp0.convert(Op1.getSemantics(), detail::rmNearestTiesToEven,
+ &LosesInfo);
+ assert(!LosesInfo && "Unexpected lossy promotion");
+ const APFloat::cmpResult Result = PromotedOp0.compare(Op1);
+
+ // When equal, the standard says we must return the second argument.
+ // This allows nice behavior such as nexttoward(0.0, -0.0) = -0.0 and
+ // nexttoward(-0.0, 0.0) = 0.0
+ if (Result == detail::cmpEqual) {
+ APFloat Ret(Op1);
+ Ret.convert(RetTy->getFltSemantics(), detail::rmNearestTiesToEven,
+ &LosesInfo);
+ return ConstantFP::get(RetTy->getContext(), Ret);
+ }
+
+ APFloat Next(Op0);
+ Next.next(/*nextDown=*/Result == APFloat::cmpGreaterThan);
+ if (Next.isZero() || Next.isDenormal() || Next.isSignaling())
+ return nullptr;
+ return ConstantFP::get(RetTy->getContext(), Next);
+}
+
static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI) {
@@ -3351,6 +3392,13 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
if (TLI->has(Func))
return ConstantFoldBinaryFP(atan2, Op1V, Op2V, Ty);
break;
+ case LibFunc_nextafter:
+ case LibFunc_nextafterf:
+ case LibFunc_nexttoward:
+ case LibFunc_nexttowardf:
+ if (TLI->has(Func))
+ return ConstantFoldNextToward(Op1V, Op2V, Ty);
+ break;
}
return nullptr;
@@ -4829,6 +4877,14 @@ bool llvm::isMathLibCallNoop(const CallBase *Call,
// may occur, so allow for that possibility.
return !Op0.isZero() || !Op1.isZero();
+ case LibFunc_nextafter:
+ case LibFunc_nextafterf:
+ case LibFunc_nextafterl:
+ case LibFunc_nexttoward:
+ case LibFunc_nexttowardf:
+ case LibFunc_nexttowardl: {
+ return ConstantFoldNextToward(Op0, Op1, F->getReturnType()) != nullptr;
+ }
default:
break;
}
diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll
new file mode 100644
index 0000000000000..cab56c27deac3
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll
@@ -0,0 +1,300 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+ at flt_nan = constant float 0x7FF8000000000000, align 4
+ at flt_pos_min_subnormal = constant float 0x36A0000000000000, align 4
+ at flt_pos_min_normal = constant float 0x3810000000000000, align 4
+ at flt_pos_max = constant float 0x47EFFFFFE0000000, align 4
+ at flt_pos_infinity = constant float 0x7FF0000000000000, align 4
+ at flt_neg_min_subnormal = constant float 0xB6A0000000000000, align 4
+ at flt_neg_min_normal = constant float 0xB810000000000000, align 4
+ at flt_neg_max = constant float 0xC7EFFFFFE0000000, align 4
+ at flt_neg_infinity = constant float 0xFFF0000000000000, align 4
+ at dbl_nan = constant double 0x7FF8000000000000, align 8
+ at dbl_snan = constant double 0x7FF0000000000001, align 8
+ at dbl_pos_min_subnormal = constant double 4.940660e-324, align 8
+ at dbl_pos_min_normal = constant double 0x10000000000000, align 8
+ at dbl_pos_max = constant double 0x7FEFFFFFFFFFFFFF, align 8
+ at dbl_pos_infinity = constant double 0x7FF0000000000000, align 8
+ at dbl_neg_min_subnormal = constant double -4.940660e-324, align 8
+ at dbl_neg_min_normal = constant double 0x8010000000000000, align 8
+ at dbl_neg_max = constant double 0xFFEFFFFFFFFFFFFF, align 8
+ at dbl_neg_infinity = constant double 0xFFF0000000000000, align 8
+
+define double @nextafter_up_direction() {
+; CHECK-LABEL: define double @nextafter_up_direction() {
+; CHECK-NEXT: ret double 0x3FF0000000000001
+;
+ %next = call double @nextafter(double 1.0, double 2.0)
+ ret double %next
+}
+
+define float @nextafterf_up_direction() {
+; CHECK-LABEL: define float @nextafterf_up_direction() {
+; CHECK-NEXT: ret float 0x3FF0000020000000
+;
+ %next = call float @nextafterf(float 1.0, float 2.0)
+ ret float %next
+}
+
+define double @nextafter_down_direction() {
+; CHECK-LABEL: define double @nextafter_down_direction() {
+; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF
+;
+ %next = call double @nextafter(double 1.0, double 0.0)
+ ret double %next
+}
+
+define float @nextafterf_down_direction() {
+; CHECK-LABEL: define float @nextafterf_down_direction() {
+; CHECK-NEXT: ret float 0x3FEFFFFFE0000000
+;
+ %next = call float @nextafterf(float 1.0, float 0.0)
+ ret float %next
+}
+
+define double @nextafter_equal_args() {
+; CHECK-LABEL: define double @nextafter_equal_args() {
+; CHECK-NEXT: ret double 1.000000e+00
+;
+ %next = call double @nextafter(double 1.0, double 1.0)
+ ret double %next
+}
+
+define float @nextafterf_equal_args() {
+; CHECK-LABEL: define float @nextafterf_equal_args() {
+; CHECK-NEXT: ret float 1.000000e+00
+;
+ %next = call float @nextafterf(float 1.0, float 1.0)
+ ret float %next
+}
+
+define double @nextafter_pos_zero_neg_zero() {
+; CHECK-LABEL: define double @nextafter_pos_zero_neg_zero() {
+; CHECK-NEXT: ret double -0.000000e+00
+;
+ %next = call double @nextafter(double 0.0, double -0.0)
+ ret double %next
+}
+
+define float @nextafterf_pos_zero_neg_zero() {
+; CHECK-LABEL: define float @nextafterf_pos_zero_neg_zero() {
+; CHECK-NEXT: ret float -0.000000e+00
+;
+ %next = call float @nextafterf(float 0.0, float -0.0)
+ ret float %next
+}
+
+define double @nextafter_neg_zero_pos_zero() {
+; CHECK-LABEL: define double @nextafter_neg_zero_pos_zero() {
+; CHECK-NEXT: ret double 0.000000e+00
+;
+ %next = call double @nextafter(double -0.0, double 0.0)
+ ret double %next
+}
+
+define float @nextafterf_neg_zero_pos_zero() {
+; CHECK-LABEL: define float @nextafterf_neg_zero_pos_zero() {
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %next = call float @nextafterf(float -0.0, float 0.0)
+ ret float %next
+}
+
+define double @nextafter_nan_with_payload() {
+; CHECK-LABEL: define double @nextafter_nan_with_payload() {
+; CHECK-NEXT: ret double 0x7FF8000000000001
+;
+ %tmp1 = load i64, ptr @dbl_nan
+ %tmp2 = or i64 %tmp1, 1
+ %nan_with_payload = bitcast i64 %tmp2 to double
+ %next = call double @nextafter(double %nan_with_payload, double 1.0)
+ ret double %next
+}
+
+define double @nextafter_nan_with_payload_2() {
+; CHECK-LABEL: define double @nextafter_nan_with_payload_2() {
+; CHECK-NEXT: ret double 0x7FF8000000000001
+;
+ %tmp1 = load i64, ptr @dbl_nan
+ %tmp2 = or i64 %tmp1, 1
+ %nan_with_payload = bitcast i64 %tmp2 to double
+ %next = call double @nextafter(double 1.0, double %nan_with_payload)
+ ret double %next
+}
+
+define double @nextafter_snan() {
+; CHECK-LABEL: define double @nextafter_snan() {
+; CHECK-NEXT: ret double 0x7FF8000000000000
+;
+ %arg1 = load double, ptr @dbl_snan
+ %next = call double @nextafter(double %arg1, double 1.0)
+ ret double %next
+}
+
+define double @nextafter_snan_2() {
+; CHECK-LABEL: define double @nextafter_snan_2() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 1.000000e+00, double 0x7FF0000000000001)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %arg2 = load double, ptr @dbl_snan
+ %next = call double @nextafter(double 1.0, double %arg2)
+ ret double %next
+}
+
+define float @nextafterf_nan_with_payload() {
+; CHECK-LABEL: define float @nextafterf_nan_with_payload() {
+; CHECK-NEXT: ret float 0x7FF8000020000000
+;
+ %tmp1 = load i32, ptr @flt_nan
+ %tmp2 = or i32 %tmp1, 1
+ %nan_with_payload = bitcast i32 %tmp2 to float
+ %next = call float @nextafterf(float %nan_with_payload, float 1.0)
+ ret float %next
+}
+
+define double @nextafter_pos_overflow () {
+; CHECK-LABEL: define double @nextafter_pos_overflow() {
+; CHECK-NEXT: ret double 0x7FF0000000000000
+;
+ %arg1 = load double, ptr @dbl_pos_max
+ %arg2 = load double, ptr @dbl_pos_infinity
+ %next = call double @nextafter(double %arg1, double %arg2)
+ ret double %next
+}
+
+define float @nextafterf_pos_overflow() {
+; CHECK-LABEL: define float @nextafterf_pos_overflow() {
+; CHECK-NEXT: ret float 0x7FF0000000000000
+;
+ %arg1 = load float, ptr @flt_pos_max
+ %arg2 = load float, ptr @flt_pos_infinity
+ %next = call float @nextafterf(float %arg1, float %arg2)
+ ret float %next
+}
+
+define double @nextafter_neg_overflow() {
+; CHECK-LABEL: define double @nextafter_neg_overflow() {
+; CHECK-NEXT: ret double 0xFFF0000000000000
+;
+ %arg1 = load double, ptr @dbl_neg_max
+ %arg2 = load double, ptr @dbl_neg_infinity
+ %next = call double @nextafter(double %arg1, double %arg2)
+ ret double %next
+}
+
+define float @nextafterf_neg_overflow() {
+; CHECK-LABEL: define float @nextafterf_neg_overflow() {
+; CHECK-NEXT: ret float 0xFFF0000000000000
+;
+ %arg1 = load float, ptr @flt_neg_max
+ %arg2 = load float, ptr @flt_neg_infinity
+ %next = call float @nextafterf(float %arg1, float %arg2)
+ ret float %next
+}
+
+define double @nextafter_zero_from_above() {
+; CHECK-LABEL: define double @nextafter_zero_from_above() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0.000000e+00)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %arg = load double, ptr @dbl_pos_min_subnormal
+ %next = call double @nextafter(double %arg, double 0.0)
+ ret double %next
+}
+
+define float @nextafterf_zero_from_above() {
+; CHECK-LABEL: define float @nextafterf_zero_from_above() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0.000000e+00)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %arg = load float, ptr @flt_pos_min_subnormal
+ %next = call float @nextafterf(float %arg, float 0.0)
+ ret float %next
+}
+
+define double @nextafter_zero_from_below() {
+; CHECK-LABEL: define double @nextafter_zero_from_below() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double -4.940660e-324, double 0.000000e+00)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %arg = load double, ptr @dbl_neg_min_subnormal
+ %next = call double @nextafter(double %arg, double 0.0)
+ ret double %next
+}
+
+define float @nextafterf_zero_from_below() {
+; CHECK-LABEL: define float @nextafterf_zero_from_below() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xB6A0000000000000, float 0.000000e+00)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %arg = load float, ptr @flt_neg_min_subnormal
+ %next = call float @nextafterf(float %arg, float 0.0)
+ ret float %next
+}
+
+define double @nextafter_subnormal() {
+; CHECK-LABEL: define double @nextafter_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0x7FF0000000000000)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_pos_min_subnormal
+ %infinity = load double, ptr @dbl_pos_infinity
+ %next = call double @nextafter(double %subnormal, double %infinity)
+ ret double %next
+}
+
+define float @nextafterf_subnormal() {
+; CHECK-LABEL: define float @nextafterf_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0x7FF0000000000000)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %subnormal = load float, ptr @flt_pos_min_subnormal
+ %infinity = load float, ptr @flt_pos_infinity
+ %next = call float @nextafterf(float %subnormal, float %infinity)
+ ret float %next
+}
+
+define double @nextafter_poison() {
+; CHECK-LABEL: define double @nextafter_poison() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double poison, double 1.000000e+00)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %next = call double @nextafter(double poison, double 1.0)
+ ret double %next
+}
+
+define double @nextafterf_poison() {
+; CHECK-LABEL: define double @nextafterf_poison() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafterf(float poison, float 1.000000e+00)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %next = call double @nextafterf(float poison, float 1.0)
+ ret double %next
+}
+
+define double @nextafter_subnormal_readnone() {
+; CHECK-LABEL: define double @nextafter_subnormal_readnone() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0x7FF0000000000000) #[[ATTR1:[0-9]+]]
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_pos_min_subnormal
+ %infinity = load double, ptr @dbl_pos_infinity
+ %next = call double @nextafter(double %subnormal, double %infinity) readnone
+ ret double %next
+}
+
+define float @nextafterf_subnormal_readnone() {
+; CHECK-LABEL: define float @nextafterf_subnormal_readnone() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0x7FF0000000000000) #[[ATTR1]]
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %subnormal = load float, ptr @flt_pos_min_subnormal
+ %infinity = load float, ptr @flt_pos_infinity
+ %next = call float @nextafterf(float %subnormal, float %infinity) readnone
+ ret float %next
+}
+
+declare double @nextafter(double, double) #0
+declare float @nextafterf(float, float) #0
+attributes #0 = { willreturn memory(errnomem: write) }
diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll
new file mode 100644
index 0000000000000..8c2a042fcc317
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll
@@ -0,0 +1,291 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+ at flt_nan = constant float 0x7FF8000000000000, align 4
+ at flt_pos_min_subnormal = constant float 0x36A0000000000000, align 4
+ at flt_pos_min_normal = constant float 0x3810000000000000, align 4
+ at flt_pos_max = constant float 0x47EFFFFFE0000000, align 4
+ at flt_pos_infinity = constant float 0x7FF0000000000000, align 4
+ at flt_neg_min_subnormal = constant float 0xB6A0000000000000, align 4
+ at flt_neg_min_normal = constant float 0xB810000000000000, align 4
+ at flt_neg_max = constant float 0xC7EFFFFFE0000000, align 4
+ at flt_neg_infinity = constant float 0xFFF0000000000000, align 4
+ at dbl_nan = constant double 0x7FF8000000000000, align 8
+ at dbl_pos_min_subnormal = constant double 4.940660e-324, align 8
+ at dbl_pos_min_normal = constant double 0x10000000000000, align 8
+ at dbl_pos_max = constant double 0x7FEFFFFFFFFFFFFF, align 8
+ at dbl_pos_infinity = constant double 0x7FF0000000000000, align 8
+ at dbl_neg_min_subnormal = constant double -4.940660e-324, align 8
+ at dbl_neg_min_normal = constant double 0x8010000000000000, align 8
+ at dbl_neg_max = constant double 0xFFEFFFFFFFFFFFFF, align 8
+ at dbl_neg_infinity = constant double 0xFFF0000000000000, align 8
+
+define double @nexttoward_up_direction() {
+; CHECK-LABEL: define double @nexttoward_up_direction() {
+; CHECK-NEXT: ret double 0x3FF0000000000001
+;
+ %arg = fpext double 2.0 to fp128
+ %next = call double @nexttoward(double 1.0, fp128 %arg)
+ ret double %next
+}
+
+define float @nexttowardf_up_direction() {
+; CHECK-LABEL: define float @nexttowardf_up_direction() {
+; CHECK-NEXT: ret float 0x3FF0000020000000
+;
+ %arg = fpext float 2.0 to fp128
+ %next = call float @nexttowardf(float 1.0, fp128 %arg)
+ ret float %next
+}
+
+define double @nexttoward_down_direction() {
+; CHECK-LABEL: define double @nexttoward_down_direction() {
+; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF
+;
+ %arg = fpext double 0.0 to fp128
+ %next = call double @nexttoward(double 1.0, fp128 %arg)
+ ret double %next
+}
+
+define float @nexttowardf_down_direction() {
+; CHECK-LABEL: define float @nexttowardf_down_direction() {
+; CHECK-NEXT: ret float 0x3FEFFFFFE0000000
+;
+ %arg = fpext float 0.0 to fp128
+ %next = call float @nexttowardf(float 1.0, fp128 %arg)
+ ret float %next
+}
+
+define double @nexttoward_equal_args() {
+; CHECK-LABEL: define double @nexttoward_equal_args() {
+; CHECK-NEXT: ret double 1.000000e+00
+;
+ %arg = fpext double 1.0 to fp128
+ %next = call double @nexttoward(double 1.0, fp128 %arg)
+ ret double %next
+}
+
+define float @nexttowardf_equal_args() {
+; CHECK-LABEL: define float @nexttowardf_equal_args() {
+; CHECK-NEXT: ret float 1.000000e+00
+;
+ %arg = fpext float 1.0 to fp128
+ %next = call float @nexttowardf(float 1.0, fp128 %arg)
+ ret float %next
+}
+
+define double @nexttoward_pos_zero_neg_zero() {
+; CHECK-LABEL: define double @nexttoward_pos_zero_neg_zero() {
+; CHECK-NEXT: ret double -0.000000e+00
+;
+ %neg_zero_ext = fpext double -0.0 to fp128
+ %next = call double @nexttoward(double 0.0, fp128 %neg_zero_ext)
+ ret double %next
+}
+
+define float @nexttowardf_pos_zero_neg_zero() {
+; CHECK-LABEL: define float @nexttowardf_pos_zero_neg_zero() {
+; CHECK-NEXT: ret float -0.000000e+00
+;
+ %neg_zero_ext = fpext float -0.0 to fp128
+ %next = call float @nexttowardf(float 0.0, fp128 %neg_zero_ext)
+ ret float %next
+}
+
+define double @nexttoward_neg_zero_pos_zero() {
+; CHECK-LABEL: define double @nexttoward_neg_zero_pos_zero() {
+; CHECK-NEXT: ret double 0.000000e+00
+;
+ %pos_zero_ext = fpext double 0.0 to fp128
+ %next = call double @nexttoward(double -0.0, fp128 %pos_zero_ext)
+ ret double %next
+}
+
+define float @nexttowardf_neg_zero_pos_zero() {
+; CHECK-LABEL: define float @nexttowardf_neg_zero_pos_zero() {
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %pos_zero_ext = fpext float 0.0 to fp128
+ %next = call float @nexttowardf(float -0.0, fp128 %pos_zero_ext)
+ ret float %next
+}
+
+define double @nexttoward_nan_with_payload() {
+; CHECK-LABEL: define double @nexttoward_nan_with_payload() {
+; CHECK-NEXT: ret double 0x7FF8000000000001
+;
+ %tmp1 = load i64, ptr @dbl_nan
+ %tmp2 = or i64 %tmp1, 1
+ %nan_with_payload = bitcast i64 %tmp2 to double
+ %dummy_arg = fpext double 1.0 to fp128
+ %next = call double @nexttoward(double %nan_with_payload, fp128 %dummy_arg)
+ ret double %next
+}
+
+define float @nexttowardf_nan_with_payload() {
+; CHECK-LABEL: define float @nexttowardf_nan_with_payload() {
+; CHECK-NEXT: ret float 0x7FF8000020000000
+;
+ %tmp1 = load i32, ptr @flt_nan
+ %tmp2 = or i32 %tmp1, 1
+ %nan_with_payload = bitcast i32 %tmp2 to float
+ %dummy_arg = fpext float 1.0 to fp128
+ %next = call float @nexttowardf(float %nan_with_payload, fp128 %dummy_arg)
+ ret float %next
+}
+
+define double @nexttoward_pos_overflow() {
+; CHECK-LABEL: define double @nexttoward_pos_overflow() {
+; CHECK-NEXT: ret double 0x7FF0000000000000
+;
+ %pos_max = load double, ptr @dbl_pos_max
+ %pos_inf = load double, ptr @dbl_pos_infinity
+ %ext_pos_inf = fpext double %pos_inf to fp128
+ %next = call double @nexttoward(double %pos_max, fp128 %ext_pos_inf)
+ ret double %next
+}
+
+define float @nexttowardf_pos_overflow () {
+; CHECK-LABEL: define float @nexttowardf_pos_overflow() {
+; CHECK-NEXT: ret float 0x7FF0000000000000
+;
+ %pos_max = load float, ptr @flt_pos_max
+ %pos_inf = load float, ptr @flt_pos_infinity
+ %ext_pos_inf = fpext float %pos_inf to fp128
+ %next = call float @nexttowardf(float %pos_max, fp128 %ext_pos_inf)
+ ret float %next
+}
+
+define double @nexttoward_neg_overflow() {
+; CHECK-LABEL: define double @nexttoward_neg_overflow() {
+; CHECK-NEXT: ret double 0xFFF0000000000000
+;
+ %neg_max = load double, ptr @dbl_neg_max
+ %neg_inf = load double, ptr @dbl_neg_infinity
+ %ext_neg_inf = fpext double %neg_inf to fp128
+ %next = call double @nexttoward(double %neg_max, fp128 %ext_neg_inf)
+ ret double %next
+}
+
+define float @nexttowardf_neg_overflow() {
+; CHECK-LABEL: define float @nexttowardf_neg_overflow() {
+; CHECK-NEXT: ret float 0xFFF0000000000000
+;
+ %neg_max = load float, ptr @flt_neg_max
+ %neg_inf = load float, ptr @flt_neg_infinity
+ %ext_neg_inf = fpext float %neg_inf to fp128
+ %next = call float @nexttowardf(float %neg_max, fp128 %ext_neg_inf)
+ ret float %next
+}
+
+define double @nexttoward_zero_from_above() {
+; CHECK-LABEL: define double @nexttoward_zero_from_above() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, fp128 0xL00000000000000000000000000000000)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_pos_min_subnormal
+ %zero = fpext double 0.0 to fp128
+ %next = call double @nexttoward(double %subnormal, fp128 %zero)
+ ret double %next
+}
+
+define float @nexttowardf_zero_from_above() {
+; CHECK-LABEL: define float @nexttowardf_zero_from_above() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, fp128 0xL00000000000000000000000000000000)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %min_subnormal = load float, ptr @flt_pos_min_subnormal
+ %zero = fpext float 0.0 to fp128
+ %next = call float @nexttowardf(float %min_subnormal, fp128 %zero)
+ ret float %next
+}
+
+define double @nexttoward_zero_from_below() {
+; CHECK-LABEL: define double @nexttoward_zero_from_below() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double -4.940660e-324, fp128 0xL00000000000000000000000000000000)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_neg_min_subnormal
+ %zero = fpext double 0.0 to fp128
+ %next = call double @nexttoward(double %subnormal, fp128 %zero)
+ ret double %next
+}
+
+define float @nexttowardf_zero_from_below() {
+; CHECK-LABEL: define float @nexttowardf_zero_from_below() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xB6A0000000000000, fp128 0xL00000000000000000000000000000000)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %min_subnormal = load float, ptr @flt_neg_min_subnormal
+ %zero = fpext float 0.0 to fp128
+ %next = call float @nexttowardf(float %min_subnormal, fp128 %zero)
+ ret float %next
+}
+
+define double @nexttoward_subnormal() {
+; CHECK-LABEL: define double @nexttoward_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, fp128 0xL00000000000000003FFF000000000000)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_pos_min_subnormal
+ %target = fpext double 1.0 to fp128
+ %next = call double @nexttoward(double %subnormal, fp128 %target)
+ ret double %next
+}
+
+define float @nexttowardf_subnormal() {
+; CHECK-LABEL: define float @nexttowardf_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, fp128 0xL00000000000000003FFF000000000000)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %subnormal = load float, ptr @flt_pos_min_subnormal
+ %target = fpext float 1.0 to fp128
+ %next = call float @nexttowardf(float %subnormal, fp128 %target)
+ ret float %next
+}
+
+define double @nexttoward_poison() {
+; CHECK-LABEL: define double @nexttoward_poison() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double poison, fp128 0xL00000000000000003FFF000000000000)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %dummy_arg = fpext double 1.0 to fp128
+ %next = call double @nexttoward(double poison, fp128 %dummy_arg)
+ ret double %next
+}
+
+define float @nexttowardf_poison() {
+; CHECK-LABEL: define float @nexttowardf_poison() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float poison, fp128 0xL00000000000000003FFF000000000000)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %dummy_arg = fpext double 1.0 to fp128
+ %next = call float @nexttowardf(float poison, fp128 %dummy_arg)
+ ret float %next
+}
+
+define double @nexttoward_subnormal_readnone() {
+; CHECK-LABEL: define double @nexttoward_subnormal_readnone() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, fp128 0xL00000000000000003FFF000000000000) #[[ATTR1:[0-9]+]]
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_pos_min_subnormal
+ %target = fpext double 1.0 to fp128
+ %next = call double @nexttoward(double %subnormal, fp128 %target) readnone
+ ret double %next
+}
+
+define float @nexttowardf_subnormal_readnone() {
+; CHECK-LABEL: define float @nexttowardf_subnormal_readnone() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, fp128 0xL00000000000000003FFF000000000000) #[[ATTR1]]
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %subnormal = load float, ptr @flt_pos_min_subnormal
+ %target = fpext float 1.0 to fp128
+ %next = call float @nexttowardf(float %subnormal, fp128 %target) readnone
+ ret float %next
+}
+
+declare double @nexttoward(double, fp128) #0
+declare float @nexttowardf(float, fp128) #0
+attributes #0 = { willreturn memory(errnomem: write) }
diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll
new file mode 100644
index 0000000000000..d94afa0b814a9
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+ at flt_nan = constant float 0x7FF8000000000000, align 4
+ at flt_pos_min_subnormal = constant float 0x36A0000000000000, align 4
+ at flt_pos_min_normal = constant float 0x3810000000000000, align 4
+ at flt_pos_max = constant float 0x47EFFFFFE0000000, align 4
+ at flt_pos_infinity = constant float 0x7FF0000000000000, align 4
+ at flt_neg_min_subnormal = constant float 0xB6A0000000000000, align 4
+ at flt_neg_min_normal = constant float 0xB810000000000000, align 4
+ at flt_neg_max = constant float 0xC7EFFFFFE0000000, align 4
+ at flt_neg_infinity = constant float 0xFFF0000000000000, align 4
+ at dbl_nan = constant double 0x7FF8000000000000, align 8
+ at dbl_pos_min_subnormal = constant double 4.940660e-324, align 8
+ at dbl_pos_min_normal = constant double 0x10000000000000, align 8
+ at dbl_pos_max = constant double 0x7FEFFFFFFFFFFFFF, align 8
+ at dbl_pos_infinity = constant double 0x7FF0000000000000, align 8
+ at dbl_neg_min_subnormal = constant double -4.940660e-324, align 8
+ at dbl_neg_min_normal = constant double 0x8010000000000000, align 8
+ at dbl_neg_max = constant double 0xFFEFFFFFFFFFFFFF, align 8
+ at dbl_neg_infinity = constant double 0xFFF0000000000000, align 8
+
+define double @nexttoward_up_direction() {
+; CHECK-LABEL: define double @nexttoward_up_direction() {
+; CHECK-NEXT: ret double 0x3FF0000000000001
+;
+ %arg = fpext double 2.0 to ppc_fp128
+ %next = call double @nexttoward(double 1.0, ppc_fp128 %arg)
+ ret double %next
+}
+
+define float @nexttowardf_up_direction() {
+; CHECK-LABEL: define float @nexttowardf_up_direction() {
+; CHECK-NEXT: ret float 0x3FF0000020000000
+;
+ %arg = fpext float 2.0 to ppc_fp128
+ %next = call float @nexttowardf(float 1.0, ppc_fp128 %arg)
+ ret float %next
+}
+
+define double @nexttoward_down_direction() {
+; CHECK-LABEL: define double @nexttoward_down_direction() {
+; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF
+;
+ %arg = fpext double 0.0 to ppc_fp128
+ %next = call double @nexttoward(double 1.0, ppc_fp128 %arg)
+ ret double %next
+}
+
+define float @nexttowardf_down_direction() {
+; CHECK-LABEL: define float @nexttowardf_down_direction() {
+; CHECK-NEXT: ret float 0x3FEFFFFFE0000000
+;
+ %arg = fpext float 0.0 to ppc_fp128
+ %next = call float @nexttowardf(float 1.0, ppc_fp128 %arg)
+ ret float %next
+}
+
+define double @nexttoward_pos_overflow() {
+; CHECK-LABEL: define double @nexttoward_pos_overflow() {
+; CHECK-NEXT: ret double 0x7FF0000000000000
+;
+ %pos_max = load double, ptr @dbl_pos_max
+ %pos_inf = load double, ptr @dbl_pos_infinity
+ %ext_pos_inf = fpext double %pos_inf to ppc_fp128
+ %next = call double @nexttoward(double %pos_max, ppc_fp128 %ext_pos_inf)
+ ret double %next
+}
+
+define float @nexttowardf_pos_overflow () {
+; CHECK-LABEL: define float @nexttowardf_pos_overflow() {
+; CHECK-NEXT: ret float 0x7FF0000000000000
+;
+ %pos_max = load float, ptr @flt_pos_max
+ %pos_inf = load float, ptr @flt_pos_infinity
+ %ext_pos_inf = fpext float %pos_inf to ppc_fp128
+ %next = call float @nexttowardf(float %pos_max, ppc_fp128 %ext_pos_inf)
+ ret float %next
+}
+
+define double @nexttoward_neg_overflow() {
+; CHECK-LABEL: define double @nexttoward_neg_overflow() {
+; CHECK-NEXT: ret double 0xFFF0000000000000
+;
+ %neg_max = load double, ptr @dbl_neg_max
+ %neg_inf = load double, ptr @dbl_neg_infinity
+ %ext_neg_inf = fpext double %neg_inf to ppc_fp128
+ %next = call double @nexttoward(double %neg_max, ppc_fp128 %ext_neg_inf)
+ ret double %next
+}
+
+define float @nexttowardf_neg_overflow() {
+; CHECK-LABEL: define float @nexttowardf_neg_overflow() {
+; CHECK-NEXT: ret float 0xFFF0000000000000
+;
+ %neg_max = load float, ptr @flt_neg_max
+ %neg_inf = load float, ptr @flt_neg_infinity
+ %ext_neg_inf = fpext float %neg_inf to ppc_fp128
+ %next = call float @nexttowardf(float %neg_max, ppc_fp128 %ext_neg_inf)
+ ret float %next
+}
+
+define double @nexttoward_subnormal() {
+; CHECK-LABEL: define double @nexttoward_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, ppc_fp128 0xM3FF00000000000000000000000000000)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_pos_min_subnormal
+ %target = fpext double 1.0 to ppc_fp128
+ %next = call double @nexttoward(double %subnormal, ppc_fp128 %target)
+ ret double %next
+}
+
+define float @nexttowardf_subnormal() {
+; CHECK-LABEL: define float @nexttowardf_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, ppc_fp128 0xM3FF00000000000000000000000000000)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %subnormal = load float, ptr @flt_pos_min_subnormal
+ %target = fpext float 1.0 to ppc_fp128
+ %next = call float @nexttowardf(float %subnormal, ppc_fp128 %target)
+ ret float %next
+}
+
+declare double @nexttoward(double, ppc_fp128) #0
+declare float @nexttowardf(float, ppc_fp128) #0
+attributes #0 = { willreturn memory(errnomem: write) }
diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll
new file mode 100644
index 0000000000000..08da8035172c4
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+ at flt_nan = constant float 0x7FF8000000000000, align 4
+ at flt_pos_min_subnormal = constant float 0x36A0000000000000, align 4
+ at flt_pos_min_normal = constant float 0x3810000000000000, align 4
+ at flt_pos_max = constant float 0x47EFFFFFE0000000, align 4
+ at flt_pos_infinity = constant float 0x7FF0000000000000, align 4
+ at flt_neg_min_subnormal = constant float 0xB6A0000000000000, align 4
+ at flt_neg_min_normal = constant float 0xB810000000000000, align 4
+ at flt_neg_max = constant float 0xC7EFFFFFE0000000, align 4
+ at flt_neg_infinity = constant float 0xFFF0000000000000, align 4
+ at dbl_nan = constant double 0x7FF8000000000000, align 8
+ at dbl_pos_min_subnormal = constant double 4.940660e-324, align 8
+ at dbl_pos_min_normal = constant double 0x10000000000000, align 8
+ at dbl_pos_max = constant double 0x7FEFFFFFFFFFFFFF, align 8
+ at dbl_pos_infinity = constant double 0x7FF0000000000000, align 8
+ at dbl_neg_min_subnormal = constant double -4.940660e-324, align 8
+ at dbl_neg_min_normal = constant double 0x8010000000000000, align 8
+ at dbl_neg_max = constant double 0xFFEFFFFFFFFFFFFF, align 8
+ at dbl_neg_infinity = constant double 0xFFF0000000000000, align 8
+
+define double @nexttoward_up_direction() {
+; CHECK-LABEL: define double @nexttoward_up_direction() {
+; CHECK-NEXT: ret double 0x3FF0000000000001
+;
+ %arg = fpext double 2.0 to x86_fp80
+ %next = call double @nexttoward(double 1.0, x86_fp80 %arg)
+ ret double %next
+}
+
+define float @nexttowardf_up_direction() {
+; CHECK-LABEL: define float @nexttowardf_up_direction() {
+; CHECK-NEXT: ret float 0x3FF0000020000000
+;
+ %arg = fpext float 2.0 to x86_fp80
+ %next = call float @nexttowardf(float 1.0, x86_fp80 %arg)
+ ret float %next
+}
+
+define double @nexttoward_down_direction() {
+; CHECK-LABEL: define double @nexttoward_down_direction() {
+; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF
+;
+ %arg = fpext double 0.0 to x86_fp80
+ %next = call double @nexttoward(double 1.0, x86_fp80 %arg)
+ ret double %next
+}
+
+define float @nexttowardf_down_direction() {
+; CHECK-LABEL: define float @nexttowardf_down_direction() {
+; CHECK-NEXT: ret float 0x3FEFFFFFE0000000
+;
+ %arg = fpext float 0.0 to x86_fp80
+ %next = call float @nexttowardf(float 1.0, x86_fp80 %arg)
+ ret float %next
+}
+
+define double @nexttoward_pos_overflow () {
+; CHECK-LABEL: define double @nexttoward_pos_overflow() {
+; CHECK-NEXT: ret double 0x7FF0000000000000
+;
+ %pos_max = load double, ptr @dbl_pos_max
+ %pos_inf = load double, ptr @dbl_pos_infinity
+ %ext_pos_inf = fpext double %pos_inf to x86_fp80
+ %next = call double @nexttoward(double %pos_max, x86_fp80 %ext_pos_inf)
+ ret double %next
+}
+
+define float @nexttowardf_pos_overflow() {
+; CHECK-LABEL: define float @nexttowardf_pos_overflow() {
+; CHECK-NEXT: ret float 0x7FF0000000000000
+;
+ %pos_max = load float, ptr @flt_pos_max
+ %pos_inf = load float, ptr @flt_pos_infinity
+ %ext_pos_inf = fpext float %pos_inf to x86_fp80
+ %next = call float @nexttowardf(float %pos_max, x86_fp80 %ext_pos_inf)
+ ret float %next
+}
+
+define double @nexttoward_neg_overflow() {
+; CHECK-LABEL: define double @nexttoward_neg_overflow() {
+; CHECK-NEXT: ret double 0xFFF0000000000000
+;
+ %neg_max = load double, ptr @dbl_neg_max
+ %neg_inf = load double, ptr @dbl_neg_infinity
+ %ext_neg_inf = fpext double %neg_inf to x86_fp80
+ %next = call double @nexttoward(double %neg_max, x86_fp80 %ext_neg_inf)
+ ret double %next
+}
+
+define float @nexttowardf_neg_overflow() {
+; CHECK-LABEL: define float @nexttowardf_neg_overflow() {
+; CHECK-NEXT: ret float 0xFFF0000000000000
+;
+ %neg_max = load float, ptr @flt_neg_max
+ %neg_inf = load float, ptr @flt_neg_infinity
+ %ext_neg_inf = fpext float %neg_inf to x86_fp80
+ %next = call float @nexttowardf(float %neg_max, x86_fp80 %ext_neg_inf)
+ ret float %next
+}
+
+define double @nexttoward_subnormal() {
+; CHECK-LABEL: define double @nexttoward_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, x86_fp80 0xK3FFF8000000000000000)
+; CHECK-NEXT: ret double [[NEXT]]
+;
+ %subnormal = load double, ptr @dbl_pos_min_subnormal
+ %target = fpext double 1.0 to x86_fp80
+ %next = call double @nexttoward(double %subnormal, x86_fp80 %target)
+ ret double %next
+}
+
+define float @nexttowardf_subnormal() {
+; CHECK-LABEL: define float @nexttowardf_subnormal() {
+; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, x86_fp80 0xK3FFF8000000000000000)
+; CHECK-NEXT: ret float [[NEXT]]
+;
+ %subnormal = load float, ptr @flt_pos_min_subnormal
+ %target = fpext float 1.0 to x86_fp80
+ %next = call float @nexttowardf(float %subnormal, x86_fp80 %target)
+ ret float %next
+}
+
+declare double @nexttoward(double, x86_fp80) #0
+declare float @nexttowardf(float, x86_fp80) #0
+attributes #0 = { willreturn memory(errnomem: write) }
More information about the llvm-commits
mailing list