]>
Commit | Line | Data |
---|---|---|
878a735d PM |
1 | // Copyright 2013, ARM Limited |
2 | // All rights reserved. | |
3 | // | |
4 | // Redistribution and use in source and binary forms, with or without | |
5 | // modification, are permitted provided that the following conditions are met: | |
6 | // | |
7 | // * Redistributions of source code must retain the above copyright notice, | |
8 | // this list of conditions and the following disclaimer. | |
9 | // * Redistributions in binary form must reproduce the above copyright notice, | |
10 | // this list of conditions and the following disclaimer in the documentation | |
11 | // and/or other materials provided with the distribution. | |
12 | // * Neither the name of ARM Limited nor the names of its contributors may be | |
13 | // used to endorse or promote products derived from this software without | |
14 | // specific prior written permission. | |
15 | // | |
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND | |
17 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
18 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
19 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
20 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
24 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 | ||
27 | #ifndef VIXL_UTILS_H | |
28 | #define VIXL_UTILS_H | |
29 | ||
09319b30 | 30 | #include <math.h> |
878a735d PM |
31 | #include <string.h> |
32 | #include "globals.h" | |
33 | ||
34 | namespace vixl { | |
35 | ||
508280f5 PM |
36 | // Macros for compile-time format checking. |
37 | #if defined(__GNUC__) | |
38 | #define PRINTF_CHECK(format_index, varargs_index) \ | |
39 | __attribute__((format(printf, format_index, varargs_index))) | |
40 | #else | |
41 | #define PRINTF_CHECK(format_index, varargs_index) | |
42 | #endif | |
43 | ||
878a735d PM |
44 | // Check number width. |
45 | inline bool is_intn(unsigned n, int64_t x) { | |
09319b30 PM |
46 | VIXL_ASSERT((0 < n) && (n < 64)); |
47 | int64_t limit = INT64_C(1) << (n - 1); | |
878a735d PM |
48 | return (-limit <= x) && (x < limit); |
49 | } | |
50 | ||
51 | inline bool is_uintn(unsigned n, int64_t x) { | |
09319b30 | 52 | VIXL_ASSERT((0 < n) && (n < 64)); |
878a735d PM |
53 | return !(x >> n); |
54 | } | |
55 | ||
56 | inline unsigned truncate_to_intn(unsigned n, int64_t x) { | |
09319b30 PM |
57 | VIXL_ASSERT((0 < n) && (n < 64)); |
58 | return (x & ((INT64_C(1) << n) - 1)); | |
878a735d PM |
59 | } |
60 | ||
61 | #define INT_1_TO_63_LIST(V) \ | |
62 | V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) \ | |
63 | V(9) V(10) V(11) V(12) V(13) V(14) V(15) V(16) \ | |
64 | V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) \ | |
65 | V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32) \ | |
66 | V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \ | |
67 | V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) \ | |
68 | V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56) \ | |
69 | V(57) V(58) V(59) V(60) V(61) V(62) V(63) | |
70 | ||
71 | #define DECLARE_IS_INT_N(N) \ | |
72 | inline bool is_int##N(int64_t x) { return is_intn(N, x); } | |
73 | #define DECLARE_IS_UINT_N(N) \ | |
74 | inline bool is_uint##N(int64_t x) { return is_uintn(N, x); } | |
75 | #define DECLARE_TRUNCATE_TO_INT_N(N) \ | |
76 | inline int truncate_to_int##N(int x) { return truncate_to_intn(N, x); } | |
77 | INT_1_TO_63_LIST(DECLARE_IS_INT_N) | |
78 | INT_1_TO_63_LIST(DECLARE_IS_UINT_N) | |
79 | INT_1_TO_63_LIST(DECLARE_TRUNCATE_TO_INT_N) | |
80 | #undef DECLARE_IS_INT_N | |
81 | #undef DECLARE_IS_UINT_N | |
82 | #undef DECLARE_TRUNCATE_TO_INT_N | |
83 | ||
84 | // Bit field extraction. | |
85 | inline uint32_t unsigned_bitextract_32(int msb, int lsb, uint32_t x) { | |
86 | return (x >> lsb) & ((1 << (1 + msb - lsb)) - 1); | |
87 | } | |
88 | ||
89 | inline uint64_t unsigned_bitextract_64(int msb, int lsb, uint64_t x) { | |
90 | return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1); | |
91 | } | |
92 | ||
93 | inline int32_t signed_bitextract_32(int msb, int lsb, int32_t x) { | |
94 | return (x << (31 - msb)) >> (lsb + 31 - msb); | |
95 | } | |
96 | ||
97 | inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) { | |
98 | return (x << (63 - msb)) >> (lsb + 63 - msb); | |
99 | } | |
100 | ||
09319b30 | 101 | // Floating point representation. |
878a735d PM |
102 | uint32_t float_to_rawbits(float value); |
103 | uint64_t double_to_rawbits(double value); | |
104 | float rawbits_to_float(uint32_t bits); | |
105 | double rawbits_to_double(uint64_t bits); | |
106 | ||
09319b30 PM |
107 | |
108 | // NaN tests. | |
109 | inline bool IsSignallingNaN(double num) { | |
110 | const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); | |
111 | uint64_t raw = double_to_rawbits(num); | |
112 | if (isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) { | |
113 | return true; | |
114 | } | |
115 | return false; | |
116 | } | |
117 | ||
118 | ||
119 | inline bool IsSignallingNaN(float num) { | |
120 | const uint32_t kFP32QuietNaNMask = 0x00400000; | |
121 | uint32_t raw = float_to_rawbits(num); | |
122 | if (isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) { | |
123 | return true; | |
124 | } | |
125 | return false; | |
126 | } | |
127 | ||
128 | ||
129 | template <typename T> | |
130 | inline bool IsQuietNaN(T num) { | |
131 | return isnan(num) && !IsSignallingNaN(num); | |
132 | } | |
133 | ||
134 | ||
135 | // Convert the NaN in 'num' to a quiet NaN. | |
136 | inline double ToQuietNaN(double num) { | |
137 | const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000); | |
138 | VIXL_ASSERT(isnan(num)); | |
139 | return rawbits_to_double(double_to_rawbits(num) | kFP64QuietNaNMask); | |
140 | } | |
141 | ||
142 | ||
143 | inline float ToQuietNaN(float num) { | |
144 | const uint32_t kFP32QuietNaNMask = 0x00400000; | |
145 | VIXL_ASSERT(isnan(num)); | |
146 | return rawbits_to_float(float_to_rawbits(num) | kFP32QuietNaNMask); | |
147 | } | |
148 | ||
149 | ||
150 | // Fused multiply-add. | |
151 | inline double FusedMultiplyAdd(double op1, double op2, double a) { | |
152 | return fma(op1, op2, a); | |
153 | } | |
154 | ||
155 | ||
156 | inline float FusedMultiplyAdd(float op1, float op2, float a) { | |
157 | return fmaf(op1, op2, a); | |
158 | } | |
159 | ||
160 | ||
161 | // Bit counting. | |
878a735d PM |
162 | int CountLeadingZeros(uint64_t value, int width); |
163 | int CountLeadingSignBits(int64_t value, int width); | |
164 | int CountTrailingZeros(uint64_t value, int width); | |
165 | int CountSetBits(uint64_t value, int width); | |
508280f5 PM |
166 | uint64_t LowestSetBit(uint64_t value); |
167 | bool IsPowerOf2(int64_t value); | |
878a735d PM |
168 | |
169 | // Pointer alignment | |
170 | // TODO: rename/refactor to make it specific to instructions. | |
171 | template<typename T> | |
172 | bool IsWordAligned(T pointer) { | |
09319b30 | 173 | VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof) |
878a735d PM |
174 | return (reinterpret_cast<intptr_t>(pointer) & 3) == 0; |
175 | } | |
176 | ||
177 | // Increment a pointer until it has the specified alignment. | |
178 | template<class T> | |
179 | T AlignUp(T pointer, size_t alignment) { | |
508280f5 PM |
180 | // Use C-style casts to get static_cast behaviour for integral types (T), and |
181 | // reinterpret_cast behaviour for other types. | |
182 | ||
183 | uintptr_t pointer_raw = (uintptr_t)pointer; | |
184 | VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(pointer_raw)); | |
185 | ||
878a735d | 186 | size_t align_step = (alignment - pointer_raw) % alignment; |
09319b30 | 187 | VIXL_ASSERT((pointer_raw + align_step) % alignment == 0); |
508280f5 PM |
188 | |
189 | return (T)(pointer_raw + align_step); | |
878a735d PM |
190 | } |
191 | ||
09319b30 PM |
192 | // Decrement a pointer until it has the specified alignment. |
193 | template<class T> | |
194 | T AlignDown(T pointer, size_t alignment) { | |
508280f5 PM |
195 | // Use C-style casts to get static_cast behaviour for integral types (T), and |
196 | // reinterpret_cast behaviour for other types. | |
197 | ||
198 | uintptr_t pointer_raw = (uintptr_t)pointer; | |
199 | VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(pointer_raw)); | |
200 | ||
09319b30 PM |
201 | size_t align_step = pointer_raw % alignment; |
202 | VIXL_ASSERT((pointer_raw - align_step) % alignment == 0); | |
508280f5 PM |
203 | |
204 | return (T)(pointer_raw - align_step); | |
09319b30 PM |
205 | } |
206 | ||
878a735d PM |
207 | |
208 | } // namespace vixl | |
209 | ||
210 | #endif // VIXL_UTILS_H |