Ruby  3.1.0dev(2021-09-10revisionb76ad15ed0da636161de0243c547ee1e6fc95681)
bits.h
Go to the documentation of this file.
1 #ifndef BIGDECIMAL_BITS_H
2 #define BIGDECIMAL_BITS_H
3 
4 #include "feature.h"
5 #include "static_assert.h"
6 
7 #if defined(__x86_64__) && defined(HAVE_X86INTRIN_H)
8 # include <x86intrin.h> /* for _lzcnt_u64, etc. */
9 #elif defined(_MSC_VER) && defined(HAVE_INTRIN_H)
10 # include <intrin.h> /* for the following intrinsics */
11 #endif
12 
13 #if defined(_MSC_VER) && defined(__AVX2__)
14 # pragma intrinsic(__lzcnt)
15 # pragma intrinsic(__lzcnt64)
16 #endif
17 
18 #define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
19 #define roomof(x, y) (((x) + (y) - 1) / (y))
20 #define type_roomof(x, y) roomof(sizeof(x), sizeof(y))
21 
22 #define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
23  (a) == 0 ? 0 : \
24  (a) == -1 ? (b) < -(max) : \
25  (a) > 0 ? \
26  ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
27  ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
28 
29 #ifdef HAVE_UINT128_T
30 # define bit_length(x) \
31  (unsigned int) \
32  (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
33  sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \
34  128 - nlz_int128((uint128_t)(x)))
35 #else
36 # define bit_length(x) \
37  (unsigned int) \
38  (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
39  64 - nlz_int64((uint64_t)(x)))
40 #endif
41 
42 static inline unsigned nlz_int32(uint32_t x);
43 static inline unsigned nlz_int64(uint64_t x);
44 #ifdef HAVE_UINT128_T
45 static inline unsigned nlz_int128(uint128_t x);
46 #endif
47 
48 static inline unsigned int
49 nlz_int32(uint32_t x)
50 {
51 #if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT)
52  /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC.
53  * AMD CPUs have had this instruction for decades (since K10) but for
54  * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum
55  * safety. */
56  return (unsigned int)__lzcnt(x);
57 
58 #elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U32)
59  return (unsigned int)_lzcnt_u32(x);
60 
61 #elif defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE)
62  unsigned long r;
63  return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
64 
65 #elif __has_builtin(__builtin_clz)
66  STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
67  return x ? (unsigned int)__builtin_clz(x) : 32;
68 
69 #else
70  uint32_t y;
71  unsigned n = 32;
72  y = x >> 16; if (y) {n -= 16; x = y;}
73  y = x >> 8; if (y) {n -= 8; x = y;}
74  y = x >> 4; if (y) {n -= 4; x = y;}
75  y = x >> 2; if (y) {n -= 2; x = y;}
76  y = x >> 1; if (y) {return n - 2;}
77  return (unsigned int)(n - x);
78 #endif
79 }
80 
81 static inline unsigned int
82 nlz_int64(uint64_t x)
83 {
84 #if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT64)
85  return (unsigned int)__lzcnt64(x);
86 
87 #elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U64)
88  return (unsigned int)_lzcnt_u64(x);
89 
90 #elif defined(_WIN64) && defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE64)
91  unsigned long r;
92  return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
93 
94 #elif __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll) && !(defined(__sun) && defined(__sparc))
95  if (x == 0) {
96  return 64;
97  }
98  else if (sizeof(long) * CHAR_BIT == 64) {
99  return (unsigned int)__builtin_clzl((unsigned long)x);
100  }
101  else if (sizeof(long long) * CHAR_BIT == 64) {
102  return (unsigned int)__builtin_clzll((unsigned long long)x);
103  }
104  else {
105  /* :FIXME: Is there a way to make this branch a compile-time error? */
106  __builtin_unreachable();
107  }
108 
109 #else
110  uint64_t y;
111  unsigned int n = 64;
112  y = x >> 32; if (y) {n -= 32; x = y;}
113  y = x >> 16; if (y) {n -= 16; x = y;}
114  y = x >> 8; if (y) {n -= 8; x = y;}
115  y = x >> 4; if (y) {n -= 4; x = y;}
116  y = x >> 2; if (y) {n -= 2; x = y;}
117  y = x >> 1; if (y) {return n - 2;}
118  return (unsigned int)(n - x);
119 
120 #endif
121 }
122 
123 #ifdef HAVE_UINT128_T
124 static inline unsigned int
125 nlz_int128(uint128_t x)
126 {
127  uint64_t y = (uint64_t)(x >> 64);
128 
129  if (x == 0) {
130  return 128;
131  }
132  else if (y == 0) {
133  return (unsigned int)nlz_int64(x) + 64;
134  }
135  else {
136  return (unsigned int)nlz_int64(y);
137  }
138 }
139 #endif
140 
141 #endif /* BIGDECIMAL_BITS_H */
STATIC_ASSERT
#define STATIC_ASSERT
Definition: static_assert.h:41
CHAR_BIT
#define CHAR_BIT
Definition: limits.h:44
uint64_t
unsigned long long uint64_t
Definition: sha2.h:102
y
size_t y
Definition: memory.h:207
uint32_t
unsigned int uint32_t
Definition: sha2.h:101
feature.h
static_assert.h