1 | /* |
2 | * Copyright (C) 2012-2019 Apple Inc. 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 |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | namespace JSC { |
29 | |
30 | ALWAYS_INLINE constexpr bool isIOS() |
31 | { |
32 | #if PLATFORM(IOS_FAMILY) |
33 | return true; |
34 | #else |
35 | return false; |
36 | #endif |
37 | } |
38 | |
39 | ALWAYS_INLINE bool isInt9(int32_t value) |
40 | { |
41 | return value == ((value << 23) >> 23); |
42 | } |
43 | |
44 | template<typename Type> |
45 | ALWAYS_INLINE bool isUInt12(Type value) |
46 | { |
47 | return !(value & ~static_cast<Type>(0xfff)); |
48 | } |
49 | |
50 | template<int datasize> |
51 | ALWAYS_INLINE bool isValidScaledUImm12(int32_t offset) |
52 | { |
53 | int32_t maxPImm = 4095 * (datasize / 8); |
54 | if (offset < 0) |
55 | return false; |
56 | if (offset > maxPImm) |
57 | return false; |
58 | if (offset & ((datasize / 8) - 1)) |
59 | return false; |
60 | return true; |
61 | } |
62 | |
63 | ALWAYS_INLINE bool isValidSignedImm9(int32_t value) |
64 | { |
65 | return isInt9(value); |
66 | } |
67 | |
68 | class ARM64LogicalImmediate { |
69 | public: |
70 | static ARM64LogicalImmediate create32(uint32_t value) |
71 | { |
72 | // Check for 0, -1 - these cannot be encoded. |
73 | if (!value || !~value) |
74 | return InvalidLogicalImmediate; |
75 | |
76 | // First look for a 32-bit pattern, then for repeating 16-bit |
77 | // patterns, 8-bit, 4-bit, and finally 2-bit. |
78 | |
79 | unsigned hsb, lsb; |
80 | bool inverted; |
81 | if (findBitRange<32>(value, hsb, lsb, inverted)) |
82 | return encodeLogicalImmediate<32>(hsb, lsb, inverted); |
83 | |
84 | if ((value & 0xffff) != (value >> 16)) |
85 | return InvalidLogicalImmediate; |
86 | value &= 0xffff; |
87 | |
88 | if (findBitRange<16>(value, hsb, lsb, inverted)) |
89 | return encodeLogicalImmediate<16>(hsb, lsb, inverted); |
90 | |
91 | if ((value & 0xff) != (value >> 8)) |
92 | return InvalidLogicalImmediate; |
93 | value &= 0xff; |
94 | |
95 | if (findBitRange<8>(value, hsb, lsb, inverted)) |
96 | return encodeLogicalImmediate<8>(hsb, lsb, inverted); |
97 | |
98 | if ((value & 0xf) != (value >> 4)) |
99 | return InvalidLogicalImmediate; |
100 | value &= 0xf; |
101 | |
102 | if (findBitRange<4>(value, hsb, lsb, inverted)) |
103 | return encodeLogicalImmediate<4>(hsb, lsb, inverted); |
104 | |
105 | if ((value & 0x3) != (value >> 2)) |
106 | return InvalidLogicalImmediate; |
107 | value &= 0x3; |
108 | |
109 | if (findBitRange<2>(value, hsb, lsb, inverted)) |
110 | return encodeLogicalImmediate<2>(hsb, lsb, inverted); |
111 | |
112 | return InvalidLogicalImmediate; |
113 | } |
114 | |
115 | static ARM64LogicalImmediate create64(uint64_t value) |
116 | { |
117 | // Check for 0, -1 - these cannot be encoded. |
118 | if (!value || !~value) |
119 | return InvalidLogicalImmediate; |
120 | |
121 | // Look for a contiguous bit range. |
122 | unsigned hsb, lsb; |
123 | bool inverted; |
124 | if (findBitRange<64>(value, hsb, lsb, inverted)) |
125 | return encodeLogicalImmediate<64>(hsb, lsb, inverted); |
126 | |
127 | // If the high & low 32 bits are equal, we can try for a 32-bit (or narrower) pattern. |
128 | if (static_cast<uint32_t>(value) == static_cast<uint32_t>(value >> 32)) |
129 | return create32(static_cast<uint32_t>(value)); |
130 | return InvalidLogicalImmediate; |
131 | } |
132 | |
133 | int value() const |
134 | { |
135 | ASSERT(isValid()); |
136 | return m_value; |
137 | } |
138 | |
139 | bool isValid() const |
140 | { |
141 | return m_value != InvalidLogicalImmediate; |
142 | } |
143 | |
144 | bool is64bit() const |
145 | { |
146 | return m_value & (1 << 12); |
147 | } |
148 | |
149 | private: |
150 | ARM64LogicalImmediate(int value) |
151 | : m_value(value) |
152 | { |
153 | } |
154 | |
155 | // Generate a mask with bits in the range hsb..0 set, for example: |
156 | // hsb:63 = 0xffffffffffffffff |
157 | // hsb:42 = 0x000007ffffffffff |
158 | // hsb: 0 = 0x0000000000000001 |
159 | static uint64_t mask(unsigned hsb) |
160 | { |
161 | ASSERT(hsb < 64); |
162 | return 0xffffffffffffffffull >> (63 - hsb); |
163 | } |
164 | |
165 | template<unsigned N> |
166 | static void partialHSB(uint64_t& value, unsigned&result) |
167 | { |
168 | if (value & (0xffffffffffffffffull << N)) { |
169 | result += N; |
170 | value >>= N; |
171 | } |
172 | } |
173 | |
174 | // Find the bit number of the highest bit set in a non-zero value, for example: |
175 | // 0x8080808080808080 = hsb:63 |
176 | // 0x0000000000000001 = hsb: 0 |
177 | // 0x000007ffffe00000 = hsb:42 |
178 | static unsigned highestSetBit(uint64_t value) |
179 | { |
180 | ASSERT(value); |
181 | unsigned hsb = 0; |
182 | partialHSB<32>(value, hsb); |
183 | partialHSB<16>(value, hsb); |
184 | partialHSB<8>(value, hsb); |
185 | partialHSB<4>(value, hsb); |
186 | partialHSB<2>(value, hsb); |
187 | partialHSB<1>(value, hsb); |
188 | return hsb; |
189 | } |
190 | |
191 | // This function takes a value and a bit width, where value obeys the following constraints: |
192 | // * bits outside of the width of the value must be zero. |
193 | // * bits within the width of value must neither be all clear or all set. |
194 | // The input is inspected to detect values that consist of either two or three contiguous |
195 | // ranges of bits. The output range hsb..lsb will describe the second range of the value. |
196 | // if the range is set, inverted will be false, and if the range is clear, inverted will |
197 | // be true. For example (with width 8): |
198 | // 00001111 = hsb:3, lsb:0, inverted:false |
199 | // 11110000 = hsb:3, lsb:0, inverted:true |
200 | // 00111100 = hsb:5, lsb:2, inverted:false |
201 | // 11000011 = hsb:5, lsb:2, inverted:true |
202 | template<unsigned width> |
203 | static bool findBitRange(uint64_t value, unsigned& hsb, unsigned& lsb, bool& inverted) |
204 | { |
205 | ASSERT(value & mask(width - 1)); |
206 | ASSERT(value != mask(width - 1)); |
207 | ASSERT(!(value & ~mask(width - 1))); |
208 | |
209 | // Detect cases where the top bit is set; if so, flip all the bits & set invert. |
210 | // This halves the number of patterns we need to look for. |
211 | const uint64_t msb = 1ull << (width - 1); |
212 | if ((inverted = (value & msb))) |
213 | value ^= mask(width - 1); |
214 | |
215 | // Find the highest set bit in value, generate a corresponding mask & flip all |
216 | // bits under it. |
217 | hsb = highestSetBit(value); |
218 | value ^= mask(hsb); |
219 | if (!value) { |
220 | // If this cleared the value, then the range hsb..0 was all set. |
221 | lsb = 0; |
222 | return true; |
223 | } |
224 | |
225 | // Try making one more mask, and flipping the bits! |
226 | lsb = highestSetBit(value); |
227 | value ^= mask(lsb); |
228 | if (!value) { |
229 | // Success - but lsb actually points to the hsb of a third range - add one |
230 | // to get to the lsb of the mid range. |
231 | ++lsb; |
232 | return true; |
233 | } |
234 | |
235 | return false; |
236 | } |
237 | |
238 | // Encodes the set of immN:immr:imms fields found in a logical immediate. |
239 | template<unsigned width> |
240 | static int encodeLogicalImmediate(unsigned hsb, unsigned lsb, bool inverted) |
241 | { |
242 | // Check width is a power of 2! |
243 | ASSERT(!(width & (width -1))); |
244 | ASSERT(width <= 64 && width >= 2); |
245 | ASSERT(hsb >= lsb); |
246 | ASSERT(hsb < width); |
247 | |
248 | int immN = 0; |
249 | int imms = 0; |
250 | int immr = 0; |
251 | |
252 | // For 64-bit values this is easy - just set immN to true, and imms just |
253 | // contains the bit number of the highest set bit of the set range. For |
254 | // values with narrower widths, these are encoded by a leading set of |
255 | // one bits, followed by a zero bit, followed by the remaining set of bits |
256 | // being the high bit of the range. For a 32-bit immediate there are no |
257 | // leading one bits, just a zero followed by a five bit number. For a |
258 | // 16-bit immediate there is one one bit, a zero bit, and then a four bit |
259 | // bit-position, etc. |
260 | if (width == 64) |
261 | immN = 1; |
262 | else |
263 | imms = 63 & ~(width + width - 1); |
264 | |
265 | if (inverted) { |
266 | // if width is 64 & hsb is 62, then we have a value something like: |
267 | // 0x80000000ffffffff (in this case with lsb 32). |
268 | // The ror should be by 1, imms (effectively set width minus 1) is |
269 | // 32. Set width is full width minus cleared width. |
270 | immr = (width - 1) - hsb; |
271 | imms |= (width - ((hsb - lsb) + 1)) - 1; |
272 | } else { |
273 | // if width is 64 & hsb is 62, then we have a value something like: |
274 | // 0x7fffffff00000000 (in this case with lsb 32). |
275 | // The value is effectively rol'ed by lsb, which is equivalent to |
276 | // a ror by width - lsb (or 0, in the case where lsb is 0). imms |
277 | // is hsb - lsb. |
278 | immr = (width - lsb) & (width - 1); |
279 | imms |= hsb - lsb; |
280 | } |
281 | |
282 | return immN << 12 | immr << 6 | imms; |
283 | } |
284 | |
285 | static constexpr int InvalidLogicalImmediate = -1; |
286 | |
287 | int m_value; |
288 | }; |
289 | |
290 | } // namespace JSC. |
291 | |