diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt index 278e1f5afde7..4e720a234d47 100644 --- a/libc/config/baremetal/aarch64/entrypoints.txt +++ b/libc/config/baremetal/aarch64/entrypoints.txt @@ -355,6 +355,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt index 9a6b9cbf3dae..c61afd0fdcc6 100644 --- a/libc/config/baremetal/arm/entrypoints.txt +++ b/libc/config/baremetal/arm/entrypoints.txt @@ -361,6 +361,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt index 1e297d14cae2..24e9cc502b73 100644 --- a/libc/config/baremetal/riscv/entrypoints.txt +++ b/libc/config/baremetal/riscv/entrypoints.txt @@ -356,6 +356,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt index ced8d1fef010..5085e95a643e 100644 --- a/libc/config/darwin/aarch64/entrypoints.txt +++ b/libc/config/darwin/aarch64/entrypoints.txt @@ -171,6 +171,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt index e899bf97ea3f..27e50b9e96e9 100644 --- a/libc/config/darwin/x86_64/entrypoints.txt +++ b/libc/config/darwin/x86_64/entrypoints.txt @@ -277,6 +277,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.llrintbf16 libc.src.math.llroundbf16 libc.src.math.log_bf16 + libc.src.math.cbrtbf16 libc.src.math.logbbf16 libc.src.math.lrintbf16 libc.src.math.lroundbf16 diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt index a65b6f0274fd..0441207ace96 100644 --- a/libc/config/gpu/amdgpu/entrypoints.txt +++ b/libc/config/gpu/amdgpu/entrypoints.txt @@ -299,6 +299,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt index fee0038c88cc..f127ba6358b4 100644 --- a/libc/config/gpu/nvptx/entrypoints.txt +++ b/libc/config/gpu/nvptx/entrypoints.txt @@ -299,6 +299,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 92210a72ee75..795784720096 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -441,6 +441,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index 6ee0ebf2b412..48d5972f71ce 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -268,6 +268,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.atanhf libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 878f8d42d6d7..7ebaa4f165c0 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -445,6 +445,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index f26b81846624..4cec9708b040 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -490,6 +490,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.canonicalizel libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.ceil libc.src.math.ceilf libc.src.math.ceill diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index fc2f3dbe7765..18910b5f9845 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -147,6 +147,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.atanhf libc.src.math.cbrt libc.src.math.cbrtf + libc.src.math.cbrtbf16 libc.src.math.copysign libc.src.math.copysignf libc.src.math.copysignl diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst index e8b3fe63b2a6..ee2b6d9b7bd1 100644 --- a/libc/docs/headers/math/index.rst +++ b/libc/docs/headers/math/index.rst @@ -281,7 +281,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ | atanpi | | | | |check| | | | 7.12.4.10 | F.10.1.10 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ -| cbrt | |check| | |check| | | | | | 7.12.7.1 | F.10.4.1 | +| cbrt | |check| | |check| | | | | |check| | 7.12.7.1 | F.10.4.1 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ | compoundn | | | | | | | 7.12.7.2 | F.10.4.2 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index e61795036899..766feb0606c6 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -93,6 +93,7 @@ add_math_entrypoint_object(iscanonicalbf16) add_math_entrypoint_object(cbrt) add_math_entrypoint_object(cbrtf) +add_math_entrypoint_object(cbrtbf16) add_math_entrypoint_object(ceil) add_math_entrypoint_object(ceilf) diff --git a/libc/src/math/cbrtbf16.h b/libc/src/math/cbrtbf16.h new file mode 100644 index 000000000000..beef9278cbe1 --- /dev/null +++ b/libc/src/math/cbrtbf16.h @@ -0,0 +1,21 @@ +//===-- Implementation header for cbrtbf16 ----------------------*- 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_MATH_CBRTBF16_H +#define LLVM_LIBC_SRC_MATH_CBRTBF16_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +bfloat16 cbrtbf16(bfloat16 x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_CBRTBF16_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index d067efdae5e8..b9de548c8bed 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -4937,6 +4937,20 @@ add_entrypoint_object( libc.src.__support.math.cbrt ) +add_entrypoint_object ( + cbrtbf16 + SRCS + cbrtbf16.cpp + HDRS + ../cbrtbf16.h + DEPENDS + libc.src.__support.common + libc.src.__support.FPUtil.bfloat16 + libc.src.math.generic.cbrt + libc.src.__support.macros.config + libc.src.__support.macros.properties.types +) + add_entrypoint_object( dmull SRCS diff --git a/libc/src/math/generic/cbrtbf16.cpp b/libc/src/math/generic/cbrtbf16.cpp new file mode 100644 index 000000000000..742cee8ae142 --- /dev/null +++ b/libc/src/math/generic/cbrtbf16.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of cbrtbf16 function -------------------------------===// +// +// 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/cbrtbf16.h" +#include "src/__support/FPUtil/bfloat16.h" +#include "src/__support/macros/config.h" +#include "src/__support/math/cbrtf.h" + +namespace LIBC_NAMESPACE_DECL { +LLVM_LIBC_FUNCTION(bfloat16, cbrtbf16, (bfloat16 x)) { + return static_cast(math::cbrtf(static_cast(x))); +} +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 73b5ebf5a856..90afe842e9de 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -3011,6 +3011,18 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + cbrtbf16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + cbrtbf16_test.cpp + DEPENDS + libc.src.math.cbrtbf16 + libc.src.__support.FPUtil.bfloat16 +) + add_fp_unittest( dmull_test NEED_MPFR diff --git a/libc/test/src/math/cbrtbf16_test.cpp b/libc/test/src/math/cbrtbf16_test.cpp new file mode 100644 index 000000000000..cf5154e8cb6e --- /dev/null +++ b/libc/test/src/math/cbrtbf16_test.cpp @@ -0,0 +1,35 @@ +//===-- Exhaustive test for cbrtbf16 --------------------------------------===// +// +// 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/__support/FPUtil/bfloat16.h" +#include "src/math/cbrtbf16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using LlvmLibcCbrtbf16Test = LIBC_NAMESPACE::testing::FPTest; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +// for the exhaustive test, we test with every 16-bit combination +// and skip NaN cases. v is uint32_t to prevent integer overflow and +// wraparound to 0. +TEST_F(LlvmLibcCbrtbf16Test, Exhaustive) { + for (uint32_t v = 0x00000; v < 0x10000; ++v) { + bfloat16 x = + LIBC_NAMESPACE::fputil::FPBits(static_cast(v)) + .get_val(); + + LIBC_NAMESPACE::fputil::FPBits bits(x); // NaN checking + if (bits.is_nan()) + continue; + + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Cbrt, x, + LIBC_NAMESPACE::cbrtbf16(x), 0.5); + } +} diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 3d52873c40bb..185f646e3aa9 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -6018,6 +6018,17 @@ add_fp_unittest( libc.src.math.cbrt ) +add_fp_unittest( + cbrtbf16_test + SUITE + libc-math-smoke-tests + SRCS + cbrtbf16_test.cpp + DEPENDS + libc.src.math.cbrtbf16 + libc.src.__support.FPUtil.bfloat16 +) + add_fp_unittest( dmull_test SUITE diff --git a/libc/test/src/math/smoke/cbrtbf16_test.cpp b/libc/test/src/math/smoke/cbrtbf16_test.cpp new file mode 100644 index 000000000000..ab38e5cc5d8d --- /dev/null +++ b/libc/test/src/math/smoke/cbrtbf16_test.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Unittests for cbrtbf16 + +#include "src/__support/FPUtil/bfloat16.h" +#include "src/math/cbrtbf16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcCbrtbf16Test = LIBC_NAMESPACE::testing::FPTest; + +using LIBC_NAMESPACE::testing::tlog; + +TEST_F(LlvmLibcCbrtbf16Test, SpecialNumbers) { + EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::cbrtbf16(sNaN), FE_INVALID); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::cbrtbf16(aNaN)); + EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::cbrtbf16(inf)); + EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, LIBC_NAMESPACE::cbrtbf16(neg_inf)); + EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::cbrtbf16(zero)); + EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, LIBC_NAMESPACE::cbrtbf16(neg_zero)); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(1.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(1.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(-1.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(-1.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(2.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(8.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(-2.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(-8.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(3.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(27.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(-3.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(-27.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(5.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(125.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(-5.0f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(-125.0f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(0x1.0p42f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(0x1.0p126f))); + EXPECT_FP_EQ_ALL_ROUNDING(bfloat16(-0x1.0p42f), + LIBC_NAMESPACE::cbrtbf16(bfloat16(-0x1.0p126f))); +} + +#ifdef LIBC_TEST_FTZ_DAZ + +using namespace LIBC_NAMESPACE::testing; + +// the float version includes explicit FTZ-mode checks for subnormal +// outputs using hex expectations. for bfloat16, this is unnecessary. +// if x=2^e then cbrt(x)=2^(e/3). to produce a subnormal result, we would +// need e/3 < -126, i.e e<-378. Since the smallest representable exponent +// in bfloat16 is -133, no finite bfloat16 input can produce a subnormal +// cube root. therefore, explicit subnormal output checks are omitted here. + +TEST_F(LlvmLibcCbrtbf16Test, DAZMode) { + ModifyMXCSR mxcsr(DAZ); + + EXPECT_FP_EQ(bfloat16(0.0f), LIBC_NAMESPACE::cbrtbf16(min_denormal)); + EXPECT_FP_EQ(bfloat16(0.0f), LIBC_NAMESPACE::cbrtbf16(max_denormal)); +} + +TEST_F(LlvmLibcCbrtbf16Test, FTZDAZMode) { + ModifyMXCSR mxcsr(FTZ | DAZ); + + EXPECT_FP_EQ(bfloat16(0.0f), LIBC_NAMESPACE::cbrtbf16(min_denormal)); + EXPECT_FP_EQ(bfloat16(0.0f), LIBC_NAMESPACE::cbrtbf16(max_denormal)); +} + +#endif