Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #ifndef ASMJIT_CORE_SUPPORT_H_INCLUDED
8 : #define ASMJIT_CORE_SUPPORT_H_INCLUDED
9 :
10 : #include "globals.h"
11 :
12 : #if defined(_MSC_VER)
13 : #include <intrin.h>
14 : #endif
15 :
16 : ASMJIT_BEGIN_NAMESPACE
17 :
18 : //! \addtogroup asmjit_utilities
19 : //! \{
20 :
21 : //! Contains support classes and functions that may be used by AsmJit source and header files. Anything defined
22 : //! here is considered internal and should not be used outside of AsmJit and related projects like AsmTK.
23 : namespace Support {
24 :
25 : // Support - Basic Traits
26 : // ======================
27 :
28 : #if ASMJIT_ARCH_X86
29 : typedef uint8_t FastUInt8;
30 : #else
31 : typedef uint32_t FastUInt8;
32 : #endif
33 :
34 : //! \cond INTERNAL
35 : namespace Internal {
36 : template<typename T, size_t Alignment>
37 : struct AliasedUInt {};
38 :
39 : template<> struct AliasedUInt<uint16_t, 2> { typedef uint16_t ASMJIT_MAY_ALIAS T; };
40 : template<> struct AliasedUInt<uint32_t, 4> { typedef uint32_t ASMJIT_MAY_ALIAS T; };
41 : template<> struct AliasedUInt<uint64_t, 8> { typedef uint64_t ASMJIT_MAY_ALIAS T; };
42 :
43 : template<> struct AliasedUInt<uint16_t, 1> { typedef uint16_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
44 : template<> struct AliasedUInt<uint32_t, 1> { typedef uint32_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
45 : template<> struct AliasedUInt<uint32_t, 2> { typedef uint32_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 2); };
46 : template<> struct AliasedUInt<uint64_t, 1> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
47 : template<> struct AliasedUInt<uint64_t, 2> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 2); };
48 : template<> struct AliasedUInt<uint64_t, 4> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 4); };
49 :
50 : // StdInt - Make an int-type by size (signed or unsigned) that is the
51 : // same as types defined by <stdint.h>.
52 : // Int32Or64 - Make an int-type that has at least 32 bits: [u]int[32|64]_t.
53 :
54 : template<size_t Size, unsigned Unsigned>
55 : struct StdInt {}; // Fail if not specialized.
56 :
57 : template<> struct StdInt<1, 0> { typedef int8_t Type; };
58 : template<> struct StdInt<1, 1> { typedef uint8_t Type; };
59 : template<> struct StdInt<2, 0> { typedef int16_t Type; };
60 : template<> struct StdInt<2, 1> { typedef uint16_t Type; };
61 : template<> struct StdInt<4, 0> { typedef int32_t Type; };
62 : template<> struct StdInt<4, 1> { typedef uint32_t Type; };
63 : template<> struct StdInt<8, 0> { typedef int64_t Type; };
64 : template<> struct StdInt<8, 1> { typedef uint64_t Type; };
65 :
66 : template<typename T, int Unsigned = std::is_unsigned<T>::value>
67 : struct Int32Or64 : public StdInt<sizeof(T) <= 4 ? size_t(4) : sizeof(T), Unsigned> {};
68 : }
69 : //! \endcond
70 :
71 : template<typename T>
72 : static constexpr bool isUnsigned() noexcept { return std::is_unsigned<T>::value; }
73 :
74 : //! Casts an integer `x` to either `int32_t` or `int64_t` depending on `T`.
75 : template<typename T>
76 : static constexpr typename Internal::Int32Or64<T, 0>::Type asInt(const T& x) noexcept {
77 : return (typename Internal::Int32Or64<T, 0>::Type)x;
78 : }
79 :
80 : //! Casts an integer `x` to either `uint32_t` or `uint64_t` depending on `T`.
81 : template<typename T>
82 : static constexpr typename Internal::Int32Or64<T, 1>::Type asUInt(const T& x) noexcept {
83 0 : return (typename Internal::Int32Or64<T, 1>::Type)x;
84 : }
85 :
86 : //! Casts an integer `x` to either `int32_t`, uint32_t`, `int64_t`, or `uint64_t` depending on `T`.
87 : template<typename T>
88 : static constexpr typename Internal::Int32Or64<T>::Type asNormalized(const T& x) noexcept {
89 : return (typename Internal::Int32Or64<T>::Type)x;
90 : }
91 :
92 : //! Casts an integer `x` to the same type as defined by `<stdint.h>`.
93 : template<typename T>
94 : static constexpr typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type asStdInt(const T& x) noexcept {
95 0 : return (typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type)x;
96 : }
97 :
98 : //! A helper class that can be used to iterate over enum values.
99 : template<typename T, T from = (T)0, T to = T::kMaxValue>
100 : struct EnumValues {
101 : typedef typename std::underlying_type<T>::type ValueType;
102 :
103 : struct Iterator {
104 : ValueType value;
105 :
106 219936 : inline T operator*() const { return (T)value; }
107 3070292 : inline void operator++() { ++value; }
108 :
109 : inline bool operator==(const Iterator& other) const noexcept { return value == other.value; }
110 274920 : inline bool operator!=(const Iterator& other) const noexcept { return value != other.value; }
111 : };
112 :
113 54984 : inline Iterator begin() const noexcept { return Iterator{ValueType(from)}; }
114 54984 : inline Iterator end() const noexcept { return Iterator{ValueType(to) + 1}; }
115 : };
116 :
117 : // Support - BitCast
118 : // =================
119 :
120 : //! \cond
121 : namespace Internal {
122 : template<typename DstT, typename SrcT>
123 : union BitCastUnion {
124 0 : inline BitCastUnion(SrcT src) noexcept : src(src) {}
125 : SrcT src;
126 : DstT dst;
127 : };
128 : }
129 : //! \endcond
130 :
131 : //! Bit-casts from `Src` type to `Dst` type.
132 : //!
133 : //! Useful to bit-cast between integers and floating points.
134 : template<typename Dst, typename Src>
135 0 : static inline Dst bitCast(const Src& x) noexcept { return Internal::BitCastUnion<Dst, Src>(x).dst; }
136 :
137 : // Support - BitOps
138 : // ================
139 :
140 : //! Storage used to store a pack of bits (should by compatible with a machine word).
141 : typedef Internal::StdInt<sizeof(uintptr_t), 1>::Type BitWord;
142 :
143 : template<typename T>
144 : static constexpr uint32_t bitSizeOf() noexcept { return uint32_t(sizeof(T) * 8u); }
145 :
146 : //! Number of bits stored in a single `BitWord`.
147 : static constexpr uint32_t kBitWordSizeInBits = bitSizeOf<BitWord>();
148 :
149 : //! Returns `0 - x` in a safe way (no undefined behavior), works for unsigned numbers as well.
150 : template<typename T>
151 : static constexpr T neg(const T& x) noexcept {
152 : typedef typename std::make_unsigned<T>::type U;
153 0 : return T(U(0) - U(x));
154 : }
155 :
156 : template<typename T>
157 : static constexpr T allOnes() noexcept { return neg<T>(T(1)); }
158 :
159 : //! Returns `x << y` (shift left logical) by explicitly casting `x` to an unsigned type and back.
160 : template<typename X, typename Y>
161 : static constexpr X shl(const X& x, const Y& y) noexcept {
162 : typedef typename std::make_unsigned<X>::type U;
163 0 : return X(U(x) << y);
164 : }
165 :
166 : //! Returns `x >> y` (shift right logical) by explicitly casting `x` to an unsigned type and back.
167 : template<typename X, typename Y>
168 : static constexpr X shr(const X& x, const Y& y) noexcept {
169 : typedef typename std::make_unsigned<X>::type U;
170 597751 : return X(U(x) >> y);
171 : }
172 :
173 : //! Returns `x >> y` (shift right arithmetic) by explicitly casting `x` to a signed type and back.
174 : template<typename X, typename Y>
175 : static constexpr X sar(const X& x, const Y& y) noexcept {
176 : typedef typename std::make_signed<X>::type S;
177 0 : return X(S(x) >> y);
178 : }
179 :
180 : template<typename X, typename Y>
181 : static constexpr X ror(const X& x, const Y& y) noexcept {
182 : typedef typename std::make_unsigned<X>::type U;
183 : return X((U(x) >> y) | (U(x) << (bitSizeOf<U>() - y)));
184 : }
185 :
186 : //! Returns `x | (x >> y)` - helper used by some bit manipulation helpers.
187 : template<typename X, typename Y>
188 206347 : static constexpr X or_shr(const X& x, const Y& y) noexcept { return X(x | shr(x, y)); }
189 :
190 : //! Returns `x & -x` - extracts lowest set isolated bit (like BLSI instruction).
191 : template<typename T>
192 : static constexpr T blsi(T x) noexcept {
193 : typedef typename std::make_unsigned<T>::type U;
194 0 : return T(U(x) & neg(U(x)));
195 : }
196 :
197 : //! Tests whether the given value `x` has `n`th bit set.
198 : template<typename T, typename IndexT>
199 : static constexpr bool bitTest(T x, IndexT n) noexcept {
200 : typedef typename std::make_unsigned<T>::type U;
201 400449 : return (U(x) & (U(1) << asStdInt(n))) != 0;
202 : }
203 :
204 : // Tests whether the given `value` is a consecutive mask of bits that starts at
205 : // the least significant bit.
206 : template<typename T>
207 : static inline constexpr bool isLsbMask(const T& value) {
208 : typedef typename std::make_unsigned<T>::type U;
209 : return value && ((U(value) + 1u) & U(value)) == 0;
210 : }
211 :
212 : // Tests whether the given value contains at least one bit or whether it's a
213 : // bit-mask of consecutive bits.
214 : //
215 : // This function is similar to \ref isLsbMask(), but the mask doesn't have to
216 : // start at a least significant bit.
217 : template<typename T>
218 : static inline constexpr bool isConsecutiveMask(const T& value) {
219 : typedef typename std::make_unsigned<T>::type U;
220 : return value && isLsbMask((U(value) - 1u) | U(value));
221 : }
222 :
223 : //! Generates a trailing bit-mask that has `n` least significant (trailing) bits set.
224 : template<typename T, typename CountT>
225 : static constexpr T lsbMask(const CountT& n) noexcept {
226 : typedef typename std::make_unsigned<T>::type U;
227 : return (sizeof(U) < sizeof(uintptr_t))
228 : // Prevent undefined behavior by using a larger type than T.
229 512436 : ? T(U((uintptr_t(1) << n) - uintptr_t(1)))
230 : // Prevent undefined behavior by checking `n` before shift.
231 473880 : : n ? T(shr(allOnes<T>(), bitSizeOf<T>() - size_t(n))) : T(0);
232 : }
233 :
234 : //! Generats a leading bit-mask that has `n` most significant (leading) bits set.
235 : template<typename T, typename CountT>
236 : static constexpr T msbMask(const CountT& n) noexcept {
237 : typedef typename std::make_unsigned<T>::type U;
238 : return (sizeof(U) < sizeof(uintptr_t))
239 : // Prevent undefined behavior by using a larger type than T.
240 : ? T(allOnes<uintptr_t>() >> (bitSizeOf<uintptr_t>() - n))
241 : // Prevent undefined behavior by performing `n & (nBits - 1)` so it's always within the range.
242 : : T(sar(U(n != 0) << (bitSizeOf<U>() - 1), n ? uint32_t(n - 1) : uint32_t(0)));
243 : }
244 :
245 : //! Returns a bit-mask that has `x` bit set.
246 : template<typename Index>
247 3188655 : static constexpr uint32_t bitMask(const Index& x) noexcept { return (1u << asUInt(x)); }
248 :
249 : //! Returns a bit-mask that has `x` bit set (multiple arguments).
250 : template<typename Index, typename... Args>
251 : static constexpr uint32_t bitMask(const Index& x, Args... args) noexcept { return bitMask(x) | bitMask(args...); }
252 :
253 : //! Converts a boolean value `b` to zero or full mask (all bits set).
254 : template<typename DstT, typename SrcT>
255 : static constexpr DstT bitMaskFromBool(SrcT b) noexcept {
256 : typedef typename std::make_unsigned<DstT>::type U;
257 571081 : return DstT(U(0) - U(b));
258 : }
259 :
260 : //! Tests whether `a & b` is non-zero.
261 : template<typename A, typename B>
262 18344093 : static inline constexpr bool test(A a, B b) noexcept { return (asUInt(a) & asUInt(b)) != 0; }
263 :
264 : //! \cond
265 : namespace Internal {
266 : // Fills all trailing bits right from the first most significant bit set.
267 : static constexpr uint8_t fillTrailingBitsImpl(uint8_t x) noexcept { return or_shr(or_shr(or_shr(x, 1), 2), 4); }
268 : // Fills all trailing bits right from the first most significant bit set.
269 : static constexpr uint16_t fillTrailingBitsImpl(uint16_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8); }
270 : // Fills all trailing bits right from the first most significant bit set.
271 : static constexpr uint32_t fillTrailingBitsImpl(uint32_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8), 16); }
272 : // Fills all trailing bits right from the first most significant bit set.
273 206347 : static constexpr uint64_t fillTrailingBitsImpl(uint64_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8), 16), 32); }
274 : }
275 : //! \endcond
276 :
277 : // Fills all trailing bits right from the first most significant bit set.
278 : template<typename T>
279 : static constexpr T fillTrailingBits(const T& x) noexcept {
280 : typedef typename std::make_unsigned<T>::type U;
281 206347 : return T(Internal::fillTrailingBitsImpl(U(x)));
282 : }
283 :
284 : // Support - Count Leading/Trailing Zeros
285 : // ======================================
286 :
287 : //! \cond
288 : namespace Internal {
289 : namespace {
290 :
291 : template<typename T>
292 : struct BitScanData { T x; uint32_t n; };
293 :
294 : template<typename T, uint32_t N>
295 : struct BitScanCalc {
296 : static constexpr BitScanData<T> advanceLeft(const BitScanData<T>& data, uint32_t n) noexcept {
297 : return BitScanData<T> { data.x << n, data.n + n };
298 : }
299 :
300 : static constexpr BitScanData<T> advanceRight(const BitScanData<T>& data, uint32_t n) noexcept {
301 : return BitScanData<T> { data.x >> n, data.n + n };
302 : }
303 :
304 : static constexpr BitScanData<T> clz(const BitScanData<T>& data) noexcept {
305 : return BitScanCalc<T, N / 2>::clz(advanceLeft(data, data.x & (allOnes<T>() << (bitSizeOf<T>() - N)) ? uint32_t(0) : N));
306 : }
307 :
308 : static constexpr BitScanData<T> ctz(const BitScanData<T>& data) noexcept {
309 : return BitScanCalc<T, N / 2>::ctz(advanceRight(data, data.x & (allOnes<T>() >> (bitSizeOf<T>() - N)) ? uint32_t(0) : N));
310 : }
311 : };
312 :
313 : template<typename T>
314 : struct BitScanCalc<T, 0> {
315 : static constexpr BitScanData<T> clz(const BitScanData<T>& ctx) noexcept {
316 : return BitScanData<T> { 0, ctx.n - uint32_t(ctx.x >> (bitSizeOf<T>() - 1)) };
317 : }
318 :
319 : static constexpr BitScanData<T> ctz(const BitScanData<T>& ctx) noexcept {
320 : return BitScanData<T> { 0, ctx.n - uint32_t(ctx.x & 0x1) };
321 : }
322 : };
323 :
324 : template<typename T>
325 : constexpr uint32_t clzFallback(const T& x) noexcept {
326 : return BitScanCalc<T, bitSizeOf<T>() / 2u>::clz(BitScanData<T>{x, 1}).n;
327 : }
328 :
329 : template<typename T>
330 : constexpr uint32_t ctzFallback(const T& x) noexcept {
331 : return BitScanCalc<T, bitSizeOf<T>() / 2u>::ctz(BitScanData<T>{x, 1}).n;
332 : }
333 :
334 : template<typename T> inline uint32_t clzImpl(const T& x) noexcept { return clzFallback(asUInt(x)); }
335 : template<typename T> inline uint32_t ctzImpl(const T& x) noexcept { return ctzFallback(asUInt(x)); }
336 :
337 : #if !defined(ASMJIT_NO_INTRINSICS)
338 : # if defined(__GNUC__)
339 0 : template<> inline uint32_t clzImpl(const uint32_t& x) noexcept { return uint32_t(__builtin_clz(x)); }
340 : template<> inline uint32_t clzImpl(const uint64_t& x) noexcept { return uint32_t(__builtin_clzll(x)); }
341 744501 : template<> inline uint32_t ctzImpl(const uint32_t& x) noexcept { return uint32_t(__builtin_ctz(x)); }
342 137560 : template<> inline uint32_t ctzImpl(const uint64_t& x) noexcept { return uint32_t(__builtin_ctzll(x)); }
343 : # elif defined(_MSC_VER)
344 : template<> inline uint32_t clzImpl(const uint32_t& x) noexcept { unsigned long i; _BitScanReverse(&i, x); return uint32_t(i ^ 31); }
345 : template<> inline uint32_t ctzImpl(const uint32_t& x) noexcept { unsigned long i; _BitScanForward(&i, x); return uint32_t(i); }
346 : # if ASMJIT_ARCH_X86 == 64 || ASMJIT_ARCH_ARM == 64
347 : template<> inline uint32_t clzImpl(const uint64_t& x) noexcept { unsigned long i; _BitScanReverse64(&i, x); return uint32_t(i ^ 63); }
348 : template<> inline uint32_t ctzImpl(const uint64_t& x) noexcept { unsigned long i; _BitScanForward64(&i, x); return uint32_t(i); }
349 : # endif
350 : # endif
351 : #endif
352 :
353 : } // {anonymous}
354 : } // {Internal}
355 : //! \endcond
356 :
357 : //! Count leading zeros in `x` (returns a position of a first bit set in `x`).
358 : //!
359 : //! \note The input MUST NOT be zero, otherwise the result is undefined.
360 : template<typename T>
361 : static inline uint32_t clz(T x) noexcept { return Internal::clzImpl(asUInt(x)); }
362 :
363 : //! Count trailing zeros in `x` (returns a position of a first bit set in `x`).
364 : //!
365 : //! \note The input MUST NOT be zero, otherwise the result is undefined.
366 : template<typename T>
367 : static inline uint32_t ctz(T x) noexcept { return Internal::ctzImpl(asUInt(x)); }
368 :
369 : template<uint64_t kInput>
370 : struct ConstCTZ {
371 : static constexpr uint32_t value =
372 : (kInput & (uint64_t(1) << 0)) ? 0 :
373 : (kInput & (uint64_t(1) << 1)) ? 1 :
374 : (kInput & (uint64_t(1) << 2)) ? 2 :
375 : (kInput & (uint64_t(1) << 3)) ? 3 :
376 : (kInput & (uint64_t(1) << 4)) ? 4 :
377 : (kInput & (uint64_t(1) << 5)) ? 5 :
378 : (kInput & (uint64_t(1) << 6)) ? 6 :
379 : (kInput & (uint64_t(1) << 7)) ? 7 :
380 : (kInput & (uint64_t(1) << 8)) ? 8 :
381 : (kInput & (uint64_t(1) << 9)) ? 9 :
382 : (kInput & (uint64_t(1) << 10)) ? 10 :
383 : (kInput & (uint64_t(1) << 11)) ? 11 :
384 : (kInput & (uint64_t(1) << 12)) ? 12 :
385 : (kInput & (uint64_t(1) << 13)) ? 13 :
386 : (kInput & (uint64_t(1) << 14)) ? 14 :
387 : (kInput & (uint64_t(1) << 15)) ? 15 :
388 : (kInput & (uint64_t(1) << 16)) ? 16 :
389 : (kInput & (uint64_t(1) << 17)) ? 17 :
390 : (kInput & (uint64_t(1) << 18)) ? 18 :
391 : (kInput & (uint64_t(1) << 19)) ? 19 :
392 : (kInput & (uint64_t(1) << 20)) ? 20 :
393 : (kInput & (uint64_t(1) << 21)) ? 21 :
394 : (kInput & (uint64_t(1) << 22)) ? 22 :
395 : (kInput & (uint64_t(1) << 23)) ? 23 :
396 : (kInput & (uint64_t(1) << 24)) ? 24 :
397 : (kInput & (uint64_t(1) << 25)) ? 25 :
398 : (kInput & (uint64_t(1) << 26)) ? 26 :
399 : (kInput & (uint64_t(1) << 27)) ? 27 :
400 : (kInput & (uint64_t(1) << 28)) ? 28 :
401 : (kInput & (uint64_t(1) << 29)) ? 29 :
402 : (kInput & (uint64_t(1) << 30)) ? 30 :
403 : (kInput & (uint64_t(1) << 31)) ? 31 :
404 : (kInput & (uint64_t(1) << 32)) ? 32 :
405 : (kInput & (uint64_t(1) << 33)) ? 33 :
406 : (kInput & (uint64_t(1) << 34)) ? 34 :
407 : (kInput & (uint64_t(1) << 35)) ? 35 :
408 : (kInput & (uint64_t(1) << 36)) ? 36 :
409 : (kInput & (uint64_t(1) << 37)) ? 37 :
410 : (kInput & (uint64_t(1) << 38)) ? 38 :
411 : (kInput & (uint64_t(1) << 39)) ? 39 :
412 : (kInput & (uint64_t(1) << 40)) ? 40 :
413 : (kInput & (uint64_t(1) << 41)) ? 41 :
414 : (kInput & (uint64_t(1) << 42)) ? 42 :
415 : (kInput & (uint64_t(1) << 43)) ? 43 :
416 : (kInput & (uint64_t(1) << 44)) ? 44 :
417 : (kInput & (uint64_t(1) << 45)) ? 45 :
418 : (kInput & (uint64_t(1) << 46)) ? 46 :
419 : (kInput & (uint64_t(1) << 47)) ? 47 :
420 : (kInput & (uint64_t(1) << 48)) ? 48 :
421 : (kInput & (uint64_t(1) << 49)) ? 49 :
422 : (kInput & (uint64_t(1) << 50)) ? 50 :
423 : (kInput & (uint64_t(1) << 51)) ? 51 :
424 : (kInput & (uint64_t(1) << 52)) ? 52 :
425 : (kInput & (uint64_t(1) << 53)) ? 53 :
426 : (kInput & (uint64_t(1) << 54)) ? 54 :
427 : (kInput & (uint64_t(1) << 55)) ? 55 :
428 : (kInput & (uint64_t(1) << 56)) ? 56 :
429 : (kInput & (uint64_t(1) << 57)) ? 57 :
430 : (kInput & (uint64_t(1) << 58)) ? 58 :
431 : (kInput & (uint64_t(1) << 59)) ? 59 :
432 : (kInput & (uint64_t(1) << 60)) ? 60 :
433 : (kInput & (uint64_t(1) << 61)) ? 61 :
434 : (kInput & (uint64_t(1) << 62)) ? 62 :
435 : (kInput & (uint64_t(1) << 63)) ? 63 : 64;
436 : };
437 :
438 : // Support - PopCnt
439 : // ================
440 :
441 : // Based on the following resource:
442 : // http://graphics.stanford.edu/~seander/bithacks.html
443 : //
444 : // Alternatively, for a very small number of bits in `x`:
445 : // uint32_t n = 0;
446 : // while (x) {
447 : // x &= x - 1;
448 : // n++;
449 : // }
450 : // return n;
451 :
452 : //! \cond
453 : namespace Internal {
454 : static inline uint32_t constPopcntImpl(uint32_t x) noexcept {
455 : x = x - ((x >> 1) & 0x55555555u);
456 : x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
457 : return (((x + (x >> 4)) & 0x0F0F0F0Fu) * 0x01010101u) >> 24;
458 : }
459 :
460 : static inline uint32_t constPopcntImpl(uint64_t x) noexcept {
461 : if (ASMJIT_ARCH_BITS >= 64) {
462 : x = x - ((x >> 1) & 0x5555555555555555u);
463 : x = (x & 0x3333333333333333u) + ((x >> 2) & 0x3333333333333333u);
464 : return uint32_t((((x + (x >> 4)) & 0x0F0F0F0F0F0F0F0Fu) * 0x0101010101010101u) >> 56);
465 : }
466 : else {
467 : return constPopcntImpl(uint32_t(x >> 32)) +
468 : constPopcntImpl(uint32_t(x & 0xFFFFFFFFu));
469 : }
470 : }
471 :
472 : static inline uint32_t popcntImpl(uint32_t x) noexcept {
473 : #if defined(__GNUC__)
474 109968 : return uint32_t(__builtin_popcount(x));
475 : #else
476 : return constPopcntImpl(asUInt(x));
477 : #endif
478 : }
479 :
480 : static inline uint32_t popcntImpl(uint64_t x) noexcept {
481 : #if defined(__GNUC__)
482 : return uint32_t(__builtin_popcountll(x));
483 : #else
484 : return constPopcntImpl(asUInt(x));
485 : #endif
486 : }
487 : }
488 : //! \endcond
489 :
490 : //! Calculates count of bits in `x`.
491 : template<typename T>
492 : static inline uint32_t popcnt(T x) noexcept { return Internal::popcntImpl(asUInt(x)); }
493 :
494 : //! Calculates count of bits in `x` (useful in constant expressions).
495 : template<typename T>
496 : static inline uint32_t constPopcnt(T x) noexcept { return Internal::constPopcntImpl(asUInt(x)); }
497 :
498 : // Support - Min/Max
499 : // =================
500 :
501 : // NOTE: These are constexpr `min()` and `max()` implementations that are not
502 : // exactly the same as `std::min()` and `std::max()`. The return value is not
503 : // a reference to `a` or `b` but it's a new value instead.
504 :
505 : template<typename T>
506 152378 : static constexpr T min(const T& a, const T& b) noexcept { return b < a ? b : a; }
507 :
508 : template<typename T, typename... Args>
509 : static constexpr T min(const T& a, const T& b, Args&&... args) noexcept { return min(min(a, b), std::forward<Args>(args)...); }
510 :
511 : template<typename T>
512 1546191 : static constexpr T max(const T& a, const T& b) noexcept { return a < b ? b : a; }
513 :
514 : template<typename T, typename... Args>
515 : static constexpr T max(const T& a, const T& b, Args&&... args) noexcept { return max(max(a, b), std::forward<Args>(args)...); }
516 :
517 : // Support - Immediate Helpers
518 : // ===========================
519 :
520 : namespace Internal {
521 : template<typename T, bool IsFloat>
522 : struct ImmConv {
523 : static inline int64_t fromT(const T& x) noexcept { return int64_t(x); }
524 0 : static inline T toT(int64_t x) noexcept { return T(uint64_t(x) & Support::allOnes<typename std::make_unsigned<T>::type>()); }
525 : };
526 :
527 : template<typename T>
528 : struct ImmConv<T, true> {
529 : static inline int64_t fromT(const T& x) noexcept { return int64_t(bitCast<int64_t>(double(x))); }
530 : static inline T toT(int64_t x) noexcept { return T(bitCast<double>(x)); }
531 : };
532 : }
533 :
534 : template<typename T>
535 : static inline int64_t immediateFromT(const T& x) noexcept { return Internal::ImmConv<T, std::is_floating_point<T>::value>::fromT(x); }
536 :
537 : template<typename T>
538 : static inline T immediateToT(int64_t x) noexcept { return Internal::ImmConv<T, std::is_floating_point<T>::value>::toT(x); }
539 :
540 : // Support - Overflow Arithmetic
541 : // =============================
542 :
543 : //! \cond
544 : namespace Internal {
545 : template<typename T>
546 : inline T addOverflowFallback(T x, T y, FastUInt8* of) noexcept {
547 : typedef typename std::make_unsigned<T>::type U;
548 :
549 : U result = U(x) + U(y);
550 : *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result < U(x) : T((U(x) ^ ~U(y)) & (U(x) ^ result)) < 0));
551 : return T(result);
552 : }
553 :
554 : template<typename T>
555 : inline T subOverflowFallback(T x, T y, FastUInt8* of) noexcept {
556 : typedef typename std::make_unsigned<T>::type U;
557 :
558 : U result = U(x) - U(y);
559 : *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result > U(x) : T((U(x) ^ U(y)) & (U(x) ^ result)) < 0));
560 : return T(result);
561 : }
562 :
563 : template<typename T>
564 : inline T mulOverflowFallback(T x, T y, FastUInt8* of) noexcept {
565 : typedef typename Internal::StdInt<sizeof(T) * 2, isUnsigned<T>()>::Type I;
566 : typedef typename std::make_unsigned<I>::type U;
567 :
568 : U mask = allOnes<U>();
569 : if (std::is_signed<T>::value) {
570 : U prod = U(I(x)) * U(I(y));
571 : *of = FastUInt8(*of | FastUInt8(I(prod) < I(std::numeric_limits<T>::lowest()) || I(prod) > I(std::numeric_limits<T>::max())));
572 : return T(I(prod & mask));
573 : }
574 : else {
575 : U prod = U(x) * U(y);
576 : *of = FastUInt8(*of | FastUInt8((prod & ~mask) != 0));
577 : return T(prod & mask);
578 : }
579 : }
580 :
581 : template<>
582 : inline int64_t mulOverflowFallback(int64_t x, int64_t y, FastUInt8* of) noexcept {
583 : int64_t result = int64_t(uint64_t(x) * uint64_t(y));
584 : *of = FastUInt8(*of | FastUInt8(x && (result / x != y)));
585 : return result;
586 : }
587 :
588 : template<>
589 : inline uint64_t mulOverflowFallback(uint64_t x, uint64_t y, FastUInt8* of) noexcept {
590 : uint64_t result = x * y;
591 : *of = FastUInt8(*of | FastUInt8(y != 0 && allOnes<uint64_t>() / y < x));
592 : return result;
593 : }
594 :
595 : // These can be specialized.
596 : template<typename T> inline T addOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return addOverflowFallback(x, y, of); }
597 : template<typename T> inline T subOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return subOverflowFallback(x, y, of); }
598 : template<typename T> inline T mulOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return mulOverflowFallback(x, y, of); }
599 :
600 : #if defined(__GNUC__) && !defined(ASMJIT_NO_INTRINSICS)
601 : #if defined(__clang__) || __GNUC__ >= 5
602 : #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, RESULT_T, BUILTIN) \
603 : template<> \
604 : inline T FUNC(const T& x, const T& y, FastUInt8* of) noexcept { \
605 : RESULT_T result; \
606 : *of = FastUInt8(*of | (BUILTIN((RESULT_T)x, (RESULT_T)y, &result))); \
607 : return T(result); \
608 : }
609 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int32_t , int , __builtin_sadd_overflow )
610 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , __builtin_uadd_overflow )
611 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int64_t , long long , __builtin_saddll_overflow)
612 27492 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned long long, __builtin_uaddll_overflow)
613 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int32_t , int , __builtin_ssub_overflow )
614 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , __builtin_usub_overflow )
615 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int64_t , long long , __builtin_ssubll_overflow)
616 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned long long, __builtin_usubll_overflow)
617 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int32_t , int , __builtin_smul_overflow )
618 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint32_t, unsigned int , __builtin_umul_overflow )
619 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int64_t , long long , __builtin_smulll_overflow)
620 0 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint64_t, unsigned long long, __builtin_umulll_overflow)
621 : #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE
622 : #endif
623 : #endif
624 :
625 : // There is a bug in MSVC that makes these specializations unusable, maybe in the future...
626 : #if defined(_MSC_VER) && 0
627 : #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, ALT_T, BUILTIN) \
628 : template<> \
629 : inline T FUNC(T x, T y, FastUInt8* of) noexcept { \
630 : ALT_T result; \
631 : *of = FastUInt8(*of | BUILTIN(0, (ALT_T)x, (ALT_T)y, &result)); \
632 : return T(result); \
633 : }
634 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , _addcarry_u32 )
635 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , _subborrow_u32)
636 : #if ARCH_BITS >= 64
637 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned __int64 , _addcarry_u64 )
638 : ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned __int64 , _subborrow_u64)
639 : #endif
640 : #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE
641 : #endif
642 : } // {Internal}
643 : //! \endcond
644 :
645 : template<typename T>
646 : static inline T addOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::addOverflowImpl(asStdInt(x), asStdInt(y), of)); }
647 :
648 : template<typename T>
649 : static inline T subOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::subOverflowImpl(asStdInt(x), asStdInt(y), of)); }
650 :
651 : template<typename T>
652 : static inline T mulOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::mulOverflowImpl(asStdInt(x), asStdInt(y), of)); }
653 :
654 : // Support - Alignment
655 : // ===================
656 :
657 : template<typename X, typename Y>
658 : static constexpr bool isAligned(X base, Y alignment) noexcept {
659 : typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
660 0 : return ((U)base % (U)alignment) == 0;
661 : }
662 :
663 : //! Tests whether the `x` is a power of two (only one bit is set).
664 : template<typename T>
665 : static constexpr bool isPowerOf2(T x) noexcept {
666 : typedef typename std::make_unsigned<T>::type U;
667 23166 : return x && !(U(x) & (U(x) - U(1)));
668 : }
669 :
670 : template<typename X, typename Y>
671 : static constexpr X alignUp(X x, Y alignment) noexcept {
672 : typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
673 6905632 : return (X)( ((U)x + ((U)(alignment) - 1u)) & ~((U)(alignment) - 1u) );
674 : }
675 :
676 : template<typename T>
677 : static constexpr T alignUpPowerOf2(T x) noexcept {
678 : typedef typename Internal::StdInt<sizeof(T), 1>::Type U;
679 0 : return (T)(fillTrailingBits(U(x) - 1u) + 1u);
680 : }
681 :
682 : //! Returns either zero or a positive difference between `base` and `base` when
683 : //! aligned to `alignment`.
684 : template<typename X, typename Y>
685 4990 : static constexpr typename Internal::StdInt<sizeof(X), 1>::Type alignUpDiff(X base, Y alignment) noexcept {
686 : typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
687 4990 : return alignUp(U(base), alignment) - U(base);
688 : }
689 :
690 : template<typename X, typename Y>
691 : static constexpr X alignDown(X x, Y alignment) noexcept {
692 : typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
693 111022 : return (X)( (U)x & ~((U)(alignment) - 1u) );
694 : }
695 :
696 : // Support - NumGranularized
697 : // =========================
698 :
699 : //! Calculates the number of elements that would be required if `base` is
700 : //! granularized by `granularity`. This function can be used to calculate
701 : //! the number of BitWords to represent N bits, for example.
702 : template<typename X, typename Y>
703 : static constexpr X numGranularized(X base, Y granularity) noexcept {
704 : typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
705 : return X((U(base) + U(granularity) - 1) / U(granularity));
706 : }
707 :
708 : // Support - IsBetween
709 : // ===================
710 :
711 : //! Checks whether `x` is greater than or equal to `a` and lesser than or equal to `b`.
712 : template<typename T>
713 0 : static constexpr bool isBetween(const T& x, const T& a, const T& b) noexcept {
714 1739753 : return x >= a && x <= b;
715 : }
716 :
717 : // Support - IsInt & IsUInt
718 : // ========================
719 :
720 : //! Checks whether the given integer `x` can be casted to a 4-bit signed integer.
721 : template<typename T>
722 : static constexpr bool isInt4(T x) noexcept {
723 : typedef typename std::make_signed<T>::type S;
724 : typedef typename std::make_unsigned<T>::type U;
725 :
726 : return std::is_signed<T>::value ? isBetween<S>(S(x), -8, 7) : U(x) <= U(7u);
727 : }
728 :
729 : //! Checks whether the given integer `x` can be casted to a 7-bit signed integer.
730 : template<typename T>
731 : static constexpr bool isInt7(T x) noexcept {
732 : typedef typename std::make_signed<T>::type S;
733 : typedef typename std::make_unsigned<T>::type U;
734 :
735 : return std::is_signed<T>::value ? isBetween<S>(S(x), -64, 63) : U(x) <= U(63u);
736 : }
737 :
738 : //! Checks whether the given integer `x` can be casted to an 8-bit signed integer.
739 : template<typename T>
740 : static constexpr bool isInt8(T x) noexcept {
741 : typedef typename std::make_signed<T>::type S;
742 : typedef typename std::make_unsigned<T>::type U;
743 :
744 : return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -128, 127) : U(x) <= U(127u);
745 : }
746 :
747 : //! Checks whether the given integer `x` can be casted to a 9-bit signed integer.
748 : template<typename T>
749 : static constexpr bool isInt9(T x) noexcept {
750 : typedef typename std::make_signed<T>::type S;
751 : typedef typename std::make_unsigned<T>::type U;
752 :
753 : return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -256, 255)
754 : : sizeof(T) <= 1 || U(x) <= U(255u);
755 : }
756 :
757 : //! Checks whether the given integer `x` can be casted to a 10-bit signed integer.
758 : template<typename T>
759 : static constexpr bool isInt10(T x) noexcept {
760 : typedef typename std::make_signed<T>::type S;
761 : typedef typename std::make_unsigned<T>::type U;
762 :
763 : return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -512, 511)
764 : : sizeof(T) <= 1 || U(x) <= U(511u);
765 : }
766 :
767 : //! Checks whether the given integer `x` can be casted to a 16-bit signed integer.
768 : template<typename T>
769 : static constexpr bool isInt16(T x) noexcept {
770 : typedef typename std::make_signed<T>::type S;
771 : typedef typename std::make_unsigned<T>::type U;
772 :
773 : return std::is_signed<T>::value ? sizeof(T) <= 2 || isBetween<S>(S(x), -32768, 32767)
774 : : sizeof(T) <= 1 || U(x) <= U(32767u);
775 : }
776 :
777 : //! Checks whether the given integer `x` can be casted to a 32-bit signed integer.
778 : template<typename T>
779 0 : static constexpr bool isInt32(T x) noexcept {
780 : typedef typename std::make_signed<T>::type S;
781 : typedef typename std::make_unsigned<T>::type U;
782 :
783 : return std::is_signed<T>::value ? sizeof(T) <= 4 || isBetween<S>(S(x), -2147483647 - 1, 2147483647)
784 0 : : sizeof(T) <= 2 || U(x) <= U(2147483647u);
785 : }
786 :
787 : //! Checks whether the given integer `x` can be casted to a 4-bit unsigned integer.
788 : template<typename T>
789 : static constexpr bool isUInt4(T x) noexcept {
790 : typedef typename std::make_unsigned<T>::type U;
791 :
792 : return std::is_signed<T>::value ? x >= T(0) && x <= T(15)
793 : : U(x) <= U(15u);
794 : }
795 :
796 : //! Checks whether the given integer `x` can be casted to an 8-bit unsigned integer.
797 : template<typename T>
798 : static constexpr bool isUInt8(T x) noexcept {
799 : typedef typename std::make_unsigned<T>::type U;
800 :
801 : return std::is_signed<T>::value ? (sizeof(T) <= 1 || T(x) <= T(255)) && x >= T(0)
802 : : (sizeof(T) <= 1 || U(x) <= U(255u));
803 : }
804 :
805 : //! Checks whether the given integer `x` can be casted to a 12-bit unsigned integer (ARM specific).
806 : template<typename T>
807 : static constexpr bool isUInt12(T x) noexcept {
808 : typedef typename std::make_unsigned<T>::type U;
809 :
810 : return std::is_signed<T>::value ? (sizeof(T) <= 1 || T(x) <= T(4095)) && x >= T(0)
811 : : (sizeof(T) <= 1 || U(x) <= U(4095u));
812 : }
813 :
814 : //! Checks whether the given integer `x` can be casted to a 16-bit unsigned integer.
815 : template<typename T>
816 : static constexpr bool isUInt16(T x) noexcept {
817 : typedef typename std::make_unsigned<T>::type U;
818 :
819 : return std::is_signed<T>::value ? (sizeof(T) <= 2 || T(x) <= T(65535)) && x >= T(0)
820 : : (sizeof(T) <= 2 || U(x) <= U(65535u));
821 : }
822 :
823 : //! Checks whether the given integer `x` can be casted to a 32-bit unsigned integer.
824 : template<typename T>
825 : static constexpr bool isUInt32(T x) noexcept {
826 : typedef typename std::make_unsigned<T>::type U;
827 :
828 0 : return std::is_signed<T>::value ? (sizeof(T) <= 4 || T(x) <= T(4294967295u)) && x >= T(0)
829 : : (sizeof(T) <= 4 || U(x) <= U(4294967295u));
830 : }
831 :
832 : //! Checks whether the given integer `x` can be casted to a 32-bit unsigned integer.
833 : template<typename T>
834 : static constexpr bool isIntOrUInt32(T x) noexcept {
835 : return sizeof(T) <= 4 ? true : (uint32_t(uint64_t(x) >> 32) + 1u) <= 1u;
836 : }
837 :
838 : static bool inline isEncodableOffset32(int32_t offset, uint32_t nBits) noexcept {
839 0 : uint32_t nRev = 32 - nBits;
840 : return Support::sar(Support::shl(offset, nRev), nRev) == offset;
841 : }
842 :
843 : static bool inline isEncodableOffset64(int64_t offset, uint32_t nBits) noexcept {
844 0 : uint32_t nRev = 64 - nBits;
845 : return Support::sar(Support::shl(offset, nRev), nRev) == offset;
846 : }
847 :
848 : // Support - ByteSwap
849 : // ==================
850 :
851 : static inline uint16_t byteswap16(uint16_t x) noexcept {
852 : return uint16_t(((x >> 8) & 0xFFu) | ((x & 0xFFu) << 8));
853 : }
854 :
855 : static inline uint32_t byteswap32(uint32_t x) noexcept {
856 : return (x << 24) | (x >> 24) | ((x << 8) & 0x00FF0000u) | ((x >> 8) & 0x0000FF00);
857 : }
858 :
859 : static inline uint64_t byteswap64(uint64_t x) noexcept {
860 : #if (defined(__GNUC__) || defined(__clang__)) && !defined(ASMJIT_NO_INTRINSICS)
861 : return uint64_t(__builtin_bswap64(uint64_t(x)));
862 : #elif defined(_MSC_VER) && !defined(ASMJIT_NO_INTRINSICS)
863 : return uint64_t(_byteswap_uint64(uint64_t(x)));
864 : #else
865 : return (uint64_t(byteswap32(uint32_t(uint64_t(x) >> 32 ))) ) |
866 : (uint64_t(byteswap32(uint32_t(uint64_t(x) & 0xFFFFFFFFu))) << 32) ;
867 : #endif
868 : }
869 :
870 : // Support - BytePack & Unpack
871 : // ===========================
872 :
873 : //! Pack four 8-bit integer into a 32-bit integer as it is an array of `{b0,b1,b2,b3}`.
874 : static constexpr uint32_t bytepack32_4x8(uint32_t a, uint32_t b, uint32_t c, uint32_t d) noexcept {
875 414284 : return ASMJIT_ARCH_LE ? (a | (b << 8) | (c << 16) | (d << 24))
876 386792 : : (d | (c << 8) | (b << 16) | (a << 24));
877 : }
878 :
879 : template<typename T>
880 88142 : static constexpr uint32_t unpackU32At0(T x) noexcept { return ASMJIT_ARCH_LE ? uint32_t(uint64_t(x) & 0xFFFFFFFFu) : uint32_t(uint64_t(x) >> 32); }
881 : template<typename T>
882 93132 : static constexpr uint32_t unpackU32At1(T x) noexcept { return ASMJIT_ARCH_BE ? uint32_t(uint64_t(x) & 0xFFFFFFFFu) : uint32_t(uint64_t(x) >> 32); }
883 :
884 : // Support - Position of byte (in bit-shift)
885 : // =========================================
886 :
887 : static inline uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept {
888 2161622 : return ASMJIT_ARCH_LE ? index * 8 : (uint32_t(sizeof(uint32_t)) - 1u - index) * 8;
889 : }
890 :
891 : // Support - String Utilities
892 : // ==========================
893 :
894 : template<typename T>
895 : static constexpr T asciiToLower(T c) noexcept { return T(c ^ T(T(c >= T('A') && c <= T('Z')) << 5)); }
896 :
897 : template<typename T>
898 : static constexpr T asciiToUpper(T c) noexcept { return T(c ^ T(T(c >= T('a') && c <= T('z')) << 5)); }
899 :
900 : static ASMJIT_FORCE_INLINE size_t strLen(const char* s, size_t maxSize) noexcept {
901 : size_t i = 0;
902 0 : while (i < maxSize && s[i] != '\0')
903 0 : i++;
904 : return i;
905 : }
906 :
907 0 : static constexpr uint32_t hashRound(uint32_t hash, uint32_t c) noexcept { return hash * 65599 + c; }
908 :
909 : // Gets a hash of the given string `data` of size `size`. Size must be valid
910 : // as this function doesn't check for a null terminator and allows it in the
911 : // middle of the string.
912 : static inline uint32_t hashString(const char* data, size_t size) noexcept {
913 : uint32_t hashCode = 0;
914 : for (uint32_t i = 0; i < size; i++)
915 : hashCode = hashRound(hashCode, uint8_t(data[i]));
916 : return hashCode;
917 : }
918 :
919 : static ASMJIT_FORCE_INLINE const char* findPackedString(const char* p, uint32_t id) noexcept {
920 : uint32_t i = 0;
921 0 : while (i < id) {
922 0 : while (p[0])
923 0 : p++;
924 0 : p++;
925 0 : i++;
926 : }
927 : return p;
928 : }
929 :
930 : //! Compares two instruction names.
931 : //!
932 : //! `a` is a null terminated instruction name from arch-specific `nameData[]`
933 : //! table. `b` is a possibly non-null terminated instruction name passed to
934 : //! `InstAPI::stringToInstId()`.
935 : static ASMJIT_FORCE_INLINE int cmpInstName(const char* a, const char* b, size_t size) noexcept {
936 0 : for (size_t i = 0; i < size; i++) {
937 0 : int c = int(uint8_t(a[i])) - int(uint8_t(b[i]));
938 0 : if (c != 0) return c;
939 : }
940 0 : return int(uint8_t(a[size]));
941 : }
942 :
943 : // Support - Memory Read Access - 8 Bits
944 : // =====================================
945 :
946 0 : static inline uint8_t readU8(const void* p) noexcept { return static_cast<const uint8_t*>(p)[0]; }
947 : static inline int8_t readI8(const void* p) noexcept { return static_cast<const int8_t*>(p)[0]; }
948 :
949 : // Support - Memory Read Access - 16 Bits
950 : // ======================================
951 :
952 : template<ByteOrder BO, size_t Alignment>
953 : static inline uint16_t readU16x(const void* p) noexcept {
954 : typedef typename Internal::AliasedUInt<uint16_t, Alignment>::T U16AlignedToN;
955 0 : uint16_t x = static_cast<const U16AlignedToN*>(p)[0];
956 : return BO == ByteOrder::kNative ? x : byteswap16(x);
957 : }
958 :
959 : template<size_t Alignment = 1>
960 : static inline uint16_t readU16u(const void* p) noexcept { return readU16x<ByteOrder::kNative, Alignment>(p); }
961 : template<size_t Alignment = 1>
962 : static inline uint16_t readU16uLE(const void* p) noexcept { return readU16x<ByteOrder::kLE, Alignment>(p); }
963 : template<size_t Alignment = 1>
964 : static inline uint16_t readU16uBE(const void* p) noexcept { return readU16x<ByteOrder::kBE, Alignment>(p); }
965 :
966 : static inline uint16_t readU16a(const void* p) noexcept { return readU16x<ByteOrder::kNative, 2>(p); }
967 : static inline uint16_t readU16aLE(const void* p) noexcept { return readU16x<ByteOrder::kLE, 2>(p); }
968 : static inline uint16_t readU16aBE(const void* p) noexcept { return readU16x<ByteOrder::kBE, 2>(p); }
969 :
970 : template<ByteOrder BO, size_t Alignment>
971 : static inline int16_t readI16x(const void* p) noexcept { return int16_t(readU16x<BO, Alignment>(p)); }
972 :
973 : template<size_t Alignment = 1>
974 : static inline int16_t readI16u(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kNative, Alignment>(p)); }
975 : template<size_t Alignment = 1>
976 : static inline int16_t readI16uLE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kLE, Alignment>(p)); }
977 : template<size_t Alignment = 1>
978 : static inline int16_t readI16uBE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kBE, Alignment>(p)); }
979 :
980 : static inline int16_t readI16a(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kNative, 2>(p)); }
981 : static inline int16_t readI16aLE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kLE, 2>(p)); }
982 : static inline int16_t readI16aBE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kBE, 2>(p)); }
983 :
984 : // Support - Memory Read Access - 24 Bits
985 : // ======================================
986 :
987 : template<ByteOrder BO = ByteOrder::kNative>
988 : static inline uint32_t readU24u(const void* p) noexcept {
989 : uint32_t b0 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 2 : 0));
990 : uint32_t b1 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 1 : 1));
991 : uint32_t b2 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 0 : 2));
992 : return (b0 << 16) | (b1 << 8) | b2;
993 : }
994 :
995 : static inline uint32_t readU24uLE(const void* p) noexcept { return readU24u<ByteOrder::kLE>(p); }
996 : static inline uint32_t readU24uBE(const void* p) noexcept { return readU24u<ByteOrder::kBE>(p); }
997 :
998 : // Support - Memory Read Access - 32 Bits
999 : // ======================================
1000 :
1001 : template<ByteOrder BO, size_t Alignment>
1002 : static inline uint32_t readU32x(const void* p) noexcept {
1003 : typedef typename Internal::AliasedUInt<uint32_t, Alignment>::T U32AlignedToN;
1004 0 : uint32_t x = static_cast<const U32AlignedToN*>(p)[0];
1005 : return BO == ByteOrder::kNative ? x : byteswap32(x);
1006 : }
1007 :
1008 : template<size_t Alignment = 1>
1009 : static inline uint32_t readU32u(const void* p) noexcept { return readU32x<ByteOrder::kNative, Alignment>(p); }
1010 : template<size_t Alignment = 1>
1011 : static inline uint32_t readU32uLE(const void* p) noexcept { return readU32x<ByteOrder::kLE, Alignment>(p); }
1012 : template<size_t Alignment = 1>
1013 : static inline uint32_t readU32uBE(const void* p) noexcept { return readU32x<ByteOrder::kBE, Alignment>(p); }
1014 :
1015 : static inline uint32_t readU32a(const void* p) noexcept { return readU32x<ByteOrder::kNative, 4>(p); }
1016 : static inline uint32_t readU32aLE(const void* p) noexcept { return readU32x<ByteOrder::kLE, 4>(p); }
1017 : static inline uint32_t readU32aBE(const void* p) noexcept { return readU32x<ByteOrder::kBE, 4>(p); }
1018 :
1019 : template<ByteOrder BO, size_t Alignment>
1020 : static inline uint32_t readI32x(const void* p) noexcept { return int32_t(readU32x<BO, Alignment>(p)); }
1021 :
1022 : template<size_t Alignment = 1>
1023 : static inline int32_t readI32u(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kNative, Alignment>(p)); }
1024 : template<size_t Alignment = 1>
1025 : static inline int32_t readI32uLE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kLE, Alignment>(p)); }
1026 : template<size_t Alignment = 1>
1027 : static inline int32_t readI32uBE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kBE, Alignment>(p)); }
1028 :
1029 : static inline int32_t readI32a(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kNative, 4>(p)); }
1030 : static inline int32_t readI32aLE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kLE, 4>(p)); }
1031 : static inline int32_t readI32aBE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kBE, 4>(p)); }
1032 :
1033 : // Support - Memory Read Access - 64 Bits
1034 : // ======================================
1035 :
1036 : template<ByteOrder BO, size_t Alignment>
1037 : static inline uint64_t readU64x(const void* p) noexcept {
1038 : typedef typename Internal::AliasedUInt<uint64_t, Alignment>::T U64AlignedToN;
1039 0 : uint64_t x = static_cast<const U64AlignedToN*>(p)[0];
1040 : return BO == ByteOrder::kNative ? x : byteswap64(x);
1041 : }
1042 :
1043 : template<size_t Alignment = 1>
1044 : static inline uint64_t readU64u(const void* p) noexcept { return readU64x<ByteOrder::kNative, Alignment>(p); }
1045 : template<size_t Alignment = 1>
1046 : static inline uint64_t readU64uLE(const void* p) noexcept { return readU64x<ByteOrder::kLE, Alignment>(p); }
1047 : template<size_t Alignment = 1>
1048 : static inline uint64_t readU64uBE(const void* p) noexcept { return readU64x<ByteOrder::kBE, Alignment>(p); }
1049 :
1050 : static inline uint64_t readU64a(const void* p) noexcept { return readU64x<ByteOrder::kNative, 8>(p); }
1051 : static inline uint64_t readU64aLE(const void* p) noexcept { return readU64x<ByteOrder::kLE, 8>(p); }
1052 : static inline uint64_t readU64aBE(const void* p) noexcept { return readU64x<ByteOrder::kBE, 8>(p); }
1053 :
1054 : template<ByteOrder BO, size_t Alignment>
1055 : static inline int64_t readI64x(const void* p) noexcept { return int64_t(readU64x<BO, Alignment>(p)); }
1056 :
1057 : template<size_t Alignment = 1>
1058 : static inline int64_t readI64u(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kNative, Alignment>(p)); }
1059 : template<size_t Alignment = 1>
1060 : static inline int64_t readI64uLE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kLE, Alignment>(p)); }
1061 : template<size_t Alignment = 1>
1062 : static inline int64_t readI64uBE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kBE, Alignment>(p)); }
1063 :
1064 : static inline int64_t readI64a(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kNative, 8>(p)); }
1065 : static inline int64_t readI64aLE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kLE, 8>(p)); }
1066 : static inline int64_t readI64aBE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kBE, 8>(p)); }
1067 :
1068 : // Support - Memory Write Access - 8 Bits
1069 : // ======================================
1070 :
1071 0 : static inline void writeU8(void* p, uint8_t x) noexcept { static_cast<uint8_t*>(p)[0] = x; }
1072 : static inline void writeI8(void* p, int8_t x) noexcept { static_cast<int8_t*>(p)[0] = x; }
1073 :
1074 : // Support - Memory Write Access - 16 Bits
1075 : // =======================================
1076 :
1077 : template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1078 : static inline void writeU16x(void* p, uint16_t x) noexcept {
1079 : typedef typename Internal::AliasedUInt<uint16_t, Alignment>::T U16AlignedToN;
1080 0 : static_cast<U16AlignedToN*>(p)[0] = BO == ByteOrder::kNative ? x : byteswap16(x);
1081 : }
1082 :
1083 : template<size_t Alignment = 1>
1084 : static inline void writeU16uLE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kLE, Alignment>(p, x); }
1085 : template<size_t Alignment = 1>
1086 : static inline void writeU16uBE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kBE, Alignment>(p, x); }
1087 :
1088 : static inline void writeU16a(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kNative, 2>(p, x); }
1089 : static inline void writeU16aLE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kLE, 2>(p, x); }
1090 : static inline void writeU16aBE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kBE, 2>(p, x); }
1091 :
1092 :
1093 : template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1094 : static inline void writeI16x(void* p, int16_t x) noexcept { writeU16x<BO, Alignment>(p, uint16_t(x)); }
1095 :
1096 : template<size_t Alignment = 1>
1097 : static inline void writeI16uLE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kLE, Alignment>(p, uint16_t(x)); }
1098 : template<size_t Alignment = 1>
1099 : static inline void writeI16uBE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kBE, Alignment>(p, uint16_t(x)); }
1100 :
1101 : static inline void writeI16a(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kNative, 2>(p, uint16_t(x)); }
1102 : static inline void writeI16aLE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kLE, 2>(p, uint16_t(x)); }
1103 : static inline void writeI16aBE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kBE, 2>(p, uint16_t(x)); }
1104 :
1105 : // Support - Memory Write Access - 24 Bits
1106 : // =======================================
1107 :
1108 : template<ByteOrder BO = ByteOrder::kNative>
1109 : static inline void writeU24u(void* p, uint32_t v) noexcept {
1110 : static_cast<uint8_t*>(p)[0] = uint8_t((v >> (BO == ByteOrder::kLE ? 0 : 16)) & 0xFFu);
1111 : static_cast<uint8_t*>(p)[1] = uint8_t((v >> (BO == ByteOrder::kLE ? 8 : 8)) & 0xFFu);
1112 : static_cast<uint8_t*>(p)[2] = uint8_t((v >> (BO == ByteOrder::kLE ? 16 : 0)) & 0xFFu);
1113 : }
1114 :
1115 : static inline void writeU24uLE(void* p, uint32_t v) noexcept { writeU24u<ByteOrder::kLE>(p, v); }
1116 : static inline void writeU24uBE(void* p, uint32_t v) noexcept { writeU24u<ByteOrder::kBE>(p, v); }
1117 :
1118 : // Support - Memory Write Access - 32 Bits
1119 : // =======================================
1120 :
1121 : template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1122 : static inline void writeU32x(void* p, uint32_t x) noexcept {
1123 : typedef typename Internal::AliasedUInt<uint32_t, Alignment>::T U32AlignedToN;
1124 128301 : static_cast<U32AlignedToN*>(p)[0] = (BO == ByteOrder::kNative) ? x : Support::byteswap32(x);
1125 : }
1126 :
1127 : template<size_t Alignment = 1>
1128 : static inline void writeU32u(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kNative, Alignment>(p, x); }
1129 : template<size_t Alignment = 1>
1130 : static inline void writeU32uLE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kLE, Alignment>(p, x); }
1131 : template<size_t Alignment = 1>
1132 : static inline void writeU32uBE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kBE, Alignment>(p, x); }
1133 :
1134 : static inline void writeU32a(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kNative, 4>(p, x); }
1135 : static inline void writeU32aLE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kLE, 4>(p, x); }
1136 : static inline void writeU32aBE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kBE, 4>(p, x); }
1137 :
1138 : template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1139 : static inline void writeI32x(void* p, int32_t x) noexcept { writeU32x<BO, Alignment>(p, uint32_t(x)); }
1140 :
1141 : template<size_t Alignment = 1>
1142 : static inline void writeI32u(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kNative, Alignment>(p, uint32_t(x)); }
1143 : template<size_t Alignment = 1>
1144 : static inline void writeI32uLE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kLE, Alignment>(p, uint32_t(x)); }
1145 : template<size_t Alignment = 1>
1146 : static inline void writeI32uBE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kBE, Alignment>(p, uint32_t(x)); }
1147 :
1148 : static inline void writeI32a(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kNative, 4>(p, uint32_t(x)); }
1149 : static inline void writeI32aLE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kLE, 4>(p, uint32_t(x)); }
1150 : static inline void writeI32aBE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kBE, 4>(p, uint32_t(x)); }
1151 :
1152 : // Support - Memory Write Access - 64 Bits
1153 : // =======================================
1154 :
1155 : template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1156 : static inline void writeU64x(void* p, uint64_t x) noexcept {
1157 : typedef typename Internal::AliasedUInt<uint64_t, Alignment>::T U64AlignedToN;
1158 0 : static_cast<U64AlignedToN*>(p)[0] = BO == ByteOrder::kNative ? x : byteswap64(x);
1159 : }
1160 :
1161 : template<size_t Alignment = 1>
1162 : static inline void writeU64u(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kNative, Alignment>(p, x); }
1163 : template<size_t Alignment = 1>
1164 0 : static inline void writeU64uLE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kLE, Alignment>(p, x); }
1165 : template<size_t Alignment = 1>
1166 : static inline void writeU64uBE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kBE, Alignment>(p, x); }
1167 :
1168 : static inline void writeU64a(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kNative, 8>(p, x); }
1169 : static inline void writeU64aLE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kLE, 8>(p, x); }
1170 : static inline void writeU64aBE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kBE, 8>(p, x); }
1171 :
1172 : template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1173 : static inline void writeI64x(void* p, int64_t x) noexcept { writeU64x<BO, Alignment>(p, uint64_t(x)); }
1174 :
1175 : template<size_t Alignment = 1>
1176 : static inline void writeI64u(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kNative, Alignment>(p, uint64_t(x)); }
1177 : template<size_t Alignment = 1>
1178 : static inline void writeI64uLE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kLE, Alignment>(p, uint64_t(x)); }
1179 : template<size_t Alignment = 1>
1180 : static inline void writeI64uBE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kBE, Alignment>(p, uint64_t(x)); }
1181 :
1182 : static inline void writeI64a(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kNative, 8>(p, uint64_t(x)); }
1183 : static inline void writeI64aLE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kLE, 8>(p, uint64_t(x)); }
1184 : static inline void writeI64aBE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kBE, 8>(p, uint64_t(x)); }
1185 :
1186 : // Support - Operators
1187 : // ===================
1188 :
1189 : //! \cond INTERNAL
1190 : struct Set { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return y; } };
1191 : struct SetNot { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return ~y; } };
1192 : struct And { template<typename T> static inline T op(T x, T y) noexcept { return x & y; } };
1193 28385 : struct AndNot { template<typename T> static inline T op(T x, T y) noexcept { return x & ~y; } };
1194 : struct NotAnd { template<typename T> static inline T op(T x, T y) noexcept { return ~x & y; } };
1195 84062 : struct Or { template<typename T> static inline T op(T x, T y) noexcept { return x | y; } };
1196 : struct Xor { template<typename T> static inline T op(T x, T y) noexcept { return x ^ y; } };
1197 : struct Add { template<typename T> static inline T op(T x, T y) noexcept { return x + y; } };
1198 : struct Sub { template<typename T> static inline T op(T x, T y) noexcept { return x - y; } };
1199 : struct Min { template<typename T> static inline T op(T x, T y) noexcept { return min<T>(x, y); } };
1200 : struct Max { template<typename T> static inline T op(T x, T y) noexcept { return max<T>(x, y); } };
1201 : //! \endcond
1202 :
1203 : // Support - BitWordIterator
1204 : // =========================
1205 :
1206 : //! Iterates over each bit in a number which is set to 1.
1207 : //!
1208 : //! Example of use:
1209 : //!
1210 : //! ```
1211 : //! uint32_t bitsToIterate = 0x110F;
1212 : //! Support::BitWordIterator<uint32_t> it(bitsToIterate);
1213 : //!
1214 : //! while (it.hasNext()) {
1215 : //! uint32_t bitIndex = it.next();
1216 : //! std::printf("Bit at %u is set\n", unsigned(bitIndex));
1217 : //! }
1218 : //! ```
1219 : template<typename T>
1220 : class BitWordIterator {
1221 : public:
1222 : ASMJIT_FORCE_INLINE explicit BitWordIterator(T bitWord) noexcept
1223 32330 : : _bitWord(bitWord) {}
1224 :
1225 : ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; }
1226 : ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; }
1227 :
1228 : ASMJIT_FORCE_INLINE uint32_t next() noexcept {
1229 : ASMJIT_ASSERT(_bitWord != 0);
1230 : uint32_t index = ctz(_bitWord);
1231 1227781 : _bitWord ^= T(1u) << index;
1232 : return index;
1233 : }
1234 :
1235 : T _bitWord;
1236 : };
1237 :
1238 : // Support - BitWordFlipIterator
1239 : // =============================
1240 :
1241 : template<typename T>
1242 : class BitWordFlipIterator {
1243 : public:
1244 : ASMJIT_FORCE_INLINE explicit BitWordFlipIterator(T bitWord) noexcept
1245 : : _bitWord(bitWord) {}
1246 :
1247 : ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; }
1248 : ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; }
1249 :
1250 : ASMJIT_FORCE_INLINE uint32_t nextAndFlip() noexcept {
1251 : ASMJIT_ASSERT(_bitWord != 0);
1252 : uint32_t index = ctz(_bitWord);
1253 : _bitWord ^= T(1u) << index;
1254 : return index;
1255 : }
1256 :
1257 : T _bitWord;
1258 : T _xorMask;
1259 : };
1260 :
1261 : // Support - BitVectorOps
1262 : // ======================
1263 :
1264 : //! \cond
1265 : namespace Internal {
1266 : template<typename T, class OperatorT, class FullWordOpT>
1267 27592 : static inline void bitVectorOp(T* buf, size_t index, size_t count) noexcept {
1268 27592 : if (count == 0)
1269 : return;
1270 :
1271 : const size_t kTSizeInBits = bitSizeOf<T>();
1272 27592 : size_t vecIndex = index / kTSizeInBits; // T[]
1273 27592 : size_t bitIndex = index % kTSizeInBits; // T[][]
1274 :
1275 27592 : buf += vecIndex;
1276 :
1277 : // The first BitWord requires special handling to preserve bits outside the fill region.
1278 : const T kFillMask = allOnes<T>();
1279 27592 : size_t firstNBits = min<size_t>(kTSizeInBits - bitIndex, count);
1280 :
1281 27592 : buf[0] = OperatorT::op(buf[0], (kFillMask >> (kTSizeInBits - firstNBits)) << bitIndex);
1282 27592 : buf++;
1283 27592 : count -= firstNBits;
1284 :
1285 : // All bits between the first and last affected BitWords can be just filled.
1286 27592 : while (count >= kTSizeInBits) {
1287 0 : buf[0] = FullWordOpT::op(buf[0], kFillMask);
1288 0 : buf++;
1289 0 : count -= kTSizeInBits;
1290 : }
1291 :
1292 : // The last BitWord requires special handling as well
1293 27592 : if (count)
1294 0 : buf[0] = OperatorT::op(buf[0], kFillMask >> (kTSizeInBits - count));
1295 : }
1296 : }
1297 : //! \endcond
1298 :
1299 : //! Sets bit in a bit-vector `buf` at `index`.
1300 : template<typename T>
1301 : static inline bool bitVectorGetBit(T* buf, size_t index) noexcept {
1302 : const size_t kTSizeInBits = bitSizeOf<T>();
1303 :
1304 913260 : size_t vecIndex = index / kTSizeInBits;
1305 : size_t bitIndex = index % kTSizeInBits;
1306 :
1307 913260 : return bool((buf[vecIndex] >> bitIndex) & 0x1u);
1308 : }
1309 :
1310 : //! Sets bit in a bit-vector `buf` at `index` to `value`.
1311 : template<typename T>
1312 1055802 : static inline void bitVectorSetBit(T* buf, size_t index, bool value) noexcept {
1313 : const size_t kTSizeInBits = bitSizeOf<T>();
1314 :
1315 1055802 : size_t vecIndex = index / kTSizeInBits;
1316 1055802 : size_t bitIndex = index % kTSizeInBits;
1317 :
1318 1055802 : T bitMask = T(1u) << bitIndex;
1319 1055802 : if (value)
1320 669438 : buf[vecIndex] |= bitMask;
1321 : else
1322 386364 : buf[vecIndex] &= ~bitMask;
1323 1055802 : }
1324 :
1325 : //! Sets bit in a bit-vector `buf` at `index` to `value`.
1326 : template<typename T>
1327 : static inline void bitVectorFlipBit(T* buf, size_t index) noexcept {
1328 : const size_t kTSizeInBits = bitSizeOf<T>();
1329 :
1330 : size_t vecIndex = index / kTSizeInBits;
1331 : size_t bitIndex = index % kTSizeInBits;
1332 :
1333 : T bitMask = T(1u) << bitIndex;
1334 : buf[vecIndex] ^= bitMask;
1335 : }
1336 :
1337 : //! Fills `count` bits in bit-vector `buf` starting at bit-index `index`.
1338 : template<typename T>
1339 27492 : static inline void bitVectorFill(T* buf, size_t index, size_t count) noexcept { Internal::bitVectorOp<T, Or, Set>(buf, index, count); }
1340 :
1341 : //! Clears `count` bits in bit-vector `buf` starting at bit-index `index`.
1342 : template<typename T>
1343 100 : static inline void bitVectorClear(T* buf, size_t index, size_t count) noexcept { Internal::bitVectorOp<T, AndNot, SetNot>(buf, index, count); }
1344 :
1345 : template<typename T>
1346 100 : static inline size_t bitVectorIndexOf(T* buf, size_t start, bool value) noexcept {
1347 : const size_t kTSizeInBits = bitSizeOf<T>();
1348 100 : size_t vecIndex = start / kTSizeInBits; // T[]
1349 100 : size_t bitIndex = start % kTSizeInBits; // T[][]
1350 :
1351 100 : T* p = buf + vecIndex;
1352 :
1353 : // We always look for zeros, if value is `true` we have to flip all bits before the search.
1354 : const T kFillMask = allOnes<T>();
1355 100 : const T kFlipMask = value ? T(0) : kFillMask;
1356 :
1357 : // The first BitWord requires special handling as there are some bits we want to ignore.
1358 100 : T bits = (*p ^ kFlipMask) & (kFillMask << bitIndex);
1359 : for (;;) {
1360 100 : if (bits)
1361 100 : return (size_t)(p - buf) * kTSizeInBits + ctz(bits);
1362 0 : bits = *++p ^ kFlipMask;
1363 : }
1364 : }
1365 :
1366 : // Support - BitVectorIterator
1367 : // ===========================
1368 :
1369 : template<typename T>
1370 : class BitVectorIterator {
1371 : public:
1372 : const T* _ptr;
1373 : size_t _idx;
1374 : size_t _end;
1375 : T _current;
1376 :
1377 : ASMJIT_FORCE_INLINE BitVectorIterator(const BitVectorIterator& other) noexcept = default;
1378 :
1379 : ASMJIT_FORCE_INLINE BitVectorIterator(const T* data, size_t numBitWords, size_t start = 0) noexcept {
1380 : init(data, numBitWords, start);
1381 : }
1382 :
1383 : ASMJIT_FORCE_INLINE void init(const T* data, size_t numBitWords, size_t start = 0) noexcept {
1384 : const T* ptr = data + (start / bitSizeOf<T>());
1385 : size_t idx = alignDown(start, bitSizeOf<T>());
1386 54984 : size_t end = numBitWords * bitSizeOf<T>();
1387 :
1388 : T bitWord = T(0);
1389 54984 : if (idx < end) {
1390 54984 : bitWord = *ptr++ & (allOnes<T>() << (start % bitSizeOf<T>()));
1391 56570 : while (!bitWord && (idx += bitSizeOf<T>()) < end)
1392 1586 : bitWord = *ptr++;
1393 : }
1394 :
1395 : _ptr = ptr;
1396 : _idx = idx;
1397 : _end = end;
1398 : _current = bitWord;
1399 : }
1400 :
1401 : ASMJIT_FORCE_INLINE bool hasNext() const noexcept {
1402 : return _current != T(0);
1403 : }
1404 :
1405 : ASMJIT_FORCE_INLINE size_t next() noexcept {
1406 : T bitWord = _current;
1407 : ASMJIT_ASSERT(bitWord != T(0));
1408 :
1409 : uint32_t bit = ctz(bitWord);
1410 0 : bitWord ^= T(1u) << bit;
1411 :
1412 0 : size_t n = _idx + bit;
1413 0 : while (!bitWord && (_idx += bitSizeOf<T>()) < _end)
1414 0 : bitWord = *_ptr++;
1415 :
1416 : _current = bitWord;
1417 : return n;
1418 : }
1419 :
1420 : ASMJIT_FORCE_INLINE size_t peekNext() const noexcept {
1421 : ASMJIT_ASSERT(_current != T(0));
1422 : return _idx + ctz(_current);
1423 : }
1424 : };
1425 :
1426 : // Support - BitVectorOpIterator
1427 : // =============================
1428 :
1429 : template<typename T, class OperatorT>
1430 : class BitVectorOpIterator {
1431 : public:
1432 : enum : uint32_t {
1433 : kTSizeInBits = bitSizeOf<T>()
1434 : };
1435 :
1436 : const T* _aPtr;
1437 : const T* _bPtr;
1438 : size_t _idx;
1439 : size_t _end;
1440 : T _current;
1441 :
1442 27492 : ASMJIT_FORCE_INLINE BitVectorOpIterator(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept {
1443 : init(aData, bData, numBitWords, start);
1444 : }
1445 :
1446 : ASMJIT_FORCE_INLINE void init(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept {
1447 : const T* aPtr = aData + (start / bitSizeOf<T>());
1448 : const T* bPtr = bData + (start / bitSizeOf<T>());
1449 : size_t idx = alignDown(start, bitSizeOf<T>());
1450 27492 : size_t end = numBitWords * bitSizeOf<T>();
1451 :
1452 : T bitWord = T(0);
1453 27492 : if (idx < end) {
1454 27492 : bitWord = OperatorT::op(*aPtr++, *bPtr++) & (allOnes<T>() << (start % bitSizeOf<T>()));
1455 28285 : while (!bitWord && (idx += kTSizeInBits) < end)
1456 793 : bitWord = OperatorT::op(*aPtr++, *bPtr++);
1457 : }
1458 :
1459 27492 : _aPtr = aPtr;
1460 27492 : _bPtr = bPtr;
1461 27492 : _idx = idx;
1462 27492 : _end = end;
1463 27492 : _current = bitWord;
1464 : }
1465 :
1466 : ASMJIT_FORCE_INLINE bool hasNext() noexcept {
1467 27492 : return _current != T(0);
1468 : }
1469 :
1470 : ASMJIT_FORCE_INLINE size_t next() noexcept {
1471 : T bitWord = _current;
1472 : ASMJIT_ASSERT(bitWord != T(0));
1473 :
1474 : uint32_t bit = ctz(bitWord);
1475 0 : bitWord ^= T(1u) << bit;
1476 :
1477 0 : size_t n = _idx + bit;
1478 0 : while (!bitWord && (_idx += kTSizeInBits) < _end)
1479 0 : bitWord = OperatorT::op(*_aPtr++, *_bPtr++);
1480 :
1481 0 : _current = bitWord;
1482 : return n;
1483 : }
1484 : };
1485 :
1486 : // Support - Sorting
1487 : // =================
1488 :
1489 : //! Sort order.
1490 : enum class SortOrder : uint32_t {
1491 : //!< Ascending order.
1492 : kAscending = 0,
1493 : //!< Descending order.
1494 : kDescending = 1
1495 : };
1496 :
1497 : //! A helper class that provides comparison of any user-defined type that
1498 : //! implements `<` and `>` operators (primitive types are supported as well).
1499 : template<SortOrder kOrder = SortOrder::kAscending>
1500 : struct Compare {
1501 : template<typename A, typename B>
1502 : inline int operator()(const A& a, const B& b) const noexcept {
1503 100 : return kOrder == SortOrder::kAscending ? int(a > b) - int(a < b) : int(a < b) - int(a > b);
1504 : }
1505 : };
1506 :
1507 : //! Insertion sort.
1508 : template<typename T, typename CompareT = Compare<SortOrder::kAscending>>
1509 78797 : static inline void iSort(T* base, size_t size, const CompareT& cmp = CompareT()) noexcept {
1510 281944 : for (T* pm = base + 1; pm < base + size; pm++)
1511 338150 : for (T* pl = pm; pl > base && cmp(pl[-1], pl[0]) > 0; pl--)
1512 : std::swap(pl[-1], pl[0]);
1513 78797 : }
1514 :
1515 : //! \cond
1516 : namespace Internal {
1517 : //! Quick-sort implementation.
1518 : template<typename T, class CompareT>
1519 : struct QSortImpl {
1520 : enum : size_t {
1521 : kStackSize = 64 * 2,
1522 : kISortThreshold = 7
1523 : };
1524 :
1525 : // Based on "PDCLib - Public Domain C Library" and rewritten to C++.
1526 82476 : static void sort(T* base, size_t size, const CompareT& cmp) noexcept {
1527 82476 : T* end = base + size;
1528 : T* stack[kStackSize];
1529 : T** stackptr = stack;
1530 :
1531 : for (;;) {
1532 122812 : if ((size_t)(end - base) > kISortThreshold) {
1533 : // We work from second to last - first will be pivot element.
1534 20168 : T* pi = base + 1;
1535 20168 : T* pj = end - 1;
1536 20168 : std::swap(base[(size_t)(end - base) / 2], base[0]);
1537 :
1538 20168 : if (cmp(*pi , *pj ) > 0) std::swap(*pi , *pj );
1539 20168 : if (cmp(*base, *pj ) > 0) std::swap(*base, *pj );
1540 20168 : if (cmp(*pi , *base) > 0) std::swap(*pi , *base);
1541 :
1542 : // Now we have the median for pivot element, entering main loop.
1543 : for (;;) {
1544 206323 : while (pi < pj && cmp(*++pi, *base) < 0) continue; // Move `i` right until `*i >= pivot`.
1545 214096 : while (pj > base && cmp(*--pj, *base) > 0) continue; // Move `j` left until `*j <= pivot`.
1546 :
1547 148339 : if (pi > pj) break;
1548 : std::swap(*pi, *pj);
1549 : }
1550 :
1551 : // Move pivot into correct place.
1552 : std::swap(*base, *pj);
1553 :
1554 : // Larger subfile base / end to stack, sort smaller.
1555 20168 : if (pj - base > end - pi) {
1556 : // Left is larger.
1557 5219 : *stackptr++ = base;
1558 5219 : *stackptr++ = pj;
1559 : base = pi;
1560 : }
1561 : else {
1562 : // Right is larger.
1563 14949 : *stackptr++ = pi;
1564 14949 : *stackptr++ = end;
1565 : end = pj;
1566 : }
1567 : ASMJIT_ASSERT(stackptr <= stack + kStackSize);
1568 123741 : }
1569 : else {
1570 : // UB sanitizer doesn't like applying offset to a nullptr base.
1571 102644 : if (base != end)
1572 78797 : iSort(base, (size_t)(end - base), cmp);
1573 :
1574 102644 : if (stackptr == stack)
1575 : break;
1576 :
1577 20168 : end = *--stackptr;
1578 20168 : base = *--stackptr;
1579 : }
1580 : }
1581 82476 : }
1582 : };
1583 : }
1584 : //! \endcond
1585 :
1586 : //! Quick sort implementation.
1587 : //!
1588 : //! The main reason to provide a custom qsort implementation is that we needed something that will
1589 : //! never throw `bad_alloc` exception. This implementation doesn't use dynamic memory allocation.
1590 : template<typename T, class CompareT = Compare<SortOrder::kAscending>>
1591 : static inline void qSort(T* base, size_t size, const CompareT& cmp = CompareT()) noexcept {
1592 82476 : Internal::QSortImpl<T, CompareT>::sort(base, size, cmp);
1593 : }
1594 :
1595 : // Support - Array
1596 : // ===============
1597 :
1598 : //! Array type, similar to std::array<T, N>, with the possibility to use enums in operator[].
1599 : //!
1600 : //! \note The array has C semantics - the elements in the array are not initialized.
1601 : template<typename T, size_t N>
1602 137460 : struct Array {
1603 : //! \name Members
1604 : //! \{
1605 :
1606 : //! The underlying array data, use \ref data() to access it.
1607 : T _data[N];
1608 :
1609 : //! \}
1610 :
1611 : //! \cond
1612 : // std compatibility.
1613 : typedef T value_type;
1614 : typedef size_t size_type;
1615 : typedef ptrdiff_t difference_type;
1616 :
1617 : typedef value_type& reference;
1618 : typedef const value_type& const_reference;
1619 :
1620 : typedef value_type* pointer;
1621 : typedef const value_type* const_pointer;
1622 :
1623 : typedef pointer iterator;
1624 : typedef const_pointer const_iterator;
1625 : //! \endcond
1626 :
1627 : //! \name Overloaded Operators
1628 : //! \{
1629 :
1630 : template<typename Index>
1631 259696 : inline T& operator[](const Index& index) noexcept {
1632 : typedef typename Internal::StdInt<sizeof(Index), 1>::Type U;
1633 : ASMJIT_ASSERT(U(index) < N);
1634 5568013 : return _data[U(index)];
1635 : }
1636 :
1637 : template<typename Index>
1638 : inline const T& operator[](const Index& index) const noexcept {
1639 : typedef typename Internal::StdInt<sizeof(Index), 1>::Type U;
1640 : ASMJIT_ASSERT(U(index) < N);
1641 1252162 : return _data[U(index)];
1642 : }
1643 :
1644 : inline bool operator==(const Array& other) const noexcept {
1645 : for (size_t i = 0; i < N; i++)
1646 : if (_data[i] != other._data[i])
1647 : return false;
1648 : return true;
1649 : }
1650 :
1651 : inline bool operator!=(const Array& other) const noexcept {
1652 : return !operator==(other);
1653 : }
1654 :
1655 : //! \}
1656 :
1657 : //! \name Accessors
1658 : //! \{
1659 :
1660 : inline bool empty() const noexcept { return false; }
1661 : inline size_t size() const noexcept { return N; }
1662 :
1663 37131 : inline T* data() noexcept { return _data; }
1664 : inline const T* data() const noexcept { return _data; }
1665 :
1666 : inline T& front() noexcept { return _data[0]; }
1667 : inline const T& front() const noexcept { return _data[0]; }
1668 :
1669 : inline T& back() noexcept { return _data[N - 1]; }
1670 : inline const T& back() const noexcept { return _data[N - 1]; }
1671 :
1672 : inline T* begin() noexcept { return _data; }
1673 : inline T* end() noexcept { return _data + N; }
1674 :
1675 : inline const T* begin() const noexcept { return _data; }
1676 : inline const T* end() const noexcept { return _data + N; }
1677 :
1678 : inline const T* cbegin() const noexcept { return _data; }
1679 : inline const T* cend() const noexcept { return _data + N; }
1680 :
1681 : //! \}
1682 :
1683 : //! \name Utilities
1684 : //! \{
1685 :
1686 : inline void swap(Array& other) noexcept {
1687 0 : for (size_t i = 0; i < N; i++)
1688 : std::swap(_data[i], other._data[i]);
1689 : }
1690 :
1691 54984 : inline void fill(const T& value) noexcept {
1692 9440344 : for (size_t i = 0; i < N; i++)
1693 7508288 : _data[i] = value;
1694 54984 : }
1695 :
1696 : inline void copyFrom(const Array& other) noexcept {
1697 : for (size_t i = 0; i < N; i++)
1698 : _data[i] = other._data[i];
1699 : }
1700 :
1701 : template<typename Operator>
1702 : inline void combine(const Array& other) noexcept {
1703 2071420 : for (size_t i = 0; i < N; i++)
1704 1657136 : _data[i] = Operator::op(_data[i], other._data[i]);
1705 : }
1706 :
1707 : template<typename Operator>
1708 : inline T aggregate(T initialValue = T()) const noexcept {
1709 : T value = initialValue;
1710 : for (size_t i = 0; i < N; i++)
1711 : value = Operator::op(value, _data[i]);
1712 : return value;
1713 : }
1714 :
1715 : template<typename Fn>
1716 : inline void forEach(Fn&& fn) noexcept {
1717 549840 : for (size_t i = 0; i < N; i++)
1718 219936 : fn(_data[i]);
1719 : }
1720 : //! \}
1721 : };
1722 :
1723 : // Support::Temporary
1724 : // ==================
1725 :
1726 : //! Used to pass a temporary buffer to:
1727 : //!
1728 : //! - Containers that use user-passed buffer as an initial storage (still can grow).
1729 : //! - Zone allocator that would use the temporary buffer as a first block.
1730 : struct Temporary {
1731 : //! \name Members
1732 : //! \{
1733 :
1734 : void* _data;
1735 : size_t _size;
1736 :
1737 : //! \}
1738 :
1739 : //! \name Construction & Destruction
1740 : //! \{
1741 :
1742 : inline constexpr Temporary(const Temporary& other) noexcept = default;
1743 : inline constexpr Temporary(void* data, size_t size) noexcept
1744 : : _data(data),
1745 : _size(size) {}
1746 :
1747 : //! \}
1748 :
1749 : //! \name Overloaded Operators
1750 : //! \{
1751 :
1752 : inline Temporary& operator=(const Temporary& other) noexcept = default;
1753 :
1754 : //! \}
1755 :
1756 : //! \name Accessors
1757 : //! \{
1758 :
1759 : //! Returns the data storage.
1760 : template<typename T = void>
1761 0 : inline constexpr T* data() const noexcept { return static_cast<T*>(_data); }
1762 : //! Returns the data storage size in bytes.
1763 0 : inline constexpr size_t size() const noexcept { return _size; }
1764 :
1765 : //! \}
1766 : };
1767 :
1768 : } // {Support}
1769 :
1770 : //! \}
1771 :
1772 : ASMJIT_END_NAMESPACE
1773 :
1774 : #endif // ASMJIT_CORE_SUPPORT_H_INCLUDED
1775 :
1776 : #endif // __PLUMED_HAS_ASMJIT
|