Warning: This file is not a C or C++ file. It does not have highlighting.

1//===-- Utility class to manipulate fixed point numbers. --*- C++ -*-=========//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_LIBC_SRC___SUPPORT_FIXED_POINT_FX_BITS_H
10#define LLVM_LIBC_SRC___SUPPORT_FIXED_POINT_FX_BITS_H
11
12#include "include/llvm-libc-macros/stdfix-macros.h"
13#include "src/__support/CPP/bit.h"
14#include "src/__support/CPP/limits.h" // numeric_limits
15#include "src/__support/CPP/type_traits.h"
16#include "src/__support/macros/attributes.h" // LIBC_INLINE
17#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
18#include "src/__support/macros/null_check.h" // LIBC_CRASH_ON_VALUE
19#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
20#include "src/__support/math_extras.h"
21
22#include "fx_rep.h"
23
24#ifdef LIBC_COMPILER_HAS_FIXED_POINT
25
26namespace LIBC_NAMESPACE_DECL {
27namespace fixed_point {
28
29template <typename T> struct FXBits {
30private:
31 using fx_rep = FXRep<T>;
32 using StorageType = typename fx_rep::StorageType;
33
34 StorageType value;
35
36 static_assert(fx_rep::FRACTION_LEN > 0);
37
38 static constexpr size_t FRACTION_OFFSET = 0; // Just for completeness
39 static constexpr size_t INTEGRAL_OFFSET =
40 fx_rep::INTEGRAL_LEN == 0 ? 0 : fx_rep::FRACTION_LEN;
41 static constexpr size_t SIGN_OFFSET =
42 fx_rep::SIGN_LEN == 0
43 ? 0
44 : ((sizeof(StorageType) * CHAR_BIT) - fx_rep::SIGN_LEN);
45
46 static constexpr StorageType FRACTION_MASK =
47 mask_trailing_ones<StorageType, fx_rep::FRACTION_LEN>()
48 << FRACTION_OFFSET;
49 static constexpr StorageType INTEGRAL_MASK =
50 mask_trailing_ones<StorageType, fx_rep::INTEGRAL_LEN>()
51 << INTEGRAL_OFFSET;
52 static constexpr StorageType SIGN_MASK =
53 (fx_rep::SIGN_LEN == 0 ? 0 : StorageType(1) << SIGN_OFFSET);
54
55 // mask for <integral | fraction>
56 static constexpr StorageType VALUE_MASK = INTEGRAL_MASK | FRACTION_MASK;
57
58 // mask for <sign | integral | fraction>
59 static constexpr StorageType TOTAL_MASK = SIGN_MASK | VALUE_MASK;
60
61public:
62 LIBC_INLINE constexpr FXBits() = default;
63
64 template <typename XType> LIBC_INLINE constexpr explicit FXBits(XType x) {
65 using Unqual = typename cpp::remove_cv_t<XType>;
66 if constexpr (cpp::is_same_v<Unqual, T>) {
67 value = cpp::bit_cast<StorageType>(x);
68 } else if constexpr (cpp::is_same_v<Unqual, StorageType>) {
69 value = x;
70 } else {
71 // We don't want accidental type promotions/conversions, so we require
72 // exact type match.
73 static_assert(cpp::always_false<XType>);
74 }
75 }
76
77 LIBC_INLINE constexpr StorageType get_fraction() {
78 return (value & FRACTION_MASK) >> FRACTION_OFFSET;
79 }
80
81 LIBC_INLINE constexpr StorageType get_integral() {
82 return (value & INTEGRAL_MASK) >> INTEGRAL_OFFSET;
83 }
84
85 // returns complete bitstring representation the fixed point number
86 // the bitstring is of the form: padding | sign | integral | fraction
87 LIBC_INLINE constexpr StorageType get_bits() {
88 return (value & TOTAL_MASK) >> FRACTION_OFFSET;
89 }
90
91 // TODO: replace bool with Sign
92 LIBC_INLINE constexpr bool get_sign() {
93 return static_cast<bool>((value & SIGN_MASK) >> SIGN_OFFSET);
94 }
95
96 // This represents the effective negative exponent applied to this number
97 LIBC_INLINE constexpr int get_exponent() { return fx_rep::FRACTION_LEN; }
98
99 LIBC_INLINE constexpr void set_fraction(StorageType fraction) {
100 value = (value & (~FRACTION_MASK)) |
101 ((fraction << FRACTION_OFFSET) & FRACTION_MASK);
102 }
103
104 LIBC_INLINE constexpr void set_integral(StorageType integral) {
105 value = (value & (~INTEGRAL_MASK)) |
106 ((integral << INTEGRAL_OFFSET) & INTEGRAL_MASK);
107 }
108
109 // TODO: replace bool with Sign
110 LIBC_INLINE constexpr void set_sign(bool sign) {
111 value = (value & (~SIGN_MASK)) |
112 ((static_cast<StorageType>(sign) << SIGN_OFFSET) & SIGN_MASK);
113 }
114
115 LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast<T>(value); }
116};
117
118// Bit-wise operations are not available for fixed point types yet.
119template <typename T>
120LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, T>
121bit_and(T x, T y) {
122 using BitType = typename FXRep<T>::StorageType;
123 BitType x_bit = cpp::bit_cast<BitType>(x);
124 BitType y_bit = cpp::bit_cast<BitType>(y);
125 // For some reason, bit_cast cannot deduce BitType from the input.
126 return cpp::bit_cast<T, BitType>(x_bit & y_bit);
127}
128
129template <typename T>
130LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, T>
131bit_or(T x, T y) {
132 using BitType = typename FXRep<T>::StorageType;
133 BitType x_bit = cpp::bit_cast<BitType>(x);
134 BitType y_bit = cpp::bit_cast<BitType>(y);
135 // For some reason, bit_cast cannot deduce BitType from the input.
136 return cpp::bit_cast<T, BitType>(x_bit | y_bit);
137}
138
139template <typename T>
140LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, T>
141bit_not(T x) {
142 using BitType = typename FXRep<T>::StorageType;
143 BitType x_bit = cpp::bit_cast<BitType>(x);
144 // For some reason, bit_cast cannot deduce BitType from the input.
145 return cpp::bit_cast<T, BitType>(static_cast<BitType>(~x_bit));
146}
147
148template <typename T> LIBC_INLINE constexpr T abs(T x) {
149 using FXRep = FXRep<T>;
150 if constexpr (FXRep::SIGN_LEN == 0)
151 return x;
152 else {
153 if (LIBC_UNLIKELY(x == FXRep::MIN()))
154 return FXRep::MAX();
155 return (x < FXRep::ZERO() ? -x : x);
156 }
157}
158
159// Round-to-nearest, tie-to-(+Inf)
160template <typename T> LIBC_INLINE constexpr T round(T x, int n) {
161 using FXRep = FXRep<T>;
162 if (LIBC_UNLIKELY(n < 0))
163 n = 0;
164 if (LIBC_UNLIKELY(n >= FXRep::FRACTION_LEN))
165 return x;
166
167 T round_bit = FXRep::EPS() << (FXRep::FRACTION_LEN - n - 1);
168 // Check for overflow.
169 if (LIBC_UNLIKELY(FXRep::MAX() - round_bit < x))
170 return FXRep::MAX();
171
172 T all_ones = bit_not(FXRep::ZERO());
173
174 int shift = FXRep::FRACTION_LEN - n;
175 T rounding_mask =
176 (shift == FXRep::TOTAL_LEN) ? FXRep::ZERO() : (all_ones << shift);
177 return bit_and((x + round_bit), rounding_mask);
178}
179
180// count leading sign bits
181// TODO: support fixed_point_padding
182template <typename T>
183LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, int>
184countls(T f) {
185 using FXRep = FXRep<T>;
186 using BitType = typename FXRep::StorageType;
187 using FXBits = FXBits<T>;
188
189 if constexpr (FXRep::SIGN_LEN > 0) {
190 if (f < 0)
191 f = bit_not(f);
192 }
193
194 BitType value_bits = FXBits(f).get_bits();
195 return cpp::countl_zero(value_bits) - FXRep::SIGN_LEN;
196}
197
198// fixed-point to integer conversion
199template <typename T, typename XType>
200LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, XType>
201bitsfx(T f) {
202 return cpp::bit_cast<XType, T>(f);
203}
204
205// divide the two fixed-point types and return an integer result
206template <typename T, typename XType>
207LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, XType>
208idiv(T x, T y) {
209 using FXBits = FXBits<T>;
210 using FXRep = FXRep<T>;
211 using CompType = typename FXRep::CompType;
212
213 // If the value of the second operand of the / operator is zero, the
214 // behavior is undefined. Ref: ISO/IEC TR 18037:2008(E) p.g. 16
215 LIBC_CRASH_ON_VALUE(y, FXRep::ZERO());
216
217 CompType x_comp = static_cast<CompType>(FXBits(x).get_bits());
218 CompType y_comp = static_cast<CompType>(FXBits(y).get_bits());
219
220 // If an integer result of one of these functions overflows, the behavior is
221 // undefined. Ref: ISO/IEC TR 18037:2008(E) p.g. 16
222 CompType result = x_comp / y_comp;
223
224 return static_cast<XType>(result);
225}
226
227} // namespace fixed_point
228} // namespace LIBC_NAMESPACE_DECL
229
230#endif // LIBC_COMPILER_HAS_FIXED_POINT
231
232#endif // LLVM_LIBC_SRC___SUPPORT_FIXED_POINT_FX_BITS_H
233

Warning: This file is not a C or C++ file. It does not have highlighting.

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of libc/src/__support/fixed_point/fx_bits.h