mirror of
https://github.com/intel/llvm.git
synced 2026-01-21 12:19:23 +08:00
[libc][math][c++23] Implement basic arithmetic operations for BFloat16 (#151228)
This PR implements addition, subtraction, multiplication and division operations for BFloat16. --------- Signed-off-by: krishna2803 <kpandey81930@gmail.com> Signed-off-by: Krishna Pandey <kpandey81930@gmail.com> Co-authored-by: OverMighty <its.overmighty@gmail.com>
This commit is contained in:
@@ -285,6 +285,9 @@ add_header_library(
|
||||
libc.hdr.stdint_proxy
|
||||
libc.src.__support.CPP.bit
|
||||
libc.src.__support.CPP.type_traits
|
||||
libc.src.__support.FPUtil.generic.add_sub
|
||||
libc.src.__support.FPUtil.generic.div
|
||||
libc.src.__support.FPUtil.generic.mul
|
||||
libc.src.__support.macros.config
|
||||
libc.src.__support.macros.properties.types
|
||||
)
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#include "src/__support/FPUtil/cast.h"
|
||||
#include "src/__support/FPUtil/comparison_operations.h"
|
||||
#include "src/__support/FPUtil/dyadic_float.h"
|
||||
#include "src/__support/FPUtil/generic/add_sub.h"
|
||||
#include "src/__support/FPUtil/generic/div.h"
|
||||
#include "src/__support/FPUtil/generic/mul.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/macros/properties/types.h"
|
||||
|
||||
@@ -81,6 +84,28 @@ struct BFloat16 {
|
||||
LIBC_INLINE bool operator>=(BFloat16 other) const {
|
||||
return fputil::greater_than_or_equals(*this, other);
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr BFloat16 operator-() const {
|
||||
fputil::FPBits<bfloat16> result(*this);
|
||||
result.set_sign(result.is_pos() ? Sign::NEG : Sign::POS);
|
||||
return result.get_val();
|
||||
}
|
||||
|
||||
LIBC_INLINE BFloat16 operator+(BFloat16 other) const {
|
||||
return fputil::generic::add<BFloat16>(*this, other);
|
||||
}
|
||||
|
||||
LIBC_INLINE BFloat16 operator-(BFloat16 other) const {
|
||||
return fputil::generic::sub<BFloat16>(*this, other);
|
||||
}
|
||||
|
||||
LIBC_INLINE BFloat16 operator*(BFloat16 other) const {
|
||||
return fputil::generic::mul<bfloat16>(*this, other);
|
||||
}
|
||||
|
||||
LIBC_INLINE BFloat16 operator/(BFloat16 other) const {
|
||||
return fputil::generic::div<bfloat16>(*this, other);
|
||||
}
|
||||
}; // struct BFloat16
|
||||
|
||||
} // namespace fputil
|
||||
|
||||
@@ -27,47 +27,47 @@ LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<OutType> &&
|
||||
OutType>
|
||||
cast(InType x) {
|
||||
// Casting to the same type is a no-op.
|
||||
if constexpr (cpp::is_same_v<InType, OutType>)
|
||||
if constexpr (cpp::is_same_v<InType, OutType>) {
|
||||
return x;
|
||||
|
||||
// bfloat16 is always defined (for now)
|
||||
if constexpr (cpp::is_same_v<OutType, bfloat16> ||
|
||||
cpp::is_same_v<InType, bfloat16>
|
||||
} else {
|
||||
if constexpr (cpp::is_same_v<OutType, bfloat16> ||
|
||||
cpp::is_same_v<InType, bfloat16>
|
||||
#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
|
||||
|| cpp::is_same_v<OutType, float16> ||
|
||||
cpp::is_same_v<InType, float16>
|
||||
|| cpp::is_same_v<OutType, float16> ||
|
||||
cpp::is_same_v<InType, float16>
|
||||
#endif
|
||||
) {
|
||||
using InFPBits = FPBits<InType>;
|
||||
using InStorageType = typename InFPBits::StorageType;
|
||||
using OutFPBits = FPBits<OutType>;
|
||||
using OutStorageType = typename OutFPBits::StorageType;
|
||||
) {
|
||||
using InFPBits = FPBits<InType>;
|
||||
using InStorageType = typename InFPBits::StorageType;
|
||||
using OutFPBits = FPBits<OutType>;
|
||||
using OutStorageType = typename OutFPBits::StorageType;
|
||||
|
||||
InFPBits x_bits(x);
|
||||
InFPBits x_bits(x);
|
||||
|
||||
if (x_bits.is_nan()) {
|
||||
if (x_bits.is_signaling_nan()) {
|
||||
raise_except_if_required(FE_INVALID);
|
||||
return OutFPBits::quiet_nan().get_val();
|
||||
if (x_bits.is_nan()) {
|
||||
if (x_bits.is_signaling_nan()) {
|
||||
raise_except_if_required(FE_INVALID);
|
||||
return OutFPBits::quiet_nan().get_val();
|
||||
}
|
||||
|
||||
InStorageType x_mant = x_bits.get_mantissa();
|
||||
if (InFPBits::FRACTION_LEN > OutFPBits::FRACTION_LEN)
|
||||
x_mant >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
|
||||
return OutFPBits::quiet_nan(x_bits.sign(),
|
||||
static_cast<OutStorageType>(x_mant))
|
||||
.get_val();
|
||||
}
|
||||
|
||||
InStorageType x_mant = x_bits.get_mantissa();
|
||||
if (InFPBits::FRACTION_LEN > OutFPBits::FRACTION_LEN)
|
||||
x_mant >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
|
||||
return OutFPBits::quiet_nan(x_bits.sign(),
|
||||
static_cast<OutStorageType>(x_mant))
|
||||
.get_val();
|
||||
if (x_bits.is_inf())
|
||||
return OutFPBits::inf(x_bits.sign()).get_val();
|
||||
|
||||
constexpr size_t MAX_FRACTION_LEN =
|
||||
cpp::max(OutFPBits::FRACTION_LEN, InFPBits::FRACTION_LEN);
|
||||
DyadicFloat<cpp::bit_ceil(MAX_FRACTION_LEN)> xd(x);
|
||||
return xd.template as<OutType, /*ShouldSignalExceptions=*/true>();
|
||||
} else {
|
||||
return static_cast<OutType>(x);
|
||||
}
|
||||
|
||||
if (x_bits.is_inf())
|
||||
return OutFPBits::inf(x_bits.sign()).get_val();
|
||||
|
||||
constexpr size_t MAX_FRACTION_LEN =
|
||||
cpp::max(OutFPBits::FRACTION_LEN, InFPBits::FRACTION_LEN);
|
||||
DyadicFloat<cpp::bit_ceil(MAX_FRACTION_LEN)> xd(x);
|
||||
return xd.template as<OutType, /*ShouldSignalExceptions=*/true>();
|
||||
} else {
|
||||
return static_cast<OutType>(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -576,7 +576,7 @@ LIBC_INLINE constexpr DyadicFloat<Bits> quick_mul(const DyadicFloat<Bits> &a,
|
||||
// Check the leading bit directly, should be faster than using clz in
|
||||
// normalize().
|
||||
if (result.mantissa.val[DyadicFloat<Bits>::MantissaType::WORD_COUNT - 1] >>
|
||||
63 ==
|
||||
(DyadicFloat<Bits>::MantissaType::WORD_SIZE - 1) ==
|
||||
0)
|
||||
result.shift_left(1);
|
||||
} else {
|
||||
|
||||
@@ -68,6 +68,7 @@ add_header_library(
|
||||
libc.src.__support.FPUtil.rounding_mode
|
||||
libc.src.__support.macros.attributes
|
||||
libc.src.__support.macros.optimization
|
||||
libc.src.__support.macros.properties.types
|
||||
)
|
||||
|
||||
add_header_library(
|
||||
@@ -77,6 +78,7 @@ add_header_library(
|
||||
DEPENDS
|
||||
libc.hdr.errno_macros
|
||||
libc.hdr.fenv_macros
|
||||
libc.src.__support.CPP.algorithm
|
||||
libc.src.__support.CPP.bit
|
||||
libc.src.__support.CPP.type_traits
|
||||
libc.src.__support.FPUtil.basic_operations
|
||||
|
||||
@@ -104,13 +104,22 @@ add_or_sub(InType x, InType y) {
|
||||
}
|
||||
}
|
||||
|
||||
// volatile prevents Clang from converting tmp to OutType and then
|
||||
// immediately back to InType before negating it, resulting in double
|
||||
// rounding.
|
||||
volatile InType tmp = y;
|
||||
if constexpr (IsSub)
|
||||
tmp = -tmp;
|
||||
return cast<OutType>(tmp);
|
||||
if constexpr (cpp::is_same_v<InType, bfloat16> &&
|
||||
cpp::is_same_v<OutType, bfloat16>) {
|
||||
OutFPBits y_bits(y);
|
||||
if constexpr (IsSub)
|
||||
y_bits.set_sign(y_bits.sign().negate());
|
||||
return y_bits.get_val();
|
||||
} else {
|
||||
|
||||
// volatile prevents Clang from converting tmp to OutType and then
|
||||
// immediately back to InType before negating it, resulting in double
|
||||
// rounding.
|
||||
volatile InType tmp = y;
|
||||
if constexpr (IsSub)
|
||||
tmp = -tmp;
|
||||
return cast<OutType>(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (y_bits.is_zero())
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "hdr/errno_macros.h"
|
||||
#include "hdr/fenv_macros.h"
|
||||
#include "src/__support/CPP/algorithm.h"
|
||||
#include "src/__support/CPP/bit.h"
|
||||
#include "src/__support/CPP/type_traits.h"
|
||||
#include "src/__support/FPUtil/BasicOperations.h"
|
||||
@@ -34,8 +35,9 @@ div(InType x, InType y) {
|
||||
using OutStorageType = typename OutFPBits::StorageType;
|
||||
using InFPBits = FPBits<InType>;
|
||||
using InStorageType = typename InFPBits::StorageType;
|
||||
using DyadicFloat =
|
||||
DyadicFloat<cpp::bit_ceil(static_cast<size_t>(InFPBits::SIG_LEN + 1))>;
|
||||
using DyadicFloat = DyadicFloat<cpp::max(
|
||||
static_cast<size_t>(16),
|
||||
cpp::bit_ceil(static_cast<size_t>(InFPBits::SIG_LEN + 1)))>;
|
||||
|
||||
InFPBits x_bits(x);
|
||||
InFPBits y_bits(y);
|
||||
|
||||
@@ -567,3 +567,75 @@ add_fp_unittest(
|
||||
LINK_LIBRARIES
|
||||
-lpthread
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_add_test
|
||||
NO_RUN_POSTBUILD
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_exhaustive_tests
|
||||
SRCS
|
||||
bfloat16_add_test.cpp
|
||||
COMPILE_OPTIONS
|
||||
${libc_opt_high_flag}
|
||||
DEPENDS
|
||||
.exhaustive_test
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
LINK_LIBRARIES
|
||||
-lpthread
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_div_test
|
||||
NO_RUN_POSTBUILD
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_exhaustive_tests
|
||||
SRCS
|
||||
bfloat16_div_test.cpp
|
||||
COMPILE_OPTIONS
|
||||
${libc_opt_high_flag}
|
||||
DEPENDS
|
||||
.exhaustive_test
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
LINK_LIBRARIES
|
||||
-lpthread
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_mul_test
|
||||
NO_RUN_POSTBUILD
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_exhaustive_tests
|
||||
SRCS
|
||||
bfloat16_mul_test.cpp
|
||||
COMPILE_OPTIONS
|
||||
${libc_opt_high_flag}
|
||||
DEPENDS
|
||||
.exhaustive_test
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
LINK_LIBRARIES
|
||||
-lpthread
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_sub_test
|
||||
NO_RUN_POSTBUILD
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_exhaustive_tests
|
||||
SRCS
|
||||
bfloat16_sub_test.cpp
|
||||
COMPILE_OPTIONS
|
||||
${libc_opt_high_flag}
|
||||
DEPENDS
|
||||
.exhaustive_test
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
LINK_LIBRARIES
|
||||
-lpthread
|
||||
)
|
||||
|
||||
65
libc/test/src/math/exhaustive/bfloat16_add_test.cpp
Normal file
65
libc/test/src/math/exhaustive/bfloat16_add_test.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
//===-- Exhaustive tests for bfloat16 addition ----------------------------===//
|
||||
//
|
||||
// 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 "exhaustive_test.h"
|
||||
#include "src/__support/FPUtil/FPBits.h"
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
#include "test/UnitTest/FPMatcher.h"
|
||||
#include "utils/MPFRWrapper/MPCommon.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
|
||||
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
|
||||
using LIBC_NAMESPACE::fputil::BFloat16;
|
||||
|
||||
static BFloat16 add_func(BFloat16 x, BFloat16 y) { return x + y; }
|
||||
|
||||
struct Bfloat16AddChecker : public virtual LIBC_NAMESPACE::testing::Test {
|
||||
using FloatType = BFloat16;
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<bfloat16>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
uint64_t check(uint16_t x_start, uint16_t x_stop, uint16_t y_start,
|
||||
uint16_t y_stop, mpfr::RoundingMode rounding) {
|
||||
mpfr::ForceRoundingMode r(rounding);
|
||||
if (!r.success)
|
||||
return true;
|
||||
uint16_t xbits = x_start;
|
||||
uint64_t failed = 0;
|
||||
do {
|
||||
BFloat16 x = FPBits(xbits).get_val();
|
||||
uint16_t ybits = xbits;
|
||||
do {
|
||||
BFloat16 y = FPBits(ybits).get_val();
|
||||
mpfr::BinaryInput<BFloat16> input{x, y};
|
||||
bool correct = TEST_MPFR_MATCH_ROUNDING_SILENTLY(
|
||||
mpfr::Operation::Add, input, add_func(x, y), 0.5, rounding);
|
||||
failed += (!correct);
|
||||
} while (ybits++ < y_stop);
|
||||
} while (xbits++ < x_stop);
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
|
||||
using LlvmLibcBfloat16ExhaustiveAddTest =
|
||||
LlvmLibcExhaustiveMathTest<Bfloat16AddChecker, 1 << 2>;
|
||||
|
||||
// range: [0, inf]
|
||||
static constexpr uint16_t POS_START = 0x0000U;
|
||||
static constexpr uint16_t POS_STOP = 0x7f80U;
|
||||
|
||||
// range: [-0, -inf]
|
||||
static constexpr uint16_t NEG_START = 0x8000U;
|
||||
static constexpr uint16_t NEG_STOP = 0xff80U;
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveAddTest, PositiveRange) {
|
||||
test_full_range_all_roundings(POS_START, POS_STOP, POS_START, POS_STOP);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveAddTest, NegativeRange) {
|
||||
test_full_range_all_roundings(NEG_START, NEG_STOP, NEG_START, NEG_STOP);
|
||||
}
|
||||
65
libc/test/src/math/exhaustive/bfloat16_div_test.cpp
Normal file
65
libc/test/src/math/exhaustive/bfloat16_div_test.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
//===-- Exhaustive tests for bfloat16 division ----------------------------===//
|
||||
//
|
||||
// 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 "exhaustive_test.h"
|
||||
#include "src/__support/FPUtil/FPBits.h"
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
#include "test/UnitTest/FPMatcher.h"
|
||||
#include "utils/MPFRWrapper/MPCommon.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
|
||||
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
|
||||
using LIBC_NAMESPACE::fputil::BFloat16;
|
||||
|
||||
static BFloat16 div_func(BFloat16 x, BFloat16 y) { return x / y; }
|
||||
|
||||
struct Bfloat16DivChecker : public virtual LIBC_NAMESPACE::testing::Test {
|
||||
using FloatType = BFloat16;
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<bfloat16>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
uint64_t check(uint16_t x_start, uint16_t x_stop, uint16_t y_start,
|
||||
uint16_t y_stop, mpfr::RoundingMode rounding) {
|
||||
mpfr::ForceRoundingMode r(rounding);
|
||||
if (!r.success)
|
||||
return true;
|
||||
uint16_t xbits = x_start;
|
||||
uint64_t failed = 0;
|
||||
do {
|
||||
BFloat16 x = FPBits(xbits).get_val();
|
||||
uint16_t ybits = xbits;
|
||||
do {
|
||||
BFloat16 y = FPBits(ybits).get_val();
|
||||
mpfr::BinaryInput<BFloat16> input{x, y};
|
||||
bool correct = TEST_MPFR_MATCH_ROUNDING_SILENTLY(
|
||||
mpfr::Operation::Div, input, div_func(x, y), 0.5, rounding);
|
||||
failed += (!correct);
|
||||
} while (ybits++ < y_stop);
|
||||
} while (xbits++ < x_stop);
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
|
||||
using LlvmLibcBfloat16ExhaustiveDivTest =
|
||||
LlvmLibcExhaustiveMathTest<Bfloat16DivChecker, 1 << 2>;
|
||||
|
||||
// range: [0, inf]
|
||||
static constexpr uint16_t POS_START = 0x0000U;
|
||||
static constexpr uint16_t POS_STOP = 0x7f80U;
|
||||
|
||||
// range: [-0, -inf]
|
||||
static constexpr uint16_t NEG_START = 0x8000U;
|
||||
static constexpr uint16_t NEG_STOP = 0xff80U;
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveDivTest, PositiveRange) {
|
||||
test_full_range_all_roundings(POS_START, POS_STOP, POS_START, POS_STOP);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveDivTest, NegativeRange) {
|
||||
test_full_range_all_roundings(NEG_START, NEG_STOP, NEG_START, NEG_STOP);
|
||||
}
|
||||
65
libc/test/src/math/exhaustive/bfloat16_mul_test.cpp
Normal file
65
libc/test/src/math/exhaustive/bfloat16_mul_test.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
//===-- Exhaustive tests for bfloat16 multiplication ----------------------===//
|
||||
//
|
||||
// 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 "exhaustive_test.h"
|
||||
#include "src/__support/FPUtil/FPBits.h"
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
#include "test/UnitTest/FPMatcher.h"
|
||||
#include "utils/MPFRWrapper/MPCommon.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
|
||||
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
|
||||
using LIBC_NAMESPACE::fputil::BFloat16;
|
||||
|
||||
static BFloat16 mul_func(BFloat16 x, BFloat16 y) { return x * y; }
|
||||
|
||||
struct Bfloat16MulChecker : public virtual LIBC_NAMESPACE::testing::Test {
|
||||
using FloatType = BFloat16;
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<bfloat16>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
uint64_t check(uint16_t x_start, uint16_t x_stop, uint16_t y_start,
|
||||
uint16_t y_stop, mpfr::RoundingMode rounding) {
|
||||
mpfr::ForceRoundingMode r(rounding);
|
||||
if (!r.success)
|
||||
return true;
|
||||
uint16_t xbits = x_start;
|
||||
uint64_t failed = 0;
|
||||
do {
|
||||
BFloat16 x = FPBits(xbits).get_val();
|
||||
uint16_t ybits = xbits;
|
||||
do {
|
||||
BFloat16 y = FPBits(ybits).get_val();
|
||||
mpfr::BinaryInput<BFloat16> input{x, y};
|
||||
bool correct = TEST_MPFR_MATCH_ROUNDING_SILENTLY(
|
||||
mpfr::Operation::Mul, input, mul_func(x, y), 0.5, rounding);
|
||||
failed += (!correct);
|
||||
} while (ybits++ < y_stop);
|
||||
} while (xbits++ < x_stop);
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
|
||||
using LlvmLibcBfloat16ExhaustiveMulTest =
|
||||
LlvmLibcExhaustiveMathTest<Bfloat16MulChecker, 1 << 2>;
|
||||
|
||||
// range: [0, inf]
|
||||
static constexpr uint16_t POS_START = 0x0000U;
|
||||
static constexpr uint16_t POS_STOP = 0x7f80U;
|
||||
|
||||
// range: [-0, -inf]
|
||||
static constexpr uint16_t NEG_START = 0x8000U;
|
||||
static constexpr uint16_t NEG_STOP = 0xff80U;
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveMulTest, PositiveRange) {
|
||||
test_full_range_all_roundings(POS_START, POS_STOP, POS_START, POS_STOP);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveMulTest, NegativeRange) {
|
||||
test_full_range_all_roundings(NEG_START, NEG_STOP, NEG_START, NEG_STOP);
|
||||
}
|
||||
65
libc/test/src/math/exhaustive/bfloat16_sub_test.cpp
Normal file
65
libc/test/src/math/exhaustive/bfloat16_sub_test.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
//===-- Exhaustive tests for bfloat16 subtraction -------------------------===//
|
||||
//
|
||||
// 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 "exhaustive_test.h"
|
||||
#include "src/__support/FPUtil/FPBits.h"
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
#include "test/UnitTest/FPMatcher.h"
|
||||
#include "utils/MPFRWrapper/MPCommon.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
|
||||
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
|
||||
using LIBC_NAMESPACE::fputil::BFloat16;
|
||||
|
||||
static BFloat16 sub_func(BFloat16 x, BFloat16 y) { return x - y; }
|
||||
|
||||
struct Bfloat16SubChecker : public virtual LIBC_NAMESPACE::testing::Test {
|
||||
using FloatType = BFloat16;
|
||||
using FPBits = LIBC_NAMESPACE::fputil::FPBits<bfloat16>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
uint64_t check(uint16_t x_start, uint16_t x_stop, uint16_t y_start,
|
||||
uint16_t y_stop, mpfr::RoundingMode rounding) {
|
||||
mpfr::ForceRoundingMode r(rounding);
|
||||
if (!r.success)
|
||||
return true;
|
||||
uint16_t xbits = x_start;
|
||||
uint64_t failed = 0;
|
||||
do {
|
||||
BFloat16 x = FPBits(xbits).get_val();
|
||||
uint16_t ybits = xbits;
|
||||
do {
|
||||
BFloat16 y = FPBits(ybits).get_val();
|
||||
mpfr::BinaryInput<BFloat16> input{x, y};
|
||||
bool correct = TEST_MPFR_MATCH_ROUNDING_SILENTLY(
|
||||
mpfr::Operation::Sub, input, sub_func(x, y), 0.5, rounding);
|
||||
failed += (!correct);
|
||||
} while (ybits++ < y_stop);
|
||||
} while (xbits++ < x_stop);
|
||||
return failed;
|
||||
}
|
||||
};
|
||||
|
||||
using LlvmLibcBfloat16ExhaustiveSubTest =
|
||||
LlvmLibcExhaustiveMathTest<Bfloat16SubChecker, 1 << 2>;
|
||||
|
||||
// range: [0, inf]
|
||||
static constexpr uint16_t POS_START = 0x0000U;
|
||||
static constexpr uint16_t POS_STOP = 0x7f80U;
|
||||
|
||||
// range: [-0, -inf]
|
||||
static constexpr uint16_t NEG_START = 0x8000U;
|
||||
static constexpr uint16_t NEG_STOP = 0xff80U;
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveSubTest, PositiveRange) {
|
||||
test_full_range_all_roundings(POS_START, POS_STOP, POS_START, POS_STOP);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcBfloat16ExhaustiveSubTest, NegativeRange) {
|
||||
test_full_range_all_roundings(NEG_START, NEG_STOP, NEG_START, NEG_STOP);
|
||||
}
|
||||
@@ -164,7 +164,7 @@ struct LlvmLibcExhaustiveMathTest
|
||||
|
||||
range_begin = current_value;
|
||||
if (stop >= Increment && stop - Increment >= current_value) {
|
||||
range_end = current_value + Increment;
|
||||
range_end = static_cast<StorageType>(current_value + Increment);
|
||||
} else {
|
||||
range_end = stop;
|
||||
}
|
||||
|
||||
@@ -5306,6 +5306,69 @@ add_fp_unittest(
|
||||
libc.src.math.ddivf128
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_add_test
|
||||
SUITE
|
||||
libc-math-smoke-tests
|
||||
SRCS
|
||||
bfloat16_add_test.cpp
|
||||
HDRS
|
||||
AddTest.h
|
||||
DEPENDS
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.src.__support.FPUtil.generic.add_sub
|
||||
libc.src.__support.macros.properties.os
|
||||
libc.src.__support.macros.properties.types
|
||||
libc.hdr.errno_macros
|
||||
libc.hdr.fenv_macros
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_div_test
|
||||
SUITE
|
||||
libc-math-smoke-tests
|
||||
SRCS
|
||||
bfloat16_div_test.cpp
|
||||
HDRS
|
||||
DivTest.h
|
||||
DEPENDS
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.hdr.errno_macros
|
||||
libc.hdr.fenv_macros
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_mul_test
|
||||
SUITE
|
||||
libc-math-smoke-tests
|
||||
SRCS
|
||||
bfloat16_mul_test.cpp
|
||||
HDRS
|
||||
MulTest.h
|
||||
DEPENDS
|
||||
libc.src.__support.FPUtil.basic_operations
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.hdr.errno_macros
|
||||
libc.hdr.fenv_macros
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
bfloat16_sub_test
|
||||
SUITE
|
||||
libc-math-smoke-tests
|
||||
SRCS
|
||||
bfloat16_sub_test.cpp
|
||||
HDRS
|
||||
SubTest.h
|
||||
DEPENDS
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.src.__support.FPUtil.generic.add_sub
|
||||
libc.src.__support.macros.properties.os
|
||||
libc.src.__support.macros.properties.types
|
||||
libc.hdr.errno_macros
|
||||
libc.hdr.fenv_macros
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
add_same_type_test
|
||||
SUITE
|
||||
|
||||
@@ -53,10 +53,12 @@ public:
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.zero, in.neg_zero));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, func(in.neg_zero, in.zero));
|
||||
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(OutType(1.0), func(1.0, 1.0));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(OutType(15.0), func(3.0, 5.0));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-13), func(0x1.0p+1, 0x1.0p-14));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-10), func(0x1.0p+2, 0x1.0p-12));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(InType(1.0), func(InType(1.0), InType(1.0)));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(InType(15.0), func(InType(3.0), InType(5.0)));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-13),
|
||||
func(InType(0x1.0p+1), InType(0x1.0p-14)));
|
||||
EXPECT_FP_EQ_ALL_ROUNDING(OutType(0x1.0p-10),
|
||||
func(InType(0x1.0p+2), InType(0x1.0p-12)));
|
||||
}
|
||||
|
||||
void test_invalid_operations(MulFunc func) {
|
||||
|
||||
15
libc/test/src/math/smoke/bfloat16_add_test.cpp
Normal file
15
libc/test/src/math/smoke/bfloat16_add_test.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
//===-- Unittests for bfloat16 addition -----------------------------------===//
|
||||
//
|
||||
// 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 "AddTest.h"
|
||||
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
|
||||
static bfloat16 add_func(bfloat16 x, bfloat16 y) { return x + y; }
|
||||
|
||||
LIST_ADD_TESTS(bfloat16, bfloat16, add_func)
|
||||
15
libc/test/src/math/smoke/bfloat16_div_test.cpp
Normal file
15
libc/test/src/math/smoke/bfloat16_div_test.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
//===-- Unittests for bfloat16 division -----------------------------------===//
|
||||
//
|
||||
// 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 "DivTest.h"
|
||||
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
|
||||
static bfloat16 div_func(bfloat16 x, bfloat16 y) { return x / y; }
|
||||
|
||||
LIST_DIV_TESTS(bfloat16, bfloat16, div_func)
|
||||
15
libc/test/src/math/smoke/bfloat16_mul_test.cpp
Normal file
15
libc/test/src/math/smoke/bfloat16_mul_test.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
//===-- Unittests for bfloat16 multiplication -----------------------------===//
|
||||
//
|
||||
// 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 "MulTest.h"
|
||||
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
|
||||
static bfloat16 mul_func(bfloat16 x, bfloat16 y) { return x * y; }
|
||||
|
||||
LIST_MUL_TESTS(bfloat16, bfloat16, mul_func)
|
||||
15
libc/test/src/math/smoke/bfloat16_sub_test.cpp
Normal file
15
libc/test/src/math/smoke/bfloat16_sub_test.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
//===-- Unittests for bfloat16 subtraction --------------------------------===//
|
||||
//
|
||||
// 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 "SubTest.h"
|
||||
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
|
||||
static bfloat16 sub_func(bfloat16 x, bfloat16 y) { return x - y; }
|
||||
|
||||
LIST_SUB_TESTS(bfloat16, bfloat16, sub_func)
|
||||
@@ -43,6 +43,7 @@ if(LIBC_TESTS_CAN_USE_MPFR)
|
||||
libc.hdr.stdint_proxy
|
||||
libc.src.__support.CPP.array
|
||||
libc.src.__support.CPP.stringstream
|
||||
libc.src.__support.FPUtil.bfloat16
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
libc.src.__support.FPUtil.fpbits_str
|
||||
LibcTest.unit
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "src/__support/CPP/array.h"
|
||||
#include "src/__support/CPP/stringstream.h"
|
||||
#include "src/__support/FPUtil/bfloat16.h"
|
||||
#include "src/__support/FPUtil/fpbits_str.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/macros/properties/types.h"
|
||||
@@ -408,6 +409,8 @@ template void explain_binary_operation_one_output_error(
|
||||
template void explain_binary_operation_one_output_error(
|
||||
Operation, const BinaryInput<float128> &, float128, double, RoundingMode);
|
||||
#endif
|
||||
template void explain_binary_operation_one_output_error(
|
||||
Operation, const BinaryInput<bfloat16> &, bfloat16, double, RoundingMode);
|
||||
|
||||
template <typename InputType, typename OutputType>
|
||||
void explain_ternary_operation_one_output_error(
|
||||
@@ -641,7 +644,10 @@ template bool compare_binary_operation_one_output(Operation,
|
||||
float128, double,
|
||||
RoundingMode);
|
||||
#endif
|
||||
|
||||
template bool compare_binary_operation_one_output(Operation,
|
||||
const BinaryInput<bfloat16> &,
|
||||
bfloat16, double,
|
||||
RoundingMode);
|
||||
template <typename InputType, typename OutputType>
|
||||
bool compare_ternary_operation_one_output(Operation op,
|
||||
const TernaryInput<InputType> &input,
|
||||
|
||||
Reference in New Issue
Block a user