[libc-commits] [libc] [libc][math] Optimize nearest integer functions using builtins when available (PR #98376)

via libc-commits libc-commits at lists.llvm.org
Mon Jul 15 06:33:44 PDT 2024


https://github.com/overmighty updated https://github.com/llvm/llvm-project/pull/98376

>From 89504b9a133f2d9f6fc591500d84c276503147f7 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 10 Jul 2024 20:41:57 +0200
Subject: [PATCH 1/8] [libc][math] Optimize nearest integer functions using
 builtins when available

---
 .../cmake/modules/CheckCompilerFeatures.cmake | 26 ++++++++++++--
 .../modules/LLVMLibCCompileOptionRules.cmake  | 20 +++++++++--
 libc/cmake/modules/LLVMLibCFlagRules.cmake    |  3 +-
 .../check_builtin_ceil_floor_trunc.cpp        |  9 +++++
 .../compiler_features/check_builtin_round.cpp |  5 +++
 .../check_builtin_roundeven.cpp               |  5 +++
 libc/src/math/generic/CMakeLists.txt          | 35 +++++++++++++++++++
 libc/src/math/generic/ceil.cpp                |  8 ++++-
 libc/src/math/generic/ceilf.cpp               |  8 ++++-
 libc/src/math/generic/ceilf16.cpp             | 10 +++++-
 libc/src/math/generic/floor.cpp               |  8 ++++-
 libc/src/math/generic/floorf.cpp              |  8 ++++-
 libc/src/math/generic/floorf16.cpp            | 10 +++++-
 libc/src/math/generic/round.cpp               |  8 ++++-
 libc/src/math/generic/roundeven.cpp           |  4 +++
 libc/src/math/generic/roundevenf.cpp          |  4 +++
 libc/src/math/generic/roundevenf16.cpp        |  6 ++++
 libc/src/math/generic/roundf.cpp              |  8 ++++-
 libc/src/math/generic/roundf16.cpp            |  9 ++++-
 libc/src/math/generic/trunc.cpp               |  8 ++++-
 libc/src/math/generic/truncf.cpp              |  8 ++++-
 libc/src/math/generic/truncf16.cpp            | 10 +++++-
 22 files changed, 202 insertions(+), 18 deletions(-)
 create mode 100644 libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
 create mode 100644 libc/cmake/modules/compiler_features/check_builtin_round.cpp
 create mode 100644 libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp

diff --git a/libc/cmake/modules/CheckCompilerFeatures.cmake b/libc/cmake/modules/CheckCompilerFeatures.cmake
index d84c07b35d2d7..83822892c8096 100644
--- a/libc/cmake/modules/CheckCompilerFeatures.cmake
+++ b/libc/cmake/modules/CheckCompilerFeatures.cmake
@@ -2,7 +2,15 @@
 # Compiler features definition and flags
 # ------------------------------------------------------------------------------
 
-set(ALL_COMPILER_FEATURES "float16" "float128" "fixed_point")
+set(
+  ALL_COMPILER_FEATURES
+    "builtin_ceil_floor_trunc"
+    "builtin_round"
+    "builtin_roundeven"
+    "float16"
+    "float128"
+    "fixed_point"
+)
 
 # Making sure ALL_COMPILER_FEATURES is sorted.
 list(SORT ALL_COMPILER_FEATURES)
@@ -39,11 +47,19 @@ endfunction()
 set(AVAILABLE_COMPILER_FEATURES "")
 
 # Try compile a C file to check if flag is supported.
-set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
 foreach(feature IN LISTS ALL_COMPILER_FEATURES)
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
   set(compile_options ${LIBC_COMPILE_OPTIONS_NATIVE})
   if(${feature} STREQUAL "fixed_point")
     list(APPEND compile_options "-ffixed-point")
+  elseif(${feature} MATCHES "^builtin_")
+    set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT})
+    # The compiler might handle calls to rounding builtins by generating calls
+    # to the respective libc math functions, in which case we cannot use these
+    # builtins in our implementations of these functions. We check that this is
+    # not the case by trying to link an executable, since linking would fail due
+    # to unresolved references if calls to libc functions were generated.
+    set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE)
   endif()
 
   try_compile(
@@ -60,6 +76,12 @@ foreach(feature IN LISTS ALL_COMPILER_FEATURES)
       set(LIBC_TYPES_HAS_FLOAT128 TRUE)
     elseif(${feature} STREQUAL "fixed_point")
       set(LIBC_COMPILER_HAS_FIXED_POINT TRUE)
+    elseif(${feature} STREQUAL "builtin_ceil_floor_trunc")
+      set(LIBC_COMPILER_HAS_BUILTIN_CEIL_FLOOR_TRUNC TRUE)
+    elseif(${feature} STREQUAL "builtin_round")
+      set(LIBC_COMPILER_HAS_BUILTIN_ROUND TRUE)
+    elseif(${feature} STREQUAL "builtin_roundeven")
+      set(LIBC_COMPILER_HAS_BUILTIN_ROUNDEVEN TRUE)
     endif()
   endif()
 endforeach()
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index c5e7dfe8abd0f..855d69d2a0fc9 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -4,7 +4,7 @@ function(_get_compile_options_from_flags output_var)
   if(LIBC_TARGET_ARCHITECTURE_IS_RISCV64 OR(LIBC_CPU_FEATURES MATCHES "FMA"))
     check_flag(ADD_FMA_FLAG ${FMA_OPT_FLAG} ${ARGN})
   endif()
-  check_flag(ADD_SSE4_2_FLAG ${ROUND_OPT_FLAG} ${ARGN})
+  check_flag(ADD_ROUND_OPT_FLAG ${ROUND_OPT_FLAG} ${ARGN})
   check_flag(ADD_EXPLICIT_SIMD_OPT_FLAG ${EXPLICIT_SIMD_OPT_FLAG} ${ARGN})
 
   if(LLVM_COMPILER_IS_GCC_COMPATIBLE)
@@ -16,8 +16,22 @@ function(_get_compile_options_from_flags output_var)
         list(APPEND compile_options "-D__LIBC_RISCV_USE_FMA")
       endif()
     endif()
-    if(ADD_SSE4_2_FLAG)
-      list(APPEND compile_options "-msse4.2")
+    if(ADD_ROUND_OPT_FLAG)
+      if(LIBC_TARGET_ARCHITECTURE_IS_X86)
+        # ROUND_OPT_FLAG is only enabled if SSE4.2 is detected, not just SSE4.1,
+        # because there was code to check for SSE4.2 already, and few CPUs only
+        # have SSE4.1.
+        list(APPEND compile_options "-msse4.2")
+      endif()
+      if(LIBC_COMPILER_HAS_BUILTIN_CEIL_FLOOR_TRUNC)
+        list(APPEND compile_options "-D__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC")
+      endif()
+      if(LIBC_COMPILER_HAS_BUILTIN_ROUND)
+        list(APPEND compile_options "-D__LIBC_USE_BUILTIN_ROUND")
+      endif()
+      if(LIBC_COMPILER_HAS_BUILTIN_ROUNDEVEN)
+        list(APPEND compile_options "-D__LIBC_USE_BUILTIN_ROUNDEVEN")
+      endif()
     endif()
     if(ADD_EXPLICIT_SIMD_OPT_FLAG)
       list(APPEND compile_options "-D__LIBC_EXPLICIT_SIMD_OPT")
diff --git a/libc/cmake/modules/LLVMLibCFlagRules.cmake b/libc/cmake/modules/LLVMLibCFlagRules.cmake
index 18e36dfde5cc1..eca7ba8d183e6 100644
--- a/libc/cmake/modules/LLVMLibCFlagRules.cmake
+++ b/libc/cmake/modules/LLVMLibCFlagRules.cmake
@@ -277,6 +277,7 @@ if(NOT(LIBC_TARGET_ARCHITECTURE_IS_X86 AND (LIBC_CPU_FEATURES MATCHES "SSE2")))
 endif()
 
 # Skip ROUND_OPT flag for targets that don't support SSE 4.2.
-if(NOT(LIBC_TARGET_ARCHITECTURE_IS_X86 AND (LIBC_CPU_FEATURES MATCHES "SSE4_2")))
+if(NOT((LIBC_TARGET_ARCHITECTURE_IS_X86 AND (LIBC_CPU_FEATURES MATCHES "SSE4_2")) OR
+       LIBC_TARGET_ARCHITECTURE_IS_AARCH64))
   set(SKIP_FLAG_EXPANSION_ROUND_OPT TRUE)
 endif()
diff --git a/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
new file mode 100644
index 0000000000000..031dd9376f3c1
--- /dev/null
+++ b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
@@ -0,0 +1,9 @@
+float try_builtin_ceilf(float x) { return __builtin_ceilf(x); }
+float try_builtin_floorf(float x) { return __builtin_ceilf(x); }
+float try_builtin_truncf(float x) { return __builtin_truncf(x); }
+
+double try_builtin_ceil(double x) { return __builtin_ceil(x); }
+double try_builtin_floor(double x) { return __builtin_ceil(x); }
+double try_builtin_trunc(double x) { return __builtin_trunc(x); }
+
+int main() {}
diff --git a/libc/cmake/modules/compiler_features/check_builtin_round.cpp b/libc/cmake/modules/compiler_features/check_builtin_round.cpp
new file mode 100644
index 0000000000000..8c3065c2de06a
--- /dev/null
+++ b/libc/cmake/modules/compiler_features/check_builtin_round.cpp
@@ -0,0 +1,5 @@
+float try_builtin_roundf(float x) { return __builtin_roundf(x); }
+
+double try_builtin_round(double x) { return __builtin_round(x); }
+
+int main() {}
diff --git a/libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp b/libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp
new file mode 100644
index 0000000000000..2480abae84c36
--- /dev/null
+++ b/libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp
@@ -0,0 +1,5 @@
+float try_builtin_roundevenf(float x) { return __builtin_roundevenf(x); }
+
+double try_builtin_roundeven(double x) { return __builtin_roundeven(x); }
+
+int main() {}
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 5e920307d39de..915fc076826f9 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -70,6 +70,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -82,6 +84,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -107,6 +111,9 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.macros.properties.types
     libc.src.__support.FPUtil.nearest_integer_operations
+    libc.src.__support.macros.properties.architectures
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -455,6 +462,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -467,6 +476,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -492,6 +503,9 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.macros.properties.types
     libc.src.__support.FPUtil.nearest_integer_operations
+    libc.src.__support.macros.properties.architectures
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -517,6 +531,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -529,6 +545,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -554,6 +572,9 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.macros.properties.types
     libc.src.__support.FPUtil.nearest_integer_operations
+    libc.src.__support.macros.properties.architectures
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -579,6 +600,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -591,6 +614,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -616,6 +641,9 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.macros.properties.types
     libc.src.__support.FPUtil.nearest_integer_operations
+    libc.src.__support.macros.properties.architectures
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -641,6 +669,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -653,6 +683,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -678,6 +710,9 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.macros.properties.types
     libc.src.__support.FPUtil.nearest_integer_operations
+    libc.src.__support.macros.properties.architectures
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
diff --git a/libc/src/math/generic/ceil.cpp b/libc/src/math/generic/ceil.cpp
index a5ac1348834d8..2b214a709f3b4 100644
--- a/libc/src/math/generic/ceil.cpp
+++ b/libc/src/math/generic/ceil.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(double, ceil, (double x)) { return fputil::ceil(x); }
+LLVM_LIBC_FUNCTION(double, ceil, (double x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+  return __builtin_ceil(x);
+#else
+  return fputil::ceil(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/ceilf.cpp b/libc/src/math/generic/ceilf.cpp
index 0fd54361648dc..a5318d8cf905a 100644
--- a/libc/src/math/generic/ceilf.cpp
+++ b/libc/src/math/generic/ceilf.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float, ceilf, (float x)) { return fputil::ceil(x); }
+LLVM_LIBC_FUNCTION(float, ceilf, (float x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+  return __builtin_ceilf(x);
+#else
+  return fputil::ceil(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/ceilf16.cpp b/libc/src/math/generic/ceilf16.cpp
index 1d17daf283d07..b88984104be8d 100644
--- a/libc/src/math/generic/ceilf16.cpp
+++ b/libc/src/math/generic/ceilf16.cpp
@@ -10,9 +10,17 @@
 #include "src/__support/FPUtil/NearestIntegerOperations.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float16, ceilf16, (float16 x)) { return fputil::ceil(x); }
+LLVM_LIBC_FUNCTION(float16, ceilf16, (float16 x)) {
+#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC) &&                            \
+    defined(LIBC_TARGET_ARCH_IS_AARCH64)
+  return static_cast<float16>(__builtin_ceilf(x));
+#else
+  return fputil::ceil(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/floor.cpp b/libc/src/math/generic/floor.cpp
index 417d6aca3ffe5..8d5ae0948c4f1 100644
--- a/libc/src/math/generic/floor.cpp
+++ b/libc/src/math/generic/floor.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(double, floor, (double x)) { return fputil::floor(x); }
+LLVM_LIBC_FUNCTION(double, floor, (double x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+  return __builtin_floor(x);
+#else
+  return fputil::floor(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/floorf.cpp b/libc/src/math/generic/floorf.cpp
index ca059e6d02d53..bfb96adc8a715 100644
--- a/libc/src/math/generic/floorf.cpp
+++ b/libc/src/math/generic/floorf.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float, floorf, (float x)) { return fputil::floor(x); }
+LLVM_LIBC_FUNCTION(float, floorf, (float x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+  return __builtin_floorf(x);
+#else
+  return fputil::floor(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/floorf16.cpp b/libc/src/math/generic/floorf16.cpp
index 46068c2a548a9..022a69e9ea18d 100644
--- a/libc/src/math/generic/floorf16.cpp
+++ b/libc/src/math/generic/floorf16.cpp
@@ -10,9 +10,17 @@
 #include "src/__support/FPUtil/NearestIntegerOperations.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float16, floorf16, (float16 x)) { return fputil::floor(x); }
+LLVM_LIBC_FUNCTION(float16, floorf16, (float16 x)) {
+#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC) &&                            \
+    defined(LIBC_TARGET_ARCH_IS_AARCH64)
+  return static_cast<float16>(__builtin_floorf(x));
+#else
+  return fputil::floor(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/round.cpp b/libc/src/math/generic/round.cpp
index d8b171a2ef092..6ed5be5065962 100644
--- a/libc/src/math/generic/round.cpp
+++ b/libc/src/math/generic/round.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(double, round, (double x)) { return fputil::round(x); }
+LLVM_LIBC_FUNCTION(double, round, (double x)) {
+#ifdef __LIBC_USE_BUILTIN_ROUND
+  return __builtin_round(x);
+#else
+  return fputil::round(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/roundeven.cpp b/libc/src/math/generic/roundeven.cpp
index e6f599991bc0f..42f19f38b5385 100644
--- a/libc/src/math/generic/roundeven.cpp
+++ b/libc/src/math/generic/roundeven.cpp
@@ -14,7 +14,11 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(double, roundeven, (double x)) {
+#ifdef __LIBC_USE_BUILTIN_ROUNDEVEN
+  return __builtin_roundeven(x);
+#else
   return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
+#endif
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/roundevenf.cpp b/libc/src/math/generic/roundevenf.cpp
index 0b63a093edf6c..98bdc6545d94e 100644
--- a/libc/src/math/generic/roundevenf.cpp
+++ b/libc/src/math/generic/roundevenf.cpp
@@ -14,7 +14,11 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float, roundevenf, (float x)) {
+#ifdef __LIBC_USE_BUILTIN_ROUNDEVEN
+  return __builtin_roundevenf(x);
+#else
   return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
+#endif
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/roundevenf16.cpp b/libc/src/math/generic/roundevenf16.cpp
index 8a27d81b895ae..b45670bd24ff1 100644
--- a/libc/src/math/generic/roundevenf16.cpp
+++ b/libc/src/math/generic/roundevenf16.cpp
@@ -10,11 +10,17 @@
 #include "src/__support/FPUtil/NearestIntegerOperations.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float16, roundevenf16, (float16 x)) {
+#if defined(__LIBC_USE_BUILTIN_ROUNDEVEN) &&                                   \
+    defined(LIBC_TARGET_ARCH_IS_AARCH64)
+  return static_cast<float16>(__builtin_roundevenf(x));
+#else
   return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
+#endif
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/roundf.cpp b/libc/src/math/generic/roundf.cpp
index 68be4b1a51987..d25f7128cb9ce 100644
--- a/libc/src/math/generic/roundf.cpp
+++ b/libc/src/math/generic/roundf.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float, roundf, (float x)) { return fputil::round(x); }
+LLVM_LIBC_FUNCTION(float, roundf, (float x)) {
+#ifdef __LIBC_USE_BUILTIN_ROUND
+  return __builtin_roundf(x);
+#else
+  return fputil::round(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/roundf16.cpp b/libc/src/math/generic/roundf16.cpp
index 06f9a79cc21f3..cb668c0e76388 100644
--- a/libc/src/math/generic/roundf16.cpp
+++ b/libc/src/math/generic/roundf16.cpp
@@ -10,9 +10,16 @@
 #include "src/__support/FPUtil/NearestIntegerOperations.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float16, roundf16, (float16 x)) { return fputil::round(x); }
+LLVM_LIBC_FUNCTION(float16, roundf16, (float16 x)) {
+#if defined(__LIBC_USE_BUILTIN_ROUND) && defined(LIBC_TARGET_ARCH_IS_AARCH64)
+  return static_cast<float16>(__builtin_roundf(x));
+#else
+  return fputil::round(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/trunc.cpp b/libc/src/math/generic/trunc.cpp
index 0bf2ac5962e7b..61593df78a2b7 100644
--- a/libc/src/math/generic/trunc.cpp
+++ b/libc/src/math/generic/trunc.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(double, trunc, (double x)) { return fputil::trunc(x); }
+LLVM_LIBC_FUNCTION(double, trunc, (double x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+  return __builtin_trunc(x);
+#else
+  return fputil::trunc(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/truncf.cpp b/libc/src/math/generic/truncf.cpp
index 371cb9f8229a6..61dafcc7bb59a 100644
--- a/libc/src/math/generic/truncf.cpp
+++ b/libc/src/math/generic/truncf.cpp
@@ -13,6 +13,12 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float, truncf, (float x)) { return fputil::trunc(x); }
+LLVM_LIBC_FUNCTION(float, truncf, (float x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+  return __builtin_truncf(x);
+#else
+  return fputil::trunc(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/truncf16.cpp b/libc/src/math/generic/truncf16.cpp
index ea7695dc95f0b..9dd7745260159 100644
--- a/libc/src/math/generic/truncf16.cpp
+++ b/libc/src/math/generic/truncf16.cpp
@@ -10,9 +10,17 @@
 #include "src/__support/FPUtil/NearestIntegerOperations.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
-LLVM_LIBC_FUNCTION(float16, truncf16, (float16 x)) { return fputil::trunc(x); }
+LLVM_LIBC_FUNCTION(float16, truncf16, (float16 x)) {
+#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC) &&                            \
+    defined(LIBC_TARGET_ARCH_IS_AARCH64)
+  return static_cast<float16>(__builtin_truncf(x));
+#else
+  return fputil::trunc(x);
+#endif
+}
 
 } // namespace LIBC_NAMESPACE_DECL

>From c83a56eeaf616b5d6aa3578245be264f7536647a Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Fri, 12 Jul 2024 12:29:09 +0200
Subject: [PATCH 2/8] fixup! [libc][math] Optimize nearest integer functions
 using builtins when available

Fix check_builtin_ceil_floor_trunc.cpp not checking for __builtin_floor{,f}.
---
 .../compiler_features/check_builtin_ceil_floor_trunc.cpp      | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
index 031dd9376f3c1..c124b5e35cb3f 100644
--- a/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
+++ b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
@@ -1,9 +1,9 @@
 float try_builtin_ceilf(float x) { return __builtin_ceilf(x); }
-float try_builtin_floorf(float x) { return __builtin_ceilf(x); }
+float try_builtin_floorf(float x) { return __builtin_floorf(x); }
 float try_builtin_truncf(float x) { return __builtin_truncf(x); }
 
 double try_builtin_ceil(double x) { return __builtin_ceil(x); }
-double try_builtin_floor(double x) { return __builtin_ceil(x); }
+double try_builtin_floor(double x) { return __builtin_floor(x); }
 double try_builtin_trunc(double x) { return __builtin_trunc(x); }
 
 int main() {}

>From fddf0188419ee7c2619ac6ac8c848a53fd3b4e94 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Fri, 12 Jul 2024 12:53:08 +0200
Subject: [PATCH 3/8] fixup! [libc][math] Optimize nearest integer functions
 using builtins when available

Optimize rint{,f,f16} using __builtin_rint{,f} when available.
---
 .../cmake/modules/CheckCompilerFeatures.cmake |  6 ++--
 .../modules/LLVMLibCCompileOptionRules.cmake  |  5 +--
 ...> check_builtin_ceil_floor_rint_trunc.cpp} |  2 ++
 libc/src/math/generic/CMakeLists.txt          |  7 +++++
 libc/src/math/generic/ceil.cpp                |  2 +-
 libc/src/math/generic/ceilf.cpp               |  2 +-
 libc/src/math/generic/ceilf16.cpp             |  2 +-
 libc/src/math/generic/floor.cpp               |  2 +-
 libc/src/math/generic/floorf.cpp              |  2 +-
 libc/src/math/generic/floorf16.cpp            |  2 +-
 libc/src/math/generic/rint.cpp                |  4 +++
 libc/src/math/generic/rintf.cpp               |  4 +++
 libc/src/math/generic/rintf16.cpp             |  6 ++++
 libc/src/math/generic/trunc.cpp               |  2 +-
 libc/src/math/generic/truncf.cpp              |  2 +-
 libc/src/math/generic/truncf16.cpp            |  2 +-
 .../math/performance_testing/CMakeLists.txt   | 12 +++++--
 .../nearest_integer_funcs_perf.cpp            | 31 +++++++++++++++++++
 18 files changed, 79 insertions(+), 16 deletions(-)
 rename libc/cmake/modules/compiler_features/{check_builtin_ceil_floor_trunc.cpp => check_builtin_ceil_floor_rint_trunc.cpp} (76%)

diff --git a/libc/cmake/modules/CheckCompilerFeatures.cmake b/libc/cmake/modules/CheckCompilerFeatures.cmake
index 83822892c8096..449160d544b0d 100644
--- a/libc/cmake/modules/CheckCompilerFeatures.cmake
+++ b/libc/cmake/modules/CheckCompilerFeatures.cmake
@@ -4,7 +4,7 @@
 
 set(
   ALL_COMPILER_FEATURES
-    "builtin_ceil_floor_trunc"
+    "builtin_ceil_floor_rint_trunc"
     "builtin_round"
     "builtin_roundeven"
     "float16"
@@ -76,8 +76,8 @@ foreach(feature IN LISTS ALL_COMPILER_FEATURES)
       set(LIBC_TYPES_HAS_FLOAT128 TRUE)
     elseif(${feature} STREQUAL "fixed_point")
       set(LIBC_COMPILER_HAS_FIXED_POINT TRUE)
-    elseif(${feature} STREQUAL "builtin_ceil_floor_trunc")
-      set(LIBC_COMPILER_HAS_BUILTIN_CEIL_FLOOR_TRUNC TRUE)
+    elseif(${feature} STREQUAL "builtin_ceil_floor_rint_trunc")
+      set(LIBC_COMPILER_HAS_BUILTIN_CEIL_FLOOR_RINT_TRUNC TRUE)
     elseif(${feature} STREQUAL "builtin_round")
       set(LIBC_COMPILER_HAS_BUILTIN_ROUND TRUE)
     elseif(${feature} STREQUAL "builtin_roundeven")
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index 855d69d2a0fc9..253da4ae890e5 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -23,8 +23,9 @@ function(_get_compile_options_from_flags output_var)
         # have SSE4.1.
         list(APPEND compile_options "-msse4.2")
       endif()
-      if(LIBC_COMPILER_HAS_BUILTIN_CEIL_FLOOR_TRUNC)
-        list(APPEND compile_options "-D__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC")
+      if(LIBC_COMPILER_HAS_BUILTIN_CEIL_FLOOR_RINT_TRUNC)
+        list(APPEND compile_options
+             "-D__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC")
       endif()
       if(LIBC_COMPILER_HAS_BUILTIN_ROUND)
         list(APPEND compile_options "-D__LIBC_USE_BUILTIN_ROUND")
diff --git a/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_rint_trunc.cpp
similarity index 76%
rename from libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
rename to libc/cmake/modules/compiler_features/check_builtin_ceil_floor_rint_trunc.cpp
index c124b5e35cb3f..51f33be1bea8a 100644
--- a/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_trunc.cpp
+++ b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_rint_trunc.cpp
@@ -1,9 +1,11 @@
 float try_builtin_ceilf(float x) { return __builtin_ceilf(x); }
 float try_builtin_floorf(float x) { return __builtin_floorf(x); }
+float try_builtin_rintf(float x) { return __builtin_rintf(x); }
 float try_builtin_truncf(float x) { return __builtin_truncf(x); }
 
 double try_builtin_ceil(double x) { return __builtin_ceil(x); }
 double try_builtin_floor(double x) { return __builtin_floor(x); }
+double try_builtin_rint(double x) { return __builtin_rint(x); }
 double try_builtin_trunc(double x) { return __builtin_trunc(x); }
 
 int main() {}
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 915fc076826f9..c2f58fb1a4f71 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -862,6 +862,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -874,6 +876,8 @@ add_entrypoint_object(
     -O3
   DEPENDS
     libc.src.__support.FPUtil.nearest_integer_operations
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
@@ -899,6 +903,9 @@ add_entrypoint_object(
   DEPENDS
     libc.src.__support.macros.properties.types
     libc.src.__support.FPUtil.nearest_integer_operations
+    libc.src.__support.macros.properties.architectures
+  FLAGS
+    ROUND_OPT
 )
 
 add_entrypoint_object(
diff --git a/libc/src/math/generic/ceil.cpp b/libc/src/math/generic/ceil.cpp
index 2b214a709f3b4..72c6e990fcc71 100644
--- a/libc/src/math/generic/ceil.cpp
+++ b/libc/src/math/generic/ceil.cpp
@@ -14,7 +14,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(double, ceil, (double x)) {
-#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
   return __builtin_ceil(x);
 #else
   return fputil::ceil(x);
diff --git a/libc/src/math/generic/ceilf.cpp b/libc/src/math/generic/ceilf.cpp
index a5318d8cf905a..dfd0dc62bc51b 100644
--- a/libc/src/math/generic/ceilf.cpp
+++ b/libc/src/math/generic/ceilf.cpp
@@ -14,7 +14,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float, ceilf, (float x)) {
-#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
   return __builtin_ceilf(x);
 #else
   return fputil::ceil(x);
diff --git a/libc/src/math/generic/ceilf16.cpp b/libc/src/math/generic/ceilf16.cpp
index b88984104be8d..708bc4cfd4860 100644
--- a/libc/src/math/generic/ceilf16.cpp
+++ b/libc/src/math/generic/ceilf16.cpp
@@ -15,7 +15,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float16, ceilf16, (float16 x)) {
-#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC) &&                            \
+#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) &&                       \
     defined(LIBC_TARGET_ARCH_IS_AARCH64)
   return static_cast<float16>(__builtin_ceilf(x));
 #else
diff --git a/libc/src/math/generic/floor.cpp b/libc/src/math/generic/floor.cpp
index 8d5ae0948c4f1..86aed6c61a7cc 100644
--- a/libc/src/math/generic/floor.cpp
+++ b/libc/src/math/generic/floor.cpp
@@ -14,7 +14,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(double, floor, (double x)) {
-#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
   return __builtin_floor(x);
 #else
   return fputil::floor(x);
diff --git a/libc/src/math/generic/floorf.cpp b/libc/src/math/generic/floorf.cpp
index bfb96adc8a715..22739eff68ec2 100644
--- a/libc/src/math/generic/floorf.cpp
+++ b/libc/src/math/generic/floorf.cpp
@@ -14,7 +14,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float, floorf, (float x)) {
-#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
   return __builtin_floorf(x);
 #else
   return fputil::floor(x);
diff --git a/libc/src/math/generic/floorf16.cpp b/libc/src/math/generic/floorf16.cpp
index 022a69e9ea18d..84e4b0730ac68 100644
--- a/libc/src/math/generic/floorf16.cpp
+++ b/libc/src/math/generic/floorf16.cpp
@@ -15,7 +15,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float16, floorf16, (float16 x)) {
-#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC) &&                            \
+#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) &&                       \
     defined(LIBC_TARGET_ARCH_IS_AARCH64)
   return static_cast<float16>(__builtin_floorf(x));
 #else
diff --git a/libc/src/math/generic/rint.cpp b/libc/src/math/generic/rint.cpp
index f7837df133484..5defa60ddac1c 100644
--- a/libc/src/math/generic/rint.cpp
+++ b/libc/src/math/generic/rint.cpp
@@ -14,7 +14,11 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(double, rint, (double x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
+  return __builtin_rint(x);
+#else
   return fputil::round_using_current_rounding_mode(x);
+#endif
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/rintf.cpp b/libc/src/math/generic/rintf.cpp
index 29a2845cc85d4..2fe7788241168 100644
--- a/libc/src/math/generic/rintf.cpp
+++ b/libc/src/math/generic/rintf.cpp
@@ -14,7 +14,11 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float, rintf, (float x)) {
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
+  return __builtin_rintf(x);
+#else
   return fputil::round_using_current_rounding_mode(x);
+#endif
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/rintf16.cpp b/libc/src/math/generic/rintf16.cpp
index 69b89de31bf40..0e8c091efcf9b 100644
--- a/libc/src/math/generic/rintf16.cpp
+++ b/libc/src/math/generic/rintf16.cpp
@@ -10,11 +10,17 @@
 #include "src/__support/FPUtil/NearestIntegerOperations.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/architectures.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float16, rintf16, (float16 x)) {
+#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) &&                       \
+    defined(LIBC_TARGET_ARCH_IS_AARCH64)
+  return static_cast<float16>(__builtin_rintf(x));
+#else
   return fputil::round_using_current_rounding_mode(x);
+#endif
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/generic/trunc.cpp b/libc/src/math/generic/trunc.cpp
index 61593df78a2b7..603750f11c9f6 100644
--- a/libc/src/math/generic/trunc.cpp
+++ b/libc/src/math/generic/trunc.cpp
@@ -14,7 +14,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(double, trunc, (double x)) {
-#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
   return __builtin_trunc(x);
 #else
   return fputil::trunc(x);
diff --git a/libc/src/math/generic/truncf.cpp b/libc/src/math/generic/truncf.cpp
index 61dafcc7bb59a..d7b0ffd96da9c 100644
--- a/libc/src/math/generic/truncf.cpp
+++ b/libc/src/math/generic/truncf.cpp
@@ -14,7 +14,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float, truncf, (float x)) {
-#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC
+#ifdef __LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC
   return __builtin_truncf(x);
 #else
   return fputil::trunc(x);
diff --git a/libc/src/math/generic/truncf16.cpp b/libc/src/math/generic/truncf16.cpp
index 9dd7745260159..b931053e53438 100644
--- a/libc/src/math/generic/truncf16.cpp
+++ b/libc/src/math/generic/truncf16.cpp
@@ -15,7 +15,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(float16, truncf16, (float16 x)) {
-#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_TRUNC) &&                            \
+#if defined(__LIBC_USE_BUILTIN_CEIL_FLOOR_RINT_TRUNC) &&                       \
     defined(LIBC_TARGET_ARCH_IS_AARCH64)
   return static_cast<float16>(__builtin_truncf(x));
 #else
diff --git a/libc/test/src/math/performance_testing/CMakeLists.txt b/libc/test/src/math/performance_testing/CMakeLists.txt
index c7241317687e0..5018a5c1c45d5 100644
--- a/libc/test/src/math/performance_testing/CMakeLists.txt
+++ b/libc/test/src/math/performance_testing/CMakeLists.txt
@@ -21,7 +21,7 @@ function(add_perf_binary target_name)
     "PERF"
     "" # No optional arguments
     "SUITE;CXX_STANDARD" # Single value arguments
-    "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS" # Multi-value arguments
+    "SRCS;HDRS;DEPENDS;COMPILE_OPTIONS;LINK_LIBRARIES" # Multi-value arguments
     ${ARGN}
   )
   if(NOT PERF_SRCS)
@@ -64,9 +64,13 @@ function(add_perf_binary target_name)
     )
   endif()
 
+  set(link_libraries ${link_object_files})
+  foreach(lib IN LISTS PERF_LINK_LIBRARIES)
+    list(APPEND link_libraries ${lib}.unit)
+  endforeach()
   target_link_libraries(
       ${fq_target_name}
-      PRIVATE ${link_object_files} libc_diff_test_utils)
+      PRIVATE ${link_libraries} libc_diff_test_utils)
 
   set_target_properties(${fq_target_name}
     PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@ -385,6 +389,8 @@ add_perf_binary(
     libc.src.math.ceilf16
     libc.src.math.floorf
     libc.src.math.floorf16
+    libc.src.math.rintf
+    libc.src.math.rintf16
     libc.src.math.roundevenf
     libc.src.math.roundevenf16
     libc.src.math.roundf
@@ -393,4 +399,6 @@ add_perf_binary(
     libc.src.math.truncf16
   COMPILE_OPTIONS
     -fno-builtin
+  LINK_LIBRARIES
+    LibcFPTestHelpers
 )
diff --git a/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp b/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
index 24176a377e9d4..1628d28319c70 100644
--- a/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
+++ b/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
@@ -11,17 +11,23 @@
 #include "src/math/ceilf16.h"
 #include "src/math/floorf.h"
 #include "src/math/floorf16.h"
+#include "src/math/rintf.h"
+#include "src/math/rintf16.h"
 #include "src/math/roundevenf.h"
 #include "src/math/roundevenf16.h"
 #include "src/math/roundf.h"
 #include "src/math/roundf16.h"
 #include "src/math/truncf.h"
 #include "src/math/truncf16.h"
+#include "test/UnitTest/RoundingModeUtils.h"
 #include "test/src/math/performance_testing/Timer.h"
 
 #include <fstream>
 #include <math.h>
 
+using LIBC_NAMESPACE::fputil::testing::ForceRoundingMode;
+using LIBC_NAMESPACE::fputil::testing::RoundingMode;
+
 namespace LIBC_NAMESPACE::testing {
 
 template <typename T> class NearestIntegerPerf {
@@ -164,5 +170,30 @@ int main() {
   NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::truncf, ::truncf, FLOAT_ROUNDS,
                        "truncf_perf.log")
 
+  if (ForceRoundingMode r(RoundingMode::Upward); r.success) {
+    NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::rintf16, ::placeholderf16,
+                         FLOAT16_ROUNDS, "rintf16_upward_perf.log")
+    NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::rintf, ::rintf, FLOAT_ROUNDS,
+                         "rintf_upward_perf.log")
+  }
+  if (ForceRoundingMode r(RoundingMode::Downward); r.success) {
+    NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::rintf16, ::placeholderf16,
+                         FLOAT16_ROUNDS, "rintf16_downward_perf.log")
+    NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::rintf, ::rintf, FLOAT_ROUNDS,
+                         "rintf_downward_perf.log")
+  }
+  if (ForceRoundingMode r(RoundingMode::TowardZero); r.success) {
+    NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::rintf16, ::placeholderf16,
+                         FLOAT16_ROUNDS, "rintf16_towardzero_perf.log")
+    NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::rintf, ::rintf, FLOAT_ROUNDS,
+                         "rintf_towardzero_perf.log")
+  }
+  if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
+    NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::rintf16, ::placeholderf16,
+                         FLOAT16_ROUNDS, "rintf16_nearest_perf.log")
+    NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::rintf, ::rintf, FLOAT_ROUNDS,
+                         "rintf_nearest_perf.log")
+  }
+
   return 0;
 }

>From 80c9798a46ca7937bc833b638402c379d4ab9f97 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Fri, 12 Jul 2024 17:16:08 +0200
Subject: [PATCH 4/8] fixup! [libc][math] Optimize nearest integer functions
 using builtins when available

Nit: sort roundeven after round.
---
 libc/test/src/math/performance_testing/CMakeLists.txt     | 4 ++--
 .../performance_testing/nearest_integer_funcs_perf.cpp    | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/libc/test/src/math/performance_testing/CMakeLists.txt b/libc/test/src/math/performance_testing/CMakeLists.txt
index 5018a5c1c45d5..a75becba04d07 100644
--- a/libc/test/src/math/performance_testing/CMakeLists.txt
+++ b/libc/test/src/math/performance_testing/CMakeLists.txt
@@ -391,10 +391,10 @@ add_perf_binary(
     libc.src.math.floorf16
     libc.src.math.rintf
     libc.src.math.rintf16
-    libc.src.math.roundevenf
-    libc.src.math.roundevenf16
     libc.src.math.roundf
     libc.src.math.roundf16
+    libc.src.math.roundevenf
+    libc.src.math.roundevenf16
     libc.src.math.truncf
     libc.src.math.truncf16
   COMPILE_OPTIONS
diff --git a/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp b/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
index 1628d28319c70..ff5e8f449719c 100644
--- a/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
+++ b/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
@@ -152,10 +152,10 @@ int main() {
                        FLOAT16_ROUNDS, "ceilf16_perf.log")
   NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::floorf16, ::placeholderf16,
                        FLOAT16_ROUNDS, "floorf16_perf.log")
-  NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::roundevenf16, ::placeholderf16,
-                       FLOAT16_ROUNDS, "roundevenf16_perf.log")
   NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::roundf16, ::placeholderf16,
                        FLOAT16_ROUNDS, "roundf16_perf.log")
+  NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::roundevenf16, ::placeholderf16,
+                       FLOAT16_ROUNDS, "roundevenf16_perf.log")
   NEAREST_INTEGER_PERF(float16, LIBC_NAMESPACE::truncf16, ::placeholderf16,
                        FLOAT16_ROUNDS, "truncf16_perf.log")
 
@@ -163,10 +163,10 @@ int main() {
                        "ceilf_perf.log")
   NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::floorf, ::floorf, FLOAT_ROUNDS,
                        "floorf_perf.log")
-  NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::roundevenf, ::placeholderf,
-                       FLOAT_ROUNDS, "roundevenf_perf.log")
   NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::roundf, ::roundf, FLOAT_ROUNDS,
                        "roundf_perf.log")
+  NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::roundevenf, ::placeholderf,
+                       FLOAT_ROUNDS, "roundevenf_perf.log")
   NEAREST_INTEGER_PERF(float, LIBC_NAMESPACE::truncf, ::truncf, FLOAT_ROUNDS,
                        "truncf_perf.log")
 

>From 9e8d9a825ca3739e65c363b93893b32a4163b140 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Fri, 12 Jul 2024 20:52:31 +0200
Subject: [PATCH 5/8] fixup! [libc][math] Optimize nearest integer functions
 using builtins when available

Fix builtin detection succeeding even when calls to functions provided by the system libc are generated.
---
 libc/cmake/modules/CheckCompilerFeatures.cmake | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libc/cmake/modules/CheckCompilerFeatures.cmake b/libc/cmake/modules/CheckCompilerFeatures.cmake
index 449160d544b0d..a6d793d495c45 100644
--- a/libc/cmake/modules/CheckCompilerFeatures.cmake
+++ b/libc/cmake/modules/CheckCompilerFeatures.cmake
@@ -50,15 +50,18 @@ set(AVAILABLE_COMPILER_FEATURES "")
 foreach(feature IN LISTS ALL_COMPILER_FEATURES)
   set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
   set(compile_options ${LIBC_COMPILE_OPTIONS_NATIVE})
+  set(link_options "")
   if(${feature} STREQUAL "fixed_point")
     list(APPEND compile_options "-ffixed-point")
   elseif(${feature} MATCHES "^builtin_")
     set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT})
+    set(link_options -nostdlib)
     # The compiler might handle calls to rounding builtins by generating calls
     # to the respective libc math functions, in which case we cannot use these
     # builtins in our implementations of these functions. We check that this is
     # not the case by trying to link an executable, since linking would fail due
-    # to unresolved references if calls to libc functions were generated.
+    # to unresolved references with -nostdlib if calls to libc functions were
+    # generated.
     set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE)
   endif()
 
@@ -67,6 +70,7 @@ foreach(feature IN LISTS ALL_COMPILER_FEATURES)
     ${CMAKE_CURRENT_BINARY_DIR}/compiler_features
     SOURCES ${LIBC_SOURCE_DIR}/cmake/modules/compiler_features/check_${feature}.cpp
     COMPILE_DEFINITIONS -I${LIBC_SOURCE_DIR} ${compile_options}
+    LINK_OPTIONS ${link_options}
   )
   if(has_feature)
     list(APPEND AVAILABLE_COMPILER_FEATURES ${feature})

>From 3fccb21986f94389030028f7e5545b955947dc2f Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Sat, 13 Jul 2024 19:37:06 +0200
Subject: [PATCH 6/8] fixup! [libc][math] Optimize nearest integer functions
 using builtins when available

Delete inline assembly implementations for AArch64.
---
 libc/src/math/aarch64/CMakeLists.txt | 79 ----------------------------
 libc/src/math/aarch64/ceil.cpp       | 21 --------
 libc/src/math/aarch64/ceilf.cpp      | 21 --------
 libc/src/math/aarch64/floor.cpp      | 21 --------
 libc/src/math/aarch64/floorf.cpp     | 21 --------
 libc/src/math/aarch64/round.cpp      | 21 --------
 libc/src/math/aarch64/roundf.cpp     | 21 --------
 libc/src/math/aarch64/trunc.cpp      | 21 --------
 libc/src/math/aarch64/truncf.cpp     | 21 --------
 9 files changed, 247 deletions(-)
 delete mode 100644 libc/src/math/aarch64/CMakeLists.txt
 delete mode 100644 libc/src/math/aarch64/ceil.cpp
 delete mode 100644 libc/src/math/aarch64/ceilf.cpp
 delete mode 100644 libc/src/math/aarch64/floor.cpp
 delete mode 100644 libc/src/math/aarch64/floorf.cpp
 delete mode 100644 libc/src/math/aarch64/round.cpp
 delete mode 100644 libc/src/math/aarch64/roundf.cpp
 delete mode 100644 libc/src/math/aarch64/trunc.cpp
 delete mode 100644 libc/src/math/aarch64/truncf.cpp

diff --git a/libc/src/math/aarch64/CMakeLists.txt b/libc/src/math/aarch64/CMakeLists.txt
deleted file mode 100644
index bbe927a1c7c88..0000000000000
--- a/libc/src/math/aarch64/CMakeLists.txt
+++ /dev/null
@@ -1,79 +0,0 @@
-add_entrypoint_object(
-  ceil
-  SRCS
-    ceil.cpp
-  HDRS
-    ../ceil.h
-  COMPILE_OPTIONS
-    -O2
-)
-
-add_entrypoint_object(
-  ceilf
-  SRCS
-    ceilf.cpp
-  HDRS
-    ../ceilf.h
-  COMPILE_OPTIONS
-    -O2
-)
-
-add_entrypoint_object(
-  floor
-  SRCS
-    floor.cpp
-  HDRS
-    ../floor.h
-  COMPILE_OPTIONS
-    -O2
-)
-
-add_entrypoint_object(
-  floorf
-  SRCS
-    floorf.cpp
-  HDRS
-    ../floorf.h
-  COMPILE_OPTIONS
-    -O2
-)
-
-add_entrypoint_object(
-  trunc
-  SRCS
-    trunc.cpp
-  HDRS
-    ../trunc.h
-  COMPILE_OPTIONS
-    -O2
-)
-
-add_entrypoint_object(
-  truncf
-  SRCS
-    truncf.cpp
-  HDRS
-    ../truncf.h
-  COMPILE_OPTIONS
-    -O2
-)
-
-add_entrypoint_object(
-  round
-  SRCS
-    round.cpp
-  HDRS
-    ../round.h
-  COMPILE_OPTIONS
-    -O2
-)
-
-add_entrypoint_object(
-  roundf
-  SRCS
-    roundf.cpp
-  HDRS
-    ../roundf.h
-  COMPILE_OPTIONS
-    -O2
-)
diff --git a/libc/src/math/aarch64/ceil.cpp b/libc/src/math/aarch64/ceil.cpp
deleted file mode 100644
index 5bfd053d603de..0000000000000
--- a/libc/src/math/aarch64/ceil.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the ceil function for aarch64 -------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/ceil.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(double, ceil, (double x)) {
-  double y;
-  __asm__ __volatile__("frintp %d0, %d1\n\t" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/aarch64/ceilf.cpp b/libc/src/math/aarch64/ceilf.cpp
deleted file mode 100644
index 2352245bc8303..0000000000000
--- a/libc/src/math/aarch64/ceilf.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the ceilf function for aarch64 ------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/ceilf.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(float, ceilf, (float x)) {
-  float y;
-  __asm__ __volatile__("frintp %s0, %s1\n\t" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/aarch64/floor.cpp b/libc/src/math/aarch64/floor.cpp
deleted file mode 100644
index f9da52bdd45a8..0000000000000
--- a/libc/src/math/aarch64/floor.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the floor function for aarch64 ------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/floor.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(double, floor, (double x)) {
-  double y;
-  __asm__ __volatile__("frintm %d0, %d1\n\t" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/aarch64/floorf.cpp b/libc/src/math/aarch64/floorf.cpp
deleted file mode 100644
index 980b3c52a00b5..0000000000000
--- a/libc/src/math/aarch64/floorf.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the floorf function for aarch64 -----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/floorf.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(float, floorf, (float x)) {
-  float y;
-  __asm__ __volatile__("frintm %s0, %s1\n\t" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/aarch64/round.cpp b/libc/src/math/aarch64/round.cpp
deleted file mode 100644
index c85445aa19ab5..0000000000000
--- a/libc/src/math/aarch64/round.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the round function for aarch64 ------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/round.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(double, round, (double x)) {
-  double y;
-  __asm__ __volatile__("frinta %d0, %d1\n\t" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/aarch64/roundf.cpp b/libc/src/math/aarch64/roundf.cpp
deleted file mode 100644
index 0c7f7640e8278..0000000000000
--- a/libc/src/math/aarch64/roundf.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the roundf function for aarch64 -----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/roundf.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(float, roundf, (float x)) {
-  float y;
-  __asm__ __volatile__("frinta %s0, %s1\n\t" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/aarch64/trunc.cpp b/libc/src/math/aarch64/trunc.cpp
deleted file mode 100644
index 1ef26f44fd234..0000000000000
--- a/libc/src/math/aarch64/trunc.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the trunc function for aarch64 ------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/trunc.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(double, trunc, (double x)) {
-  double y;
-  __asm__ __volatile__("frintz %d0, %d1\n" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/math/aarch64/truncf.cpp b/libc/src/math/aarch64/truncf.cpp
deleted file mode 100644
index 0c64ef60e91c4..0000000000000
--- a/libc/src/math/aarch64/truncf.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-//===-- Implementation of the truncf function for aarch64 -----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "src/math/truncf.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-LLVM_LIBC_FUNCTION(float, truncf, (float x)) {
-  float y;
-  __asm__ __volatile__("frintz %s0, %s1\n\t" : "=w"(y) : "w"(x));
-  return y;
-}
-
-} // namespace LIBC_NAMESPACE_DECL

>From 8970edfe70135e787334cfe5fbd6bae1beb60da2 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Sat, 13 Jul 2024 19:40:07 +0200
Subject: [PATCH 7/8] fixup! [libc][math] Optimize nearest integer functions
 using builtins when available
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fix GCC warning "variable ‘result’ set but not used".
---
 .../src/math/performance_testing/nearest_integer_funcs_perf.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp b/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
index ff5e8f449719c..b7bd6636a72e1 100644
--- a/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
+++ b/libc/test/src/math/performance_testing/nearest_integer_funcs_perf.cpp
@@ -42,7 +42,7 @@ template <typename T> class NearestIntegerPerf {
                                 StorageType ending_bit, StorageType step,
                                 size_t rounds, std::ofstream &log) {
     auto runner = [=](Func func) {
-      volatile T result;
+      [[maybe_unused]] volatile T result;
       for (size_t i = 0; i < rounds; i++) {
         for (StorageType bits = starting_bit; bits <= ending_bit;
              bits += step) {

>From 7f212a30e88baf60752647377a074c319c2fb070 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Sat, 13 Jul 2024 19:54:15 +0200
Subject: [PATCH 8/8] fixup! [libc][math] Optimize nearest integer functions
 using builtins when available

Fix builtin detection on Android due to missing _start being an error with LLD from Android NDK r26d.
---
 .../compiler_features/check_builtin_ceil_floor_rint_trunc.cpp   | 2 +-
 libc/cmake/modules/compiler_features/check_builtin_round.cpp    | 2 +-
 .../cmake/modules/compiler_features/check_builtin_roundeven.cpp | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_rint_trunc.cpp b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_rint_trunc.cpp
index 51f33be1bea8a..946200001d69f 100644
--- a/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_rint_trunc.cpp
+++ b/libc/cmake/modules/compiler_features/check_builtin_ceil_floor_rint_trunc.cpp
@@ -8,4 +8,4 @@ double try_builtin_floor(double x) { return __builtin_floor(x); }
 double try_builtin_rint(double x) { return __builtin_rint(x); }
 double try_builtin_trunc(double x) { return __builtin_trunc(x); }
 
-int main() {}
+extern "C" void _start() {}
diff --git a/libc/cmake/modules/compiler_features/check_builtin_round.cpp b/libc/cmake/modules/compiler_features/check_builtin_round.cpp
index 8c3065c2de06a..79a347ada8b60 100644
--- a/libc/cmake/modules/compiler_features/check_builtin_round.cpp
+++ b/libc/cmake/modules/compiler_features/check_builtin_round.cpp
@@ -2,4 +2,4 @@ float try_builtin_roundf(float x) { return __builtin_roundf(x); }
 
 double try_builtin_round(double x) { return __builtin_round(x); }
 
-int main() {}
+extern "C" void _start() {}
diff --git a/libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp b/libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp
index 2480abae84c36..0aa40dc7f4b7a 100644
--- a/libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp
+++ b/libc/cmake/modules/compiler_features/check_builtin_roundeven.cpp
@@ -2,4 +2,4 @@ float try_builtin_roundevenf(float x) { return __builtin_roundevenf(x); }
 
 double try_builtin_roundeven(double x) { return __builtin_roundeven(x); }
 
-int main() {}
+extern "C" void _start() {}



More information about the libc-commits mailing list