[llvm] Fill in some missing C23 math libcall handling (PR #170672)

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 4 08:01:45 PST 2025


https://github.com/valadaptive updated https://github.com/llvm/llvm-project/pull/170672

>From 2cc5630e08a3b5f9708f1dc8703cd626c197c94a Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:37:27 -0500
Subject: [PATCH 01/13] [InstSimplify] Add roundeven constant-propagation tests

The libcall versions will later be optimized and constant-folded.
---
 .../InstSimplify/ConstProp/roundeven.ll       | 165 ++++++++++++++++++
 1 file changed, 165 insertions(+)
 create mode 100644 llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll

diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll b/llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll
new file mode 100644
index 0000000000000..68938b3c6244c
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll
@@ -0,0 +1,165 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=early-cse -earlycse-debug-hash < %s | FileCheck %s
+
+declare float @roundevenf(float) #0
+declare float @llvm.roundeven.f32(float)
+declare double @roundeven(double) #0
+declare double @llvm.roundeven.f64(double)
+
+define float @constant_fold_roundeven_f32_01() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_01(
+; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 1.250000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret float [[X]]
+;
+  %x = call float @roundevenf(float 1.25) #0
+  ret float %x
+}
+
+define float @constant_fold_roundeven_f32_02() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_02(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret float -1.000000e+00
+;
+  %x = call float @llvm.roundeven.f32(float -1.25) #0
+  ret float %x
+}
+
+; roundeven rounds ties to even, so 1.5 -> 2.0 (nearest even)
+define float @constant_fold_roundeven_f32_03() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_03(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 1.500000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret float [[X]]
+;
+  %x = call float @roundevenf(float 1.5) #0
+  ret float %x
+}
+
+; roundeven rounds ties to even, so -1.5 -> -2.0 (nearest even)
+define float @constant_fold_roundeven_f32_04() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_04(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret float -2.000000e+00
+;
+  %x = call float @llvm.roundeven.f32(float -1.5) #0
+  ret float %x
+}
+
+; roundeven rounds ties to even, so 2.5 -> 2.0 (nearest even)
+define float @constant_fold_roundeven_f32_05() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_05(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 2.500000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret float [[X]]
+;
+  %x = call float @roundevenf(float 2.5) #0
+  ret float %x
+}
+
+; roundeven rounds ties to even, so -2.5 -> -2.0 (nearest even)
+define float @constant_fold_roundeven_f32_06() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_06(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret float -2.000000e+00
+;
+  %x = call float @llvm.roundeven.f32(float -2.5) #0
+  ret float %x
+}
+
+define float @constant_fold_roundeven_f32_07() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_07(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 2.750000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret float [[X]]
+;
+  %x = call float @roundevenf(float 2.75) #0
+  ret float %x
+}
+
+define float @constant_fold_roundeven_f32_08() #0 {
+; CHECK-LABEL: define float @constant_fold_roundeven_f32_08(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret float -3.000000e+00
+;
+  %x = call float @llvm.roundeven.f32(float -2.75) #0
+  ret float %x
+}
+
+define double @constant_fold_roundeven_f64_01() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_01(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 1.300000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret double [[X]]
+;
+  %x = call double @roundeven(double 1.3) #0
+  ret double %x
+}
+
+define double @constant_fold_roundeven_f64_02() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_02(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret double -1.000000e+00
+;
+  %x = call double @llvm.roundeven.f64(double -1.3) #0
+  ret double %x
+}
+
+define double @constant_fold_roundeven_f64_03() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_03(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 1.500000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret double [[X]]
+;
+  %x = call double @roundeven(double 1.5) #0
+  ret double %x
+}
+
+define double @constant_fold_roundeven_f64_04() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_04(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret double -2.000000e+00
+;
+  %x = call double @llvm.roundeven.f64(double -1.5) #0
+  ret double %x
+}
+
+define double @constant_fold_roundeven_f64_05() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_05(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 2.500000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret double [[X]]
+;
+  %x = call double @roundeven(double 2.5) #0
+  ret double %x
+}
+
+define double @constant_fold_roundeven_f64_06() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_06(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret double -2.000000e+00
+;
+  %x = call double @llvm.roundeven.f64(double -2.5) #0
+  ret double %x
+}
+
+define double @constant_fold_roundeven_f64_07() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_07(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 2.700000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret double [[X]]
+;
+  %x = call double @roundeven(double 2.7) #0
+  ret double %x
+}
+
+define double @constant_fold_roundeven_f64_08() #0 {
+; CHECK-LABEL: define double @constant_fold_roundeven_f64_08(
+; CHECK-SAME: ) #[[ATTR0]] {
+; CHECK-NEXT:    ret double -3.000000e+00
+;
+  %x = call double @llvm.roundeven.f64(double -2.7) #0
+  ret double %x
+}
+
+attributes #0 = { nounwind readnone willreturn }

