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
28namespace JSC {
29
30ALWAYS_INLINE constexpr bool isIOS()
31{
32#if PLATFORM(IOS_FAMILY)
33 return true;
34#else
35 return false;
36#endif
37}
38
39ALWAYS_INLINE bool isInt9(int32_t value)
40{
41 return value == ((value << 23) >> 23);
42}
43
44template<typename Type>
45ALWAYS_INLINE bool isUInt12(Type value)
46{
47 return !(value & ~static_cast<Type>(0xfff));
48}
49
50template<int datasize>
51ALWAYS_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
63ALWAYS_INLINE bool isValidSignedImm9(int32_t value)
64{
65 return isInt9(value);
66}
67
68class ARM64LogicalImmediate {
69public:
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
149private:
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