[libc-commits] [libc] [libc][math] Do not use __builtin_round* with clang on x86 by default. (PR #220739)
via libc-commits
libc-commits at lists.llvm.org
Wed Sep 2 14:51:12 PDT 2026
https://github.com/lntue updated https://github.com/llvm/llvm-project/pull/220739
>From 02a1b42fdc4790bf3639bc8b2d7dfc081f597675 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Wed, 2 Sep 2026 21:26:52 +0000
Subject: [PATCH 1/2] [libc][math] Do not use __builtin_round* with clang on
x86 by default.
---
libc/src/__support/math/CMakeLists.txt | 5 +-
libc/src/__support/math/round.h | 12 ++++-
libc/src/__support/math/roundf.h | 12 ++++-
libc/test/src/math/smoke/RoundTest.h | 66 +++++++++++++-------------
4 files changed, 59 insertions(+), 36 deletions(-)
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 25489d60383a1..0f81197510ab3 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -2453,6 +2453,8 @@ add_header_library(
libc.src.__support.FPUtil.nearest_integer_operations
libc.src.__support.macros.attributes
libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+ libc.src.__support.macros.properties.architectures
libc.src.__support.macros.properties.compiler
libc.src.__support.macros.properties.cpu_features
FLAGS
@@ -2543,9 +2545,10 @@ add_header_library(
roundf.h
DEPENDS
libc.src.__support.FPUtil.nearest_integer_operations
- libc.src.__support.macros.config
libc.src.__support.macros.attributes
libc.src.__support.macros.config
+ libc.src.__support.macros.optimization
+ libc.src.__support.macros.properties.architectures
libc.src.__support.macros.properties.compiler
libc.src.__support.macros.properties.cpu_features
FLAGS
diff --git a/libc/src/__support/math/round.h b/libc/src/__support/math/round.h
index d35c9f437a630..1f0d018957988 100644
--- a/libc/src/__support/math/round.h
+++ b/libc/src/__support/math/round.h
@@ -12,6 +12,8 @@
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/architectures.h"
#include "src/__support/macros/properties/compiler.h"
#include "src/__support/macros/properties/cpu_features.h"
@@ -38,12 +40,20 @@ namespace math {
// still generate callback for ARM version < 8, and for x86-64 with
// `-ffp-model=strict`.
+// Notes: `__builtin_round` expansion for x86-64 using SSE4.1 rounding
+// instruction by clang is only correct for the default rounding mode.
+// See https://github.com/llvm/llvm-project/issues/140252
+// So we will only use `__builtin_round` with clang on x86-64 if we assume
+// default rounding mode (FE_TONEAREST) only.
+
LIBC_INLINE LIBC_CONSTEXPR double round(double x) {
#if __has_builtin(__builtin_round) && !defined(LIBC_USE_CONSTEXPR) && \
(defined(__LIBC_USE_BUILTIN_ROUND) || \
(defined(LIBC_COMPILER_IS_CLANG) && \
defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE) && \
- (!defined(__ARM_ARCH) || (__ARM_ARCH >= 8))))
+ (!defined(__ARM_ARCH) || (__ARM_ARCH >= 8)) && \
+ (!defined(LIBC_TARGET_ARCH_IS_X86) || \
+ defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY))))
return __builtin_round(x);
#else
return fputil::round(x);
diff --git a/libc/src/__support/math/roundf.h b/libc/src/__support/math/roundf.h
index 5abe9ebad15b0..e1cb4fc9c2e9e 100644
--- a/libc/src/__support/math/roundf.h
+++ b/libc/src/__support/math/roundf.h
@@ -12,6 +12,8 @@
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/__support/macros/properties/architectures.h"
#include "src/__support/macros/properties/compiler.h"
#include "src/__support/macros/properties/cpu_features.h"
@@ -38,12 +40,20 @@ namespace math {
// still generate callback for ARM version < 8, and for x86-64 with
// `-ffp-model=strict`.
+// Notes: `__builtin_roundf` expansion for x86-64 using SSE4.1 rounding
+// instruction by clang is only correct for the default rounding mode.
+// See https://github.com/llvm/llvm-project/issues/140252
+// So we will only use `__builtin_round` with clang on x86-64 if we assume
+// default rounding mode (FE_TONEAREST) only.
+
LIBC_INLINE LIBC_CONSTEXPR float roundf(float x) {
#if __has_builtin(__builtin_roundf) && !defined(LIBC_USE_CONSTEXPR) && \
(defined(__LIBC_USE_BUILTIN_ROUND) || \
(defined(LIBC_COMPILER_IS_CLANG) && \
defined(LIBC_TARGET_CPU_HAS_FPU_FLOAT) && \
- (!defined(__ARM_ARCH) || (__ARM_ARCH >= 8))))
+ (!defined(__ARM_ARCH) || (__ARM_ARCH >= 8)) && \
+ (!defined(LIBC_TARGET_ARCH_IS_X86) || \
+ defined(LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY))))
return __builtin_roundf(x);
#else
return fputil::round(x);
diff --git a/libc/test/src/math/smoke/RoundTest.h b/libc/test/src/math/smoke/RoundTest.h
index 72889dada1378..82a557e77e90d 100644
--- a/libc/test/src/math/smoke/RoundTest.h
+++ b/libc/test/src/math/smoke/RoundTest.h
@@ -24,47 +24,47 @@ class RoundTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
typedef T (*RoundFunc)(T);
void testSpecialNumbers(RoundFunc func) {
- EXPECT_FP_EQ(zero, func(zero));
- EXPECT_FP_EQ(neg_zero, func(neg_zero));
+ EXPECT_FP_EQ_ALL_ROUNDING(zero, func(zero));
+ EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(neg_zero));
- EXPECT_FP_EQ(inf, func(inf));
- EXPECT_FP_EQ(neg_inf, func(neg_inf));
+ EXPECT_FP_EQ_ALL_ROUNDING(inf, func(inf));
+ EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, func(neg_inf));
- EXPECT_FP_EQ(aNaN, func(aNaN));
+ EXPECT_FP_EQ_ALL_ROUNDING(aNaN, func(aNaN));
}
void testRoundedNumbers(RoundFunc func) {
- EXPECT_FP_EQ(T(1.0), func(T(1.0)));
- EXPECT_FP_EQ(T(-1.0), func(T(-1.0)));
- EXPECT_FP_EQ(T(10.0), func(T(10.0)));
- EXPECT_FP_EQ(T(-10.0), func(T(-10.0)));
- EXPECT_FP_EQ(T(1234.0), func(T(1234.0)));
- EXPECT_FP_EQ(T(-1234.0), func(T(-1234.0)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(1.0), func(T(1.0)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-1.0), func(T(-1.0)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(10.0), func(T(10.0)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-10.0), func(T(-10.0)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(1234.0), func(T(1234.0)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-1234.0), func(T(-1234.0)));
}
void testFractions(RoundFunc func) {
- EXPECT_FP_EQ(T(1.0), func(T(0.5)));
- EXPECT_FP_EQ(T(-1.0), func(T(-0.5)));
- EXPECT_FP_EQ(T(0.0), func(T(0.115)));
- EXPECT_FP_EQ(T(-0.0), func(T(-0.115)));
- EXPECT_FP_EQ(T(1.0), func(T(0.715)));
- EXPECT_FP_EQ(T(-1.0), func(T(-0.715)));
- EXPECT_FP_EQ(T(1.0), func(T(1.3)));
- EXPECT_FP_EQ(T(-1.0), func(T(-1.3)));
- EXPECT_FP_EQ(T(2.0), func(T(1.5)));
- EXPECT_FP_EQ(T(-2.0), func(T(-1.5)));
- EXPECT_FP_EQ(T(2.0), func(T(1.75)));
- EXPECT_FP_EQ(T(-2.0), func(T(-1.75)));
- EXPECT_FP_EQ(T(10.0), func(T(10.32)));
- EXPECT_FP_EQ(T(-10.0), func(T(-10.32)));
- EXPECT_FP_EQ(T(11.0), func(T(10.65)));
- EXPECT_FP_EQ(T(-11.0), func(T(-10.65)));
- EXPECT_FP_EQ(T(50.0), func(T(49.63)));
- EXPECT_FP_EQ(T(-50.0), func(T(-50.31)));
- EXPECT_FP_EQ(T(124.0), func(T(123.5)));
- EXPECT_FP_EQ(T(-124.0), func(T(-123.5)));
- EXPECT_FP_EQ(T(124.0), func(T(123.96)));
- EXPECT_FP_EQ(T(-124.0), func(T(-123.96)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(1.0), func(T(0.5)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-1.0), func(T(-0.5)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(0.0), func(T(0.115)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-0.0), func(T(-0.115)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(1.0), func(T(0.715)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-1.0), func(T(-0.715)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(1.0), func(T(1.3)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-1.0), func(T(-1.3)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(2.0), func(T(1.5)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-2.0), func(T(-1.5)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(2.0), func(T(1.75)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-2.0), func(T(-1.75)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(10.0), func(T(10.32)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-10.0), func(T(-10.32)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(11.0), func(T(10.65)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-11.0), func(T(-10.65)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(50.0), func(T(49.63)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-50.0), func(T(-50.31)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(124.0), func(T(123.5)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-124.0), func(T(-123.5)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(124.0), func(T(123.96)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-124.0), func(T(-123.96)));
}
};
>From d793c8e87020bdd6a1de45f688490afb9e19fd52 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Wed, 2 Sep 2026 21:50:06 +0000
Subject: [PATCH 2/2] Adjust RoundTest to accommodate bf16.
---
libc/test/src/math/smoke/RoundTest.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/test/src/math/smoke/RoundTest.h b/libc/test/src/math/smoke/RoundTest.h
index 82a557e77e90d..5459986db0451 100644
--- a/libc/test/src/math/smoke/RoundTest.h
+++ b/libc/test/src/math/smoke/RoundTest.h
@@ -60,7 +60,7 @@ class RoundTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
EXPECT_FP_EQ_ALL_ROUNDING(T(11.0), func(T(10.65)));
EXPECT_FP_EQ_ALL_ROUNDING(T(-11.0), func(T(-10.65)));
EXPECT_FP_EQ_ALL_ROUNDING(T(50.0), func(T(49.63)));
- EXPECT_FP_EQ_ALL_ROUNDING(T(-50.0), func(T(-50.31)));
+ EXPECT_FP_EQ_ALL_ROUNDING(T(-50.0), func(T(-50.25)));
EXPECT_FP_EQ_ALL_ROUNDING(T(124.0), func(T(123.5)));
EXPECT_FP_EQ_ALL_ROUNDING(T(-124.0), func(T(-123.5)));
EXPECT_FP_EQ_ALL_ROUNDING(T(124.0), func(T(123.96)));
More information about the libc-commits
mailing list