[libc-commits] [libc] [libc][stdfix] Add abs functions for signed fixed point types. (PR #81823)
via libc-commits
libc-commits at lists.llvm.org
Wed Feb 14 21:16:17 PST 2024
https://github.com/lntue created https://github.com/llvm/llvm-project/pull/81823
This depends on https://github.com/llvm/llvm-project/pull/81819.
>From 0df0e4f4b1af6bd045e3d2ac8462c73a1c531e74 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 15 Feb 2024 04:35:04 +0000
Subject: [PATCH 1/2] [libc][stdfix] Add support for fixed point types in the
testing infrastructure.
---
libc/src/__support/fixed_point/CMakeLists.txt | 1 +
libc/src/__support/fixed_point/fx_rep.h | 103 ++++++++++++-
libc/test/UnitTest/CMakeLists.txt | 1 +
libc/test/UnitTest/LibcTest.cpp | 136 +++++++-----------
libc/test/UnitTest/LibcTest.h | 4 +-
5 files changed, 161 insertions(+), 84 deletions(-)
diff --git a/libc/src/__support/fixed_point/CMakeLists.txt b/libc/src/__support/fixed_point/CMakeLists.txt
index 644cbff37aaade..27382f5a7bb80e 100644
--- a/libc/src/__support/fixed_point/CMakeLists.txt
+++ b/libc/src/__support/fixed_point/CMakeLists.txt
@@ -5,4 +5,5 @@ add_header_library(
DEPENDS
libc.include.llvm-libc-macros.stdfix_macros
libc.src.__support.macros.attributes
+ libc.src.__support.CPP.type_traits
)
diff --git a/libc/src/__support/fixed_point/fx_rep.h b/libc/src/__support/fixed_point/fx_rep.h
index 88cba3c95c6656..fcd7554c4d8550 100644
--- a/libc/src/__support/fixed_point/fx_rep.h
+++ b/libc/src/__support/fixed_point/fx_rep.h
@@ -10,144 +10,245 @@
#define LLVM_LIBC_SRC___SUPPORT_FIXEDPOINT_FXREP_H
#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR
+#include <stdint.h>
+
#ifdef LIBC_COMPILER_HAS_FIXED_POINT
namespace LIBC_NAMESPACE::fixed_point {
+namespace internal {
+
+template <int Bits> struct Storage {
+ static_assert(Bits > 0 && Bits <= 64, "Bits has to be between 1 and 64.");
+ using Type = typename cpp::conditional_t<
+ (Bits <= 8), uint8_t,
+ typename cpp::conditional_t<
+ (Bits <= 16 && Bits > 8), uint16_t,
+ typename cpp::conditional_t<(Bits <= 32 && Bits > 16), uint32_t,
+ uint64_t>>>;
+};
+
+} // namespace internal
+
template <typename T> struct FXRep;
template <> struct FXRep<short fract> {
using Type = short _Fract;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = 0;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SFRACT_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return SFRACT_MIN; }
LIBC_INLINE static constexpr Type MAX() { return SFRACT_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0HR; }
LIBC_INLINE static constexpr Type EPS() { return SFRACT_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_signed_t<StorageType>;
};
template <> struct FXRep<unsigned short fract> {
using Type = unsigned short fract;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 0;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = 0;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = USFRACT_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return USFRACT_MIN; }
LIBC_INLINE static constexpr Type MAX() { return USFRACT_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0UHR; }
LIBC_INLINE static constexpr Type EPS() { return USFRACT_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_unsigned_t<StorageType>;
};
template <> struct FXRep<fract> {
using Type = fract;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = 0;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = FRACT_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return FRACT_MIN; }
LIBC_INLINE static constexpr Type MAX() { return FRACT_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0R; }
LIBC_INLINE static constexpr Type EPS() { return FRACT_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_signed_t<StorageType>;
};
template <> struct FXRep<unsigned fract> {
using Type = unsigned fract;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 0;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = 0;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = UFRACT_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return UFRACT_MIN; }
LIBC_INLINE static constexpr Type MAX() { return UFRACT_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0UR; }
LIBC_INLINE static constexpr Type EPS() { return UFRACT_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_unsigned_t<StorageType>;
};
template <> struct FXRep<long fract> {
using Type = long fract;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = 0;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = LFRACT_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return LFRACT_MIN; }
LIBC_INLINE static constexpr Type MAX() { return LFRACT_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0LR; }
LIBC_INLINE static constexpr Type EPS() { return LFRACT_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_signed_t<StorageType>;
};
template <> struct FXRep<unsigned long fract> {
using Type = unsigned long fract;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 0;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = 0;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = ULFRACT_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return ULFRACT_MIN; }
LIBC_INLINE static constexpr Type MAX() { return ULFRACT_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0ULR; }
LIBC_INLINE static constexpr Type EPS() { return ULFRACT_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_unsigned_t<StorageType>;
};
template <> struct FXRep<short accum> {
using Type = short accum;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = SACCUM_IBIT;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SACCUM_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return SACCUM_MIN; }
LIBC_INLINE static constexpr Type MAX() { return SACCUM_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0HK; }
LIBC_INLINE static constexpr Type EPS() { return SACCUM_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_signed_t<StorageType>;
};
template <> struct FXRep<unsigned short accum> {
using Type = unsigned short accum;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 0;
- LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = UACCUM_IBIT;
+ LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = USACCUM_IBIT;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = USACCUM_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return USACCUM_MIN; }
LIBC_INLINE static constexpr Type MAX() { return USACCUM_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0UHK; }
LIBC_INLINE static constexpr Type EPS() { return USACCUM_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_unsigned_t<StorageType>;
};
template <> struct FXRep<accum> {
using Type = accum;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = ACCUM_IBIT;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = ACCUM_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return ACCUM_MIN; }
LIBC_INLINE static constexpr Type MAX() { return ACCUM_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0K; }
LIBC_INLINE static constexpr Type EPS() { return ACCUM_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_signed_t<StorageType>;
};
template <> struct FXRep<unsigned accum> {
using Type = unsigned accum;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 0;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = UACCUM_IBIT;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = UACCUM_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return UACCUM_MIN; }
LIBC_INLINE static constexpr Type MAX() { return UACCUM_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0UK; }
LIBC_INLINE static constexpr Type EPS() { return UACCUM_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_unsigned_t<StorageType>;
};
template <> struct FXRep<long accum> {
using Type = long accum;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = LACCUM_IBIT;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = LACCUM_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return LACCUM_MIN; }
LIBC_INLINE static constexpr Type MAX() { return LACCUM_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0LK; }
LIBC_INLINE static constexpr Type EPS() { return LACCUM_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_signed_t<StorageType>;
};
template <> struct FXRep<unsigned long accum> {
using Type = unsigned long accum;
+
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 0;
LIBC_INLINE_VAR static constexpr int INTEGRAL_LEN = ULACCUM_IBIT;
LIBC_INLINE_VAR static constexpr int FRACTION_LEN = ULACCUM_FBIT;
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
+ SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+
LIBC_INLINE static constexpr Type MIN() { return ULACCUM_MIN; }
LIBC_INLINE static constexpr Type MAX() { return ULACCUM_MIN; }
LIBC_INLINE static constexpr Type ZERO() { return 0.0ULK; }
LIBC_INLINE static constexpr Type EPS() { return ULACCUM_EPSILON; }
+
+ using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
+ using CompType = cpp::make_unsigned_t<StorageType>;
};
template <> struct FXRep<short sat fract> : FXRep<short fract> {};
diff --git a/libc/test/UnitTest/CMakeLists.txt b/libc/test/UnitTest/CMakeLists.txt
index e3099e45154765..53ade3698c76e5 100644
--- a/libc/test/UnitTest/CMakeLists.txt
+++ b/libc/test/UnitTest/CMakeLists.txt
@@ -71,6 +71,7 @@ add_unittest_framework_library(
libc.src.__support.CPP.string
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
+ libc.src.__support.fixed_point.fx_rep
libc.src.__support.OSUtil.osutil
libc.src.__support.uint128
)
diff --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp
index 201b40a178dca0..7b0e4fca83683b 100644
--- a/libc/test/UnitTest/LibcTest.cpp
+++ b/libc/test/UnitTest/LibcTest.cpp
@@ -8,9 +8,11 @@
#include "LibcTest.h"
+#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/string.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/UInt128.h"
+#include "src/__support/fixed_point/fx_rep.h"
#include "test/UnitTest/TestLogger.h"
#if __STDC_HOSTED__
@@ -53,6 +55,17 @@ describeValue(ValType Value) {
return cpp::to_string(Value);
}
+#ifdef LIBC_COMPILER_HAS_FIXED_POINT
+template <typename T>
+cpp::enable_if_t<cpp::is_fixed_point_v<T>, cpp::string> describeValue(T Value) {
+ using FXRep = fixed_point::FXRep<T>;
+ using comp_t = typename FXRep::CompType;
+
+ return cpp::to_string(cpp::bit_cast<comp_t>(Value)) + " * 2^-" +
+ cpp::to_string(FXRep::FRACTION_LEN);
+}
+#endif // LIBC_COMPILER_HAS_FIXED_POINT
+
cpp::string_view describeValue(const cpp::string &Value) { return Value; }
cpp::string_view describeValue(cpp::string_view Value) { return Value; }
@@ -181,99 +194,58 @@ int Test::runTests(const char *TestFilter) {
namespace internal {
-template bool test<char>(RunContext *Ctx, TestCond Cond, char LHS, char RHS,
- const char *LHSStr, const char *RHSStr, Location Loc);
-
-template bool test<short>(RunContext *Ctx, TestCond Cond, short LHS, short RHS,
- const char *LHSStr, const char *RHSStr, Location Loc);
-
-template bool test<int>(RunContext *Ctx, TestCond Cond, int LHS, int RHS,
- const char *LHSStr, const char *RHSStr, Location Loc);
-
-template bool test<long>(RunContext *Ctx, TestCond Cond, long LHS, long RHS,
- const char *LHSStr, const char *RHSStr, Location Loc);
-
-template bool test<long long>(RunContext *Ctx, TestCond Cond, long long LHS,
- long long RHS, const char *LHSStr,
- const char *RHSStr, Location Loc);
-
-template bool test<unsigned char>(RunContext *Ctx, TestCond Cond,
- unsigned char LHS, unsigned char RHS,
- const char *LHSStr, const char *RHSStr,
- Location Loc);
-
-template bool test<unsigned short>(RunContext *Ctx, TestCond Cond,
- unsigned short LHS, unsigned short RHS,
- const char *LHSStr, const char *RHSStr,
- Location Loc);
-
-template bool test<unsigned int>(RunContext *Ctx, TestCond Cond,
- unsigned int LHS, unsigned int RHS,
- const char *LHSStr, const char *RHSStr,
- Location Loc);
+#define TEST_SPECIALIZATION(TYPE) \
+ template bool test<TYPE>(RunContext * Ctx, TestCond Cond, TYPE LHS, \
+ TYPE RHS, const char *LHSStr, const char *RHSStr, \
+ Location Loc)
-template bool test<unsigned long>(RunContext *Ctx, TestCond Cond,
- unsigned long LHS, unsigned long RHS,
- const char *LHSStr, const char *RHSStr,
- Location Loc);
+TEST_SPECIALIZATION(char);
+TEST_SPECIALIZATION(short);
+TEST_SPECIALIZATION(int);
+TEST_SPECIALIZATION(long);
+TEST_SPECIALIZATION(long long);
-template bool test<bool>(RunContext *Ctx, TestCond Cond, bool LHS, bool RHS,
- const char *LHSStr, const char *RHSStr, Location Loc);
+TEST_SPECIALIZATION(unsigned char);
+TEST_SPECIALIZATION(unsigned short);
+TEST_SPECIALIZATION(unsigned int);
+TEST_SPECIALIZATION(unsigned long);
+TEST_SPECIALIZATION(unsigned long long);
-template bool test<unsigned long long>(RunContext *Ctx, TestCond Cond,
- unsigned long long LHS,
- unsigned long long RHS,
- const char *LHSStr, const char *RHSStr,
- Location Loc);
+TEST_SPECIALIZATION(bool);
// We cannot just use a single UInt128 specialization as that resolves to only
// one type, UInt<128> or __uint128_t. We want both overloads as we want to
-// be able to unittest UInt<128> on platforms where UInt128 resolves to
-// UInt128.
#ifdef __SIZEOF_INT128__
// When builtin __uint128_t type is available, include its specialization
// also.
-template bool test<__uint128_t>(RunContext *Ctx, TestCond Cond, __uint128_t LHS,
- __uint128_t RHS, const char *LHSStr,
- const char *RHSStr, Location Loc);
+TEST_SPECIALIZATION(__uint128_t);
#endif
-template bool test<LIBC_NAMESPACE::cpp::Int<128>>(
- RunContext *Ctx, TestCond Cond, LIBC_NAMESPACE::cpp::Int<128> LHS,
- LIBC_NAMESPACE::cpp::Int<128> RHS, const char *LHSStr, const char *RHSStr,
- Location Loc);
-
-template bool test<LIBC_NAMESPACE::cpp::UInt<128>>(
- RunContext *Ctx, TestCond Cond, LIBC_NAMESPACE::cpp::UInt<128> LHS,
- LIBC_NAMESPACE::cpp::UInt<128> RHS, const char *LHSStr, const char *RHSStr,
- Location Loc);
-
-template bool test<LIBC_NAMESPACE::cpp::UInt<192>>(
- RunContext *Ctx, TestCond Cond, LIBC_NAMESPACE::cpp::UInt<192> LHS,
- LIBC_NAMESPACE::cpp::UInt<192> RHS, const char *LHSStr, const char *RHSStr,
- Location Loc);
-
-template bool test<LIBC_NAMESPACE::cpp::UInt<256>>(
- RunContext *Ctx, TestCond Cond, LIBC_NAMESPACE::cpp::UInt<256> LHS,
- LIBC_NAMESPACE::cpp::UInt<256> RHS, const char *LHSStr, const char *RHSStr,
- Location Loc);
-
-template bool test<LIBC_NAMESPACE::cpp::UInt<320>>(
- RunContext *Ctx, TestCond Cond, LIBC_NAMESPACE::cpp::UInt<320> LHS,
- LIBC_NAMESPACE::cpp::UInt<320> RHS, const char *LHSStr, const char *RHSStr,
- Location Loc);
-
-template bool test<LIBC_NAMESPACE::cpp::string_view>(
- RunContext *Ctx, TestCond Cond, LIBC_NAMESPACE::cpp::string_view LHS,
- LIBC_NAMESPACE::cpp::string_view RHS, const char *LHSStr,
- const char *RHSStr, Location Loc);
-
-template bool test<LIBC_NAMESPACE::cpp::string>(RunContext *Ctx, TestCond Cond,
- LIBC_NAMESPACE::cpp::string LHS,
- LIBC_NAMESPACE::cpp::string RHS,
- const char *LHSStr,
- const char *RHSStr,
- Location Loc);
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::Int<128>);
+
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::UInt<128>);
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::UInt<192>);
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::UInt<256>);
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::UInt<320>);
+
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string_view);
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string);
+
+#ifdef LIBC_COMPILER_HAS_FIXED_POINT
+TEST_SPECIALIZATION(short fract);
+TEST_SPECIALIZATION(fract);
+TEST_SPECIALIZATION(long fract);
+TEST_SPECIALIZATION(unsigned short fract);
+TEST_SPECIALIZATION(unsigned fract);
+TEST_SPECIALIZATION(unsigned long fract);
+
+TEST_SPECIALIZATION(short accum);
+TEST_SPECIALIZATION(accum);
+TEST_SPECIALIZATION(long accum);
+TEST_SPECIALIZATION(unsigned short accum);
+TEST_SPECIALIZATION(unsigned accum);
+TEST_SPECIALIZATION(unsigned long accum);
+#endif // LIBC_COMPILER_HAS_FIXED_POINT
} // namespace internal
diff --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h
index 047f18036b0ac2..00e34a4da85852 100644
--- a/libc/test/UnitTest/LibcTest.h
+++ b/libc/test/UnitTest/LibcTest.h
@@ -126,7 +126,9 @@ class Test {
// |Cond| on mismatched |LHS| and |RHS| types can potentially succeed because
// of type promotion.
template <typename ValType,
- cpp::enable_if_t<cpp::is_integral_v<ValType>, int> = 0>
+ cpp::enable_if_t<cpp::is_integral_v<ValType> ||
+ cpp::is_fixed_point_v<ValType>,
+ int> = 0>
bool test(TestCond Cond, ValType LHS, ValType RHS, const char *LHSStr,
const char *RHSStr, internal::Location Loc) {
return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, Loc);
>From faf903cd29b48cbaf76b7e6f530c2e5631e4d770 Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Thu, 15 Feb 2024 05:13:59 +0000
Subject: [PATCH 2/2] [libc][stdfix] Add abs functions for signed fixed point
types.
---
libc/config/linux/x86_64/entrypoints.txt | 12 ++++++
libc/docs/math/stdfix.rst | 2 +-
libc/spec/spec.td | 17 +++++++++
libc/spec/stdc_ext.td | 7 ++++
libc/src/CMakeLists.txt | 1 +
libc/src/__support/fixed_point/CMakeLists.txt | 11 ++++++
libc/src/__support/fixed_point/fx_bits.h | 37 +++++++++++++++++++
libc/src/stdfix/CMakeLists.txt | 18 +++++++++
libc/src/stdfix/abshk.cpp | 19 ++++++++++
libc/src/stdfix/abshk.h | 20 ++++++++++
libc/src/stdfix/abshr.cpp | 19 ++++++++++
libc/src/stdfix/abshr.h | 20 ++++++++++
libc/src/stdfix/absk.cpp | 17 +++++++++
libc/src/stdfix/absk.h | 20 ++++++++++
libc/src/stdfix/abslk.cpp | 19 ++++++++++
libc/src/stdfix/abslk.h | 20 ++++++++++
libc/src/stdfix/abslr.cpp | 19 ++++++++++
libc/src/stdfix/abslr.h | 20 ++++++++++
libc/src/stdfix/absr.cpp | 17 +++++++++
libc/src/stdfix/absr.h | 20 ++++++++++
libc/test/src/CMakeLists.txt | 1 +
libc/test/src/stdfix/AbsTest.h | 37 +++++++++++++++++++
libc/test/src/stdfix/CMakeLists.txt | 23 ++++++++++++
libc/test/src/stdfix/abshk_test.cpp | 13 +++++++
libc/test/src/stdfix/abshr_test.cpp | 13 +++++++
libc/test/src/stdfix/absk_test.cpp | 13 +++++++
libc/test/src/stdfix/abslk_test.cpp | 13 +++++++
libc/test/src/stdfix/abslr_test.cpp | 13 +++++++
libc/test/src/stdfix/absr_test.cpp | 13 +++++++
29 files changed, 473 insertions(+), 1 deletion(-)
create mode 100644 libc/src/__support/fixed_point/fx_bits.h
create mode 100644 libc/src/stdfix/CMakeLists.txt
create mode 100644 libc/src/stdfix/abshk.cpp
create mode 100644 libc/src/stdfix/abshk.h
create mode 100644 libc/src/stdfix/abshr.cpp
create mode 100644 libc/src/stdfix/abshr.h
create mode 100644 libc/src/stdfix/absk.cpp
create mode 100644 libc/src/stdfix/absk.h
create mode 100644 libc/src/stdfix/abslk.cpp
create mode 100644 libc/src/stdfix/abslk.h
create mode 100644 libc/src/stdfix/abslr.cpp
create mode 100644 libc/src/stdfix/abslr.h
create mode 100644 libc/src/stdfix/absr.cpp
create mode 100644 libc/src/stdfix/absr.h
create mode 100644 libc/test/src/stdfix/AbsTest.h
create mode 100644 libc/test/src/stdfix/CMakeLists.txt
create mode 100644 libc/test/src/stdfix/abshk_test.cpp
create mode 100644 libc/test/src/stdfix/abshr_test.cpp
create mode 100644 libc/test/src/stdfix/absk_test.cpp
create mode 100644 libc/test/src/stdfix/abslk_test.cpp
create mode 100644 libc/test/src/stdfix/abslr_test.cpp
create mode 100644 libc/test/src/stdfix/absr_test.cpp
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 33f6e97af0e183..69912d3b32f030 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -442,6 +442,18 @@ if(LIBC_COMPILER_HAS_FLOAT128)
)
endif()
+if(LIBC_COMPILER_HAS_FIXED_POINT)
+ list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # stdfix.h _Fract and _Accum entrypoints
+ libc.src.stdfix.abshk
+ libc.src.stdfix.abshr
+ libc.src.stdfix.absk
+ libc.src.stdfix.absr
+ libc.src.stdfix.abslk
+ libc.src.stdfix.abslr
+ )
+endif()
+
if(LLVM_LIBC_FULL_BUILD)
list(APPEND TARGET_LIBC_ENTRYPOINTS
# assert.h entrypoints
diff --git a/libc/docs/math/stdfix.rst b/libc/docs/math/stdfix.rst
index 85d721b358f5ec..d05e3fdeabf1c5 100644
--- a/libc/docs/math/stdfix.rst
+++ b/libc/docs/math/stdfix.rst
@@ -60,7 +60,7 @@ Fixed-point Arithmetics
| +----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| | unsigned (uhr) | signed (hr) | unsigned (ur) | signed (r) | unsigned (ulr) | signed (lr) | unsigned (uhk) | signed (hk) | unsigned (uk) | signed (k) | unsigned (ulk) | signed (lk) |
+===============+================+=============+===============+============+================+=============+================+=============+===============+============+================+=============+
-| abs | | | | | | | | | | | | |
+| abs | | |check| | | |check| | | |check| | | |check| | | |check| | | |check| |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| bits\* | | | | | | | | | | | | |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
diff --git a/libc/spec/spec.td b/libc/spec/spec.td
index aebf4955382862..8d761764c22277 100644
--- a/libc/spec/spec.td
+++ b/libc/spec/spec.td
@@ -55,6 +55,23 @@ def UnsignedShortType : NamedType<"unsigned short">;
// TODO: Add compatibility layer to use C23 type _Float128 if possible.
def Float128Type : NamedType<"float128">;
+// Fixed point types.
+// From ISO/IEC TR 18037:2008 standard:
+// https://standards.iso.org/ittf/PubliclyAvailableStandards/c051126_ISO_IEC_TR_18037_2008.zip
+def ShortFractType : NamedType<"short fract">;
+def FractType : NamedType<"fract">;
+def LongFractType : NamedType<"long fract">;
+def UnsignedShortFractType : NamedType<"unsigned short fract">;
+def UnsignedFractType : NamedType<"unsigned fract">;
+def UnsignedLongFractType : NamedType<"unsigned long fract">;
+
+def ShortAccumType : NamedType<"short accum">;
+def AccumType : NamedType<"accum">;
+def LongAccumType : NamedType<"long accum">;
+def UnsignedShortAccumType : NamedType<"unsigned short accum">;
+def UnsignedAccumType : NamedType<"unsigned accum">;
+def UnsignedLongAccumType : NamedType<"unsigned long accum">;
+
// Common types
def VoidPtr : PtrType<VoidType>;
def VoidPtrPtr : PtrType<VoidPtr>;
diff --git a/libc/spec/stdc_ext.td b/libc/spec/stdc_ext.td
index 4a5b74f7bdc364..8af9624e532733 100644
--- a/libc/spec/stdc_ext.td
+++ b/libc/spec/stdc_ext.td
@@ -7,6 +7,13 @@ def StdcExt : StandardSpec<"stdc_ext"> {
[], // types
[], // enums
[ // functions
+ GuardedFunctionSpec<"abshr", RetValSpec<ShortFractType>, [ArgSpec<ShortFractType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+ GuardedFunctionSpec<"absr", RetValSpec<FractType>, [ArgSpec<FractType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+ GuardedFunctionSpec<"abslr", RetValSpec<LongFractType>, [ArgSpec<LongFractType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+
+ GuardedFunctionSpec<"abshk", RetValSpec<ShortAccumType>, [ArgSpec<ShortAccumType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+ GuardedFunctionSpec<"absk", RetValSpec<AccumType>, [ArgSpec<AccumType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+ GuardedFunctionSpec<"abslk", RetValSpec<LongAccumType>, [ArgSpec<LongAccumType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
]
>;
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 5211db7bc1f993..09b16be1e2d42e 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -6,6 +6,7 @@ add_subdirectory(fenv)
add_subdirectory(inttypes)
add_subdirectory(math)
add_subdirectory(stdbit)
+add_subdirectory(stdfix)
add_subdirectory(stdio)
add_subdirectory(stdlib)
add_subdirectory(string)
diff --git a/libc/src/__support/fixed_point/CMakeLists.txt b/libc/src/__support/fixed_point/CMakeLists.txt
index 27382f5a7bb80e..4dac9b33325adb 100644
--- a/libc/src/__support/fixed_point/CMakeLists.txt
+++ b/libc/src/__support/fixed_point/CMakeLists.txt
@@ -7,3 +7,14 @@ add_header_library(
libc.src.__support.macros.attributes
libc.src.__support.CPP.type_traits
)
+
+add_header_library(
+ fx_bits
+ HDRS
+ fx_bits.h
+ DEPENDS
+ .fx_rep
+ libc.include.llvm-libc-macros.stdfix_macros
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.optimization
+)
diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
new file mode 100644
index 00000000000000..ad3a6fc97c0a1f
--- /dev/null
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -0,0 +1,37 @@
+//===-- Utility class to manipulate fixed point numbers. --*- 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_FIXEDPOINT_FXBITS_H
+#define LLVM_LIBC_SRC___SUPPORT_FIXEDPOINT_FXBITS_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/attributes.h" // LIBC_INLINE
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
+
+#include "fx_rep.h"
+
+#ifdef LIBC_COMPILER_HAS_FIXED_POINT
+
+namespace LIBC_NAMESPACE::fixed_point {
+
+template <typename T> LIBC_INLINE constexpr T abs(T x) {
+ using FXRep = FXRep<T>;
+ if constexpr (FXRep::SIGN_LEN == 0)
+ return x;
+ else {
+ if (LIBC_UNLIKELY(x == FXRep::MIN()))
+ return FXRep::MAX();
+ return (x < FXRep::ZERO() ? -x : x);
+ }
+}
+
+} // namespace LIBC_NAMESPACE::fixed_point
+
+#endif // LIBC_COMPILER_HAS_FIXED_POINT
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FIXEDPOINT_FXBITS_H
diff --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt
new file mode 100644
index 00000000000000..1eaf64bb82a21b
--- /dev/null
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -0,0 +1,18 @@
+if(NOT LIBC_COMPILER_HAS_FIXED_POINT)
+ return()
+endif()
+
+foreach(suffix IN ITEMS hr r lr hk k lk)
+ add_entrypoint_object(
+ abs${suffix}
+ HDRS
+ abs${suffix}.h
+ SRCS
+ abs${suffix}.cpp
+ COMPILE_OPTIONS
+ -O3
+ -ffixed-point
+ DEPENDS
+ libc.src.__support.fixed_point.fx_bits
+ )
+endforeach()
diff --git a/libc/src/stdfix/abshk.cpp b/libc/src/stdfix/abshk.cpp
new file mode 100644
index 00000000000000..d76a5e64e61079
--- /dev/null
+++ b/libc/src/stdfix/abshk.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of abshk 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 "abshk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(short accum, abshk, (short accum x)) {
+ return fixed_point::abs(x);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdfix/abshk.h b/libc/src/stdfix/abshk.h
new file mode 100644
index 00000000000000..13c9300caab883
--- /dev/null
+++ b/libc/src/stdfix/abshk.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for abshk -------------------------*- 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_STDFIX_ABSHK_H
+#define LLVM_LIBC_SRC_STDFIX_ABSHK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+
+namespace LIBC_NAMESPACE {
+
+short accum abshk(short accum x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDFIX_ABSHK_H
diff --git a/libc/src/stdfix/abshr.cpp b/libc/src/stdfix/abshr.cpp
new file mode 100644
index 00000000000000..db887046b662cd
--- /dev/null
+++ b/libc/src/stdfix/abshr.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of abshr 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 "abshr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(short fract, abshr, (short fract x)) {
+ return fixed_point::abs(x);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdfix/abshr.h b/libc/src/stdfix/abshr.h
new file mode 100644
index 00000000000000..5acd0cfc4a60db
--- /dev/null
+++ b/libc/src/stdfix/abshr.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for abshr -------------------------*- 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_STDFIX_ABSHR_H
+#define LLVM_LIBC_SRC_STDFIX_ABSHR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+
+namespace LIBC_NAMESPACE {
+
+short fract abshr(short fract x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDFIX_ABSHR_H
diff --git a/libc/src/stdfix/absk.cpp b/libc/src/stdfix/absk.cpp
new file mode 100644
index 00000000000000..ca231d95a0ab71
--- /dev/null
+++ b/libc/src/stdfix/absk.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of absk 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 "absk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(accum, absk, (accum x)) { return fixed_point::abs(x); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdfix/absk.h b/libc/src/stdfix/absk.h
new file mode 100644
index 00000000000000..73dfcac0ac8e7f
--- /dev/null
+++ b/libc/src/stdfix/absk.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for absk --------------------------*- 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_STDFIX_ABSK_H
+#define LLVM_LIBC_SRC_STDFIX_ABSK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+
+namespace LIBC_NAMESPACE {
+
+accum absk(accum x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDFIX_ABSK_H
diff --git a/libc/src/stdfix/abslk.cpp b/libc/src/stdfix/abslk.cpp
new file mode 100644
index 00000000000000..5e085198ce428e
--- /dev/null
+++ b/libc/src/stdfix/abslk.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of abslk 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 "abslk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long accum, abslk, (long accum x)) {
+ return fixed_point::abs(x);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdfix/abslk.h b/libc/src/stdfix/abslk.h
new file mode 100644
index 00000000000000..7de116fa227932
--- /dev/null
+++ b/libc/src/stdfix/abslk.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for abslk -------------------------*- 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_STDFIX_ABSLK_H
+#define LLVM_LIBC_SRC_STDFIX_ABSLK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+
+namespace LIBC_NAMESPACE {
+
+long accum abslk(long accum x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDFIX_ABSLK_H
diff --git a/libc/src/stdfix/abslr.cpp b/libc/src/stdfix/abslr.cpp
new file mode 100644
index 00000000000000..0f8969510a5055
--- /dev/null
+++ b/libc/src/stdfix/abslr.cpp
@@ -0,0 +1,19 @@
+//===-- Implementation of abslr 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 "abslr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(long fract, abslr, (long fract x)) {
+ return fixed_point::abs(x);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdfix/abslr.h b/libc/src/stdfix/abslr.h
new file mode 100644
index 00000000000000..bf5b585bbbb669
--- /dev/null
+++ b/libc/src/stdfix/abslr.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for abslr -------------------------*- 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_STDFIX_ABSLR_H
+#define LLVM_LIBC_SRC_STDFIX_ABSLR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+
+namespace LIBC_NAMESPACE {
+
+long fract abslr(long fract x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDFIX_ABSLR_H
diff --git a/libc/src/stdfix/absr.cpp b/libc/src/stdfix/absr.cpp
new file mode 100644
index 00000000000000..dbbecb4947da91
--- /dev/null
+++ b/libc/src/stdfix/absr.cpp
@@ -0,0 +1,17 @@
+//===-- Implementation of absr 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 "absr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(fract, absr, (fract x)) { return fixed_point::abs(x); }
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdfix/absr.h b/libc/src/stdfix/absr.h
new file mode 100644
index 00000000000000..b5ead7ce14e2a0
--- /dev/null
+++ b/libc/src/stdfix/absr.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for absr --------------------------*- 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_STDFIX_ABSR_H
+#define LLVM_LIBC_SRC_STDFIX_ABSR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+
+namespace LIBC_NAMESPACE {
+
+fract absr(fract x);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDFIX_ABSR_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 6c99c6735befff..9ad868551f071c 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -44,6 +44,7 @@ add_subdirectory(inttypes)
add_subdirectory(math)
add_subdirectory(search)
add_subdirectory(stdbit)
+add_subdirectory(stdfix)
add_subdirectory(stdio)
add_subdirectory(stdlib)
add_subdirectory(string)
diff --git a/libc/test/src/stdfix/AbsTest.h b/libc/test/src/stdfix/AbsTest.h
new file mode 100644
index 00000000000000..3d23a475720c25
--- /dev/null
+++ b/libc/test/src/stdfix/AbsTest.h
@@ -0,0 +1,37 @@
+//===-- Utility class to test fixed-point abs -------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "test/UnitTest/Test.h"
+
+#include "src/__support/fixed_point/fx_rep.h"
+
+template <typename T> class AbsTest : public LIBC_NAMESPACE::testing::Test {
+
+ using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<T>;
+ static constexpr T zero = FXRep::ZERO();
+ static constexpr T min = FXRep::MIN();
+ static constexpr T max = FXRep::MAX();
+ static constexpr T half = static_cast<T>(0.5);
+ static constexpr T neg_half = static_cast<T>(-0.5);
+
+public:
+ typedef T (*AbsFunc)(T);
+
+ void testSpecialNumbers(AbsFunc func) {
+ EXPECT_EQ(zero, func(zero));
+ EXPECT_EQ(max, func(min));
+ EXPECT_EQ(max, func(max));
+ EXPECT_EQ(half, func(half));
+ EXPECT_EQ(half, func(neg_half));
+ }
+};
+
+#define LIST_ABS_TESTS(T, func) \
+ using LlvmLibcAbsTest = AbsTest<T>; \
+ TEST_F(LlvmLibcAbsTest, SpecialNumbers) { testSpecialNumbers(&func); } \
+ static_assert(true, "Require semicolon.")
diff --git a/libc/test/src/stdfix/CMakeLists.txt b/libc/test/src/stdfix/CMakeLists.txt
new file mode 100644
index 00000000000000..3b2ea9e9893126
--- /dev/null
+++ b/libc/test/src/stdfix/CMakeLists.txt
@@ -0,0 +1,23 @@
+if(NOT LIBC_COMPILER_HAS_FIXED_POINT)
+ return()
+endif()
+
+add_custom_target(libc-stdfix-tests)
+
+foreach(suffix IN ITEMS hr r lr hk k lk)
+ add_libc_test(
+ abs${suffix}_test
+ SUITE
+ libc-stdfix-tests
+ HDRS
+ AbsTest.h
+ SRCS
+ abs${suffix}_test.cpp
+ COMPILE_OPTIONS
+ -O3
+ -ffixed-point
+ DEPENDS
+ libc.src.stdfix.abs${suffix}
+ libc.src.__support.fixed_point.fx_bits
+ )
+endforeach()
diff --git a/libc/test/src/stdfix/abshk_test.cpp b/libc/test/src/stdfix/abshk_test.cpp
new file mode 100644
index 00000000000000..c3f58625ac58ce
--- /dev/null
+++ b/libc/test/src/stdfix/abshk_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for abshk -----------------------------------------------===//
+//
+// 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 "AbsTest.h"
+
+#include "src/stdfix/abshk.h"
+
+LIST_ABS_TESTS(short accum, LIBC_NAMESPACE::abshk);
diff --git a/libc/test/src/stdfix/abshr_test.cpp b/libc/test/src/stdfix/abshr_test.cpp
new file mode 100644
index 00000000000000..d7a962ea1f98d3
--- /dev/null
+++ b/libc/test/src/stdfix/abshr_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for abshr -----------------------------------------------===//
+//
+// 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 "AbsTest.h"
+
+#include "src/stdfix/abshr.h"
+
+LIST_ABS_TESTS(short fract, LIBC_NAMESPACE::abshr);
diff --git a/libc/test/src/stdfix/absk_test.cpp b/libc/test/src/stdfix/absk_test.cpp
new file mode 100644
index 00000000000000..729cf143a4130a
--- /dev/null
+++ b/libc/test/src/stdfix/absk_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for absk ------------------------------------------------===//
+//
+// 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 "AbsTest.h"
+
+#include "src/stdfix/absk.h"
+
+LIST_ABS_TESTS(accum, LIBC_NAMESPACE::absk);
diff --git a/libc/test/src/stdfix/abslk_test.cpp b/libc/test/src/stdfix/abslk_test.cpp
new file mode 100644
index 00000000000000..93ef3469a225af
--- /dev/null
+++ b/libc/test/src/stdfix/abslk_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for abslk -----------------------------------------------===//
+//
+// 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 "AbsTest.h"
+
+#include "src/stdfix/abslk.h"
+
+LIST_ABS_TESTS(long accum, LIBC_NAMESPACE::abslk);
diff --git a/libc/test/src/stdfix/abslr_test.cpp b/libc/test/src/stdfix/abslr_test.cpp
new file mode 100644
index 00000000000000..c50a5587380288
--- /dev/null
+++ b/libc/test/src/stdfix/abslr_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for abslr -----------------------------------------------===//
+//
+// 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 "AbsTest.h"
+
+#include "src/stdfix/abslr.h"
+
+LIST_ABS_TESTS(long fract, LIBC_NAMESPACE::abslr);
diff --git a/libc/test/src/stdfix/absr_test.cpp b/libc/test/src/stdfix/absr_test.cpp
new file mode 100644
index 00000000000000..7b811735397935
--- /dev/null
+++ b/libc/test/src/stdfix/absr_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for absr ------------------------------------------------===//
+//
+// 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 "AbsTest.h"
+
+#include "src/stdfix/absr.h"
+
+LIST_ABS_TESTS(fract, LIBC_NAMESPACE::absr);
More information about the libc-commits
mailing list