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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/src/__support/fixed_point/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
103 changes: 102 additions & 1 deletion libc/src/__support/fixed_point/fx_rep.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>>>;
};
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.


} // 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> {};
Expand Down
1 change: 1 addition & 0 deletions libc/test/UnitTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
Loading