1 | //===- AArch64AddressingModes.h - AArch64 Addressing Modes ------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains the AArch64 addressing mode implementation stuff. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H |
14 | #define LLVM_LIB_TARGET_AARCH64_MCTARGETDESC_AARCH64ADDRESSINGMODES_H |
15 | |
16 | #include "llvm/ADT/APFloat.h" |
17 | #include "llvm/ADT/APInt.h" |
18 | #include "llvm/ADT/bit.h" |
19 | #include "llvm/Support/ErrorHandling.h" |
20 | #include "llvm/Support/MathExtras.h" |
21 | #include <cassert> |
22 | |
23 | namespace llvm { |
24 | |
25 | /// AArch64_AM - AArch64 Addressing Mode Stuff |
26 | namespace AArch64_AM { |
27 | |
28 | //===----------------------------------------------------------------------===// |
29 | // Shifts |
30 | // |
31 | |
32 | enum ShiftExtendType { |
33 | InvalidShiftExtend = -1, |
34 | LSL = 0, |
35 | LSR, |
36 | ASR, |
37 | ROR, |
38 | MSL, |
39 | |
40 | UXTB, |
41 | UXTH, |
42 | UXTW, |
43 | UXTX, |
44 | |
45 | SXTB, |
46 | SXTH, |
47 | SXTW, |
48 | SXTX, |
49 | }; |
50 | |
51 | /// getShiftName - Get the string encoding for the shift type. |
52 | static inline const char *getShiftExtendName(AArch64_AM::ShiftExtendType ST) { |
53 | switch (ST) { |
54 | default: llvm_unreachable("unhandled shift type!" ); |
55 | case AArch64_AM::LSL: return "lsl" ; |
56 | case AArch64_AM::LSR: return "lsr" ; |
57 | case AArch64_AM::ASR: return "asr" ; |
58 | case AArch64_AM::ROR: return "ror" ; |
59 | case AArch64_AM::MSL: return "msl" ; |
60 | case AArch64_AM::UXTB: return "uxtb" ; |
61 | case AArch64_AM::UXTH: return "uxth" ; |
62 | case AArch64_AM::UXTW: return "uxtw" ; |
63 | case AArch64_AM::UXTX: return "uxtx" ; |
64 | case AArch64_AM::SXTB: return "sxtb" ; |
65 | case AArch64_AM::SXTH: return "sxth" ; |
66 | case AArch64_AM::SXTW: return "sxtw" ; |
67 | case AArch64_AM::SXTX: return "sxtx" ; |
68 | } |
69 | return nullptr; |
70 | } |
71 | |
72 | /// getShiftType - Extract the shift type. |
73 | static inline AArch64_AM::ShiftExtendType getShiftType(unsigned Imm) { |
74 | switch ((Imm >> 6) & 0x7) { |
75 | default: return AArch64_AM::InvalidShiftExtend; |
76 | case 0: return AArch64_AM::LSL; |
77 | case 1: return AArch64_AM::LSR; |
78 | case 2: return AArch64_AM::ASR; |
79 | case 3: return AArch64_AM::ROR; |
80 | case 4: return AArch64_AM::MSL; |
81 | } |
82 | } |
83 | |
84 | /// getShiftValue - Extract the shift value. |
85 | static inline unsigned getShiftValue(unsigned Imm) { |
86 | return Imm & 0x3f; |
87 | } |
88 | |
89 | /// getShifterImm - Encode the shift type and amount: |
90 | /// imm: 6-bit shift amount |
91 | /// shifter: 000 ==> lsl |
92 | /// 001 ==> lsr |
93 | /// 010 ==> asr |
94 | /// 011 ==> ror |
95 | /// 100 ==> msl |
96 | /// {8-6} = shifter |
97 | /// {5-0} = imm |
98 | static inline unsigned getShifterImm(AArch64_AM::ShiftExtendType ST, |
99 | unsigned Imm) { |
100 | assert((Imm & 0x3f) == Imm && "Illegal shifted immedate value!" ); |
101 | unsigned STEnc = 0; |
102 | switch (ST) { |
103 | default: llvm_unreachable("Invalid shift requested" ); |
104 | case AArch64_AM::LSL: STEnc = 0; break; |
105 | case AArch64_AM::LSR: STEnc = 1; break; |
106 | case AArch64_AM::ASR: STEnc = 2; break; |
107 | case AArch64_AM::ROR: STEnc = 3; break; |
108 | case AArch64_AM::MSL: STEnc = 4; break; |
109 | } |
110 | return (STEnc << 6) | (Imm & 0x3f); |
111 | } |
112 | |
113 | //===----------------------------------------------------------------------===// |
114 | // Extends |
115 | // |
116 | |
117 | /// getArithShiftValue - get the arithmetic shift value. |
118 | static inline unsigned getArithShiftValue(unsigned Imm) { |
119 | return Imm & 0x7; |
120 | } |
121 | |
122 | /// getExtendType - Extract the extend type for operands of arithmetic ops. |
123 | static inline AArch64_AM::ShiftExtendType getExtendType(unsigned Imm) { |
124 | assert((Imm & 0x7) == Imm && "invalid immediate!" ); |
125 | switch (Imm) { |
126 | default: llvm_unreachable("Compiler bug!" ); |
127 | case 0: return AArch64_AM::UXTB; |
128 | case 1: return AArch64_AM::UXTH; |
129 | case 2: return AArch64_AM::UXTW; |
130 | case 3: return AArch64_AM::UXTX; |
131 | case 4: return AArch64_AM::SXTB; |
132 | case 5: return AArch64_AM::SXTH; |
133 | case 6: return AArch64_AM::SXTW; |
134 | case 7: return AArch64_AM::SXTX; |
135 | } |
136 | } |
137 | |
138 | static inline AArch64_AM::ShiftExtendType getArithExtendType(unsigned Imm) { |
139 | return getExtendType(Imm: (Imm >> 3) & 0x7); |
140 | } |
141 | |
142 | /// Mapping from extend bits to required operation: |
143 | /// shifter: 000 ==> uxtb |
144 | /// 001 ==> uxth |
145 | /// 010 ==> uxtw |
146 | /// 011 ==> uxtx |
147 | /// 100 ==> sxtb |
148 | /// 101 ==> sxth |
149 | /// 110 ==> sxtw |
150 | /// 111 ==> sxtx |
151 | inline unsigned getExtendEncoding(AArch64_AM::ShiftExtendType ET) { |
152 | switch (ET) { |
153 | default: llvm_unreachable("Invalid extend type requested" ); |
154 | case AArch64_AM::UXTB: return 0; break; |
155 | case AArch64_AM::UXTH: return 1; break; |
156 | case AArch64_AM::UXTW: return 2; break; |
157 | case AArch64_AM::UXTX: return 3; break; |
158 | case AArch64_AM::SXTB: return 4; break; |
159 | case AArch64_AM::SXTH: return 5; break; |
160 | case AArch64_AM::SXTW: return 6; break; |
161 | case AArch64_AM::SXTX: return 7; break; |
162 | } |
163 | } |
164 | |
165 | /// getArithExtendImm - Encode the extend type and shift amount for an |
166 | /// arithmetic instruction: |
167 | /// imm: 3-bit extend amount |
168 | /// {5-3} = shifter |
169 | /// {2-0} = imm3 |
170 | static inline unsigned getArithExtendImm(AArch64_AM::ShiftExtendType ET, |
171 | unsigned Imm) { |
172 | assert((Imm & 0x7) == Imm && "Illegal shifted immedate value!" ); |
173 | return (getExtendEncoding(ET) << 3) | (Imm & 0x7); |
174 | } |
175 | |
176 | /// getMemDoShift - Extract the "do shift" flag value for load/store |
177 | /// instructions. |
178 | static inline bool getMemDoShift(unsigned Imm) { |
179 | return (Imm & 0x1) != 0; |
180 | } |
181 | |
182 | /// getExtendType - Extract the extend type for the offset operand of |
183 | /// loads/stores. |
184 | static inline AArch64_AM::ShiftExtendType getMemExtendType(unsigned Imm) { |
185 | return getExtendType(Imm: (Imm >> 1) & 0x7); |
186 | } |
187 | |
188 | /// getExtendImm - Encode the extend type and amount for a load/store inst: |
189 | /// doshift: should the offset be scaled by the access size |
190 | /// shifter: 000 ==> uxtb |
191 | /// 001 ==> uxth |
192 | /// 010 ==> uxtw |
193 | /// 011 ==> uxtx |
194 | /// 100 ==> sxtb |
195 | /// 101 ==> sxth |
196 | /// 110 ==> sxtw |
197 | /// 111 ==> sxtx |
198 | /// {3-1} = shifter |
199 | /// {0} = doshift |
200 | static inline unsigned getMemExtendImm(AArch64_AM::ShiftExtendType ET, |
201 | bool DoShift) { |
202 | return (getExtendEncoding(ET) << 1) | unsigned(DoShift); |
203 | } |
204 | |
205 | static inline uint64_t ror(uint64_t elt, unsigned size) { |
206 | return ((elt & 1) << (size-1)) | (elt >> 1); |
207 | } |
208 | |
209 | /// processLogicalImmediate - Determine if an immediate value can be encoded |
210 | /// as the immediate operand of a logical instruction for the given register |
211 | /// size. If so, return true with "encoding" set to the encoded value in |
212 | /// the form N:immr:imms. |
213 | static inline bool processLogicalImmediate(uint64_t Imm, unsigned RegSize, |
214 | uint64_t &Encoding) { |
215 | if (Imm == 0ULL || Imm == ~0ULL || |
216 | (RegSize != 64 && |
217 | (Imm >> RegSize != 0 || Imm == (~0ULL >> (64 - RegSize))))) |
218 | return false; |
219 | |
220 | // First, determine the element size. |
221 | unsigned Size = RegSize; |
222 | |
223 | do { |
224 | Size /= 2; |
225 | uint64_t Mask = (1ULL << Size) - 1; |
226 | |
227 | if ((Imm & Mask) != ((Imm >> Size) & Mask)) { |
228 | Size *= 2; |
229 | break; |
230 | } |
231 | } while (Size > 2); |
232 | |
233 | // Second, determine the rotation to make the element be: 0^m 1^n. |
234 | uint32_t CTO, I; |
235 | uint64_t Mask = ((uint64_t)-1LL) >> (64 - Size); |
236 | Imm &= Mask; |
237 | |
238 | if (isShiftedMask_64(Value: Imm)) { |
239 | I = llvm::countr_zero(Val: Imm); |
240 | assert(I < 64 && "undefined behavior" ); |
241 | CTO = llvm::countr_one(Value: Imm >> I); |
242 | } else { |
243 | Imm |= ~Mask; |
244 | if (!isShiftedMask_64(Value: ~Imm)) |
245 | return false; |
246 | |
247 | unsigned CLO = llvm::countl_one(Value: Imm); |
248 | I = 64 - CLO; |
249 | CTO = CLO + llvm::countr_one(Value: Imm) - (64 - Size); |
250 | } |
251 | |
252 | // Encode in Immr the number of RORs it would take to get *from* 0^m 1^n |
253 | // to our target value, where I is the number of RORs to go the opposite |
254 | // direction. |
255 | assert(Size > I && "I should be smaller than element size" ); |
256 | unsigned Immr = (Size - I) & (Size - 1); |
257 | |
258 | // If size has a 1 in the n'th bit, create a value that has zeroes in |
259 | // bits [0, n] and ones above that. |
260 | uint64_t NImms = ~(Size-1) << 1; |
261 | |
262 | // Or the CTO value into the low bits, which must be below the Nth bit |
263 | // bit mentioned above. |
264 | NImms |= (CTO-1); |
265 | |
266 | // Extract the seventh bit and toggle it to create the N field. |
267 | unsigned N = ((NImms >> 6) & 1) ^ 1; |
268 | |
269 | Encoding = (N << 12) | (Immr << 6) | (NImms & 0x3f); |
270 | return true; |
271 | } |
272 | |
273 | /// isLogicalImmediate - Return true if the immediate is valid for a logical |
274 | /// immediate instruction of the given register size. Return false otherwise. |
275 | static inline bool isLogicalImmediate(uint64_t imm, unsigned regSize) { |
276 | uint64_t encoding; |
277 | return processLogicalImmediate(Imm: imm, RegSize: regSize, Encoding&: encoding); |
278 | } |
279 | |
280 | /// encodeLogicalImmediate - Return the encoded immediate value for a logical |
281 | /// immediate instruction of the given register size. |
282 | static inline uint64_t encodeLogicalImmediate(uint64_t imm, unsigned regSize) { |
283 | uint64_t encoding = 0; |
284 | bool res = processLogicalImmediate(Imm: imm, RegSize: regSize, Encoding&: encoding); |
285 | assert(res && "invalid logical immediate" ); |
286 | (void)res; |
287 | return encoding; |
288 | } |
289 | |
290 | /// decodeLogicalImmediate - Decode a logical immediate value in the form |
291 | /// "N:immr:imms" (where the immr and imms fields are each 6 bits) into the |
292 | /// integer value it represents with regSize bits. |
293 | static inline uint64_t decodeLogicalImmediate(uint64_t val, unsigned regSize) { |
294 | // Extract the N, imms, and immr fields. |
295 | unsigned N = (val >> 12) & 1; |
296 | unsigned immr = (val >> 6) & 0x3f; |
297 | unsigned imms = val & 0x3f; |
298 | |
299 | assert((regSize == 64 || N == 0) && "undefined logical immediate encoding" ); |
300 | int len = 31 - llvm::countl_zero(Val: (N << 6) | (~imms & 0x3f)); |
301 | assert(len >= 0 && "undefined logical immediate encoding" ); |
302 | unsigned size = (1 << len); |
303 | unsigned R = immr & (size - 1); |
304 | unsigned S = imms & (size - 1); |
305 | assert(S != size - 1 && "undefined logical immediate encoding" ); |
306 | uint64_t pattern = (1ULL << (S + 1)) - 1; |
307 | for (unsigned i = 0; i < R; ++i) |
308 | pattern = ror(elt: pattern, size); |
309 | |
310 | // Replicate the pattern to fill the regSize. |
311 | while (size != regSize) { |
312 | pattern |= (pattern << size); |
313 | size *= 2; |
314 | } |
315 | return pattern; |
316 | } |
317 | |
318 | /// isValidDecodeLogicalImmediate - Check to see if the logical immediate value |
319 | /// in the form "N:immr:imms" (where the immr and imms fields are each 6 bits) |
320 | /// is a valid encoding for an integer value with regSize bits. |
321 | static inline bool isValidDecodeLogicalImmediate(uint64_t val, |
322 | unsigned regSize) { |
323 | // Extract the N and imms fields needed for checking. |
324 | unsigned N = (val >> 12) & 1; |
325 | unsigned imms = val & 0x3f; |
326 | |
327 | if (regSize == 32 && N != 0) // undefined logical immediate encoding |
328 | return false; |
329 | int len = 31 - llvm::countl_zero(Val: (N << 6) | (~imms & 0x3f)); |
330 | if (len < 0) // undefined logical immediate encoding |
331 | return false; |
332 | unsigned size = (1 << len); |
333 | unsigned S = imms & (size - 1); |
334 | if (S == size - 1) // undefined logical immediate encoding |
335 | return false; |
336 | |
337 | return true; |
338 | } |
339 | |
340 | //===----------------------------------------------------------------------===// |
341 | // Floating-point Immediates |
342 | // |
343 | static inline float getFPImmFloat(unsigned Imm) { |
344 | // We expect an 8-bit binary encoding of a floating-point number here. |
345 | |
346 | uint8_t Sign = (Imm >> 7) & 0x1; |
347 | uint8_t Exp = (Imm >> 4) & 0x7; |
348 | uint8_t Mantissa = Imm & 0xf; |
349 | |
350 | // 8-bit FP IEEE Float Encoding |
351 | // abcd efgh aBbbbbbc defgh000 00000000 00000000 |
352 | // |
353 | // where B = NOT(b); |
354 | |
355 | uint32_t I = 0; |
356 | I |= Sign << 31; |
357 | I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30; |
358 | I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25; |
359 | I |= (Exp & 0x3) << 23; |
360 | I |= Mantissa << 19; |
361 | return bit_cast<float>(from: I); |
362 | } |
363 | |
364 | /// getFP16Imm - Return an 8-bit floating-point version of the 16-bit |
365 | /// floating-point value. If the value cannot be represented as an 8-bit |
366 | /// floating-point value, then return -1. |
367 | static inline int getFP16Imm(const APInt &Imm) { |
368 | uint32_t Sign = Imm.lshr(shiftAmt: 15).getZExtValue() & 1; |
369 | int32_t Exp = (Imm.lshr(shiftAmt: 10).getSExtValue() & 0x1f) - 15; // -14 to 15 |
370 | int32_t Mantissa = Imm.getZExtValue() & 0x3ff; // 10 bits |
371 | |
372 | // We can handle 4 bits of mantissa. |
373 | // mantissa = (16+UInt(e:f:g:h))/16. |
374 | if (Mantissa & 0x3f) |
375 | return -1; |
376 | Mantissa >>= 6; |
377 | |
378 | // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 |
379 | if (Exp < -3 || Exp > 4) |
380 | return -1; |
381 | Exp = ((Exp+3) & 0x7) ^ 4; |
382 | |
383 | return ((int)Sign << 7) | (Exp << 4) | Mantissa; |
384 | } |
385 | |
386 | static inline int getFP16Imm(const APFloat &FPImm) { |
387 | return getFP16Imm(Imm: FPImm.bitcastToAPInt()); |
388 | } |
389 | |
390 | /// getFP32Imm - Return an 8-bit floating-point version of the 32-bit |
391 | /// floating-point value. If the value cannot be represented as an 8-bit |
392 | /// floating-point value, then return -1. |
393 | static inline int getFP32Imm(const APInt &Imm) { |
394 | uint32_t Sign = Imm.lshr(shiftAmt: 31).getZExtValue() & 1; |
395 | int32_t Exp = (Imm.lshr(shiftAmt: 23).getSExtValue() & 0xff) - 127; // -126 to 127 |
396 | int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits |
397 | |
398 | // We can handle 4 bits of mantissa. |
399 | // mantissa = (16+UInt(e:f:g:h))/16. |
400 | if (Mantissa & 0x7ffff) |
401 | return -1; |
402 | Mantissa >>= 19; |
403 | if ((Mantissa & 0xf) != Mantissa) |
404 | return -1; |
405 | |
406 | // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 |
407 | if (Exp < -3 || Exp > 4) |
408 | return -1; |
409 | Exp = ((Exp+3) & 0x7) ^ 4; |
410 | |
411 | return ((int)Sign << 7) | (Exp << 4) | Mantissa; |
412 | } |
413 | |
414 | static inline int getFP32Imm(const APFloat &FPImm) { |
415 | return getFP32Imm(Imm: FPImm.bitcastToAPInt()); |
416 | } |
417 | |
418 | /// getFP64Imm - Return an 8-bit floating-point version of the 64-bit |
419 | /// floating-point value. If the value cannot be represented as an 8-bit |
420 | /// floating-point value, then return -1. |
421 | static inline int getFP64Imm(const APInt &Imm) { |
422 | uint64_t Sign = Imm.lshr(shiftAmt: 63).getZExtValue() & 1; |
423 | int64_t Exp = (Imm.lshr(shiftAmt: 52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023 |
424 | uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL; |
425 | |
426 | // We can handle 4 bits of mantissa. |
427 | // mantissa = (16+UInt(e:f:g:h))/16. |
428 | if (Mantissa & 0xffffffffffffULL) |
429 | return -1; |
430 | Mantissa >>= 48; |
431 | if ((Mantissa & 0xf) != Mantissa) |
432 | return -1; |
433 | |
434 | // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 |
435 | if (Exp < -3 || Exp > 4) |
436 | return -1; |
437 | Exp = ((Exp+3) & 0x7) ^ 4; |
438 | |
439 | return ((int)Sign << 7) | (Exp << 4) | Mantissa; |
440 | } |
441 | |
442 | static inline int getFP64Imm(const APFloat &FPImm) { |
443 | return getFP64Imm(Imm: FPImm.bitcastToAPInt()); |
444 | } |
445 | |
446 | //===--------------------------------------------------------------------===// |
447 | // AdvSIMD Modified Immediates |
448 | //===--------------------------------------------------------------------===// |
449 | |
450 | // 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh |
451 | static inline bool isAdvSIMDModImmType1(uint64_t Imm) { |
452 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
453 | ((Imm & 0xffffff00ffffff00ULL) == 0); |
454 | } |
455 | |
456 | static inline uint8_t encodeAdvSIMDModImmType1(uint64_t Imm) { |
457 | return (Imm & 0xffULL); |
458 | } |
459 | |
460 | static inline uint64_t decodeAdvSIMDModImmType1(uint8_t Imm) { |
461 | uint64_t EncVal = Imm; |
462 | return (EncVal << 32) | EncVal; |
463 | } |
464 | |
465 | // 0x00 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 |
466 | static inline bool isAdvSIMDModImmType2(uint64_t Imm) { |
467 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
468 | ((Imm & 0xffff00ffffff00ffULL) == 0); |
469 | } |
470 | |
471 | static inline uint8_t encodeAdvSIMDModImmType2(uint64_t Imm) { |
472 | return (Imm & 0xff00ULL) >> 8; |
473 | } |
474 | |
475 | static inline uint64_t decodeAdvSIMDModImmType2(uint8_t Imm) { |
476 | uint64_t EncVal = Imm; |
477 | return (EncVal << 40) | (EncVal << 8); |
478 | } |
479 | |
480 | // 0x00 abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00 |
481 | static inline bool isAdvSIMDModImmType3(uint64_t Imm) { |
482 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
483 | ((Imm & 0xff00ffffff00ffffULL) == 0); |
484 | } |
485 | |
486 | static inline uint8_t encodeAdvSIMDModImmType3(uint64_t Imm) { |
487 | return (Imm & 0xff0000ULL) >> 16; |
488 | } |
489 | |
490 | static inline uint64_t decodeAdvSIMDModImmType3(uint8_t Imm) { |
491 | uint64_t EncVal = Imm; |
492 | return (EncVal << 48) | (EncVal << 16); |
493 | } |
494 | |
495 | // abcdefgh 0x00 0x00 0x00 abcdefgh 0x00 0x00 0x00 |
496 | static inline bool isAdvSIMDModImmType4(uint64_t Imm) { |
497 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
498 | ((Imm & 0x00ffffff00ffffffULL) == 0); |
499 | } |
500 | |
501 | static inline uint8_t encodeAdvSIMDModImmType4(uint64_t Imm) { |
502 | return (Imm & 0xff000000ULL) >> 24; |
503 | } |
504 | |
505 | static inline uint64_t decodeAdvSIMDModImmType4(uint8_t Imm) { |
506 | uint64_t EncVal = Imm; |
507 | return (EncVal << 56) | (EncVal << 24); |
508 | } |
509 | |
510 | // 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh |
511 | static inline bool isAdvSIMDModImmType5(uint64_t Imm) { |
512 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
513 | (((Imm & 0x00ff0000ULL) >> 16) == (Imm & 0x000000ffULL)) && |
514 | ((Imm & 0xff00ff00ff00ff00ULL) == 0); |
515 | } |
516 | |
517 | static inline uint8_t encodeAdvSIMDModImmType5(uint64_t Imm) { |
518 | return (Imm & 0xffULL); |
519 | } |
520 | |
521 | static inline uint64_t decodeAdvSIMDModImmType5(uint8_t Imm) { |
522 | uint64_t EncVal = Imm; |
523 | return (EncVal << 48) | (EncVal << 32) | (EncVal << 16) | EncVal; |
524 | } |
525 | |
526 | // abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 |
527 | static inline bool isAdvSIMDModImmType6(uint64_t Imm) { |
528 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
529 | (((Imm & 0xff000000ULL) >> 16) == (Imm & 0x0000ff00ULL)) && |
530 | ((Imm & 0x00ff00ff00ff00ffULL) == 0); |
531 | } |
532 | |
533 | static inline uint8_t encodeAdvSIMDModImmType6(uint64_t Imm) { |
534 | return (Imm & 0xff00ULL) >> 8; |
535 | } |
536 | |
537 | static inline uint64_t decodeAdvSIMDModImmType6(uint8_t Imm) { |
538 | uint64_t EncVal = Imm; |
539 | return (EncVal << 56) | (EncVal << 40) | (EncVal << 24) | (EncVal << 8); |
540 | } |
541 | |
542 | // 0x00 0x00 abcdefgh 0xFF 0x00 0x00 abcdefgh 0xFF |
543 | static inline bool isAdvSIMDModImmType7(uint64_t Imm) { |
544 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
545 | ((Imm & 0xffff00ffffff00ffULL) == 0x000000ff000000ffULL); |
546 | } |
547 | |
548 | static inline uint8_t encodeAdvSIMDModImmType7(uint64_t Imm) { |
549 | return (Imm & 0xff00ULL) >> 8; |
550 | } |
551 | |
552 | static inline uint64_t decodeAdvSIMDModImmType7(uint8_t Imm) { |
553 | uint64_t EncVal = Imm; |
554 | return (EncVal << 40) | (EncVal << 8) | 0x000000ff000000ffULL; |
555 | } |
556 | |
557 | // 0x00 abcdefgh 0xFF 0xFF 0x00 abcdefgh 0xFF 0xFF |
558 | static inline bool isAdvSIMDModImmType8(uint64_t Imm) { |
559 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
560 | ((Imm & 0xff00ffffff00ffffULL) == 0x0000ffff0000ffffULL); |
561 | } |
562 | |
563 | static inline uint64_t decodeAdvSIMDModImmType8(uint8_t Imm) { |
564 | uint64_t EncVal = Imm; |
565 | return (EncVal << 48) | (EncVal << 16) | 0x0000ffff0000ffffULL; |
566 | } |
567 | |
568 | static inline uint8_t encodeAdvSIMDModImmType8(uint64_t Imm) { |
569 | return (Imm & 0x00ff0000ULL) >> 16; |
570 | } |
571 | |
572 | // abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh abcdefgh |
573 | static inline bool isAdvSIMDModImmType9(uint64_t Imm) { |
574 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
575 | ((Imm >> 48) == (Imm & 0x0000ffffULL)) && |
576 | ((Imm >> 56) == (Imm & 0x000000ffULL)); |
577 | } |
578 | |
579 | static inline uint8_t encodeAdvSIMDModImmType9(uint64_t Imm) { |
580 | return (Imm & 0xffULL); |
581 | } |
582 | |
583 | static inline uint64_t decodeAdvSIMDModImmType9(uint8_t Imm) { |
584 | uint64_t EncVal = Imm; |
585 | EncVal |= (EncVal << 8); |
586 | EncVal |= (EncVal << 16); |
587 | EncVal |= (EncVal << 32); |
588 | return EncVal; |
589 | } |
590 | |
591 | // aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh |
592 | // cmode: 1110, op: 1 |
593 | static inline bool isAdvSIMDModImmType10(uint64_t Imm) { |
594 | #if defined(_MSC_VER) && _MSC_VER == 1937 && !defined(__clang__) && \ |
595 | defined(_M_ARM64) |
596 | // The MSVC compiler 19.37 for ARM64 has an optimization bug that |
597 | // causes an incorrect behavior with the orignal version. Work around |
598 | // by using a slightly different variation. |
599 | // https://developercommunity.visualstudio.com/t/C-ARM64-compiler-optimization-bug/10481261 |
600 | constexpr uint64_t Mask = 0xFFULL; |
601 | uint64_t ByteA = (Imm >> 56) & Mask; |
602 | uint64_t ByteB = (Imm >> 48) & Mask; |
603 | uint64_t ByteC = (Imm >> 40) & Mask; |
604 | uint64_t ByteD = (Imm >> 32) & Mask; |
605 | uint64_t ByteE = (Imm >> 24) & Mask; |
606 | uint64_t ByteF = (Imm >> 16) & Mask; |
607 | uint64_t ByteG = (Imm >> 8) & Mask; |
608 | uint64_t ByteH = Imm & Mask; |
609 | |
610 | return (ByteA == 0ULL || ByteA == Mask) && (ByteB == 0ULL || ByteB == Mask) && |
611 | (ByteC == 0ULL || ByteC == Mask) && (ByteD == 0ULL || ByteD == Mask) && |
612 | (ByteE == 0ULL || ByteE == Mask) && (ByteF == 0ULL || ByteF == Mask) && |
613 | (ByteG == 0ULL || ByteG == Mask) && (ByteH == 0ULL || ByteH == Mask); |
614 | #else |
615 | uint64_t ByteA = Imm & 0xff00000000000000ULL; |
616 | uint64_t ByteB = Imm & 0x00ff000000000000ULL; |
617 | uint64_t ByteC = Imm & 0x0000ff0000000000ULL; |
618 | uint64_t ByteD = Imm & 0x000000ff00000000ULL; |
619 | uint64_t ByteE = Imm & 0x00000000ff000000ULL; |
620 | uint64_t ByteF = Imm & 0x0000000000ff0000ULL; |
621 | uint64_t ByteG = Imm & 0x000000000000ff00ULL; |
622 | uint64_t ByteH = Imm & 0x00000000000000ffULL; |
623 | |
624 | return (ByteA == 0ULL || ByteA == 0xff00000000000000ULL) && |
625 | (ByteB == 0ULL || ByteB == 0x00ff000000000000ULL) && |
626 | (ByteC == 0ULL || ByteC == 0x0000ff0000000000ULL) && |
627 | (ByteD == 0ULL || ByteD == 0x000000ff00000000ULL) && |
628 | (ByteE == 0ULL || ByteE == 0x00000000ff000000ULL) && |
629 | (ByteF == 0ULL || ByteF == 0x0000000000ff0000ULL) && |
630 | (ByteG == 0ULL || ByteG == 0x000000000000ff00ULL) && |
631 | (ByteH == 0ULL || ByteH == 0x00000000000000ffULL); |
632 | #endif |
633 | } |
634 | |
635 | static inline uint8_t encodeAdvSIMDModImmType10(uint64_t Imm) { |
636 | uint8_t BitA = (Imm & 0xff00000000000000ULL) != 0; |
637 | uint8_t BitB = (Imm & 0x00ff000000000000ULL) != 0; |
638 | uint8_t BitC = (Imm & 0x0000ff0000000000ULL) != 0; |
639 | uint8_t BitD = (Imm & 0x000000ff00000000ULL) != 0; |
640 | uint8_t BitE = (Imm & 0x00000000ff000000ULL) != 0; |
641 | uint8_t BitF = (Imm & 0x0000000000ff0000ULL) != 0; |
642 | uint8_t BitG = (Imm & 0x000000000000ff00ULL) != 0; |
643 | uint8_t BitH = (Imm & 0x00000000000000ffULL) != 0; |
644 | |
645 | uint8_t EncVal = BitA; |
646 | EncVal <<= 1; |
647 | EncVal |= BitB; |
648 | EncVal <<= 1; |
649 | EncVal |= BitC; |
650 | EncVal <<= 1; |
651 | EncVal |= BitD; |
652 | EncVal <<= 1; |
653 | EncVal |= BitE; |
654 | EncVal <<= 1; |
655 | EncVal |= BitF; |
656 | EncVal <<= 1; |
657 | EncVal |= BitG; |
658 | EncVal <<= 1; |
659 | EncVal |= BitH; |
660 | return EncVal; |
661 | } |
662 | |
663 | static inline uint64_t decodeAdvSIMDModImmType10(uint8_t Imm) { |
664 | uint64_t EncVal = 0; |
665 | if (Imm & 0x80) EncVal |= 0xff00000000000000ULL; |
666 | if (Imm & 0x40) EncVal |= 0x00ff000000000000ULL; |
667 | if (Imm & 0x20) EncVal |= 0x0000ff0000000000ULL; |
668 | if (Imm & 0x10) EncVal |= 0x000000ff00000000ULL; |
669 | if (Imm & 0x08) EncVal |= 0x00000000ff000000ULL; |
670 | if (Imm & 0x04) EncVal |= 0x0000000000ff0000ULL; |
671 | if (Imm & 0x02) EncVal |= 0x000000000000ff00ULL; |
672 | if (Imm & 0x01) EncVal |= 0x00000000000000ffULL; |
673 | return EncVal; |
674 | } |
675 | |
676 | // aBbbbbbc defgh000 0x00 0x00 aBbbbbbc defgh000 0x00 0x00 |
677 | static inline bool isAdvSIMDModImmType11(uint64_t Imm) { |
678 | uint64_t BString = (Imm & 0x7E000000ULL) >> 25; |
679 | return ((Imm >> 32) == (Imm & 0xffffffffULL)) && |
680 | (BString == 0x1f || BString == 0x20) && |
681 | ((Imm & 0x0007ffff0007ffffULL) == 0); |
682 | } |
683 | |
684 | static inline uint8_t encodeAdvSIMDModImmType11(uint64_t Imm) { |
685 | uint8_t BitA = (Imm & 0x80000000ULL) != 0; |
686 | uint8_t BitB = (Imm & 0x20000000ULL) != 0; |
687 | uint8_t BitC = (Imm & 0x01000000ULL) != 0; |
688 | uint8_t BitD = (Imm & 0x00800000ULL) != 0; |
689 | uint8_t BitE = (Imm & 0x00400000ULL) != 0; |
690 | uint8_t BitF = (Imm & 0x00200000ULL) != 0; |
691 | uint8_t BitG = (Imm & 0x00100000ULL) != 0; |
692 | uint8_t BitH = (Imm & 0x00080000ULL) != 0; |
693 | |
694 | uint8_t EncVal = BitA; |
695 | EncVal <<= 1; |
696 | EncVal |= BitB; |
697 | EncVal <<= 1; |
698 | EncVal |= BitC; |
699 | EncVal <<= 1; |
700 | EncVal |= BitD; |
701 | EncVal <<= 1; |
702 | EncVal |= BitE; |
703 | EncVal <<= 1; |
704 | EncVal |= BitF; |
705 | EncVal <<= 1; |
706 | EncVal |= BitG; |
707 | EncVal <<= 1; |
708 | EncVal |= BitH; |
709 | return EncVal; |
710 | } |
711 | |
712 | static inline uint64_t decodeAdvSIMDModImmType11(uint8_t Imm) { |
713 | uint64_t EncVal = 0; |
714 | if (Imm & 0x80) EncVal |= 0x80000000ULL; |
715 | if (Imm & 0x40) EncVal |= 0x3e000000ULL; |
716 | else EncVal |= 0x40000000ULL; |
717 | if (Imm & 0x20) EncVal |= 0x01000000ULL; |
718 | if (Imm & 0x10) EncVal |= 0x00800000ULL; |
719 | if (Imm & 0x08) EncVal |= 0x00400000ULL; |
720 | if (Imm & 0x04) EncVal |= 0x00200000ULL; |
721 | if (Imm & 0x02) EncVal |= 0x00100000ULL; |
722 | if (Imm & 0x01) EncVal |= 0x00080000ULL; |
723 | return (EncVal << 32) | EncVal; |
724 | } |
725 | |
726 | // aBbbbbbb bbcdefgh 0x00 0x00 0x00 0x00 0x00 0x00 |
727 | static inline bool isAdvSIMDModImmType12(uint64_t Imm) { |
728 | uint64_t BString = (Imm & 0x7fc0000000000000ULL) >> 54; |
729 | return ((BString == 0xff || BString == 0x100) && |
730 | ((Imm & 0x0000ffffffffffffULL) == 0)); |
731 | } |
732 | |
733 | static inline uint8_t encodeAdvSIMDModImmType12(uint64_t Imm) { |
734 | uint8_t BitA = (Imm & 0x8000000000000000ULL) != 0; |
735 | uint8_t BitB = (Imm & 0x0040000000000000ULL) != 0; |
736 | uint8_t BitC = (Imm & 0x0020000000000000ULL) != 0; |
737 | uint8_t BitD = (Imm & 0x0010000000000000ULL) != 0; |
738 | uint8_t BitE = (Imm & 0x0008000000000000ULL) != 0; |
739 | uint8_t BitF = (Imm & 0x0004000000000000ULL) != 0; |
740 | uint8_t BitG = (Imm & 0x0002000000000000ULL) != 0; |
741 | uint8_t BitH = (Imm & 0x0001000000000000ULL) != 0; |
742 | |
743 | uint8_t EncVal = BitA; |
744 | EncVal <<= 1; |
745 | EncVal |= BitB; |
746 | EncVal <<= 1; |
747 | EncVal |= BitC; |
748 | EncVal <<= 1; |
749 | EncVal |= BitD; |
750 | EncVal <<= 1; |
751 | EncVal |= BitE; |
752 | EncVal <<= 1; |
753 | EncVal |= BitF; |
754 | EncVal <<= 1; |
755 | EncVal |= BitG; |
756 | EncVal <<= 1; |
757 | EncVal |= BitH; |
758 | return EncVal; |
759 | } |
760 | |
761 | static inline uint64_t decodeAdvSIMDModImmType12(uint8_t Imm) { |
762 | uint64_t EncVal = 0; |
763 | if (Imm & 0x80) EncVal |= 0x8000000000000000ULL; |
764 | if (Imm & 0x40) EncVal |= 0x3fc0000000000000ULL; |
765 | else EncVal |= 0x4000000000000000ULL; |
766 | if (Imm & 0x20) EncVal |= 0x0020000000000000ULL; |
767 | if (Imm & 0x10) EncVal |= 0x0010000000000000ULL; |
768 | if (Imm & 0x08) EncVal |= 0x0008000000000000ULL; |
769 | if (Imm & 0x04) EncVal |= 0x0004000000000000ULL; |
770 | if (Imm & 0x02) EncVal |= 0x0002000000000000ULL; |
771 | if (Imm & 0x01) EncVal |= 0x0001000000000000ULL; |
772 | return (EncVal << 32) | EncVal; |
773 | } |
774 | |
775 | /// Returns true if Imm is the concatenation of a repeating pattern of type T. |
776 | template <typename T> |
777 | static inline bool isSVEMaskOfIdenticalElements(int64_t Imm) { |
778 | auto Parts = bit_cast<std::array<T, sizeof(int64_t) / sizeof(T)>>(Imm); |
779 | return llvm::all_equal(Parts); |
780 | } |
781 | |
782 | /// Returns true if Imm is valid for CPY/DUP. |
783 | template <typename T> |
784 | static inline bool isSVECpyImm(int64_t Imm) { |
785 | // Imm is interpreted as a signed value, which means top bits must be all ones |
786 | // (sign bits if the immediate value is negative and passed in a larger |
787 | // container), or all zeroes. |
788 | int64_t Mask = ~int64_t(std::numeric_limits<std::make_unsigned_t<T>>::max()); |
789 | if ((Imm & Mask) != 0 && (Imm & Mask) != Mask) |
790 | return false; |
791 | |
792 | // Imm is a signed 8-bit value. |
793 | // Top bits must be zeroes or sign bits. |
794 | if (Imm & 0xff) |
795 | return int8_t(Imm) == T(Imm); |
796 | |
797 | // Imm is a signed 16-bit value and multiple of 256. |
798 | // Top bits must be zeroes or sign bits. |
799 | if (Imm & 0xff00) |
800 | return int16_t(Imm) == T(Imm); |
801 | |
802 | return Imm == 0; |
803 | } |
804 | |
805 | /// Returns true if Imm is valid for ADD/SUB. |
806 | template <typename T> |
807 | static inline bool isSVEAddSubImm(int64_t Imm) { |
808 | bool IsInt8t = std::is_same<int8_t, std::make_signed_t<T>>::value || |
809 | std::is_same<int8_t, T>::value; |
810 | return uint8_t(Imm) == Imm || (!IsInt8t && uint16_t(Imm & ~0xff) == Imm); |
811 | } |
812 | |
813 | /// Return true if Imm is valid for DUPM and has no single CPY/DUP equivalent. |
814 | static inline bool isSVEMoveMaskPreferredLogicalImmediate(int64_t Imm) { |
815 | if (isSVECpyImm<int64_t>(Imm)) |
816 | return false; |
817 | |
818 | auto S = bit_cast<std::array<int32_t, 2>>(from: Imm); |
819 | auto H = bit_cast<std::array<int16_t, 4>>(from: Imm); |
820 | auto B = bit_cast<std::array<int8_t, 8>>(from: Imm); |
821 | |
822 | if (isSVEMaskOfIdenticalElements<int32_t>(Imm) && isSVECpyImm<int32_t>(Imm: S[0])) |
823 | return false; |
824 | if (isSVEMaskOfIdenticalElements<int16_t>(Imm) && isSVECpyImm<int16_t>(Imm: H[0])) |
825 | return false; |
826 | if (isSVEMaskOfIdenticalElements<int8_t>(Imm) && isSVECpyImm<int8_t>(Imm: B[0])) |
827 | return false; |
828 | return isLogicalImmediate(imm: Imm, regSize: 64); |
829 | } |
830 | |
831 | inline static bool isAnyMOVZMovAlias(uint64_t Value, int RegWidth) { |
832 | for (int Shift = 0; Shift <= RegWidth - 16; Shift += 16) |
833 | if ((Value & ~(0xffffULL << Shift)) == 0) |
834 | return true; |
835 | |
836 | return false; |
837 | } |
838 | |
839 | inline static bool isMOVZMovAlias(uint64_t Value, int Shift, int RegWidth) { |
840 | if (RegWidth == 32) |
841 | Value &= 0xffffffffULL; |
842 | |
843 | // "lsl #0" takes precedence: in practice this only affects "#0, lsl #0". |
844 | if (Value == 0 && Shift != 0) |
845 | return false; |
846 | |
847 | return (Value & ~(0xffffULL << Shift)) == 0; |
848 | } |
849 | |
850 | inline static bool isMOVNMovAlias(uint64_t Value, int Shift, int RegWidth) { |
851 | // MOVZ takes precedence over MOVN. |
852 | if (isAnyMOVZMovAlias(Value, RegWidth)) |
853 | return false; |
854 | |
855 | Value = ~Value; |
856 | if (RegWidth == 32) |
857 | Value &= 0xffffffffULL; |
858 | |
859 | return isMOVZMovAlias(Value, Shift, RegWidth); |
860 | } |
861 | |
862 | inline static bool isAnyMOVWMovAlias(uint64_t Value, int RegWidth) { |
863 | if (isAnyMOVZMovAlias(Value, RegWidth)) |
864 | return true; |
865 | |
866 | // It's not a MOVZ, but it might be a MOVN. |
867 | Value = ~Value; |
868 | if (RegWidth == 32) |
869 | Value &= 0xffffffffULL; |
870 | |
871 | return isAnyMOVZMovAlias(Value, RegWidth); |
872 | } |
873 | |
874 | } // end namespace AArch64_AM |
875 | |
876 | } // end namespace llvm |
877 | |
878 | #endif |
879 | |