[llvm] [ConstantFolding] Add constant folding support for nextafter/nexttoward (PR #167324)

via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 10 11:04:33 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Sayan Sivakumaran (sivakusayan)

<details>
<summary>Changes</summary>

Fixes issue #<!-- -->74368.

This patch enables us to constant fold `nextafter` and `nexttoward` as long as we know that `errno` won't be written. In the latter case, we should keep the function call so the programmer can observe the side effect. 

Apologies for the large patch, the majority of it are `lit` tests. I wasn't sure how to cut down on the repetitiveness here, let me know if you have  any better ideas. I got the idea for reusing the constants across `.ll` files from the LLVM Discord.

---

Patch is 38.99 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/167324.diff


7 Files Affected:

- (modified) llvm/include/llvm/ADT/APFloat.h (+13) 
- (modified) llvm/lib/Analysis/ConstantFolding.cpp (+39-1) 
- (added) llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll (+171) 
- (added) llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll (+187) 
- (added) llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll (+187) 
- (added) llvm/test/Transforms/InstCombine/constant-fold-nexttoward-x86-fp80.ll (+187) 
- (added) llvm/test/Transforms/InstCombine/floating-point-constants.ll (+48) 


``````````diff
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
new file mode 100644
index 0000000000000..9af0a5aeba871
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/constant-fold-nextafter.ll
@@ -0,0 +1,171 @@
+; 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:    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:    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:    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:    ret double 0x7FF8000000000000
+;
+  %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 0x7FF0000000000000
+;
+  %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 0xFFF0000000000000
+;
+  %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 0.000000e+00
+;
+  %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 -0.000000e+00
+;
+  %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 9.881310e-324
+;
+  %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:    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:    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:    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:    ret float 0x7FF8000000000000
+;
+  %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 0x7FF0000000000000
+;
+  %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 0xFFF0000000000000
+;
+  %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 0.000000e+00
+;
+  %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 -0.000000e+00
+;
+  %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 0x36B0000000000000
+;
+  %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..5f044241fbce8
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-fp128.ll
@@ -0,0 +1,187 @@
+; 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:    ret double 0x3FF0000000000001
+;
+  %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:    ret double 0x3FEFFFFFFFFFFFFF
+;
+  %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:    ret double 1.000000e+00
+;
+  %arg = fpext double 1.0 to fp128
+  %next = call double @nexttoward(double 1.0, fp128 %arg)
+  ret double %next
+}
+define double @nexttoward_can_constant_fold_with_nan_arg() {
+; CHECK-LABEL: define double @nexttoward_can_constant_fold_with_nan_arg() {
+; CHECK-NEXT:    ret double 0x7FF8000000000000
+;
+  %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 0x7FF0000000000000
+;
+  %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 0xFFF0000000000000
+;
+  %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 0.000000e+00
+;
+  %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 -0.000000e+00
+;
+  %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 9.881310e-324
+;
+  %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:    ret float 0x3FF0000020000000
+;
+  %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:    ret float 0x3FEFFFFFE0000000
+;
+  %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:    ret float 1.000000e+00
+;
+  %arg = fpext float 1.0 to fp128
+  %next = call float @nexttowardf(float 1.0, fp128 %arg)
+  ret float %next
+}
+define float @nexttowardf_can_constant_fold_with_nan_arg() {
+; CHECK-LABEL: define float @nexttowardf_can_constant_fold_with_nan_arg() {
+; CHECK-NEXT:    ret float 0x7FF8000000000000
+;
+  %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 0x7FF0000000000000
+;
+  %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 0xFFF0000000000000
+;
+  %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 0.000000e+00
+;
+  %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 -0.000000e+00
+;
+  %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 0x36B0000000000000
+;
+  %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..30da81b1bd01f
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/constant-fold-nexttoward-ppc-fp128.ll
@@ -0,0 +1,187 @@
+; 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
+
+attribut...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/167324


More information about the llvm-commits mailing list