>From 416811a24f06c8cae99116d9cd9509b58e079afe Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 07:48:07 -0500
Subject: [PATCH 02/13] [InferAttrs] Mark ceil and round as memory(none)

This probably should've been done in
https://github.com/llvm/llvm-project/pull/124742, but it wasn't. The
floor, ceil, round, and trunc family of functions all behave the same.
---
 llvm/lib/Transforms/Utils/BuildLibCalls.cpp         | 12 ++++++------
 llvm/test/Transforms/InferFunctionAttrs/annotate.ll | 12 ++++++------
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 02b73e85d783f..213869fb993d7 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -1227,9 +1227,6 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
   case LibFunc_atanhf:
   case LibFunc_atanhl:
   case LibFunc_atanl:
-  case LibFunc_ceil:
-  case LibFunc_ceilf:
-  case LibFunc_ceill:
   case LibFunc_cos:
   case LibFunc_cosh:
   case LibFunc_coshf:
@@ -1298,9 +1295,6 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
   case LibFunc_rint:
   case LibFunc_rintf:
   case LibFunc_rintl:
-  case LibFunc_round:
-  case LibFunc_roundf:
-  case LibFunc_roundl:
   case LibFunc_scalbln:
   case LibFunc_scalblnf:
   case LibFunc_scalblnl:
@@ -1338,6 +1332,9 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
   case LibFunc_copysign:
   case LibFunc_copysignf:
   case LibFunc_copysignl:
+  case LibFunc_ceil:
+  case LibFunc_ceilf:
+  case LibFunc_ceill:
   case LibFunc_fabs:
   case LibFunc_fabsf:
   case LibFunc_fabsl:
@@ -1361,6 +1358,9 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
   case LibFunc_nearbyint:
   case LibFunc_nearbyintf:
   case LibFunc_nearbyintl:
+  case LibFunc_round:
+  case LibFunc_roundf:
+  case LibFunc_roundl:
   case LibFunc_toascii:
   case LibFunc_trunc:
   case LibFunc_truncf:
diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
index 25a70a026a0b7..4a0a20b71dfde 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
@@ -304,13 +304,13 @@ declare float @cbrtf(float)
 ; CHECK: declare x86_fp80 @cbrtl(x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare x86_fp80 @cbrtl(x86_fp80)
 
-; CHECK: declare double @ceil(double) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+; CHECK: declare double @ceil(double) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare double @ceil(double)
 
-; CHECK: declare float @ceilf(float) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+; CHECK: declare float @ceilf(float) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare float @ceilf(float)
 
-; CHECK: declare x86_fp80 @ceill(x86_fp80) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+; CHECK: declare x86_fp80 @ceill(x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare x86_fp80 @ceill(x86_fp80)
 
 ; The second argument of int chmod(FILE*, mode_t) is a 32-bit int on most
@@ -909,13 +909,13 @@ declare x86_fp80 @rintl(x86_fp80)
 ; CHECK: declare noundef i32 @rmdir(ptr noundef readonly captures(none)) [[NOFREE_NOUNWIND]]
 declare i32 @rmdir(ptr)
 
-; CHECK: declare double @round(double) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+; CHECK: declare double @round(double) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare double @round(double)
 
-; CHECK: declare float @roundf(float) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+; CHECK: declare float @roundf(float) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare float @roundf(float)
 
-; CHECK: declare x86_fp80 @roundl(x86_fp80) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+; CHECK: declare x86_fp80 @roundl(x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare x86_fp80 @roundl(x86_fp80)
 
 ; CHECK: declare double @scalbln(double, i64) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]

>From a50096bf4fbd31dd847aabbf1df3e5f1042c3f92 Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:39:28 -0500
Subject: [PATCH 03/13] [TLI] Handle roundeven libcall in hasOptimizedCodegen

This is a prerequisite to being able to turn it into an intrinsic.
---
 llvm/include/llvm/Analysis/TargetLibraryInfo.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index 0f98af69f12c6..a88497beb20ae 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -417,6 +417,7 @@ class TargetLibraryInfo {
     case LibFunc_nearbyint:    case LibFunc_nearbyintf: case LibFunc_nearbyintl:
     case LibFunc_rint:         case LibFunc_rintf:      case LibFunc_rintl:
     case LibFunc_round:        case LibFunc_roundf:     case LibFunc_roundl:
+    case LibFunc_roundeven:    case LibFunc_roundevenf: case LibFunc_roundevenl:
     case LibFunc_sin:          case LibFunc_sinf:       case LibFunc_sinl:
     case LibFunc_sinh:         case LibFunc_sinhf:      case LibFunc_sinhl:
     case LibFunc_sqrt:         case LibFunc_sqrtf:      case LibFunc_sqrtl:

>From 28589a3a2f223c05b1138b6f86107aa9b203998d Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:40:01 -0500
Subject: [PATCH 04/13] [SelectionDAG] Handle roundeven libcall in visitCall

We can now lower it to its proper instruction.
---
 llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 09a0673bfe1bb..6f22730c90efe 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -9710,6 +9710,12 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
         if (visitUnaryFloatCall(I, ISD::FROUND))
           return;
         break;
+      case LibFunc_roundeven:
+      case LibFunc_roundevenf:
+      case LibFunc_roundevenl:
+        if (visitUnaryFloatCall(I, ISD::FROUNDEVEN))
+          return;
+        break;
       case LibFunc_trunc:
       case LibFunc_truncf:
       case LibFunc_truncl:

>From 2536928fab13c63602620f93be673c545934b1fa Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:40:55 -0500
Subject: [PATCH 05/13] [InferAttrs] Handle roundeven like other libm functions

It was previously missing entirely. It behaves like floor, ceil, round,
and trunc, having no side effects.
---
 llvm/lib/Transforms/Utils/BuildLibCalls.cpp         | 3 +++
 llvm/test/Transforms/InferFunctionAttrs/annotate.ll | 9 +++++++++
 2 files changed, 12 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 213869fb993d7..05c882da38d61 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -1361,6 +1361,9 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
   case LibFunc_round:
   case LibFunc_roundf:
   case LibFunc_roundl:
+  case LibFunc_roundeven:
+  case LibFunc_roundevenf:
+  case LibFunc_roundevenl:
   case LibFunc_toascii:
   case LibFunc_trunc:
   case LibFunc_truncf:
diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
index 4a0a20b71dfde..f5020a93250ea 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
@@ -918,6 +918,15 @@ declare float @roundf(float)
 ; CHECK: declare x86_fp80 @roundl(x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare x86_fp80 @roundl(x86_fp80)
 
+; CHECK: declare double @roundeven(double) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare double @roundeven(double)
+
+; CHECK: declare float @roundevenf(float) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare float @roundevenf(float)
+
+; CHECK: declare x86_fp80 @roundevenl(x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare x86_fp80 @roundevenl(x86_fp80)
+
 ; CHECK: declare double @scalbln(double, i64) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare double @scalbln(double, i64)
 

>From d0d46899144e3b4b9384b257ce93fa7c5b838b1d Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:42:03 -0500
Subject: [PATCH 06/13] [ConstantFolding] Handle roundeven libcalls

Basically identical to nearbyint and rint, which we already treat as
rounding to nearest with ties to even during constant folding.
---
 llvm/lib/Analysis/ConstantFolding.cpp         | 10 ++++++--
 .../InstSimplify/ConstProp/roundeven.ll       | 24 +++++++------------
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 63d12ee585e64..b39b32042dd2f 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1984,6 +1984,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
   switch (Name[0]) {
   default:
     return false;
+    // clang-format off
   case 'a':
     return Name == "acos" || Name == "acosf" ||
            Name == "asin" || Name == "asinf" ||
@@ -2014,7 +2015,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
   case 'r':
     return Name == "remainder" || Name == "remainderf" ||
            Name == "rint" || Name == "rintf" ||
-           Name == "round" || Name == "roundf";
+           Name == "round" || Name == "roundf" ||
+           Name == "roundeven" || Name == "roundevenf";
   case 's':
     return Name == "sin" || Name == "sinf" ||
            Name == "sinh" || Name == "sinhf" ||
@@ -2052,6 +2054,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
     case 's':
       return Name == "__sinh_finite" || Name == "__sinhf_finite";
     }
+    // clang-format on
   }
 }
 
@@ -2516,7 +2519,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
 
     // Use internal versions of these intrinsics.
 
-    if (IntrinsicID == Intrinsic::nearbyint || IntrinsicID == Intrinsic::rint) {
+    if (IntrinsicID == Intrinsic::nearbyint || IntrinsicID == Intrinsic::rint ||
+        IntrinsicID == Intrinsic::roundeven) {
       U.roundToIntegral(APFloat::rmNearestTiesToEven);
       return ConstantFP::get(Ty->getContext(), U);
     }
@@ -2988,6 +2992,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
     case LibFunc_nearbyintf:
     case LibFunc_rint:
     case LibFunc_rintf:
+    case LibFunc_roundeven:
+    case LibFunc_roundevenf:
       if (TLI->has(Func)) {
         U.roundToIntegral(APFloat::rmNearestTiesToEven);
         return ConstantFP::get(Ty->getContext(), U);
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll b/llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll
index 68938b3c6244c..e6448847112fb 100644
--- a/llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/roundeven.ll
@@ -9,8 +9,7 @@ declare double @llvm.roundeven.f64(double)
 define float @constant_fold_roundeven_f32_01() #0 {
 ; CHECK-LABEL: define float @constant_fold_roundeven_f32_01(
 ; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
-; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 1.250000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret float [[X]]
+; CHECK-NEXT:    ret float 1.000000e+00
 ;
   %x = call float @roundevenf(float 1.25) #0
   ret float %x
@@ -29,8 +28,7 @@ define float @constant_fold_roundeven_f32_02() #0 {
 define float @constant_fold_roundeven_f32_03() #0 {
 ; CHECK-LABEL: define float @constant_fold_roundeven_f32_03(
 ; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 1.500000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret float [[X]]
+; CHECK-NEXT:    ret float 2.000000e+00
 ;
   %x = call float @roundevenf(float 1.5) #0
   ret float %x
@@ -50,8 +48,7 @@ define float @constant_fold_roundeven_f32_04() #0 {
 define float @constant_fold_roundeven_f32_05() #0 {
 ; CHECK-LABEL: define float @constant_fold_roundeven_f32_05(
 ; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 2.500000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret float [[X]]
+; CHECK-NEXT:    ret float 2.000000e+00
 ;
   %x = call float @roundevenf(float 2.5) #0
   ret float %x
@@ -70,8 +67,7 @@ define float @constant_fold_roundeven_f32_06() #0 {
 define float @constant_fold_roundeven_f32_07() #0 {
 ; CHECK-LABEL: define float @constant_fold_roundeven_f32_07(
 ; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT:    [[X:%.*]] = call float @roundevenf(float 2.750000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret float [[X]]
+; CHECK-NEXT:    ret float 3.000000e+00
 ;
   %x = call float @roundevenf(float 2.75) #0
   ret float %x
@@ -89,8 +85,7 @@ define float @constant_fold_roundeven_f32_08() #0 {
 define double @constant_fold_roundeven_f64_01() #0 {
 ; CHECK-LABEL: define double @constant_fold_roundeven_f64_01(
 ; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 1.300000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret double [[X]]
+; CHECK-NEXT:    ret double 1.000000e+00
 ;
   %x = call double @roundeven(double 1.3) #0
   ret double %x
@@ -108,8 +103,7 @@ define double @constant_fold_roundeven_f64_02() #0 {
 define double @constant_fold_roundeven_f64_03() #0 {
 ; CHECK-LABEL: define double @constant_fold_roundeven_f64_03(
 ; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 1.500000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret double [[X]]
+; CHECK-NEXT:    ret double 2.000000e+00
 ;
   %x = call double @roundeven(double 1.5) #0
   ret double %x
@@ -127,8 +121,7 @@ define double @constant_fold_roundeven_f64_04() #0 {
 define double @constant_fold_roundeven_f64_05() #0 {
 ; CHECK-LABEL: define double @constant_fold_roundeven_f64_05(
 ; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 2.500000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret double [[X]]
+; CHECK-NEXT:    ret double 2.000000e+00
 ;
   %x = call double @roundeven(double 2.5) #0
   ret double %x
@@ -146,8 +139,7 @@ define double @constant_fold_roundeven_f64_06() #0 {
 define double @constant_fold_roundeven_f64_07() #0 {
 ; CHECK-LABEL: define double @constant_fold_roundeven_f64_07(
 ; CHECK-SAME: ) #[[ATTR0]] {
-; CHECK-NEXT:    [[X:%.*]] = call double @roundeven(double 2.700000e+00) #[[ATTR0]]
-; CHECK-NEXT:    ret double [[X]]
+; CHECK-NEXT:    ret double 3.000000e+00
 ;
   %x = call double @roundeven(double 2.7) #0
   ret double %x

>From 09cae4b5053c58ac1dba8072016841df51e10962 Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:42:19 -0500
Subject: [PATCH 07/13] [NumericalStabilitySanitizer] Handle roundeven libcalls

Here, it's a simple matter of wiring them up.
---
 .../Transforms/Instrumentation/NumericalStabilitySanitizer.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
index 66d570b3f831e..3bbf049a1d8b9 100644
--- a/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
@@ -1514,6 +1514,9 @@ const KnownIntrinsic::LFEntry KnownIntrinsic::kLibfuncIntrinsics[] = {
     {LibFunc_roundf, "llvm.round.f32"},
     {LibFunc_round, "llvm.round.f64"},
     {LibFunc_roundl, "llvm.round.f80"},
+    {LibFunc_roundevenf, "llvm.roundeven.f32"},
+    {LibFunc_roundeven, "llvm.roundeven.f64"},
+    {LibFunc_roundevenl, "llvm.roundeven.f80"},
 };
 
 const char *KnownIntrinsic::get(LibFunc LFunc) {

>From 3fb29b79894cee481142d49cf59d9ed368629fd1 Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:37:16 -0500
Subject: [PATCH 08/13] [InstCombine] Add regression tests for
 f[min][max]imum_num libcalls

Add tests corresponding to the existing fmin/fmax tests, as we'll later
begin optimizing these into intrinsics.
---
 .../InstCombine/float-shrink-compare.ll       | 36 +++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/float-shrink-compare.ll b/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
index 77b6ed7c5abe8..46341cf3d346f 100644
--- a/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
+++ b/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
@@ -463,6 +463,40 @@ define i1 @test18(float %x, float %y, float %z) {
   ret i1 %5
 }
 
+define i1 @test_fminimum_num(float %x, float %y, float %z) {
+; CHECK-LABEL: @test_fminimum_num(
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[X:%.*]] to double
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[Y:%.*]] to double
+; CHECK-NEXT:    [[TMP3:%.*]] = call double @fminimum_num(double [[TMP1]], double [[TMP2]]) #[[ATTR3:[0-9]+]]
+; CHECK-NEXT:    [[TMP4:%.*]] = fpext float [[Z:%.*]] to double
+; CHECK-NEXT:    [[TMP5:%.*]] = fcmp oeq double [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %1 = fpext float %x to double
+  %2 = fpext float %y to double
+  %3 = call double @fminimum_num(double %1, double %2) nounwind
+  %4 = fpext float %z to double
+  %5 = fcmp oeq double %3, %4
+  ret i1 %5
+}
+
+define i1 @test_fmaximum_num(float %x, float %y, float %z) {
+; CHECK-LABEL: @test_fmaximum_num(
+; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[X:%.*]] to double
+; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[Y:%.*]] to double
+; CHECK-NEXT:    [[TMP3:%.*]] = call double @fmaximum_num(double [[TMP1]], double [[TMP2]]) #[[ATTR3]]
+; CHECK-NEXT:    [[TMP4:%.*]] = fpext float [[Z:%.*]] to double
+; CHECK-NEXT:    [[TMP5:%.*]] = fcmp oeq double [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    ret i1 [[TMP5]]
+;
+  %1 = fpext float %x to double
+  %2 = fpext float %y to double
+  %3 = call double @fmaximum_num(double %1, double %2) nounwind
+  %4 = fpext float %z to double
+  %5 = fcmp oeq double %3, %4
+  ret i1 %5
+}
+
 define i1 @test19(float %x, float %y, float %z) {
 ; CHECK-LABEL: @test19(
 ; CHECK-NEXT:    [[COPYSIGNF:%.*]] = call float @copysignf(float [[X:%.*]], float [[Y:%.*]]) #[[ATTR0:[0-9]+]]
@@ -518,6 +552,8 @@ declare double @roundeven(double) nounwind readnone
 declare double @trunc(double) nounwind readnone
 declare double @fmin(double, double) nounwind readnone
 declare double @fmax(double, double) nounwind readnone
+declare double @fminimum_num(double, double) nounwind readnone
+declare double @fmaximum_num(double, double) nounwind readnone
 
 declare double @llvm.fabs.f64(double) nounwind readnone
 declare double @llvm.ceil.f64(double) nounwind readnone

>From 95677da47cf749cff3c4f32740da2a1e228e87b3 Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:42:54 -0500
Subject: [PATCH 09/13] [TLI] Handle f[min/max]imum_num in hasOptimizedCodegen

This is a prerequisite to lowering them to intrinsics later.
---
 llvm/include/llvm/Analysis/TargetLibraryInfo.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
index a88497beb20ae..022f0dbb04421 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h
@@ -410,6 +410,10 @@ class TargetLibraryInfo {
     case LibFunc_floor:        case LibFunc_floorf:     case LibFunc_floorl:
     case LibFunc_fmax:         case LibFunc_fmaxf:      case LibFunc_fmaxl:
     case LibFunc_fmin:         case LibFunc_fminf:      case LibFunc_fminl:
+    case LibFunc_fmaximum_num: case LibFunc_fmaximum_numf:
+                                                  case LibFunc_fmaximum_numl:
+    case LibFunc_fminimum_num: case LibFunc_fminimum_numf:
+                                                  case LibFunc_fminimum_numl:
     case LibFunc_ldexp:        case LibFunc_ldexpf:     case LibFunc_ldexpl:
     case LibFunc_log2:         case LibFunc_log2f:      case LibFunc_log2l:
     case LibFunc_memcmp:       case LibFunc_bcmp:       case LibFunc_strcmp:

>From e0a160bed23ba133a70aea408c621fe6dbe1e051 Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:43:22 -0500
Subject: [PATCH 10/13] [InferAttrs] Handle f[min/max]imum_num like other libm
 functions

These behave like fmin and fmax.
---
 llvm/lib/Transforms/Utils/BuildLibCalls.cpp    |  6 ++++++
 .../Transforms/InferFunctionAttrs/annotate.ll  | 18 ++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
index 05c882da38d61..a245b9405cfb7 100644
--- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -1353,6 +1353,12 @@ bool llvm::inferNonMandatoryLibFuncAttrs(Function &F,
   case LibFunc_fmin:
   case LibFunc_fminf:
   case LibFunc_fminl:
+  case LibFunc_fmaximum_num:
+  case LibFunc_fmaximum_numf:
+  case LibFunc_fmaximum_numl:
+  case LibFunc_fminimum_num:
+  case LibFunc_fminimum_numf:
+  case LibFunc_fminimum_numl:
   case LibFunc_labs:
   case LibFunc_llabs:
   case LibFunc_nearbyint:
diff --git a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
index f5020a93250ea..27ae0d53350f4 100644
--- a/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
+++ b/llvm/test/Transforms/InferFunctionAttrs/annotate.ll
@@ -473,6 +473,24 @@ declare float @fminf(float, float)
 ; CHECK: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare x86_fp80 @fminl(x86_fp80, x86_fp80)
 
+; CHECK: declare double @fmaximum_num(double, double) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare double @fmaximum_num(double, double)
+
+; CHECK: declare float @fmaximum_numf(float, float) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare float @fmaximum_numf(float, float)
+
+; CHECK: declare x86_fp80 @fmaximum_numl(x86_fp80, x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare x86_fp80 @fmaximum_numl(x86_fp80, x86_fp80)
+
+; CHECK: declare double @fminimum_num(double, double) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare double @fminimum_num(double, double)
+
+; CHECK: declare float @fminimum_numf(float, float) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare float @fminimum_numf(float, float)
+
+; CHECK: declare x86_fp80 @fminimum_numl(x86_fp80, x86_fp80) [[MEMNONE_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
+declare x86_fp80 @fminimum_numl(x86_fp80, x86_fp80)
+
 ; CHECK: declare double @fmod(double, double) [[ERRNOMEMONLY_NOFREE_NOUNWIND_WILLRETURN:#[0-9]+]]
 declare double @fmod(double, double)
 

>From 3696d6254fedd41f6184adb012ef63b2a0a7b77b Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:44:16 -0500
Subject: [PATCH 11/13] [ValueTracking] Handle f[min/max]imum_num in
 getIntrinsicForCallSite

A straightforward mapping onto the corresponding intrinsic.
---
 llvm/lib/Analysis/ValueTracking.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 9cb6f19b9340c..6de4f57f75273 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4680,6 +4680,14 @@ Intrinsic::ID llvm::getIntrinsicForCallSite(const CallBase &CB,
   case LibFunc_fmaxf:
   case LibFunc_fmaxl:
     return Intrinsic::maxnum;
+  case LibFunc_fminimum_num:
+  case LibFunc_fminimum_numf:
+  case LibFunc_fminimum_numl:
+    return Intrinsic::minimumnum;
+  case LibFunc_fmaximum_num:
+  case LibFunc_fmaximum_numf:
+  case LibFunc_fmaximum_numl:
+    return Intrinsic::maximumnum;
   case LibFunc_copysign:
   case LibFunc_copysignf:
   case LibFunc_copysignl:

>From 11e899cfa8970d8e93db9a011904b59e986faf32 Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:44:47 -0500
Subject: [PATCH 12/13] [SimplifyLibCalls] Recognize and simplify
 f[min/max]imumnum

Unlike fmin and fmax, these are deterministic with regards to signed
zero.
---
 .../llvm/Transforms/Utils/SimplifyLibCalls.h  |  1 +
 .../lib/Transforms/Utils/SimplifyLibCalls.cpp | 31 +++++++++++++++++++
 .../InstCombine/float-shrink-compare.ll       | 14 +++------
 3 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index 4e7c97194cc59..64d2512308935 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -205,6 +205,7 @@ class LibCallSimplifier {
   Value *replacePowWithSqrt(CallInst *Pow, IRBuilderBase &B);
   Value *optimizeExp2(CallInst *CI, IRBuilderBase &B);
   Value *optimizeFMinFMax(CallInst *CI, IRBuilderBase &B);
+  Value *optimizeFMinimumnumFMaximumnum(CallInst *CI, IRBuilderBase &B);
   Value *optimizeLog(CallInst *CI, IRBuilderBase &B);
   Value *optimizeSqrt(CallInst *CI, IRBuilderBase &B);
   Value *optimizeFMod(CallInst *CI, IRBuilderBase &B);
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index d1548694baa27..20d9b03bd87c8 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -2543,6 +2543,30 @@ Value *LibCallSimplifier::optimizeFMinFMax(CallInst *CI, IRBuilderBase &B) {
                                                 CI->getArgOperand(1), FMF));
 }
 
+Value *LibCallSimplifier::optimizeFMinimumnumFMaximumnum(CallInst *CI,
+                                                         IRBuilderBase &B) {
+  Module *M = CI->getModule();
+
+  // If we can shrink the call to a float function rather than a double
+  // function, do that first.
+  Function *Callee = CI->getCalledFunction();
+  StringRef Name = Callee->getName();
+  if ((Name == "fminimum_num" || Name == "fmaximum_num") &&
+      hasFloatVersion(M, Name))
+    if (Value *Ret = optimizeBinaryDoubleFP(CI, B, TLI))
+      return Ret;
+
+  // The new fminimum_num/fmaximum_num functions, unlike fmin/fmax, *are*
+  // sensitive to the sigh of zero, so we don't change the fast-math flags like
+  // we did for those.
+
+  Intrinsic::ID IID = Callee->getName().starts_with("fminimum_num")
+                          ? Intrinsic::minimumnum
+                          : Intrinsic::maximumnum;
+  return copyFlags(*CI, B.CreateBinaryIntrinsic(IID, CI->getArgOperand(0),
+                                                CI->getArgOperand(1), CI));
+}
+
 Value *LibCallSimplifier::optimizeLog(CallInst *Log, IRBuilderBase &B) {
   Function *LogFn = Log->getCalledFunction();
   StringRef LogNm = LogFn->getName();
@@ -4123,6 +4147,13 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
   case LibFunc_fmax:
   case LibFunc_fmaxl:
     return optimizeFMinFMax(CI, Builder);
+  case LibFunc_fminimum_numf:
+  case LibFunc_fminimum_num:
+  case LibFunc_fminimum_numl:
+  case LibFunc_fmaximum_numf:
+  case LibFunc_fmaximum_num:
+  case LibFunc_fmaximum_numl:
+    return optimizeFMinimumnumFMaximumnum(CI, Builder);
   case LibFunc_cabs:
   case LibFunc_cabsf:
   case LibFunc_cabsl:
diff --git a/llvm/test/Transforms/InstCombine/float-shrink-compare.ll b/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
index 46341cf3d346f..6383feff3a6ee 100644
--- a/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
+++ b/llvm/test/Transforms/InstCombine/float-shrink-compare.ll
@@ -465,11 +465,8 @@ define i1 @test18(float %x, float %y, float %z) {
 
 define i1 @test_fminimum_num(float %x, float %y, float %z) {
 ; CHECK-LABEL: @test_fminimum_num(
-; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[X:%.*]] to double
-; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[Y:%.*]] to double
-; CHECK-NEXT:    [[TMP3:%.*]] = call double @fminimum_num(double [[TMP1]], double [[TMP2]]) #[[ATTR3:[0-9]+]]
-; CHECK-NEXT:    [[TMP4:%.*]] = fpext float [[Z:%.*]] to double
-; CHECK-NEXT:    [[TMP5:%.*]] = fcmp oeq double [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    [[FMINIMUM_NUMF:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[TMP5:%.*]] = fcmp oeq float [[FMINIMUM_NUMF]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %1 = fpext float %x to double
@@ -482,11 +479,8 @@ define i1 @test_fminimum_num(float %x, float %y, float %z) {
 
 define i1 @test_fmaximum_num(float %x, float %y, float %z) {
 ; CHECK-LABEL: @test_fmaximum_num(
-; CHECK-NEXT:    [[TMP1:%.*]] = fpext float [[X:%.*]] to double
-; CHECK-NEXT:    [[TMP2:%.*]] = fpext float [[Y:%.*]] to double
-; CHECK-NEXT:    [[TMP3:%.*]] = call double @fmaximum_num(double [[TMP1]], double [[TMP2]]) #[[ATTR3]]
-; CHECK-NEXT:    [[TMP4:%.*]] = fpext float [[Z:%.*]] to double
-; CHECK-NEXT:    [[TMP5:%.*]] = fcmp oeq double [[TMP3]], [[TMP4]]
+; CHECK-NEXT:    [[FMAXIMUM_NUMF:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[TMP5:%.*]] = fcmp oeq float [[FMAXIMUM_NUMF]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i1 [[TMP5]]
 ;
   %1 = fpext float %x to double

>From f055c83345390fcdb6aadc7d2fd3d0d95e1435e4 Mon Sep 17 00:00:00 2001
From: valadaptive <valadaptive at protonmail.com>
Date: Thu, 4 Dec 2025 10:45:13 -0500
Subject: [PATCH 13/13] [NumericalStabilitySanitizer] Handle f[min/max]imum_num
 libcalls

A simple matter of adding them to the table.
---
 .../Instrumentation/NumericalStabilitySanitizer.cpp         | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
index 3bbf049a1d8b9..8b1d765d77818 100644
--- a/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
@@ -1499,6 +1499,12 @@ const KnownIntrinsic::LFEntry KnownIntrinsic::kLibfuncIntrinsics[] = {
     {LibFunc_fminf, "llvm.minnum.f32"},
     {LibFunc_fmin, "llvm.minnum.f64"},
     {LibFunc_fminl, "llvm.minnum.f80"},
+    {LibFunc_fmaximum_numf, "llvm.maximumnum.f32"},
+    {LibFunc_fmaximum_num, "llvm.maximumnum.f64"},
+    {LibFunc_fmaximum_numl, "llvm.maximumnum.f80"},
+    {LibFunc_fminimum_numf, "llvm.minimumnum.f32"},
+    {LibFunc_fminimum_num, "llvm.minimumnum.f64"},
+    {LibFunc_fminimum_numl, "llvm.minimumnum.f80"},
     {LibFunc_ceilf, "llvm.ceil.f32"},
     {LibFunc_ceil, "llvm.ceil.f64"},
     {LibFunc_ceill, "llvm.ceil.f80"},



More information about the llvm-commits mailing list