[libc-commits] [libc] [llvm] [libc][math] Refactor hypotf to Header Only. (PR #175679)
Muhammad Bassiouni via libc-commits
libc-commits at lists.llvm.org
Fri Jan 16 15:34:12 PST 2026
https://github.com/bassiounix updated https://github.com/llvm/llvm-project/pull/175679
>From 7a5f007573592dfedb8e0f41b9c3377d9dde2583 Mon Sep 17 00:00:00 2001
From: anonmiraj <nabilmalek48 at gmail.com>
Date: Tue, 13 Jan 2026 00:46:45 +0200
Subject: [PATCH 1/4] [libc][math] Refactor hypotf to Header Only.
---
libc/shared/math.h | 1 +
libc/shared/math/hypotf.h | 22 ++++
libc/src/__support/math/CMakeLists.txt | 13 +++
libc/src/__support/math/hypotf.h | 107 ++++++++++++++++++
libc/src/math/generic/CMakeLists.txt | 8 +-
libc/src/math/generic/hypotf.cpp | 85 +-------------
libc/test/shared/CMakeLists.txt | 1 +
libc/test/shared/shared_math_test.cpp | 1 +
.../llvm-project-overlay/libc/BUILD.bazel | 19 +++-
9 files changed, 166 insertions(+), 91 deletions(-)
create mode 100644 libc/shared/math/hypotf.h
create mode 100644 libc/src/__support/math/hypotf.h
diff --git a/libc/shared/math.h b/libc/shared/math.h
index de1f7b0cc0b5d..51fd4006feb4d 100644
--- a/libc/shared/math.h
+++ b/libc/shared/math.h
@@ -62,6 +62,7 @@
#include "math/frexpf128.h"
#include "math/frexpf16.h"
#include "math/fsqrt.h"
+#include "math/hypotf.h"
#include "math/ilogbf16.h"
#include "math/ldexpf.h"
#include "math/ldexpf128.h"
diff --git a/libc/shared/math/hypotf.h b/libc/shared/math/hypotf.h
new file mode 100644
index 0000000000000..6feca6c5d6595
--- /dev/null
+++ b/libc/shared/math/hypotf.h
@@ -0,0 +1,22 @@
+//===-- Shared hypotf function ----------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SHARED_MATH_HYPOTF_H
+#define LLVM_LIBC_SHARED_MATH_HYPOTF_H
+
+#include "src/__support/math/hypotf.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace shared {
+
+using math::hypotf;
+
+} // namespace shared
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SHARED_MATH_HYPOTF_H
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 9716a2a3b1ff4..0f3b17d467579 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -943,6 +943,19 @@ add_header_library(
libc.src.__support.macros.optimization
)
+add_header_library(
+ hypotf
+ HDRS
+ hypotf.h
+ DEPENDS
+ libc.src.__support.FPUtil.double_double
+ libc.src.__support.FPUtil.fenv_impl
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.FPUtil.multiply_add
+ libc.src.__support.FPUtil.sqrt
+ libc.src.__support.macros.optimization
+)
+
add_header_library(
range_reduction_double
HDRS
diff --git a/libc/src/__support/math/hypotf.h b/libc/src/__support/math/hypotf.h
new file mode 100644
index 0000000000000..0169cf398f361
--- /dev/null
+++ b/libc/src/__support/math/hypotf.h
@@ -0,0 +1,107 @@
+//===-- Implementation header for hypotf ------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_HYPOTF_H
+#define LLVM_LIBC_SRC___SUPPORT_MATH_HYPOTF_H
+
+#include "src/__support/FPUtil/FEnvImpl.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/double_double.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/FPUtil/sqrt.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace math {
+
+LIBC_INLINE static constexpr float hypotf(float x, float y) {
+ using DoubleBits = fputil::FPBits<double>;
+ using FPBits = fputil::FPBits<float>;
+
+ FPBits x_abs = FPBits(x).abs();
+ FPBits y_abs = FPBits(y).abs();
+
+ bool x_abs_larger = x_abs.uintval() >= y_abs.uintval();
+
+ FPBits a_bits = x_abs_larger ? x_abs : y_abs;
+ FPBits b_bits = x_abs_larger ? y_abs : x_abs;
+
+ uint32_t a_u = a_bits.uintval();
+ uint32_t b_u = b_bits.uintval();
+
+ // Note: replacing `a_u >= FPBits::EXP_MASK` with `a_bits.is_inf_or_nan()`
+ // generates extra exponent bit masking instructions on x86-64.
+ if (LIBC_UNLIKELY(a_u >= FPBits::EXP_MASK)) {
+ // x or y is inf or nan
+ if (a_bits.is_signaling_nan() || b_bits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ if (a_bits.is_inf() || b_bits.is_inf())
+ return FPBits::inf().get_val();
+ return a_bits.get_val();
+ }
+
+ if (LIBC_UNLIKELY(a_u - b_u >=
+ static_cast<uint32_t>((FPBits::FRACTION_LEN + 2)
+ << FPBits::FRACTION_LEN)))
+ return x_abs.get_val() + y_abs.get_val();
+
+ double ad = static_cast<double>(a_bits.get_val());
+ double bd = static_cast<double>(b_bits.get_val());
+
+ // These squares are exact.
+ double a_sq = ad * ad;
+#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
+ double sum_sq = fputil::multiply_add(bd, bd, a_sq);
+#else
+ double b_sq = bd * bd;
+ double sum_sq = a_sq + b_sq;
+#endif
+
+ // Take sqrt in double precision.
+ DoubleBits result(fputil::sqrt<double>(sum_sq));
+ uint64_t r_u = result.uintval();
+
+ // If any of the sticky bits of the result are non-zero, except the LSB, then
+ // the rounded result is correct.
+ if (LIBC_UNLIKELY(((r_u + 1) & 0x0000'0000'0FFF'FFFE) == 0)) {
+ double r_d = result.get_val();
+
+ // Perform rounding correction.
+#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
+ double sum_sq_lo = fputil::multiply_add(bd, bd, a_sq - sum_sq);
+ double err = sum_sq_lo - fputil::multiply_add(r_d, r_d, -sum_sq);
+#else
+ fputil::DoubleDouble r_sq = fputil::exact_mult(r_d, r_d);
+ double sum_sq_lo = b_sq - (sum_sq - a_sq);
+ double err = (sum_sq - r_sq.hi) + (sum_sq_lo - r_sq.lo);
+#endif
+
+ if (err > 0) {
+ r_u |= 1;
+ } else if ((err < 0) && (r_u & 1) == 0) {
+ r_u -= 1;
+ } else if ((r_u & 0x0000'0000'1FFF'FFFF) == 0) {
+ // The rounded result is exact.
+ fputil::clear_except_if_required(FE_INEXACT);
+ }
+ return static_cast<float>(DoubleBits(r_u).get_val());
+ }
+
+ return static_cast<float>(result.get_val());
+}
+
+} // namespace math
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_MATH_HYPOTF_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 2729c987d6369..95398f4c9e074 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3270,12 +3270,8 @@ add_entrypoint_object(
HDRS
../hypotf.h
DEPENDS
- libc.src.__support.FPUtil.double_double
- libc.src.__support.FPUtil.fenv_impl
- libc.src.__support.FPUtil.fp_bits
- libc.src.__support.FPUtil.multiply_add
- libc.src.__support.FPUtil.sqrt
- libc.src.__support.macros.optimization
+ libc.src.__support.math.hypotf
+ libc.src.errno.errno
)
add_entrypoint_object(
diff --git a/libc/src/math/generic/hypotf.cpp b/libc/src/math/generic/hypotf.cpp
index ec48f62163a48..fa1697c71b72e 100644
--- a/libc/src/math/generic/hypotf.cpp
+++ b/libc/src/math/generic/hypotf.cpp
@@ -6,93 +6,12 @@
//
//===----------------------------------------------------------------------===//
#include "src/math/hypotf.h"
-#include "src/__support/FPUtil/FEnvImpl.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/double_double.h"
-#include "src/__support/FPUtil/multiply_add.h"
-#include "src/__support/FPUtil/sqrt.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-#include "src/__support/macros/optimization.h"
+#include "src/__support/math/hypotf.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float, hypotf, (float x, float y)) {
- using DoubleBits = fputil::FPBits<double>;
- using FPBits = fputil::FPBits<float>;
-
- FPBits x_abs = FPBits(x).abs();
- FPBits y_abs = FPBits(y).abs();
-
- bool x_abs_larger = x_abs.uintval() >= y_abs.uintval();
-
- FPBits a_bits = x_abs_larger ? x_abs : y_abs;
- FPBits b_bits = x_abs_larger ? y_abs : x_abs;
-
- uint32_t a_u = a_bits.uintval();
- uint32_t b_u = b_bits.uintval();
-
- // Note: replacing `a_u >= FPBits::EXP_MASK` with `a_bits.is_inf_or_nan()`
- // generates extra exponent bit masking instructions on x86-64.
- if (LIBC_UNLIKELY(a_u >= FPBits::EXP_MASK)) {
- // x or y is inf or nan
- if (a_bits.is_signaling_nan() || b_bits.is_signaling_nan()) {
- fputil::raise_except_if_required(FE_INVALID);
- return FPBits::quiet_nan().get_val();
- }
- if (a_bits.is_inf() || b_bits.is_inf())
- return FPBits::inf().get_val();
- return a_bits.get_val();
- }
-
- if (LIBC_UNLIKELY(a_u - b_u >=
- static_cast<uint32_t>((FPBits::FRACTION_LEN + 2)
- << FPBits::FRACTION_LEN)))
- return x_abs.get_val() + y_abs.get_val();
-
- double ad = static_cast<double>(a_bits.get_val());
- double bd = static_cast<double>(b_bits.get_val());
-
- // These squares are exact.
- double a_sq = ad * ad;
-#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
- double sum_sq = fputil::multiply_add(bd, bd, a_sq);
-#else
- double b_sq = bd * bd;
- double sum_sq = a_sq + b_sq;
-#endif
-
- // Take sqrt in double precision.
- DoubleBits result(fputil::sqrt<double>(sum_sq));
- uint64_t r_u = result.uintval();
-
- // If any of the sticky bits of the result are non-zero, except the LSB, then
- // the rounded result is correct.
- if (LIBC_UNLIKELY(((r_u + 1) & 0x0000'0000'0FFF'FFFE) == 0)) {
- double r_d = result.get_val();
-
- // Perform rounding correction.
-#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE
- double sum_sq_lo = fputil::multiply_add(bd, bd, a_sq - sum_sq);
- double err = sum_sq_lo - fputil::multiply_add(r_d, r_d, -sum_sq);
-#else
- fputil::DoubleDouble r_sq = fputil::exact_mult(r_d, r_d);
- double sum_sq_lo = b_sq - (sum_sq - a_sq);
- double err = (sum_sq - r_sq.hi) + (sum_sq_lo - r_sq.lo);
-#endif
-
- if (err > 0) {
- r_u |= 1;
- } else if ((err < 0) && (r_u & 1) == 0) {
- r_u -= 1;
- } else if ((r_u & 0x0000'0000'1FFF'FFFF) == 0) {
- // The rounded result is exact.
- fputil::clear_except_if_required(FE_INEXACT);
- }
- return static_cast<float>(DoubleBits(r_u).get_val());
- }
-
- return static_cast<float>(result.get_val());
+ return math::hypotf(x, y);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt
index 51bf25d60451d..d0800cf84dcd5 100644
--- a/libc/test/shared/CMakeLists.txt
+++ b/libc/test/shared/CMakeLists.txt
@@ -58,6 +58,7 @@ add_fp_unittest(
libc.src.__support.math.frexpf128
libc.src.__support.math.frexpf16
libc.src.__support.math.fsqrt
+ libc.src.__support.math.hypotf
libc.src.__support.math.ilogbf16
libc.src.__support.math.log
libc.src.__support.math.logbf
diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp
index 8079890357ca0..79a15f127d853 100644
--- a/libc/test/shared/shared_math_test.cpp
+++ b/libc/test/shared/shared_math_test.cpp
@@ -70,6 +70,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat) {
EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::expf(0.0f));
EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::exp2f(0.0f));
EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::expm1f(0.0f));
+ EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::hypotf(0.0f, 0.0f));
EXPECT_FP_EQ_ALL_ROUNDING(0.75f,
LIBC_NAMESPACE::shared::frexpf(24.0f, &exponent));
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index de7aa4dfa74ab..953565e75a096 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3284,6 +3284,21 @@ libc_support_library(
],
)
+libc_support_library(
+ name = "__support_math_hypotf",
+ hdrs = ["src/__support/math/hypotf.h"],
+ deps = [
+ ":__support_common",
+ ":__support_fputil_double_double",
+ ":__support_fputil_fenv_impl",
+ ":__support_fputil_fp_bits",
+ ":__support_fputil_multiply_add",
+ ":__support_fputil_sqrt",
+ ":__support_macros_config",
+ ":__support_macros_optimization",
+ ],
+)
+
############################### complex targets ################################
libc_function(
@@ -4360,8 +4375,8 @@ libc_math_function(name = "hypot")
libc_math_function(
name = "hypotf",
additional_deps = [
- ":__support_fputil_double_double",
- ":__support_fputil_sqrt",
+ ":__support_math_hypotf",
+ ":errno",
],
)
>From 7985e164c594b80e4d07a4a4893b4fd1f485bfb7 Mon Sep 17 00:00:00 2001
From: anonmiraj <nabilmalek48 at gmail.com>
Date: Sat, 17 Jan 2026 01:32:58 +0200
Subject: [PATCH 2/4] remove constexpr
---
libc/src/__support/math/hypotf.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/__support/math/hypotf.h b/libc/src/__support/math/hypotf.h
index 0169cf398f361..e712a07bda01a 100644
--- a/libc/src/__support/math/hypotf.h
+++ b/libc/src/__support/math/hypotf.h
@@ -22,7 +22,7 @@ namespace LIBC_NAMESPACE_DECL {
namespace math {
-LIBC_INLINE static constexpr float hypotf(float x, float y) {
+LIBC_INLINE static float hypotf(float x, float y) {
using DoubleBits = fputil::FPBits<double>;
using FPBits = fputil::FPBits<float>;
>From 01a863c3841208399d84054bd6ec765f929f2dc0 Mon Sep 17 00:00:00 2001
From: Muhammad Bassiouni <60100307+bassiounix at users.noreply.github.com>
Date: Sat, 17 Jan 2026 01:33:22 +0200
Subject: [PATCH 3/4] Apply suggestion from @bassiounix
---
libc/src/math/generic/hypotf.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/libc/src/math/generic/hypotf.cpp b/libc/src/math/generic/hypotf.cpp
index fa1697c71b72e..454cfd9093147 100644
--- a/libc/src/math/generic/hypotf.cpp
+++ b/libc/src/math/generic/hypotf.cpp
@@ -8,6 +8,7 @@
#include "src/math/hypotf.h"
#include "src/__support/math/hypotf.h"
+
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float, hypotf, (float x, float y)) {
>From 894d36ade77b9b3a35ad700b1b610999f6966031 Mon Sep 17 00:00:00 2001
From: Muhammad Bassiouni <60100307+bassiounix at users.noreply.github.com>
Date: Sat, 17 Jan 2026 01:34:03 +0200
Subject: [PATCH 4/4] Apply suggestion from @bassiounix
---
libc/src/math/generic/hypotf.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/libc/src/math/generic/hypotf.cpp b/libc/src/math/generic/hypotf.cpp
index 454cfd9093147..fa1697c71b72e 100644
--- a/libc/src/math/generic/hypotf.cpp
+++ b/libc/src/math/generic/hypotf.cpp
@@ -8,7 +8,6 @@
#include "src/math/hypotf.h"
#include "src/__support/math/hypotf.h"
-
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(float, hypotf, (float x, float y)) {
More information about the libc-commits
mailing list