From 0065b07916af6aa4034c6d4283a04cf9b3f52661 Mon Sep 17 00:00:00 2001 From: Sayan Sivakumaran Date: Sun, 9 Nov 2025 21:47:29 -0600 Subject: [PATCH 1/7] Precommit tests --- .../InstCombine/constant-fold-nextafter.ll | 179 ++++++++++++++++ .../constant-fold-nexttoward-fp128.ll | 195 ++++++++++++++++++ .../constant-fold-nexttoward-ppc-fp128.ll | 195 ++++++++++++++++++ .../constant-fold-nexttoward-x86-fp80.ll | 195 ++++++++++++++++++ .../InstCombine/floating-point-constants.ll | 48 +++++ 5 files changed, 812 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll create mode 100644 llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll create mode 100644 llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll create mode 100644 llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll create mode 100644 llvm/test/Transforms/InstCombine/floating-point-constants.ll 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..c0b949e59f847 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll @@ -0,0 +1,179 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: cat %S/floating-point-constants.ll %s | opt -passes=instcombine -S | FileCheck %s + +declare double @nextafter(double noundef, double noundef) #0 +declare float @nextafterf(float noundef, float noundef) #0 + +attributes #0 = { willreturn memory(errnomem: write) } + +; ================== +; nextafter tests +; ================== + +define double @nextafter_can_constant_fold_up_direction() { +; CHECK-LABEL: define double @nextafter_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 2.000000e+00) +; CHECK-NEXT: ret double [[NEXT]] +; + %next = call double @nextafter(double noundef 1.0, double noundef 2.0) + ret double %next +} +define double @nextafter_can_constant_fold_down_direction() { +; CHECK-LABEL: define double @nextafter_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 0.000000e+00) +; CHECK-NEXT: ret double [[NEXT]] +; + %next = call double @nextafter(double noundef 1.0, double noundef 0.0) + ret double %next +} +define double @nextafter_can_constant_fold_equal_args() { +; CHECK-LABEL: define double @nextafter_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 1.000000e+00) +; CHECK-NEXT: ret double [[NEXT]] +; + %next = call double @nextafter(double noundef 1.0, double noundef 1.0) + ret double %next +} +define double @nextafter_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define double @nextafter_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 1.000000e+00, double 0x7FF8000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = load double, double* @dbl_nan + %next = call double @nextafter(double 1.0, double %arg) + ret double %next +} +define double @nextafter_not_marked_dead_on_pos_overflow () { +; CHECK-LABEL: define double @nextafter_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0x7FEFFFFFFFFFFFFF, double 0x7FF0000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg1 = load double, double* @dbl_pos_max + %arg2 = load double, double* @dbl_pos_infinity + %next = call double @nextafter(double %arg1, double %arg2) + ret double %next +} +define double @nextafter_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define double @nextafter_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0xFFEFFFFFFFFFFFFF, double 0xFFF0000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg1 = load double, double* @dbl_neg_max + %arg2 = load double, double* @dbl_neg_infinity + %next = call double @nextafter(double %arg1, double %arg2) + ret double %next +} +define double @nextafter_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define double @nextafter_not_marked_dead_on_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, double* @dbl_pos_min_subnormal + %next = call double @nextafter(double %arg, double 0.0) + ret double %next +} +define double @nextafter_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define double @nextafter_not_marked_dead_on_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, double* @dbl_neg_min_subnormal + %next = call double @nextafter(double %arg, double 0.0) + ret double %next +} +define double @nextafter_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define double @nextafter_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0x7FF0000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %infinity = load double, double* @dbl_pos_infinity + %next = call double @nextafter(double %subnormal, double %infinity) + ret double %next +} + +; ================== +; nextafterf tests +; ================== + +define float @nextafterf_can_constant_fold_up_direction() { +; CHECK-LABEL: define float @nextafterf_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 2.000000e+00) +; CHECK-NEXT: ret float [[NEXT]] +; + %next = call float @nextafterf(float noundef 1.0, float noundef 2.0) + ret float %next +} +define float @nextafterf_can_constant_fold_down_direction() { +; CHECK-LABEL: define float @nextafterf_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 0.000000e+00) +; CHECK-NEXT: ret float [[NEXT]] +; + %next = call float @nextafterf(float noundef 1.0, float noundef 0.0) + ret float %next +} +define float @nextafterf_can_constant_fold_equal_args() { +; CHECK-LABEL: define float @nextafterf_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 1.000000e+00) +; CHECK-NEXT: ret float [[NEXT]] +; + %next = call float @nextafterf(float noundef 1.0, float noundef 1.0) + ret float %next +} +define float @nextafterf_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define float @nextafterf_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 1.000000e+00, float 0x7FF8000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = load float, float* @flt_nan + %next = call float @nextafterf(float 1.0, float %arg) + ret float %next +} +define float @nextafterf_not_marked_dead_on_pos_overflow() { +; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x47EFFFFFE0000000, float 0x7FF0000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg1 = load float, float* @flt_pos_max + %arg2 = load float, float* @flt_pos_infinity + %next = call float @nextafterf(float %arg1, float %arg2) + ret float %next +} +define float @nextafterf_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xC7EFFFFFE0000000, float 0xFFF0000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg1 = load float, float* @flt_neg_max + %arg2 = load float, float* @flt_neg_infinity + %next = call float @nextafterf(float %arg1, float %arg2) + ret float %next +} +define float @nextafterf_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_zero_from_above() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0.000000e+00) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = load float, float* @flt_pos_min_subnormal + %next = call float @nextafterf(float %arg, float 0.0) + ret float %next +} +define float @nextafterf_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_zero_from_below() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xB6A0000000000000, float 0.000000e+00) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = load float, float* @flt_neg_min_subnormal + %next = call float @nextafterf(float %arg, float 0.0) + ret float %next +} +define float @nextafterf_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0x7FF0000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %subnormal = load float, float* @flt_pos_min_subnormal + %infinity = load float, float* @flt_pos_infinity + %next = call float @nextafterf(float %subnormal, float %infinity) + ret float %next +} 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..917191350f98b --- /dev/null +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll @@ -0,0 +1,195 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: cat %S/floating-point-constants.ll %s | opt -passes=instcombine -S | FileCheck %s + +declare double @nexttoward(double noundef, fp128 noundef) #0 +declare float @nexttowardf(float noundef, fp128 noundef) #0 + +attributes #0 = { willreturn memory(errnomem: write) } + +; ================== +; nexttoward tests +; ================== + +define double @nexttoward_can_constant_fold_up_direction() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, fp128 0xL00000000000000004000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 2.0 to fp128 + %next = call double @nexttoward(double noundef 1.0, fp128 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_down_direction() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, fp128 0xL00000000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 0.0 to fp128 + %next = call double @nexttoward(double noundef 1.0, fp128 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_equal_args() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, fp128 0xL00000000000000003FFF000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 1.0 to fp128 + %next = call double @nexttoward(double 1.0, fp128 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, fp128 0xL00000000000000007FFF800000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %nan = load double, double* @dbl_nan + %arg = fpext double %nan to fp128 + %next = call double @nexttoward(double 1.0, fp128 %arg) + ret double %next +} +define double @nexttoward_not_marked_dead_on_pos_overflow() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, fp128 0xL00000000000000007FFF000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %pos_max = load double, double* @dbl_pos_max + %pos_inf = load double, double* @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 double @nexttoward_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0xFFEFFFFFFFFFFFFF, fp128 0xL0000000000000000FFFF000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %neg_max = load double, double* @dbl_neg_max + %neg_inf = load double, double* @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 double @nexttoward_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_above() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, fp128 0xL00000000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %zero = fpext double 0.0 to fp128 + %next = call double @nexttoward(double %subnormal, fp128 %zero) + ret double %next +} +define double @nexttoward_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_below() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double -4.940660e-324, fp128 0xL00000000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_neg_min_subnormal + %zero = fpext double 0.0 to fp128 + %next = call double @nexttoward(double %subnormal, fp128 %zero) + ret double %next +} +define double @nexttoward_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, fp128 0xL00000000000000003FFF000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %target = fpext double 1.0 to fp128 + %next = call double @nexttoward(double %subnormal, fp128 %target) + ret double %next +} + +; ================== +; nexttowardf tests +; ================== + +define float @nexttowardf_can_constant_fold_up_direction() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, fp128 0xL00000000000000004000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 2.0 to fp128 + %next = call float @nexttowardf(float noundef 1.0, fp128 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_down_direction() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, fp128 0xL00000000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 0.0 to fp128 + %next = call float @nexttowardf(float noundef 1.0, fp128 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_equal_args() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttoward(float 1.000000e+00, fp128 0xL00000000000000003FFF000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 1.0 to fp128 + %next = call float @nexttoward(float 1.0, fp128 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 1.000000e+00, fp128 0xL00000000000000007FFF800000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %nan = load float, float* @flt_nan + %ext_nan = fpext float %nan to fp128 + %next = call float @nexttowardf(float 1.0, fp128 %ext_nan) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_pos_overflow () { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, fp128 0xL00000000000000007FFF000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %pos_max = load float, float* @flt_pos_max + %pos_inf = load float, float* @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 float @nexttowardf_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xC7EFFFFFE0000000, fp128 0xL0000000000000000FFFF000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %neg_max = load float, float* @flt_neg_max + %neg_inf = load float, float* @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 float @nexttowardf_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_above() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, fp128 0xL00000000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %min_subnormal = load float, float* @flt_pos_min_subnormal + %zero = fpext float 0.0 to fp128 + %next = call float @nexttowardf(float %min_subnormal, fp128 %zero) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_below() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xB6A0000000000000, fp128 0xL00000000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %min_subnormal = load float, float* @flt_neg_min_subnormal + %zero = fpext float 0.0 to fp128 + %next = call float @nexttowardf(float %min_subnormal, fp128 %zero) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, fp128 0xL00000000000000003FFF000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %subnormal = load float, float* @flt_pos_min_subnormal + %target = fpext float 1.0 to fp128 + %next = call float @nexttowardf(float %subnormal, fp128 %target) + ret float %next +} 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..f275c2ce833de --- /dev/null +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll @@ -0,0 +1,195 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: cat %S/floating-point-constants.ll %s | opt -passes=instcombine -S | FileCheck %s + +declare double @nexttoward(double noundef, ppc_fp128 noundef) #0 +declare float @nexttowardf(float noundef, ppc_fp128 noundef) #0 + +attributes #0 = { willreturn memory(errnomem: write) } + +; ================== +; nexttoward tests +; ================== + +define double @nexttoward_can_constant_fold_up_direction() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, ppc_fp128 0xM40000000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 2.0 to ppc_fp128 + %next = call double @nexttoward(double noundef 1.0, ppc_fp128 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_down_direction() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, ppc_fp128 0xM00000000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 0.0 to ppc_fp128 + %next = call double @nexttoward(double noundef 1.0, ppc_fp128 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_equal_args() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, ppc_fp128 0xM3FF00000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 1.0 to ppc_fp128 + %next = call double @nexttoward(double 1.0, ppc_fp128 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, ppc_fp128 0xM7FF80000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %nan = load double, double* @dbl_nan + %arg = fpext double %nan to ppc_fp128 + %next = call double @nexttoward(double 1.0, ppc_fp128 %arg) + ret double %next +} +define double @nexttoward_not_marked_dead_on_pos_overflow() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, ppc_fp128 0xM7FF00000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %pos_max = load double, double* @dbl_pos_max + %pos_inf = load double, double* @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 double @nexttoward_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0xFFEFFFFFFFFFFFFF, ppc_fp128 0xMFFF00000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %neg_max = load double, double* @dbl_neg_max + %neg_inf = load double, double* @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 double @nexttoward_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_above() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, ppc_fp128 0xM00000000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %zero = fpext double 0.0 to ppc_fp128 + %next = call double @nexttoward(double %subnormal, ppc_fp128 %zero) + ret double %next +} +define double @nexttoward_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_below() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double -4.940660e-324, ppc_fp128 0xM00000000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_neg_min_subnormal + %zero = fpext double 0.0 to ppc_fp128 + %next = call double @nexttoward(double %subnormal, ppc_fp128 %zero) + ret double %next +} +define double @nexttoward_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, ppc_fp128 0xM3FF00000000000000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %target = fpext double 1.0 to ppc_fp128 + %next = call double @nexttoward(double %subnormal, ppc_fp128 %target) + ret double %next +} + +; ================== +; nexttowardf tests +; ================== + +define float @nexttowardf_can_constant_fold_up_direction() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, ppc_fp128 0xM40000000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 2.0 to ppc_fp128 + %next = call float @nexttowardf(float noundef 1.0, ppc_fp128 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_down_direction() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, ppc_fp128 0xM00000000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 0.0 to ppc_fp128 + %next = call float @nexttowardf(float noundef 1.0, ppc_fp128 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_equal_args() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttoward(float 1.000000e+00, ppc_fp128 0xM3FF00000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 1.0 to ppc_fp128 + %next = call float @nexttoward(float 1.0, ppc_fp128 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 1.000000e+00, ppc_fp128 0xM7FF80000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %nan = load float, float* @flt_nan + %ext_nan = fpext float %nan to ppc_fp128 + %next = call float @nexttowardf(float 1.0, ppc_fp128 %ext_nan) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_pos_overflow () { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, ppc_fp128 0xM7FF00000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %pos_max = load float, float* @flt_pos_max + %pos_inf = load float, float* @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 float @nexttowardf_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xC7EFFFFFE0000000, ppc_fp128 0xMFFF00000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %neg_max = load float, float* @flt_neg_max + %neg_inf = load float, float* @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 float @nexttowardf_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_above() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, ppc_fp128 0xM00000000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %min_subnormal = load float, float* @flt_pos_min_subnormal + %zero = fpext float 0.0 to ppc_fp128 + %next = call float @nexttowardf(float %min_subnormal, ppc_fp128 %zero) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_below() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xB6A0000000000000, ppc_fp128 0xM00000000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %min_subnormal = load float, float* @flt_neg_min_subnormal + %zero = fpext float 0.0 to ppc_fp128 + %next = call float @nexttowardf(float %min_subnormal, ppc_fp128 %zero) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, ppc_fp128 0xM3FF00000000000000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %subnormal = load float, float* @flt_pos_min_subnormal + %target = fpext float 1.0 to ppc_fp128 + %next = call float @nexttowardf(float %subnormal, ppc_fp128 %target) + ret float %next +} 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..f059bdc1f8492 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll @@ -0,0 +1,195 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: cat %S/floating-point-constants.ll %s | opt -passes=instcombine -S | FileCheck %s + +declare double @nexttoward(double noundef, x86_fp80 noundef) #0 +declare float @nexttowardf(float noundef, x86_fp80 noundef) #0 + +attributes #0 = { willreturn memory(errnomem: write) } + +; ================== +; nexttoward tests +; ================== + +define double @nexttoward_can_constant_fold_up_direction() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, x86_fp80 0xK40008000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 2.0 to x86_fp80 + %next = call double @nexttoward(double noundef 1.0, x86_fp80 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_down_direction() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, x86_fp80 0xK00000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 0.0 to x86_fp80 + %next = call double @nexttoward(double noundef 1.0, x86_fp80 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_equal_args() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, x86_fp80 0xK3FFF8000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %arg = fpext double 1.0 to x86_fp80 + %next = call double @nexttoward(double 1.0, x86_fp80 %arg) + ret double %next +} +define double @nexttoward_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define double @nexttoward_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, x86_fp80 0xK7FFFC000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %nan = load double, double* @dbl_nan + %arg = fpext double %nan to x86_fp80 + %next = call double @nexttoward(double 1.0, x86_fp80 %arg) + ret double %next +} +define double @nexttoward_not_marked_dead_on_pos_overflow () { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, x86_fp80 0xK7FFF8000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %pos_max = load double, double* @dbl_pos_max + %pos_inf = load double, double* @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 double @nexttoward_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0xFFEFFFFFFFFFFFFF, x86_fp80 0xKFFFF8000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %neg_max = load double, double* @dbl_neg_max + %neg_inf = load double, double* @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 double @nexttoward_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_above() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, x86_fp80 0xK00000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %zero = fpext double 0.0 to x86_fp80 + %next = call double @nexttoward(double %subnormal, x86_fp80 %zero) + ret double %next +} +define double @nexttoward_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_below() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double -4.940660e-324, x86_fp80 0xK00000000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_neg_min_subnormal + %zero = fpext double 0.0 to x86_fp80 + %next = call double @nexttoward(double %subnormal, x86_fp80 %zero) + ret double %next +} +define double @nexttoward_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, x86_fp80 0xK3FFF8000000000000000) +; CHECK-NEXT: ret double [[NEXT]] +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %target = fpext double 1.0 to x86_fp80 + %next = call double @nexttoward(double %subnormal, x86_fp80 %target) + ret double %next +} + +; ================== +; nexttowardf tests +; ================== + +define float @nexttowardf_can_constant_fold_up_direction() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_up_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, x86_fp80 0xK40008000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 2.0 to x86_fp80 + %next = call float @nexttowardf(float noundef 1.0, x86_fp80 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_down_direction() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_down_direction() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, x86_fp80 0xK00000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 0.0 to x86_fp80 + %next = call float @nexttowardf(float noundef 1.0, x86_fp80 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_equal_args() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_equal_args() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttoward(float 1.000000e+00, x86_fp80 0xK3FFF8000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %arg = fpext float 1.0 to x86_fp80 + %next = call float @nexttoward(float 1.0, x86_fp80 %arg) + ret float %next +} +define float @nexttowardf_can_constant_fold_with_nan_arg() { +; CHECK-LABEL: define float @nexttowardf_can_constant_fold_with_nan_arg() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 1.000000e+00, x86_fp80 0xK7FFFC000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %nan = load float, float* @flt_nan + %ext_nan = fpext float %nan to x86_fp80 + %next = call float @nexttowardf(float 1.0, x86_fp80 %ext_nan) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_pos_overflow() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, x86_fp80 0xK7FFF8000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %pos_max = load float, float* @flt_pos_max + %pos_inf = load float, float* @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 float @nexttowardf_not_marked_dead_on_neg_overflow() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_neg_overflow() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xC7EFFFFFE0000000, x86_fp80 0xKFFFF8000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %neg_max = load float, float* @flt_neg_max + %neg_inf = load float, float* @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 float @nexttowardf_not_marked_dead_on_zero_from_above() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_above() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, x86_fp80 0xK00000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %min_subnormal = load float, float* @flt_pos_min_subnormal + %zero = fpext float 0.0 to x86_fp80 + %next = call float @nexttowardf(float %min_subnormal, x86_fp80 %zero) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_zero_from_below() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_below() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xB6A0000000000000, x86_fp80 0xK00000000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %min_subnormal = load float, float* @flt_neg_min_subnormal + %zero = fpext float 0.0 to x86_fp80 + %next = call float @nexttowardf(float %min_subnormal, x86_fp80 %zero) + ret float %next +} +define float @nexttowardf_not_marked_dead_on_subnormal() { +; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_subnormal() { +; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, x86_fp80 0xK3FFF8000000000000000) +; CHECK-NEXT: ret float [[NEXT]] +; + %subnormal = load float, float* @flt_pos_min_subnormal + %target = fpext float 1.0 to x86_fp80 + %next = call float @nexttowardf(float %subnormal, x86_fp80 %target) + ret float %next +} diff --git a/llvm/test/Transforms/InstCombine/floating-point-constants.ll b/llvm/test/Transforms/InstCombine/floating-point-constants.ll new file mode 100644 index 0000000000000..5d135b0aaebaa --- /dev/null +++ b/llvm/test/Transforms/InstCombine/floating-point-constants.ll @@ -0,0 +1,48 @@ +; RUN: true +; Constants for edge case float testing. + +; Generated with: +; clang -S -emit-llvm floating-point-constants.c +; +; // floating-point-constants.c +; #include +; #include +; +; const float flt_nan = NAN; +; const float flt_pos_min_subnormal = FLT_TRUE_MIN; +; const float flt_pos_min_normal = FLT_MIN; +; const float flt_pos_max = FLT_MAX; +; const float flt_pos_infinity = INFINITY; +; const float flt_neg_min_subnormal = -FLT_TRUE_MIN; +; const float flt_neg_min_normal = -FLT_MIN; +; const float flt_neg_max = -FLT_MAX; +; const float flt_neg_infinity = -INFINITY; +; +; const double dbl_nan = NAN; +; const double dbl_pos_min_subnormal = DBL_TRUE_MIN; +; const double dbl_pos_min_normal = DBL_MIN; +; const double dbl_pos_max = DBL_MAX; +; const double dbl_pos_infinity = INFINITY; +; const double dbl_neg_min_subnormal = -DBL_TRUE_MIN; +; const double dbl_neg_min_normal = -DBL_MIN; +; const double dbl_neg_max = -DBL_MAX; +; const double dbl_neg_infinity = -INFINITY; + +@flt_nan = dso_local constant float 0x7FF8000000000000, align 4 +@flt_pos_min_subnormal = dso_local constant float 0x36A0000000000000, align 4 +@flt_pos_min_normal = dso_local constant float 0x3810000000000000, align 4 +@flt_pos_max = dso_local constant float 0x47EFFFFFE0000000, align 4 +@flt_pos_infinity = dso_local constant float 0x7FF0000000000000, align 4 +@flt_neg_min_subnormal = dso_local constant float 0xB6A0000000000000, align 4 +@flt_neg_min_normal = dso_local constant float 0xB810000000000000, align 4 +@flt_neg_max = dso_local constant float 0xC7EFFFFFE0000000, align 4 +@flt_neg_infinity = dso_local constant float 0xFFF0000000000000, align 4 +@dbl_nan = dso_local constant double 0x7FF8000000000000, align 8 +@dbl_pos_min_subnormal = dso_local constant double 4.940660e-324, align 8 +@dbl_pos_min_normal = dso_local constant double 0x10000000000000, align 8 +@dbl_pos_max = dso_local constant double 0x7FEFFFFFFFFFFFFF, align 8 +@dbl_pos_infinity = dso_local constant double 0x7FF0000000000000, align 8 +@dbl_neg_min_subnormal = dso_local constant double -4.940660e-324, align 8 +@dbl_neg_min_normal = dso_local constant double 0x8010000000000000, align 8 +@dbl_neg_max = dso_local constant double 0xFFEFFFFFFFFFFFFF, align 8 +@dbl_neg_infinity = dso_local constant double 0xFFF0000000000000, align 8 From e94017f49f87974ecade73ee0239200d0d8e9002 Mon Sep 17 00:00:00 2001 From: Sayan Sivakumaran Date: Mon, 10 Nov 2025 08:32:08 -0600 Subject: [PATCH 2/7] Add constantfolding for nextafter/nexttoward --- llvm/include/llvm/ADT/APFloat.h | 13 ++++++ llvm/lib/Analysis/ConstantFolding.cpp | 40 +++++++++++++++- .../InstCombine/constant-fold-nextafter.ll | 44 ++++++++---------- .../constant-fold-nexttoward-fp128.ll | 46 ++++++++----------- .../constant-fold-nexttoward-ppc-fp128.ll | 46 ++++++++----------- .../constant-fold-nexttoward-x86-fp80.ll | 46 ++++++++----------- 6 files changed, 127 insertions(+), 108 deletions(-) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 82ac9a3a1ef80..32e5c1aafc245 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1149,6 +1149,19 @@ class APFloat : public APFloatBase { /// \param Semantics - type float semantics LLVM_ABI static APFloat getAllOnesValue(const fltSemantics &Semantics); + /// Returns a copy of this APFloat with the requested semantics. + /// The requested semantics should be equal to or stronger + /// than the semantics of the current instance. + APFloat getPromoted(const fltSemantics &Sem) const { + assert(isRepresentableBy(this->getSemantics(), Sem) && + "Target semantics will lose information."); + APFloat Val(*this); + bool LosesInfo; + Val.convert(Sem, rmNearestTiesToEven, &LosesInfo); + assert(!LosesInfo); + return Val; + } + /// Returns true if the given semantics has actual significand. /// /// \param Sem - type float semantics diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index da32542cf7870..fadd3e7896c3a 100755 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1996,7 +1996,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': @@ -3221,6 +3223,26 @@ 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)) { + if (Op1V.isNaN() || Op2V.isNaN()) { + return ConstantFP::get(Ty->getContext(), + APFloat::getNaN(Ty->getFltSemantics())); + } + + APFloat PromotedOp1V = Op1V.getPromoted(APFloat::IEEEquad()); + APFloat PromotedOp2V = Op2V.getPromoted(APFloat::IEEEquad()); + if (PromotedOp1V == PromotedOp2V) { + return ConstantFP::get(Ty->getContext(), Op1V); + } + + APFloat Next(Op1V); + Next.next(/*nextDown=*/PromotedOp1V > PromotedOp2V); + return ConstantFP::get(Ty->getContext(), Next); + } } return nullptr; @@ -4655,6 +4677,22 @@ 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: { + APFloat PromotedOp0 = Op0.getPromoted(APFloat::IEEEquad()); + APFloat PromotedOp1 = Op1.getPromoted(APFloat::IEEEquad()); + if (PromotedOp0 == PromotedOp1) + return true; + + APFloat Next(Op0); + Next.next(/*nextDown=*/PromotedOp0 > PromotedOp1); + bool DidOverflow = Op0.isLargest() && Next.isInfinity(); + return !Next.isZero() && !Next.isDenormal() && !DidOverflow; + } default: break; } diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll index c0b949e59f847..9af0a5aeba871 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll @@ -12,32 +12,28 @@ attributes #0 = { willreturn memory(errnomem: write) } define double @nextafter_can_constant_fold_up_direction() { ; CHECK-LABEL: define double @nextafter_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 2.000000e+00) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FF0000000000001 ; %next = call double @nextafter(double noundef 1.0, double noundef 2.0) ret double %next } define double @nextafter_can_constant_fold_down_direction() { ; CHECK-LABEL: define double @nextafter_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 0.000000e+00) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF ; %next = call double @nextafter(double noundef 1.0, double noundef 0.0) ret double %next } define double @nextafter_can_constant_fold_equal_args() { ; CHECK-LABEL: define double @nextafter_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double noundef 1.000000e+00, double noundef 1.000000e+00) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 1.000000e+00 ; %next = call double @nextafter(double noundef 1.0, double noundef 1.0) ret double %next } define double @nextafter_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define double @nextafter_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 1.000000e+00, double 0x7FF8000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF8000000000000 ; %arg = load double, double* @dbl_nan %next = call double @nextafter(double 1.0, double %arg) @@ -46,7 +42,7 @@ define double @nextafter_can_constant_fold_with_nan_arg() { define double @nextafter_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define double @nextafter_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0x7FEFFFFFFFFFFFFF, double 0x7FF0000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF0000000000000 ; %arg1 = load double, double* @dbl_pos_max %arg2 = load double, double* @dbl_pos_infinity @@ -56,7 +52,7 @@ define double @nextafter_not_marked_dead_on_pos_overflow () { define double @nextafter_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define double @nextafter_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0xFFEFFFFFFFFFFFFF, double 0xFFF0000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0xFFF0000000000000 ; %arg1 = load double, double* @dbl_neg_max %arg2 = load double, double* @dbl_neg_infinity @@ -66,7 +62,7 @@ define double @nextafter_not_marked_dead_on_neg_overflow() { define double @nextafter_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define double @nextafter_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0.000000e+00) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0.000000e+00 ; %arg = load double, double* @dbl_pos_min_subnormal %next = call double @nextafter(double %arg, double 0.0) @@ -75,7 +71,7 @@ define double @nextafter_not_marked_dead_on_zero_from_above() { define double @nextafter_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define double @nextafter_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double -4.940660e-324, double 0.000000e+00) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double -0.000000e+00 ; %arg = load double, double* @dbl_neg_min_subnormal %next = call double @nextafter(double %arg, double 0.0) @@ -84,7 +80,7 @@ define double @nextafter_not_marked_dead_on_zero_from_below() { define double @nextafter_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define double @nextafter_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 0x7FF0000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 9.881310e-324 ; %subnormal = load double, double* @dbl_pos_min_subnormal %infinity = load double, double* @dbl_pos_infinity @@ -98,32 +94,28 @@ define double @nextafter_not_marked_dead_on_subnormal() { define float @nextafterf_can_constant_fold_up_direction() { ; CHECK-LABEL: define float @nextafterf_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 2.000000e+00) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FF0000020000000 ; %next = call float @nextafterf(float noundef 1.0, float noundef 2.0) ret float %next } define float @nextafterf_can_constant_fold_down_direction() { ; CHECK-LABEL: define float @nextafterf_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 0.000000e+00) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FEFFFFFE0000000 ; %next = call float @nextafterf(float noundef 1.0, float noundef 0.0) ret float %next } define float @nextafterf_can_constant_fold_equal_args() { ; CHECK-LABEL: define float @nextafterf_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float noundef 1.000000e+00, float noundef 1.000000e+00) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 1.000000e+00 ; %next = call float @nextafterf(float noundef 1.0, float noundef 1.0) ret float %next } define float @nextafterf_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define float @nextafterf_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 1.000000e+00, float 0x7FF8000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF8000000000000 ; %arg = load float, float* @flt_nan %next = call float @nextafterf(float 1.0, float %arg) @@ -132,7 +124,7 @@ define float @nextafterf_can_constant_fold_with_nan_arg() { define float @nextafterf_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x47EFFFFFE0000000, float 0x7FF0000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF0000000000000 ; %arg1 = load float, float* @flt_pos_max %arg2 = load float, float* @flt_pos_infinity @@ -142,7 +134,7 @@ define float @nextafterf_not_marked_dead_on_pos_overflow() { define float @nextafterf_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xC7EFFFFFE0000000, float 0xFFF0000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0xFFF0000000000000 ; %arg1 = load float, float* @flt_neg_max %arg2 = load float, float* @flt_neg_infinity @@ -152,7 +144,7 @@ define float @nextafterf_not_marked_dead_on_neg_overflow() { define float @nextafterf_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0.000000e+00) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0.000000e+00 ; %arg = load float, float* @flt_pos_min_subnormal %next = call float @nextafterf(float %arg, float 0.0) @@ -161,7 +153,7 @@ define float @nextafterf_not_marked_dead_on_zero_from_above() { define float @nextafterf_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0xB6A0000000000000, float 0.000000e+00) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float -0.000000e+00 ; %arg = load float, float* @flt_neg_min_subnormal %next = call float @nextafterf(float %arg, float 0.0) @@ -170,7 +162,7 @@ define float @nextafterf_not_marked_dead_on_zero_from_below() { define float @nextafterf_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x36A0000000000000, float 0x7FF0000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x36B0000000000000 ; %subnormal = load float, float* @flt_pos_min_subnormal %infinity = load float, float* @flt_pos_infinity diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll index 917191350f98b..5f044241fbce8 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll @@ -12,8 +12,7 @@ attributes #0 = { willreturn memory(errnomem: write) } define double @nexttoward_can_constant_fold_up_direction() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, fp128 0xL00000000000000004000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FF0000000000001 ; %arg = fpext double 2.0 to fp128 %next = call double @nexttoward(double noundef 1.0, fp128 %arg) @@ -21,8 +20,7 @@ define double @nexttoward_can_constant_fold_up_direction() { } define double @nexttoward_can_constant_fold_down_direction() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, fp128 0xL00000000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF ; %arg = fpext double 0.0 to fp128 %next = call double @nexttoward(double noundef 1.0, fp128 %arg) @@ -30,8 +28,7 @@ define double @nexttoward_can_constant_fold_down_direction() { } define double @nexttoward_can_constant_fold_equal_args() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, fp128 0xL00000000000000003FFF000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 1.000000e+00 ; %arg = fpext double 1.0 to fp128 %next = call double @nexttoward(double 1.0, fp128 %arg) @@ -39,8 +36,7 @@ define double @nexttoward_can_constant_fold_equal_args() { } define double @nexttoward_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, fp128 0xL00000000000000007FFF800000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF8000000000000 ; %nan = load double, double* @dbl_nan %arg = fpext double %nan to fp128 @@ -50,7 +46,7 @@ define double @nexttoward_can_constant_fold_with_nan_arg() { define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, fp128 0xL00000000000000007FFF000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF0000000000000 ; %pos_max = load double, double* @dbl_pos_max %pos_inf = load double, double* @dbl_pos_infinity @@ -61,7 +57,7 @@ define double @nexttoward_not_marked_dead_on_pos_overflow() { define double @nexttoward_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0xFFEFFFFFFFFFFFFF, fp128 0xL0000000000000000FFFF000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0xFFF0000000000000 ; %neg_max = load double, double* @dbl_neg_max %neg_inf = load double, double* @dbl_neg_infinity @@ -72,7 +68,7 @@ define double @nexttoward_not_marked_dead_on_neg_overflow() { define double @nexttoward_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, fp128 0xL00000000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0.000000e+00 ; %subnormal = load double, double* @dbl_pos_min_subnormal %zero = fpext double 0.0 to fp128 @@ -82,7 +78,7 @@ define double @nexttoward_not_marked_dead_on_zero_from_above() { define double @nexttoward_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double -4.940660e-324, fp128 0xL00000000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double -0.000000e+00 ; %subnormal = load double, double* @dbl_neg_min_subnormal %zero = fpext double 0.0 to fp128 @@ -92,7 +88,7 @@ define double @nexttoward_not_marked_dead_on_zero_from_below() { define double @nexttoward_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, fp128 0xL00000000000000003FFF000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 9.881310e-324 ; %subnormal = load double, double* @dbl_pos_min_subnormal %target = fpext double 1.0 to fp128 @@ -106,8 +102,7 @@ define double @nexttoward_not_marked_dead_on_subnormal() { define float @nexttowardf_can_constant_fold_up_direction() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, fp128 0xL00000000000000004000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FF0000020000000 ; %arg = fpext float 2.0 to fp128 %next = call float @nexttowardf(float noundef 1.0, fp128 %arg) @@ -115,8 +110,7 @@ define float @nexttowardf_can_constant_fold_up_direction() { } define float @nexttowardf_can_constant_fold_down_direction() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, fp128 0xL00000000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FEFFFFFE0000000 ; %arg = fpext float 0.0 to fp128 %next = call float @nexttowardf(float noundef 1.0, fp128 %arg) @@ -124,17 +118,15 @@ define float @nexttowardf_can_constant_fold_down_direction() { } define float @nexttowardf_can_constant_fold_equal_args() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttoward(float 1.000000e+00, fp128 0xL00000000000000003FFF000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 1.000000e+00 ; %arg = fpext float 1.0 to fp128 - %next = call float @nexttoward(float 1.0, fp128 %arg) + %next = call float @nexttowardf(float 1.0, fp128 %arg) ret float %next } define float @nexttowardf_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 1.000000e+00, fp128 0xL00000000000000007FFF800000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF8000000000000 ; %nan = load float, float* @flt_nan %ext_nan = fpext float %nan to fp128 @@ -144,7 +136,7 @@ define float @nexttowardf_can_constant_fold_with_nan_arg() { define float @nexttowardf_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, fp128 0xL00000000000000007FFF000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF0000000000000 ; %pos_max = load float, float* @flt_pos_max %pos_inf = load float, float* @flt_pos_infinity @@ -155,7 +147,7 @@ define float @nexttowardf_not_marked_dead_on_pos_overflow () { define float @nexttowardf_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xC7EFFFFFE0000000, fp128 0xL0000000000000000FFFF000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0xFFF0000000000000 ; %neg_max = load float, float* @flt_neg_max %neg_inf = load float, float* @flt_neg_infinity @@ -166,7 +158,7 @@ define float @nexttowardf_not_marked_dead_on_neg_overflow() { define float @nexttowardf_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, fp128 0xL00000000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0.000000e+00 ; %min_subnormal = load float, float* @flt_pos_min_subnormal %zero = fpext float 0.0 to fp128 @@ -176,7 +168,7 @@ define float @nexttowardf_not_marked_dead_on_zero_from_above() { define float @nexttowardf_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xB6A0000000000000, fp128 0xL00000000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float -0.000000e+00 ; %min_subnormal = load float, float* @flt_neg_min_subnormal %zero = fpext float 0.0 to fp128 @@ -186,7 +178,7 @@ define float @nexttowardf_not_marked_dead_on_zero_from_below() { define float @nexttowardf_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, fp128 0xL00000000000000003FFF000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x36B0000000000000 ; %subnormal = load float, float* @flt_pos_min_subnormal %target = fpext float 1.0 to fp128 diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll index f275c2ce833de..30da81b1bd01f 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll @@ -12,8 +12,7 @@ attributes #0 = { willreturn memory(errnomem: write) } define double @nexttoward_can_constant_fold_up_direction() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, ppc_fp128 0xM40000000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FF0000000000001 ; %arg = fpext double 2.0 to ppc_fp128 %next = call double @nexttoward(double noundef 1.0, ppc_fp128 %arg) @@ -21,8 +20,7 @@ define double @nexttoward_can_constant_fold_up_direction() { } define double @nexttoward_can_constant_fold_down_direction() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, ppc_fp128 0xM00000000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF ; %arg = fpext double 0.0 to ppc_fp128 %next = call double @nexttoward(double noundef 1.0, ppc_fp128 %arg) @@ -30,8 +28,7 @@ define double @nexttoward_can_constant_fold_down_direction() { } define double @nexttoward_can_constant_fold_equal_args() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, ppc_fp128 0xM3FF00000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 1.000000e+00 ; %arg = fpext double 1.0 to ppc_fp128 %next = call double @nexttoward(double 1.0, ppc_fp128 %arg) @@ -39,8 +36,7 @@ define double @nexttoward_can_constant_fold_equal_args() { } define double @nexttoward_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, ppc_fp128 0xM7FF80000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF8000000000000 ; %nan = load double, double* @dbl_nan %arg = fpext double %nan to ppc_fp128 @@ -50,7 +46,7 @@ define double @nexttoward_can_constant_fold_with_nan_arg() { define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, ppc_fp128 0xM7FF00000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF0000000000000 ; %pos_max = load double, double* @dbl_pos_max %pos_inf = load double, double* @dbl_pos_infinity @@ -61,7 +57,7 @@ define double @nexttoward_not_marked_dead_on_pos_overflow() { define double @nexttoward_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0xFFEFFFFFFFFFFFFF, ppc_fp128 0xMFFF00000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0xFFF0000000000000 ; %neg_max = load double, double* @dbl_neg_max %neg_inf = load double, double* @dbl_neg_infinity @@ -72,7 +68,7 @@ define double @nexttoward_not_marked_dead_on_neg_overflow() { define double @nexttoward_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, ppc_fp128 0xM00000000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0.000000e+00 ; %subnormal = load double, double* @dbl_pos_min_subnormal %zero = fpext double 0.0 to ppc_fp128 @@ -82,7 +78,7 @@ define double @nexttoward_not_marked_dead_on_zero_from_above() { define double @nexttoward_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double -4.940660e-324, ppc_fp128 0xM00000000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double -0.000000e+00 ; %subnormal = load double, double* @dbl_neg_min_subnormal %zero = fpext double 0.0 to ppc_fp128 @@ -92,7 +88,7 @@ define double @nexttoward_not_marked_dead_on_zero_from_below() { define double @nexttoward_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, ppc_fp128 0xM3FF00000000000000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 9.881310e-324 ; %subnormal = load double, double* @dbl_pos_min_subnormal %target = fpext double 1.0 to ppc_fp128 @@ -106,8 +102,7 @@ define double @nexttoward_not_marked_dead_on_subnormal() { define float @nexttowardf_can_constant_fold_up_direction() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, ppc_fp128 0xM40000000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FF0000020000000 ; %arg = fpext float 2.0 to ppc_fp128 %next = call float @nexttowardf(float noundef 1.0, ppc_fp128 %arg) @@ -115,8 +110,7 @@ define float @nexttowardf_can_constant_fold_up_direction() { } define float @nexttowardf_can_constant_fold_down_direction() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, ppc_fp128 0xM00000000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FEFFFFFE0000000 ; %arg = fpext float 0.0 to ppc_fp128 %next = call float @nexttowardf(float noundef 1.0, ppc_fp128 %arg) @@ -124,17 +118,15 @@ define float @nexttowardf_can_constant_fold_down_direction() { } define float @nexttowardf_can_constant_fold_equal_args() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttoward(float 1.000000e+00, ppc_fp128 0xM3FF00000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 1.000000e+00 ; %arg = fpext float 1.0 to ppc_fp128 - %next = call float @nexttoward(float 1.0, ppc_fp128 %arg) + %next = call float @nexttowardf(float 1.0, ppc_fp128 %arg) ret float %next } define float @nexttowardf_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 1.000000e+00, ppc_fp128 0xM7FF80000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF8000000000000 ; %nan = load float, float* @flt_nan %ext_nan = fpext float %nan to ppc_fp128 @@ -144,7 +136,7 @@ define float @nexttowardf_can_constant_fold_with_nan_arg() { define float @nexttowardf_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, ppc_fp128 0xM7FF00000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF0000000000000 ; %pos_max = load float, float* @flt_pos_max %pos_inf = load float, float* @flt_pos_infinity @@ -155,7 +147,7 @@ define float @nexttowardf_not_marked_dead_on_pos_overflow () { define float @nexttowardf_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xC7EFFFFFE0000000, ppc_fp128 0xMFFF00000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0xFFF0000000000000 ; %neg_max = load float, float* @flt_neg_max %neg_inf = load float, float* @flt_neg_infinity @@ -166,7 +158,7 @@ define float @nexttowardf_not_marked_dead_on_neg_overflow() { define float @nexttowardf_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, ppc_fp128 0xM00000000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0.000000e+00 ; %min_subnormal = load float, float* @flt_pos_min_subnormal %zero = fpext float 0.0 to ppc_fp128 @@ -176,7 +168,7 @@ define float @nexttowardf_not_marked_dead_on_zero_from_above() { define float @nexttowardf_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xB6A0000000000000, ppc_fp128 0xM00000000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float -0.000000e+00 ; %min_subnormal = load float, float* @flt_neg_min_subnormal %zero = fpext float 0.0 to ppc_fp128 @@ -186,7 +178,7 @@ define float @nexttowardf_not_marked_dead_on_zero_from_below() { define float @nexttowardf_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, ppc_fp128 0xM3FF00000000000000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x36B0000000000000 ; %subnormal = load float, float* @flt_pos_min_subnormal %target = fpext float 1.0 to ppc_fp128 diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll index f059bdc1f8492..3ac632678765d 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll @@ -12,8 +12,7 @@ attributes #0 = { willreturn memory(errnomem: write) } define double @nexttoward_can_constant_fold_up_direction() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, x86_fp80 0xK40008000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FF0000000000001 ; %arg = fpext double 2.0 to x86_fp80 %next = call double @nexttoward(double noundef 1.0, x86_fp80 %arg) @@ -21,8 +20,7 @@ define double @nexttoward_can_constant_fold_up_direction() { } define double @nexttoward_can_constant_fold_down_direction() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double noundef 1.000000e+00, x86_fp80 0xK00000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x3FEFFFFFFFFFFFFF ; %arg = fpext double 0.0 to x86_fp80 %next = call double @nexttoward(double noundef 1.0, x86_fp80 %arg) @@ -30,8 +28,7 @@ define double @nexttoward_can_constant_fold_down_direction() { } define double @nexttoward_can_constant_fold_equal_args() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, x86_fp80 0xK3FFF8000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 1.000000e+00 ; %arg = fpext double 1.0 to x86_fp80 %next = call double @nexttoward(double 1.0, x86_fp80 %arg) @@ -39,8 +36,7 @@ define double @nexttoward_can_constant_fold_equal_args() { } define double @nexttoward_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define double @nexttoward_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 1.000000e+00, x86_fp80 0xK7FFFC000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF8000000000000 ; %nan = load double, double* @dbl_nan %arg = fpext double %nan to x86_fp80 @@ -50,7 +46,7 @@ define double @nexttoward_can_constant_fold_with_nan_arg() { define double @nexttoward_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, x86_fp80 0xK7FFF8000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0x7FF0000000000000 ; %pos_max = load double, double* @dbl_pos_max %pos_inf = load double, double* @dbl_pos_infinity @@ -61,7 +57,7 @@ define double @nexttoward_not_marked_dead_on_pos_overflow () { define double @nexttoward_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0xFFEFFFFFFFFFFFFF, x86_fp80 0xKFFFF8000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0xFFF0000000000000 ; %neg_max = load double, double* @dbl_neg_max %neg_inf = load double, double* @dbl_neg_infinity @@ -72,7 +68,7 @@ define double @nexttoward_not_marked_dead_on_neg_overflow() { define double @nexttoward_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, x86_fp80 0xK00000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 0.000000e+00 ; %subnormal = load double, double* @dbl_pos_min_subnormal %zero = fpext double 0.0 to x86_fp80 @@ -82,7 +78,7 @@ define double @nexttoward_not_marked_dead_on_zero_from_above() { define double @nexttoward_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double -4.940660e-324, x86_fp80 0xK00000000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double -0.000000e+00 ; %subnormal = load double, double* @dbl_neg_min_subnormal %zero = fpext double 0.0 to x86_fp80 @@ -92,7 +88,7 @@ define double @nexttoward_not_marked_dead_on_zero_from_below() { define double @nexttoward_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 4.940660e-324, x86_fp80 0xK3FFF8000000000000000) -; CHECK-NEXT: ret double [[NEXT]] +; CHECK-NEXT: ret double 9.881310e-324 ; %subnormal = load double, double* @dbl_pos_min_subnormal %target = fpext double 1.0 to x86_fp80 @@ -106,8 +102,7 @@ define double @nexttoward_not_marked_dead_on_subnormal() { define float @nexttowardf_can_constant_fold_up_direction() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_up_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, x86_fp80 0xK40008000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FF0000020000000 ; %arg = fpext float 2.0 to x86_fp80 %next = call float @nexttowardf(float noundef 1.0, x86_fp80 %arg) @@ -115,8 +110,7 @@ define float @nexttowardf_can_constant_fold_up_direction() { } define float @nexttowardf_can_constant_fold_down_direction() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_down_direction() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float noundef 1.000000e+00, x86_fp80 0xK00000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x3FEFFFFFE0000000 ; %arg = fpext float 0.0 to x86_fp80 %next = call float @nexttowardf(float noundef 1.0, x86_fp80 %arg) @@ -124,17 +118,15 @@ define float @nexttowardf_can_constant_fold_down_direction() { } define float @nexttowardf_can_constant_fold_equal_args() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_equal_args() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttoward(float 1.000000e+00, x86_fp80 0xK3FFF8000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 1.000000e+00 ; %arg = fpext float 1.0 to x86_fp80 - %next = call float @nexttoward(float 1.0, x86_fp80 %arg) + %next = call float @nexttowardf(float 1.0, x86_fp80 %arg) ret float %next } define float @nexttowardf_can_constant_fold_with_nan_arg() { ; CHECK-LABEL: define float @nexttowardf_can_constant_fold_with_nan_arg() { -; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 1.000000e+00, x86_fp80 0xK7FFFC000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF8000000000000 ; %nan = load float, float* @flt_nan %ext_nan = fpext float %nan to x86_fp80 @@ -144,7 +136,7 @@ define float @nexttowardf_can_constant_fold_with_nan_arg() { define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, x86_fp80 0xK7FFF8000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x7FF0000000000000 ; %pos_max = load float, float* @flt_pos_max %pos_inf = load float, float* @flt_pos_infinity @@ -155,7 +147,7 @@ define float @nexttowardf_not_marked_dead_on_pos_overflow() { define float @nexttowardf_not_marked_dead_on_neg_overflow() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_neg_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xC7EFFFFFE0000000, x86_fp80 0xKFFFF8000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0xFFF0000000000000 ; %neg_max = load float, float* @flt_neg_max %neg_inf = load float, float* @flt_neg_infinity @@ -166,7 +158,7 @@ define float @nexttowardf_not_marked_dead_on_neg_overflow() { define float @nexttowardf_not_marked_dead_on_zero_from_above() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_above() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, x86_fp80 0xK00000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0.000000e+00 ; %min_subnormal = load float, float* @flt_pos_min_subnormal %zero = fpext float 0.0 to x86_fp80 @@ -176,7 +168,7 @@ define float @nexttowardf_not_marked_dead_on_zero_from_above() { define float @nexttowardf_not_marked_dead_on_zero_from_below() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_zero_from_below() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0xB6A0000000000000, x86_fp80 0xK00000000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float -0.000000e+00 ; %min_subnormal = load float, float* @flt_neg_min_subnormal %zero = fpext float 0.0 to x86_fp80 @@ -186,7 +178,7 @@ define float @nexttowardf_not_marked_dead_on_zero_from_below() { define float @nexttowardf_not_marked_dead_on_subnormal() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_subnormal() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x36A0000000000000, x86_fp80 0xK3FFF8000000000000000) -; CHECK-NEXT: ret float [[NEXT]] +; CHECK-NEXT: ret float 0x36B0000000000000 ; %subnormal = load float, float* @flt_pos_min_subnormal %target = fpext float 1.0 to x86_fp80 From a0029be8b6b2e2c7e27bfeb945725f4813d925e0 Mon Sep 17 00:00:00 2001 From: Sayan Sivakumaran Date: Mon, 10 Nov 2025 19:41:58 -0600 Subject: [PATCH 3/7] Make sure to propagate NaN payloads when folding --- llvm/lib/Analysis/ConstantFolding.cpp | 20 +++++++++++++--- .../InstCombine/constant-fold-nextafter.ll | 22 +++++++++++++++++ .../constant-fold-nexttoward-fp128.ll | 24 +++++++++++++++++++ .../constant-fold-nexttoward-ppc-fp128.ll | 24 +++++++++++++++++++ .../constant-fold-nexttoward-x86-fp80.ll | 24 +++++++++++++++++++ 5 files changed, 111 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index fadd3e7896c3a..58946195eaf0f 100755 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -3228,11 +3228,22 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty, case LibFunc_nexttoward: case LibFunc_nexttowardf: if (TLI->has(Func)) { - if (Op1V.isNaN() || Op2V.isNaN()) { - return ConstantFP::get(Ty->getContext(), - APFloat::getNaN(Ty->getFltSemantics())); + // Make sure to propagate NaN payloads. + if (Op1V.isNaN()) { + return ConstantFP::get(Ty->getContext(), Op1V); + } + if (Op2V.isNaN()) { + // Payload propagation might not make sense if the second argument's + // type is wider than the return value. We'll give up in the latter + // case. + bool SemEqual = &Op2V.getSemantics() == &Ty->getFltSemantics(); + APFloat Ret = SemEqual ? Op2V : APFloat::getNaN(Ty->getFltSemantics()); + return ConstantFP::get(Ty->getContext(), Ret); } + // The two arguments of nexttoward can have differing semantics. + // We need to convert both arguments to the same semantics so + // we can do comparisons. APFloat PromotedOp1V = Op1V.getPromoted(APFloat::IEEEquad()); APFloat PromotedOp2V = Op2V.getPromoted(APFloat::IEEEquad()); if (PromotedOp1V == PromotedOp2V) { @@ -4683,6 +4694,9 @@ bool llvm::isMathLibCallNoop(const CallBase *Call, case LibFunc_nexttoward: case LibFunc_nexttowardf: case LibFunc_nexttowardl: { + // The two arguments of nexttoward can have differing semantics. + // We need to convert both arguments to the same semantics so + // we can do comparisons. APFloat PromotedOp0 = Op0.getPromoted(APFloat::IEEEquad()); APFloat PromotedOp1 = Op1.getPromoted(APFloat::IEEEquad()); if (PromotedOp0 == PromotedOp1) diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll index 9af0a5aeba871..a038532abc84b 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll @@ -39,6 +39,17 @@ define double @nextafter_can_constant_fold_with_nan_arg() { %next = call double @nextafter(double 1.0, double %arg) ret double %next } +define double @nextafter_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define double @nextafter_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret double 0x7FF8000000000001 +; + %nan = load double, double* @dbl_nan + %tmp1 = bitcast double %nan to i64 + %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_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define double @nextafter_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 0x7FEFFFFFFFFFFFFF, double 0x7FF0000000000000) @@ -121,6 +132,17 @@ define float @nextafterf_can_constant_fold_with_nan_arg() { %next = call float @nextafterf(float 1.0, float %arg) ret float %next } +define float @nextafterf_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define float @nextafterf_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret float 0x7FF8000020000000 +; + %nan = load float, float* @flt_nan + %tmp1 = bitcast float %nan to i32 + %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 float @nextafterf_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define float @nextafterf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nextafterf(float 0x47EFFFFFE0000000, float 0x7FF0000000000000) diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll index 5f044241fbce8..dedf3e76a788e 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll @@ -43,6 +43,18 @@ define double @nexttoward_can_constant_fold_with_nan_arg() { %next = call double @nexttoward(double 1.0, fp128 %arg) ret double %next } +define double @nexttoward_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define double @nexttoward_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret double 0x7FF8000000000001 +; + %nan = load double, double* @dbl_nan + %tmp1 = bitcast double %nan to i64 + %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 double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, fp128 0xL00000000000000007FFF000000000000) @@ -133,6 +145,18 @@ define float @nexttowardf_can_constant_fold_with_nan_arg() { %next = call float @nexttowardf(float 1.0, fp128 %ext_nan) ret float %next } +define float @nexttowardf_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define float @nexttowardf_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret float 0x7FF8000020000000 +; + %nan = load float, float* @flt_nan + %tmp1 = bitcast float %nan to i32 + %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 float @nexttowardf_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, fp128 0xL00000000000000007FFF000000000000) diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll index 30da81b1bd01f..718e3333cefee 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll @@ -43,6 +43,18 @@ define double @nexttoward_can_constant_fold_with_nan_arg() { %next = call double @nexttoward(double 1.0, ppc_fp128 %arg) ret double %next } +define double @nexttoward_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define double @nexttoward_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret double 0x7FF8000000000001 +; + %nan = load double, double* @dbl_nan + %tmp1 = bitcast double %nan to i64 + %tmp2 = or i64 %tmp1, 1 + %nan_with_payload = bitcast i64 %tmp2 to double + %dummy_arg = fpext double 1.0 to ppc_fp128 + %next = call double @nexttoward(double %nan_with_payload, ppc_fp128 %dummy_arg) + ret double %next +} define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, ppc_fp128 0xM7FF00000000000000000000000000000) @@ -133,6 +145,18 @@ define float @nexttowardf_can_constant_fold_with_nan_arg() { %next = call float @nexttowardf(float 1.0, ppc_fp128 %ext_nan) ret float %next } +define float @nexttowardf_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define float @nexttowardf_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret float 0x7FF8000020000000 +; + %nan = load float, float* @flt_nan + %tmp1 = bitcast float %nan to i32 + %tmp2 = or i32 %tmp1, 1 + %nan_with_payload = bitcast i32 %tmp2 to float + %dummy_arg = fpext float 1.0 to ppc_fp128 + %next = call float @nexttowardf(float %nan_with_payload, ppc_fp128 %dummy_arg) + ret float %next +} define float @nexttowardf_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, ppc_fp128 0xM7FF00000000000000000000000000000) diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll index 3ac632678765d..590d0655f4009 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll @@ -43,6 +43,18 @@ define double @nexttoward_can_constant_fold_with_nan_arg() { %next = call double @nexttoward(double 1.0, x86_fp80 %arg) ret double %next } +define double @nexttoward_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define double @nexttoward_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret double 0x7FF8000000000001 +; + %nan = load double, double* @dbl_nan + %tmp1 = bitcast double %nan to i64 + %tmp2 = or i64 %tmp1, 1 + %nan_with_payload = bitcast i64 %tmp2 to double + %dummy_arg = fpext double 1.0 to x86_fp80 + %next = call double @nexttoward(double %nan_with_payload, x86_fp80 %dummy_arg) + ret double %next +} define double @nexttoward_not_marked_dead_on_pos_overflow () { ; CHECK-LABEL: define double @nexttoward_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call double @nexttoward(double 0x7FEFFFFFFFFFFFFF, x86_fp80 0xK7FFF8000000000000000) @@ -133,6 +145,18 @@ define float @nexttowardf_can_constant_fold_with_nan_arg() { %next = call float @nexttowardf(float 1.0, x86_fp80 %ext_nan) ret float %next } +define float @nexttowardf_constant_fold_propagates_nan_payload() { +; CHECK-LABEL: define float @nexttowardf_constant_fold_propagates_nan_payload() { +; CHECK-NEXT: ret float 0x7FF8000020000000 +; + %nan = load float, float* @flt_nan + %tmp1 = bitcast float %nan to i32 + %tmp2 = or i32 %tmp1, 1 + %nan_with_payload = bitcast i32 %tmp2 to float + %dummy_arg = fpext float 1.0 to x86_fp80 + %next = call float @nexttowardf(float %nan_with_payload, x86_fp80 %dummy_arg) + ret float %next +} define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-LABEL: define float @nexttowardf_not_marked_dead_on_pos_overflow() { ; CHECK-NEXT: [[NEXT:%.*]] = call float @nexttowardf(float 0x47EFFFFFE0000000, x86_fp80 0xK7FFF8000000000000000) From 1de09dd0f6b276f16735551fc6ab3d0989f7d1a6 Mon Sep 17 00:00:00 2001 From: Sayan Sivakumaran Date: Mon, 10 Nov 2025 20:05:36 -0600 Subject: [PATCH 4/7] Add tests for APFloat::getPromoted --- llvm/unittests/ADT/APFloatTest.cpp | 109 +++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 99cc38b6b422b..53336e1ccb113 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -10182,4 +10182,113 @@ TEST(APFloatTest, FrexpQuietSNaN) { EXPECT_FALSE(Result.isSignaling()); } +TEST(APFloatTest, getPromoted) { + // Strengthening promotions are allowed. + bool LosesInfo = false; + APFloat ValidPromotionTest(1.0f); + APFloat FloatVal = ValidPromotionTest.getPromoted(APFloat::IEEEsingle()); + APFloat DoubleVal = ValidPromotionTest.getPromoted(APFloat::IEEEdouble()); + APFloat QuadVal = ValidPromotionTest.getPromoted(APFloat::IEEEquad()); + APFloat X87DoubleVal = + ValidPromotionTest.getPromoted(APFloat::x87DoubleExtended()); + APFloat PPCDoubleDoubleVal = + ValidPromotionTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()); + + // Trivial promotions to the same semantics are allowed. + FloatVal.getPromoted(FloatVal.getSemantics()); + DoubleVal.getPromoted(DoubleVal.getSemantics()); + QuadVal.getPromoted(QuadVal.getSemantics()); + X87DoubleVal.getPromoted(X87DoubleVal.getSemantics()); + PPCDoubleDoubleVal.getPromoted(PPCDoubleDoubleVal.getSemantics()); + + // Promotions have the expected semantics. + EXPECT_EQ(&FloatVal.getSemantics(), &APFloat::IEEEsingle()); + EXPECT_EQ(&DoubleVal.getSemantics(), &APFloat::IEEEdouble()); + EXPECT_EQ(&QuadVal.getSemantics(), &APFloat::IEEEquad()); + EXPECT_EQ(&X87DoubleVal.getSemantics(), &APFloat::x87DoubleExtended()); + EXPECT_EQ(&PPCDoubleDoubleVal.getSemantics(), + &APFloat::PPCDoubleDoubleLegacy()); + + // Promotions preserve the initial value. + QuadVal.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, + &LosesInfo); + EXPECT_FALSE(LosesInfo); + X87DoubleVal.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, + &LosesInfo); + EXPECT_FALSE(LosesInfo); + PPCDoubleDoubleVal.convert(APFloat::IEEEdouble(), + APFloat::rmNearestTiesToEven, &LosesInfo); + EXPECT_FALSE(LosesInfo); + EXPECT_EQ(1.0, FloatVal.convertToFloat()); + EXPECT_EQ(1.0, DoubleVal.convertToDouble()); + EXPECT_EQ(1.0, QuadVal.convertToDouble()); + EXPECT_EQ(1.0, X87DoubleVal.convertToDouble()); + EXPECT_EQ(1.0, PPCDoubleDoubleVal.convertToDouble()); + + // All invalid promotions are swiftly killed. + APFloat InvalidPromotionTest(1.0f); + EXPECT_DEATH(InvalidPromotionTest.getPromoted(APFloat::IEEEhalf()), + "Target semantics will lose information"); + EXPECT_DEATH(InvalidPromotionTest.getPromoted(APFloat::BFloat()), + "Target semantics will lose information."); + + APFloat InvalidPromotionDoubleTest = + InvalidPromotionTest.getPromoted(APFloat::IEEEdouble()); + EXPECT_DEATH(InvalidPromotionDoubleTest.getPromoted(APFloat::BFloat()), + "Target semantics will lose information."); + EXPECT_DEATH(InvalidPromotionDoubleTest.getPromoted(APFloat::IEEEsingle()), + "Target semantics will lose information"); + EXPECT_DEATH(InvalidPromotionDoubleTest.getPromoted(APFloat::IEEEhalf()), + "Target semantics will lose information"); + + APFloat InvalidPromotionQuadTest = + InvalidPromotionTest.getPromoted(APFloat::IEEEquad()); + EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::BFloat()), + "Target semantics will lose information."); + EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::IEEEsingle()), + "Target semantics will lose information"); + EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::IEEEhalf()), + "Target semantics will lose information"); + EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::IEEEdouble()), + "Target semantics will lose information"); + EXPECT_DEATH( + InvalidPromotionQuadTest.getPromoted(APFloat::x87DoubleExtended()), + "Target semantics will lose information"); + EXPECT_DEATH( + InvalidPromotionQuadTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()), + "Target semantics will lose information"); + + APFloat InvalidPromotionX87Test = + InvalidPromotionTest.getPromoted(APFloat::x87DoubleExtended()); + EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::BFloat()), + "Target semantics will lose information."); + EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::IEEEsingle()), + "Target semantics will lose information"); + EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::IEEEhalf()), + "Target semantics will lose information"); + EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::IEEEdouble()), + "Target semantics will lose information"); + EXPECT_DEATH( + InvalidPromotionX87Test.getPromoted(APFloat::PPCDoubleDoubleLegacy()), + "Target semantics will lose information"); + + APFloat InvalidPromotionPPCDoubleDoubleTest = + InvalidPromotionTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()); + EXPECT_DEATH( + InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::BFloat()), + "Target semantics will lose information."); + EXPECT_DEATH( + InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::IEEEsingle()), + "Target semantics will lose information"); + EXPECT_DEATH( + InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::IEEEhalf()), + "Target semantics will lose information"); + EXPECT_DEATH( + InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::IEEEdouble()), + "Target semantics will lose information"); + EXPECT_DEATH(InvalidPromotionPPCDoubleDoubleTest.getPromoted( + APFloat::x87DoubleExtended()), + "Target semantics will lose information"); +} + } // namespace From 678ba1e3b39d0d4f72ca2423e5a26631718de573 Mon Sep 17 00:00:00 2001 From: Sayan Sivakumaran Date: Tue, 11 Nov 2025 11:07:53 -0600 Subject: [PATCH 5/7] Remove unnecessary repetitive tests --- llvm/unittests/ADT/APFloatTest.cpp | 101 +++-------------------------- 1 file changed, 10 insertions(+), 91 deletions(-) diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 53336e1ccb113..005f54c5e6d1d 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -10184,111 +10184,30 @@ TEST(APFloatTest, FrexpQuietSNaN) { TEST(APFloatTest, getPromoted) { // Strengthening promotions are allowed. - bool LosesInfo = false; APFloat ValidPromotionTest(1.0f); - APFloat FloatVal = ValidPromotionTest.getPromoted(APFloat::IEEEsingle()); APFloat DoubleVal = ValidPromotionTest.getPromoted(APFloat::IEEEdouble()); - APFloat QuadVal = ValidPromotionTest.getPromoted(APFloat::IEEEquad()); - APFloat X87DoubleVal = - ValidPromotionTest.getPromoted(APFloat::x87DoubleExtended()); - APFloat PPCDoubleDoubleVal = - ValidPromotionTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()); // Trivial promotions to the same semantics are allowed. - FloatVal.getPromoted(FloatVal.getSemantics()); DoubleVal.getPromoted(DoubleVal.getSemantics()); - QuadVal.getPromoted(QuadVal.getSemantics()); - X87DoubleVal.getPromoted(X87DoubleVal.getSemantics()); - PPCDoubleDoubleVal.getPromoted(PPCDoubleDoubleVal.getSemantics()); - // Promotions have the expected semantics. - EXPECT_EQ(&FloatVal.getSemantics(), &APFloat::IEEEsingle()); + // Promotions have the expected semantics and preserve the initial value. EXPECT_EQ(&DoubleVal.getSemantics(), &APFloat::IEEEdouble()); - EXPECT_EQ(&QuadVal.getSemantics(), &APFloat::IEEEquad()); - EXPECT_EQ(&X87DoubleVal.getSemantics(), &APFloat::x87DoubleExtended()); - EXPECT_EQ(&PPCDoubleDoubleVal.getSemantics(), - &APFloat::PPCDoubleDoubleLegacy()); - - // Promotions preserve the initial value. - QuadVal.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, - &LosesInfo); - EXPECT_FALSE(LosesInfo); - X87DoubleVal.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, - &LosesInfo); - EXPECT_FALSE(LosesInfo); - PPCDoubleDoubleVal.convert(APFloat::IEEEdouble(), - APFloat::rmNearestTiesToEven, &LosesInfo); - EXPECT_FALSE(LosesInfo); - EXPECT_EQ(1.0, FloatVal.convertToFloat()); EXPECT_EQ(1.0, DoubleVal.convertToDouble()); - EXPECT_EQ(1.0, QuadVal.convertToDouble()); - EXPECT_EQ(1.0, X87DoubleVal.convertToDouble()); - EXPECT_EQ(1.0, PPCDoubleDoubleVal.convertToDouble()); +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG // All invalid promotions are swiftly killed. - APFloat InvalidPromotionTest(1.0f); - EXPECT_DEATH(InvalidPromotionTest.getPromoted(APFloat::IEEEhalf()), - "Target semantics will lose information"); - EXPECT_DEATH(InvalidPromotionTest.getPromoted(APFloat::BFloat()), - "Target semantics will lose information."); - - APFloat InvalidPromotionDoubleTest = - InvalidPromotionTest.getPromoted(APFloat::IEEEdouble()); - EXPECT_DEATH(InvalidPromotionDoubleTest.getPromoted(APFloat::BFloat()), - "Target semantics will lose information."); - EXPECT_DEATH(InvalidPromotionDoubleTest.getPromoted(APFloat::IEEEsingle()), - "Target semantics will lose information"); - EXPECT_DEATH(InvalidPromotionDoubleTest.getPromoted(APFloat::IEEEhalf()), - "Target semantics will lose information"); - - APFloat InvalidPromotionQuadTest = - InvalidPromotionTest.getPromoted(APFloat::IEEEquad()); - EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::BFloat()), - "Target semantics will lose information."); - EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::IEEEsingle()), - "Target semantics will lose information"); - EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::IEEEhalf()), - "Target semantics will lose information"); - EXPECT_DEATH(InvalidPromotionQuadTest.getPromoted(APFloat::IEEEdouble()), - "Target semantics will lose information"); - EXPECT_DEATH( - InvalidPromotionQuadTest.getPromoted(APFloat::x87DoubleExtended()), - "Target semantics will lose information"); - EXPECT_DEATH( - InvalidPromotionQuadTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()), - "Target semantics will lose information"); - - APFloat InvalidPromotionX87Test = - InvalidPromotionTest.getPromoted(APFloat::x87DoubleExtended()); - EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::BFloat()), - "Target semantics will lose information."); - EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::IEEEsingle()), - "Target semantics will lose information"); - EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::IEEEhalf()), + APFloat InvalidPromotionTest = + ValidPromotionTest.getPromoted(APFloat::IEEEquad()); + EXPECT_DEATH(InvalidPromotionTest.getPromoted(APFloat::IEEEdouble()), "Target semantics will lose information"); - EXPECT_DEATH(InvalidPromotionX87Test.getPromoted(APFloat::IEEEdouble()), + EXPECT_DEATH(InvalidPromotionTest.getPromoted(APFloat::x87DoubleExtended()), "Target semantics will lose information"); EXPECT_DEATH( - InvalidPromotionX87Test.getPromoted(APFloat::PPCDoubleDoubleLegacy()), + InvalidPromotionTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()), "Target semantics will lose information"); - - APFloat InvalidPromotionPPCDoubleDoubleTest = - InvalidPromotionTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()); - EXPECT_DEATH( - InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::BFloat()), - "Target semantics will lose information."); - EXPECT_DEATH( - InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::IEEEsingle()), - "Target semantics will lose information"); - EXPECT_DEATH( - InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::IEEEhalf()), - "Target semantics will lose information"); - EXPECT_DEATH( - InvalidPromotionPPCDoubleDoubleTest.getPromoted(APFloat::IEEEdouble()), - "Target semantics will lose information"); - EXPECT_DEATH(InvalidPromotionPPCDoubleDoubleTest.getPromoted( - APFloat::x87DoubleExtended()), - "Target semantics will lose information"); +#endif +#endif } } // namespace From 8b3a10c341d86e8ed5292a7c1e5a0cf3746f0c46 Mon Sep 17 00:00:00 2001 From: Sayan Sivakumaran Date: Wed, 12 Nov 2025 08:47:19 -0600 Subject: [PATCH 6/7] Code style fixes and add const where appropriate --- llvm/lib/Analysis/ConstantFolding.cpp | 28 +++++++++++++-------------- llvm/unittests/ADT/APFloatTest.cpp | 4 +--- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 58946195eaf0f..0253606c4eedb 100755 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -3228,27 +3228,25 @@ static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty, case LibFunc_nexttoward: case LibFunc_nexttowardf: if (TLI->has(Func)) { - // Make sure to propagate NaN payloads. - if (Op1V.isNaN()) { + if (Op1V.isNaN()) return ConstantFP::get(Ty->getContext(), Op1V); - } if (Op2V.isNaN()) { - // Payload propagation might not make sense if the second argument's - // type is wider than the return value. We'll give up in the latter - // case. - bool SemEqual = &Op2V.getSemantics() == &Ty->getFltSemantics(); - APFloat Ret = SemEqual ? Op2V : APFloat::getNaN(Ty->getFltSemantics()); + // IEEE 754, 6.5.4 recommends the inclusion of diagnostic + // information if the NaN payload can't be preserved. Should + // we do something special here? + const bool SemEqual = &Op2V.getSemantics() == &Ty->getFltSemantics(); + const APFloat Ret = + SemEqual ? Op2V : APFloat::getNaN(Ty->getFltSemantics()); return ConstantFP::get(Ty->getContext(), Ret); } // The two arguments of nexttoward can have differing semantics. // We need to convert both arguments to the same semantics so // we can do comparisons. - APFloat PromotedOp1V = Op1V.getPromoted(APFloat::IEEEquad()); - APFloat PromotedOp2V = Op2V.getPromoted(APFloat::IEEEquad()); - if (PromotedOp1V == PromotedOp2V) { + const APFloat PromotedOp1V = Op1V.getPromoted(APFloat::IEEEquad()); + const APFloat PromotedOp2V = Op2V.getPromoted(APFloat::IEEEquad()); + if (PromotedOp1V == PromotedOp2V) return ConstantFP::get(Ty->getContext(), Op1V); - } APFloat Next(Op1V); Next.next(/*nextDown=*/PromotedOp1V > PromotedOp2V); @@ -4697,14 +4695,14 @@ bool llvm::isMathLibCallNoop(const CallBase *Call, // The two arguments of nexttoward can have differing semantics. // We need to convert both arguments to the same semantics so // we can do comparisons. - APFloat PromotedOp0 = Op0.getPromoted(APFloat::IEEEquad()); - APFloat PromotedOp1 = Op1.getPromoted(APFloat::IEEEquad()); + const APFloat PromotedOp0 = Op0.getPromoted(APFloat::IEEEquad()); + const APFloat PromotedOp1 = Op1.getPromoted(APFloat::IEEEquad()); if (PromotedOp0 == PromotedOp1) return true; APFloat Next(Op0); Next.next(/*nextDown=*/PromotedOp0 > PromotedOp1); - bool DidOverflow = Op0.isLargest() && Next.isInfinity(); + const bool DidOverflow = Op0.isLargest() && Next.isInfinity(); return !Next.isZero() && !Next.isDenormal() && !DidOverflow; } default: diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 005f54c5e6d1d..a6fe35e66684c 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -10194,8 +10194,7 @@ TEST(APFloatTest, getPromoted) { EXPECT_EQ(&DoubleVal.getSemantics(), &APFloat::IEEEdouble()); EXPECT_EQ(1.0, DoubleVal.convertToDouble()); -#ifdef GTEST_HAS_DEATH_TEST -#ifndef NDEBUG +#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) // All invalid promotions are swiftly killed. APFloat InvalidPromotionTest = ValidPromotionTest.getPromoted(APFloat::IEEEquad()); @@ -10207,7 +10206,6 @@ TEST(APFloatTest, getPromoted) { InvalidPromotionTest.getPromoted(APFloat::PPCDoubleDoubleLegacy()), "Target semantics will lose information"); #endif -#endif } } // namespace From 70a9760eef319b2675ade357525d64dad05ff670 Mon Sep 17 00:00:00 2001 From: Sayan Sivakumaran Date: Wed, 12 Nov 2025 08:48:17 -0600 Subject: [PATCH 7/7] Add poison and readnone tests --- .../InstCombine/constant-fold-nextafter.ll | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll index a038532abc84b..5ffcaef5be9c0 100644 --- a/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll +++ b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll @@ -99,6 +99,25 @@ define double @nextafter_not_marked_dead_on_subnormal() { ret double %next } +define double @nextafter_not_marked_dead_on_poison() { +; CHECK-LABEL: define double @nextafter_not_marked_dead_on_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 @nextafter_marked_dead_when_readnone() { +; CHECK-LABEL: define double @nextafter_marked_dead_when_readnone() { +; CHECK-NEXT: [[NEXT:%.*]] = call double @nextafter(double 4.940660e-324, double 1.000000e+00) #[[ATTR1:[0-9]+]] +; CHECK-NEXT: ret double 9.881310e-324 +; + %subnormal = load double, double* @dbl_pos_min_subnormal + %next = call double @nextafter(double %subnormal, double 1.0) readnone + ret double %next +} + ; ================== ; nextafterf tests ; ==================