Skip to content

[libc][stdfix] Add support for fixed point types in the testing infrastructure. #81819

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 15, 2024

Conversation

lntue
Copy link
Contributor

@lntue lntue commented Feb 15, 2024

No description provided.

@llvmbot
Copy link
Member

llvmbot commented Feb 15, 2024

@llvm/pr-subscribers-libc

Author: None (lntue)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/81819.diff

5 Files Affected:

  • (modified) libc/src/__support/fixed_point/CMakeLists.txt (+1)
  • (modified) libc/src/__support/fixed_point/fx_rep.h (+102-1)
  • (modified) libc/test/UnitTest/CMakeLists.txt (+1)
  • (modified) libc/test/UnitTest/LibcTest.cpp (+54-82)
  • (modified) libc/test/UnitTest/LibcTest.h (+3-1)
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);

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

using FXRep = fixed_point::FXRep<T>;
using comp_t = typename FXRep::CompType;

return cpp::to_string(cpp::bit_cast<comp_t>(Value)) + " * 2^-" +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add a TODO to switch this to proper fixed point printing when that's available?

@@ -8,9 +8,11 @@

#include "LibcTest.h"

#include "include/llvm-libc-macros/stdfix-macros.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This broke the Bazel build.

(Bits <= 16 && Bits > 8), uint16_t,
typename cpp::conditional_t<(Bits <= 32 && Bits > 16), uint32_t,
uint64_t>>>;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In C++20 we can express this logic with regular functions :)
https://godbolt.org/z/cn1qqTWez

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is blowing my mind right now. 🤯

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks much better than these types of conditional chains.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might have to replicate this logic in C, probably inside include/llvm-libc-types/stdfix_types.h in order to add definitions for int_*_t and uint_*_t as specified in the standard (section 7.18a.2). Then probably we can remove this conditional template and use those instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants