1 // Copyright 2019, VIXL authors
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_AARCH64_REGISTERS_AARCH64_H_
28 #define VIXL_AARCH64_REGISTERS_AARCH64_H_
29 
30 #include <string>
31 
32 #include "instructions-aarch64.h"
33 
34 namespace vixl {
35 namespace aarch64 {
36 
37 // An integer type capable of representing a homogeneous, non-overlapping set of
38 // registers as a bitmask of their codes.
39 typedef uint64_t RegList;
40 static const int kRegListSizeInBits = sizeof(RegList) * 8;
41 
42 class Register;
43 class WRegister;
44 class XRegister;
45 
46 class VRegister;
47 class BRegister;
48 class HRegister;
49 class SRegister;
50 class DRegister;
51 class QRegister;
52 
53 class ZRegister;
54 
55 class PRegister;
56 class PRegisterWithLaneSize;
57 class PRegisterM;
58 class PRegisterZ;
59 
60 // A container for any single register supported by the processor. Selected
61 // qualifications are also supported. Basic registers can be constructed
62 // directly as CPURegister objects. Other variants should be constructed as one
63 // of the derived classes.
64 //
65 // CPURegister aims to support any getter that would also be available to more
66 // specialised register types. However, using the equivalent functions on the
67 // specialised register types can avoid run-time checks, and should therefore be
68 // preferred where run-time polymorphism isn't required.
69 //
70 // Type-specific modifiers are typically implemented only on the derived
71 // classes.
72 //
73 // The encoding is such that CPURegister objects are cheap to pass by value.
74 class CPURegister {
75  public:
76   enum RegisterBank : uint8_t {
77     kNoRegisterBank = 0,
78     kRRegisterBank,
79     kVRegisterBank,
80     kPRegisterBank
81   };
82   enum RegisterType {
83     kNoRegister,
84     kRegister,
85     kVRegister,
86     kZRegister,
87     kPRegister
88   };
89 
90   static const unsigned kUnknownSize = 0;
91 
CPURegister()92   VIXL_CONSTEXPR CPURegister()
93       : code_(0),
94         bank_(kNoRegisterBank),
95         size_(kEncodedUnknownSize),
96         qualifiers_(kNoQualifiers),
97         lane_size_(kEncodedUnknownSize) {}
98 
CPURegister(int code, int size_in_bits, RegisterType type)99   CPURegister(int code, int size_in_bits, RegisterType type)
100       : code_(code),
101         bank_(GetBankFor(type)),
102         size_(EncodeSizeInBits(size_in_bits)),
103         qualifiers_(kNoQualifiers),
104         lane_size_(EncodeSizeInBits(size_in_bits)) {
105     VIXL_ASSERT(IsValid());
106   }
107 
108   // Basic accessors.
109 
110   // TODO: Make this return 'int'.
GetCode() const111   unsigned GetCode() const { return code_; }
112 
GetBank() const113   RegisterBank GetBank() const { return bank_; }
114 
115   // For scalar registers, the lane size matches the register size, and is
116   // always known.
HasSize() const117   bool HasSize() const { return size_ != kEncodedUnknownSize; }
HasLaneSize() const118   bool HasLaneSize() const { return lane_size_ != kEncodedUnknownSize; }
119 
GetBit() const120   RegList GetBit() const {
121     if (IsNone()) return 0;
122     VIXL_ASSERT(code_ < kRegListSizeInBits);
123     return static_cast<RegList>(1) << code_;
124   }
125 
126   // Return the architectural name for this register.
127   // TODO: This is temporary. Ultimately, we should move the
128   // Simulator::*RegNameForCode helpers out of the simulator, and provide an
129   // independent way to obtain the name of a register.
130   inline std::string GetArchitecturalName() const;
131 
132   // Return the highest valid register code for this type, to allow generic
133   // loops to be written. This excludes kSPRegInternalCode, since it is not
134   // contiguous, and sp usually requires special handling anyway.
135   unsigned GetMaxCode() const { return GetMaxCodeFor(GetBank()); }
136 
137   // Registers without a known size report kUnknownSize.
138   int GetSizeInBits() const { return DecodeSizeInBits(size_); }
139   int GetSizeInBytes() const { return DecodeSizeInBytes(size_); }
140   // TODO: Make these return 'int'.
141   unsigned GetLaneSizeInBits() const { return DecodeSizeInBits(lane_size_); }
142   unsigned GetLaneSizeInBytes() const { return DecodeSizeInBytes(lane_size_); }
143   unsigned GetLaneSizeInBytesLog2() const {
144     VIXL_ASSERT(HasLaneSize());
145     return DecodeSizeInBytesLog2(lane_size_);
146   }
147 
148   int GetLanes() const {
149     if (HasSize() && HasLaneSize()) {
150       // Take advantage of the size encoding to calculate this efficiently.
151       VIXL_STATIC_ASSERT(kEncodedHRegSize == (kEncodedBRegSize + 1));
152       VIXL_STATIC_ASSERT(kEncodedSRegSize == (kEncodedHRegSize + 1));
153       VIXL_STATIC_ASSERT(kEncodedDRegSize == (kEncodedSRegSize + 1));
154       VIXL_STATIC_ASSERT(kEncodedQRegSize == (kEncodedDRegSize + 1));
155       int log2_delta = static_cast<int>(size_) - static_cast<int>(lane_size_);
156       VIXL_ASSERT(log2_delta >= 0);
157       return 1 << log2_delta;
158     }
159     return kUnknownSize;
160   }
161 
162   bool Is8Bits() const { return size_ == kEncodedBRegSize; }
163   bool Is16Bits() const { return size_ == kEncodedHRegSize; }
164   bool Is32Bits() const { return size_ == kEncodedSRegSize; }
165   bool Is64Bits() const { return size_ == kEncodedDRegSize; }
166   bool Is128Bits() const { return size_ == kEncodedQRegSize; }
167 
168   bool IsLaneSizeB() const { return lane_size_ == kEncodedBRegSize; }
169   bool IsLaneSizeH() const { return lane_size_ == kEncodedHRegSize; }
170   bool IsLaneSizeS() const { return lane_size_ == kEncodedSRegSize; }
171   bool IsLaneSizeD() const { return lane_size_ == kEncodedDRegSize; }
172   bool IsLaneSizeQ() const { return lane_size_ == kEncodedQRegSize; }
173 
174   // If Is<Foo>Register(), then it is valid to convert the CPURegister to some
175   // <Foo>Register<Bar> type.
176   //
177   //  If...                              ... then it is safe to construct ...
178   //      r.IsRegister()                       -> Register(r)
179   //      r.IsVRegister()                      -> VRegister(r)
180   //      r.IsZRegister()                      -> ZRegister(r)
181   //      r.IsPRegister()                      -> PRegister(r)
182   //
183   //      r.IsPRegister() && HasLaneSize()     -> PRegisterWithLaneSize(r)
184   //      r.IsPRegister() && IsMerging()       -> PRegisterM(r)
185   //      r.IsPRegister() && IsZeroing()       -> PRegisterZ(r)
186   bool IsRegister() const { return GetType() == kRegister; }
187   bool IsVRegister() const { return GetType() == kVRegister; }
188   bool IsZRegister() const { return GetType() == kZRegister; }
189   bool IsPRegister() const { return GetType() == kPRegister; }
190 
191   bool IsNone() const { return GetType() == kNoRegister; }
192 
193   // `GetType() == kNoRegister` implies IsNone(), and vice-versa.
194   // `GetType() == k<Foo>Register` implies Is<Foo>Register(), and vice-versa.
195   RegisterType GetType() const {
196     switch (bank_) {
197       case kNoRegisterBank:
198         return kNoRegister;
199       case kRRegisterBank:
200         return kRegister;
201       case kVRegisterBank:
202         return HasSize() ? kVRegister : kZRegister;
203       case kPRegisterBank:
204         return kPRegister;
205     }
206     VIXL_UNREACHABLE();
207     return kNoRegister;
208   }
209 
210   // IsFPRegister() is true for scalar FP types (and therefore implies
211   // IsVRegister()). There is no corresponding FPRegister type.
212   bool IsFPRegister() const { return Is1H() || Is1S() || Is1D(); }
213 
214   // TODO: These are stricter forms of the helpers above. We should make the
215   // basic helpers strict, and remove these.
216 bool IsValidRegister() const {
217   return ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)) &&
218          (bank_ == kRRegisterBank) &&
219          ((size_ == kEncodedWRegSize) || (size_ == kEncodedXRegSize)) &&
220          (qualifiers_ == kNoQualifiers) && (lane_size_ == size_);
221 }
222 
223 bool IsValidVRegister() const {
224   VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
225   return (code_ < kNumberOfVRegisters) && (bank_ == kVRegisterBank) &&
226          ((size_ >= kEncodedBRegSize) && (size_ <= kEncodedQRegSize)) &&
227          (qualifiers_ == kNoQualifiers) &&
228          (lane_size_ != kEncodedUnknownSize) && (lane_size_ <= size_);
229 }
230 
231 bool IsValidFPRegister() const {
232   return IsValidVRegister() && IsFPRegister();
233 }
234 
235 bool IsValidZRegister() const {
236   VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
237   // Z registers are valid with or without a lane size, so we don't need to
238   // check lane_size_.
239   return (code_ < kNumberOfZRegisters) && (bank_ == kVRegisterBank) &&
240          (size_ == kEncodedUnknownSize) && (qualifiers_ == kNoQualifiers);
241 }
242 
243 bool IsValidPRegister() const {
244   VIXL_STATIC_ASSERT(kEncodedBRegSize < kEncodedQRegSize);
245   // P registers are valid with or without a lane size, so we don't need to
246   // check lane_size_.
247   return (code_ < kNumberOfPRegisters) && (bank_ == kPRegisterBank) &&
248          (size_ == kEncodedUnknownSize) &&
249          ((qualifiers_ == kNoQualifiers) || (qualifiers_ == kMerging) ||
250           (qualifiers_ == kZeroing));
251 }
252 
253   bool IsValid() const {
254     return IsValidRegister() || IsValidVRegister() || IsValidZRegister() ||
255            IsValidPRegister();
256   }
257 
258   bool IsValidOrNone() const { return IsNone() || IsValid(); }
259 
260   bool IsVector() const { return HasLaneSize() && (size_ != lane_size_); }
261   bool IsScalar() const { return HasLaneSize() && (size_ == lane_size_); }
262 
263   bool IsSameType(const CPURegister& other) const {
264     return GetType() == other.GetType();
265   }
266 
267   bool IsSameBank(const CPURegister& other) const {
268     return GetBank() == other.GetBank();
269   }
270 
271   // Two registers with unknown size are considered to have the same size if
272   // they also have the same type. For example, all Z registers have the same
273   // size, even though we don't know what that is.
274   bool IsSameSizeAndType(const CPURegister& other) const {
275     return IsSameType(other) && (size_ == other.size_);
276   }
277 
278   bool IsSameFormat(const CPURegister& other) const {
279     return IsSameSizeAndType(other) && (lane_size_ == other.lane_size_);
280   }
281 
282   // Note that NoReg aliases itself, so that 'Is' implies 'Aliases'.
283   bool Aliases(const CPURegister& other) const {
284     return IsSameBank(other) && (code_ == other.code_);
285   }
286 
287   bool Is(const CPURegister& other) const {
288     if (IsRegister() || IsVRegister()) {
289       // For core (W, X) and FP/NEON registers, we only consider the code, size
290       // and type. This is legacy behaviour.
291       // TODO: We should probably check every field for all registers.
292       return Aliases(other) && (size_ == other.size_);
293     } else {
294       // For Z and P registers, we require all fields to match exactly.
295       VIXL_ASSERT(IsNone() || IsZRegister() || IsPRegister());
296       return (code_ == other.code_) && (bank_ == other.bank_) &&
297              (size_ == other.size_) && (qualifiers_ == other.qualifiers_) &&
298              (lane_size_ == other.lane_size_);
299     }
300   }
301 
302   // Conversions to specific register types. The result is a register that
303   // aliases the original CPURegister. That is, the original register bank
304   // (`GetBank()`) is checked and the code (`GetCode()`) preserved, but all
305   // other properties are ignored.
306   //
307   // Typical usage:
308   //
309   //     if (reg.GetBank() == kVRegisterBank) {
310   //       DRegister d = reg.D();
311   //       ...
312   //     }
313   //
314   // These could all return types with compile-time guarantees (like XRegister),
315   // but this breaks backwards-compatibility quite severely, particularly with
316   // code like `cond ? reg.W() : reg.X()`, which would have indeterminate type.
317 
318   // Core registers, like "w0".
319   inline Register W() const;
320   inline Register X() const;
321   // FP/NEON registers, like "b0".
322   inline VRegister B() const;
323   inline VRegister H() const;
324   inline VRegister S() const;
325   inline VRegister D() const;
326   inline VRegister Q() const;
327   inline VRegister V() const;
328   // SVE registers, like "z0".
329   inline ZRegister Z() const;
330   inline PRegister P() const;
331 
332   // Utilities for kRegister types.
333 
334   bool IsZero() const { return IsRegister() && (code_ == kZeroRegCode); }
335   bool IsSP() const { return IsRegister() && (code_ == kSPRegInternalCode); }
336   bool IsW() const { return IsRegister() && Is32Bits(); }
337   bool IsX() const { return IsRegister() && Is64Bits(); }
338 
339   // Utilities for FP/NEON kVRegister types.
340 
341   // These helpers ensure that the size and type of the register are as
342   // described. They do not consider the number of lanes that make up a vector.
343   // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
344   // does not imply Is1D() or Is8B().
345   // Check the number of lanes, ie. the format of the vector, using methods such
346   // as Is8B(), Is1D(), etc.
347   bool IsB() const { return IsVRegister() && Is8Bits(); }
348   bool IsH() const { return IsVRegister() && Is16Bits(); }
349   bool IsS() const { return IsVRegister() && Is32Bits(); }
350   bool IsD() const { return IsVRegister() && Is64Bits(); }
351   bool IsQ() const { return IsVRegister() && Is128Bits(); }
352 
353   // As above, but also check that the register has exactly one lane. For
354   // example, reg.Is1D() implies DRegister(reg).IsValid(), but reg.IsD() does
355   // not.
356   bool Is1B() const { return IsB() && IsScalar(); }
357   bool Is1H() const { return IsH() && IsScalar(); }
358   bool Is1S() const { return IsS() && IsScalar(); }
359   bool Is1D() const { return IsD() && IsScalar(); }
360   bool Is1Q() const { return IsQ() && IsScalar(); }
361 
362   // Check the specific NEON format.
363   bool Is8B() const { return IsD() && IsLaneSizeB(); }
364   bool Is16B() const { return IsQ() && IsLaneSizeB(); }
365   bool Is2H() const { return IsS() && IsLaneSizeH(); }
366   bool Is4H() const { return IsD() && IsLaneSizeH(); }
367   bool Is8H() const { return IsQ() && IsLaneSizeH(); }
368   bool Is2S() const { return IsD() && IsLaneSizeS(); }
369   bool Is4S() const { return IsQ() && IsLaneSizeS(); }
370   bool Is2D() const { return IsQ() && IsLaneSizeD(); }
371 
372   // A semantic alias for sdot and udot (indexed and by element) instructions.
373   // The current CPURegister implementation cannot not tell this from Is1S(),
374   // but it might do later.
375   // TODO: Do this with the qualifiers_ field.
376   bool Is1S4B() const { return Is1S(); }
377 
378   // Utilities for SVE registers.
379 
380   bool IsUnqualified() const { return qualifiers_ == kNoQualifiers; }
381   bool IsMerging() const { return IsPRegister() && (qualifiers_ == kMerging); }
382   bool IsZeroing() const { return IsPRegister() && (qualifiers_ == kZeroing); }
383 
384   // SVE types have unknown sizes, but within known bounds.
385 
386   int GetMaxSizeInBytes() const {
387     switch (GetType()) {
388       case kZRegister:
389         return kZRegMaxSizeInBytes;
390       case kPRegister:
391         return kPRegMaxSizeInBytes;
392       default:
393         VIXL_ASSERT(HasSize());
394         return GetSizeInBits();
395     }
396   }
397 
398   int GetMinSizeInBytes() const {
399     switch (GetType()) {
400       case kZRegister:
401         return kZRegMinSizeInBytes;
402       case kPRegister:
403         return kPRegMinSizeInBytes;
404       default:
405         VIXL_ASSERT(HasSize());
406         return GetSizeInBits();
407     }
408   }
409 
410   int GetMaxSizeInBits() const { return GetMaxSizeInBytes() * kBitsPerByte; }
411   int GetMinSizeInBits() const { return GetMinSizeInBytes() * kBitsPerByte; }
412 
413   static RegisterBank GetBankFor(RegisterType type) {
414     switch (type) {
415       case kNoRegister:
416         return kNoRegisterBank;
417       case kRegister:
418         return kRRegisterBank;
419       case kVRegister:
420       case kZRegister:
421         return kVRegisterBank;
422       case kPRegister:
423         return kPRegisterBank;
424     }
425     VIXL_UNREACHABLE();
426     return kNoRegisterBank;
427   }
428 
429   static unsigned GetMaxCodeFor(CPURegister::RegisterType type) {
430     return GetMaxCodeFor(GetBankFor(type));
431   }
432 
433  protected:
434   enum EncodedSize : uint8_t {
435     // Ensure that kUnknownSize (and therefore kNoRegister) is encoded as zero.
436     kEncodedUnknownSize = 0,
437 
438     // The implementation assumes that the remaining sizes are encoded as
439     // `log2(size) + c`, so the following names must remain in sequence.
440     kEncodedBRegSize,
441     kEncodedHRegSize,
442     kEncodedSRegSize,
443     kEncodedDRegSize,
444     kEncodedQRegSize,
445 
446     kEncodedWRegSize = kEncodedSRegSize,
447     kEncodedXRegSize = kEncodedDRegSize
448   };
449   VIXL_STATIC_ASSERT(kSRegSize == kWRegSize);
450   VIXL_STATIC_ASSERT(kDRegSize == kXRegSize);
451 
452   char GetLaneSizeSymbol() const {
453     switch (lane_size_) {
454       case kEncodedBRegSize:
455         return 'B';
456       case kEncodedHRegSize:
457         return 'H';
458       case kEncodedSRegSize:
459         return 'S';
460       case kEncodedDRegSize:
461         return 'D';
462       case kEncodedQRegSize:
463         return 'Q';
464       case kEncodedUnknownSize:
465         break;
466     }
467     VIXL_UNREACHABLE();
468     return '?';
469   }
470 
471   static EncodedSize EncodeSizeInBits(int size_in_bits) {
472     switch (size_in_bits) {
473       case kUnknownSize:
474         return kEncodedUnknownSize;
475       case kBRegSize:
476         return kEncodedBRegSize;
477       case kHRegSize:
478         return kEncodedHRegSize;
479       case kSRegSize:
480         return kEncodedSRegSize;
481       case kDRegSize:
482         return kEncodedDRegSize;
483       case kQRegSize:
484         return kEncodedQRegSize;
485     }
486     VIXL_UNREACHABLE();
487     return kEncodedUnknownSize;
488   }
489 
490   static int DecodeSizeInBytesLog2(EncodedSize encoded_size) {
491     switch (encoded_size) {
492       case kEncodedUnknownSize:
493         // Log2 of B-sized lane in bytes is 0, so we can't just return 0 here.
494         VIXL_UNREACHABLE();
495         return -1;
496       case kEncodedBRegSize:
497         return kBRegSizeInBytesLog2;
498       case kEncodedHRegSize:
499         return kHRegSizeInBytesLog2;
500       case kEncodedSRegSize:
501         return kSRegSizeInBytesLog2;
502       case kEncodedDRegSize:
503         return kDRegSizeInBytesLog2;
504       case kEncodedQRegSize:
505         return kQRegSizeInBytesLog2;
506     }
507     VIXL_UNREACHABLE();
508     return kUnknownSize;
509   }
510 
511   static int DecodeSizeInBytes(EncodedSize encoded_size) {
512     if (encoded_size == kEncodedUnknownSize) {
513       return kUnknownSize;
514     }
515     return 1 << DecodeSizeInBytesLog2(encoded_size);
516   }
517 
518   static int DecodeSizeInBits(EncodedSize encoded_size) {
519     VIXL_STATIC_ASSERT(kUnknownSize == 0);
520     return DecodeSizeInBytes(encoded_size) * kBitsPerByte;
521   }
522 
523   inline static unsigned GetMaxCodeFor(CPURegister::RegisterBank bank);
524 
525   enum Qualifiers : uint8_t {
526     kNoQualifiers = 0,
527     // Used by P registers.
528     kMerging,
529     kZeroing
530   };
531 
532   // An unchecked constructor, for use by derived classes.
533   CPURegister(int code,
534               EncodedSize size,
535               RegisterBank bank,
536               EncodedSize lane_size,
537               Qualifiers qualifiers = kNoQualifiers)
538       : code_(code),
539         bank_(bank),
540         size_(size),
541         qualifiers_(qualifiers),
542         lane_size_(lane_size) {}
543 
544   // TODO: Check that access to these fields is reasonably efficient.
545   uint8_t code_;
546   RegisterBank bank_;
547   EncodedSize size_;
548   Qualifiers qualifiers_;
549   EncodedSize lane_size_;
550 };
551 // Ensure that CPURegisters can fit in a single (64-bit) register. This is a
552 // proxy for being "cheap to pass by value", which is hard to check directly.
553 VIXL_STATIC_ASSERT(sizeof(CPURegister) <= sizeof(uint64_t));
554 
555 // TODO: Add constexpr constructors.
556 #define VIXL_DECLARE_REGISTER_COMMON(NAME, REGISTER_TYPE, PARENT_TYPE) \
557   VIXL_CONSTEXPR NAME() : PARENT_TYPE() {}                             \
558                                                                        \
559   explicit NAME(CPURegister other) : PARENT_TYPE(other) {              \
560     VIXL_ASSERT(IsValid());                                            \
561   }                                                                    \
562                                                                        \
563   VIXL_CONSTEXPR static unsigned GetMaxCode() {                        \
564     return kNumberOf##REGISTER_TYPE##s - 1;                            \
565   }
566 
567 // Any W or X register, including the zero register and the stack pointer.
568 class Register : public CPURegister {
569  public:
570   VIXL_DECLARE_REGISTER_COMMON(Register, Register, CPURegister)
571 
572   Register(int code, int size_in_bits)
573       : CPURegister(code, size_in_bits, kRegister) {
574     VIXL_ASSERT(IsValidRegister());
575   }
576 
577   bool IsValid() const { return IsValidRegister(); }
578 };
579 
580 // Any FP or NEON V register, including vector (V.<T>) and scalar forms
581 // (B, H, S, D, Q).
582 class VRegister : public CPURegister {
583  public:
584   VIXL_DECLARE_REGISTER_COMMON(VRegister, VRegister, CPURegister)
585 
586   // For historical reasons, VRegister(0) returns v0.1Q (or equivalently, q0).
587   explicit VRegister(int code, int size_in_bits = kQRegSize, int lanes = 1)
588       : CPURegister(code,
589                     EncodeSizeInBits(size_in_bits),
590                     kVRegisterBank,
591                     EncodeLaneSizeInBits(size_in_bits, lanes)) {
592     VIXL_ASSERT(IsValidVRegister());
593   }
594 
595   VRegister(int code, VectorFormat format)
596       : CPURegister(code,
597                     EncodeSizeInBits(RegisterSizeInBitsFromFormat(format)),
598                     kVRegisterBank,
599                     EncodeSizeInBits(LaneSizeInBitsFromFormat(format)),
600                     kNoQualifiers) {
601     VIXL_ASSERT(IsValid());
602   }
603 
604   inline VRegister V8B() const;
605   inline VRegister V16B() const;
606   inline VRegister V2H() const;
607   inline VRegister V4H() const;
608   inline VRegister V8H() const;
609   inline VRegister V2S() const;
610   inline VRegister V4S() const;
611   inline VRegister V1D() const;
612   inline VRegister V2D() const;
613 
614   // Semantic type coersion for sdot and udot.
615   // TODO: Use the qualifiers_ field to distinguish this from ::S().
616   inline VRegister S4B() const;
617 
618   bool IsValid() const { return IsValidVRegister(); }
619 
620  protected:
621   static EncodedSize EncodeLaneSizeInBits(int size_in_bits, int lanes) {
622     VIXL_ASSERT(lanes >= 1);
623     VIXL_ASSERT((size_in_bits % lanes) == 0);
624     return EncodeSizeInBits(size_in_bits / lanes);
625   }
626 };
627 
628 // Any SVE Z register, with or without a lane size specifier.
629 class ZRegister : public CPURegister {
630  public:
631   VIXL_DECLARE_REGISTER_COMMON(ZRegister, ZRegister, CPURegister)
632 
633   explicit ZRegister(int code, int lane_size_in_bits = kUnknownSize)
634       : CPURegister(code,
635                     kEncodedUnknownSize,
636                     kVRegisterBank,
637                     EncodeSizeInBits(lane_size_in_bits)) {
638     VIXL_ASSERT(IsValid());
639   }
640 
641   ZRegister(int code, VectorFormat format)
642       : CPURegister(code,
643                     kEncodedUnknownSize,
644                     kVRegisterBank,
645                     EncodeSizeInBits(LaneSizeInBitsFromFormat(format)),
646                     kNoQualifiers) {
647     VIXL_ASSERT(IsValid());
648   }
649 
650   // Return a Z register with a known lane size (like "z0.B").
651   ZRegister VnB() const { return ZRegister(GetCode(), kBRegSize); }
652   ZRegister VnH() const { return ZRegister(GetCode(), kHRegSize); }
653   ZRegister VnS() const { return ZRegister(GetCode(), kSRegSize); }
654   ZRegister VnD() const { return ZRegister(GetCode(), kDRegSize); }
655   ZRegister VnQ() const { return ZRegister(GetCode(), kQRegSize); }
656 
657   template <typename T>
658   ZRegister WithLaneSize(T format) const {
659     return ZRegister(GetCode(), format);
660   }
661 
662   ZRegister WithSameLaneSizeAs(const CPURegister& other) const {
663     VIXL_ASSERT(other.HasLaneSize());
664     return this->WithLaneSize(other.GetLaneSizeInBits());
665   }
666 
667   bool IsValid() const { return IsValidZRegister(); }
668 };
669 
670 // Any SVE P register, with or without a qualifier or lane size specifier.
671 class PRegister : public CPURegister {
672  public:
673   VIXL_DECLARE_REGISTER_COMMON(PRegister, PRegister, CPURegister)
674 
675   explicit PRegister(int code) : CPURegister(code, kUnknownSize, kPRegister) {
676     VIXL_ASSERT(IsValid());
677   }
678 
679   bool IsValid() const {
680     return IsValidPRegister() && !HasLaneSize() && IsUnqualified();
681   }
682 
683   // Return a P register with a known lane size (like "p0.B").
684   PRegisterWithLaneSize VnB() const;
685   PRegisterWithLaneSize VnH() const;
686   PRegisterWithLaneSize VnS() const;
687   PRegisterWithLaneSize VnD() const;
688 
689   template <typename T>
690   PRegisterWithLaneSize WithLaneSize(T format) const;
691 
692   PRegisterWithLaneSize WithSameLaneSizeAs(const CPURegister& other) const;
693 
694   // SVE predicates are specified (in normal assembly) with a "/z" (zeroing) or
695   // "/m" (merging) suffix. These methods are VIXL's equivalents.
696   PRegisterZ Zeroing() const;
697   PRegisterM Merging() const;
698 
699  protected:
700   // Unchecked constructors, for use by derived classes.
701   PRegister(int code, EncodedSize encoded_lane_size)
702       : CPURegister(code,
703                     kEncodedUnknownSize,
704                     kPRegisterBank,
705                     encoded_lane_size,
706                     kNoQualifiers) {}
707 
708   PRegister(int code, Qualifiers qualifiers)
709       : CPURegister(code,
710                     kEncodedUnknownSize,
711                     kPRegisterBank,
712                     kEncodedUnknownSize,
713                     qualifiers) {}
714 };
715 
716 // Any SVE P register with a known lane size (like "p0.B").
717 class PRegisterWithLaneSize : public PRegister {
718  public:
719   VIXL_DECLARE_REGISTER_COMMON(PRegisterWithLaneSize, PRegister, PRegister)
720 
721   PRegisterWithLaneSize(int code, int lane_size_in_bits)
722       : PRegister(code, EncodeSizeInBits(lane_size_in_bits)) {
723     VIXL_ASSERT(IsValid());
724   }
725 
726   PRegisterWithLaneSize(int code, VectorFormat format)
727       : PRegister(code, EncodeSizeInBits(LaneSizeInBitsFromFormat(format))) {
728     VIXL_ASSERT(IsValid());
729   }
730 
731   bool IsValid() const {
732     return IsValidPRegister() && HasLaneSize() && IsUnqualified();
733   }
734 
735   // Overload lane size accessors so we can assert `HasLaneSize()`. This allows
736   // tools such as clang-tidy to prove that the result of GetLaneSize* is
737   // non-zero.
738 
739   // TODO: Make these return 'int'.
740   unsigned GetLaneSizeInBits() const {
741     VIXL_ASSERT(HasLaneSize());
742     return PRegister::GetLaneSizeInBits();
743   }
744 
745   unsigned GetLaneSizeInBytes() const {
746     VIXL_ASSERT(HasLaneSize());
747     return PRegister::GetLaneSizeInBytes();
748   }
749 };
750 
751 // Any SVE P register with the zeroing qualifier (like "p0/z").
752 class PRegisterZ : public PRegister {
753  public:
754   VIXL_DECLARE_REGISTER_COMMON(PRegisterZ, PRegister, PRegister)
755 
756   explicit PRegisterZ(int code) : PRegister(code, kZeroing) {
757     VIXL_ASSERT(IsValid());
758   }
759 
760   bool IsValid() const {
761     return IsValidPRegister() && !HasLaneSize() && IsZeroing();
762   }
763 };
764 
765 // Any SVE P register with the merging qualifier (like "p0/m").
766 class PRegisterM : public PRegister {
767  public:
768   VIXL_DECLARE_REGISTER_COMMON(PRegisterM, PRegister, PRegister)
769 
770   explicit PRegisterM(int code) : PRegister(code, kMerging) {
771     VIXL_ASSERT(IsValid());
772   }
773 
774   bool IsValid() const {
775     return IsValidPRegister() && !HasLaneSize() && IsMerging();
776   }
777 };
778 
779 inline PRegisterWithLaneSize PRegister::VnB() const {
780   return PRegisterWithLaneSize(GetCode(), kBRegSize);
781 }
782 inline PRegisterWithLaneSize PRegister::VnH() const {
783   return PRegisterWithLaneSize(GetCode(), kHRegSize);
784 }
785 inline PRegisterWithLaneSize PRegister::VnS() const {
786   return PRegisterWithLaneSize(GetCode(), kSRegSize);
787 }
788 inline PRegisterWithLaneSize PRegister::VnD() const {
789   return PRegisterWithLaneSize(GetCode(), kDRegSize);
790 }
791 
792 template <typename T>
793 inline PRegisterWithLaneSize PRegister::WithLaneSize(T format) const {
794   return PRegisterWithLaneSize(GetCode(), format);
795 }
796 
797 inline PRegisterWithLaneSize PRegister::WithSameLaneSizeAs(
798     const CPURegister& other) const {
799   VIXL_ASSERT(other.HasLaneSize());
800   return this->WithLaneSize(other.GetLaneSizeInBits());
801 }
802 
803 inline PRegisterZ PRegister::Zeroing() const { return PRegisterZ(GetCode()); }
804 inline PRegisterM PRegister::Merging() const { return PRegisterM(GetCode()); }
805 
806 #define VIXL_REGISTER_WITH_SIZE_LIST(V) \
807   V(WRegister, kWRegSize, Register)     \
808   V(XRegister, kXRegSize, Register)     \
809   V(QRegister, kQRegSize, VRegister)    \
810   V(DRegister, kDRegSize, VRegister)    \
811   V(SRegister, kSRegSize, VRegister)    \
812   V(HRegister, kHRegSize, VRegister)    \
813   V(BRegister, kBRegSize, VRegister)
814 
815 #define VIXL_DEFINE_REGISTER_WITH_SIZE(NAME, SIZE, PARENT)           \
816   class NAME : public PARENT {                                       \
817    public:                                                           \
818     VIXL_CONSTEXPR NAME() : PARENT() {}                              \
819     explicit NAME(int code) : PARENT(code, SIZE) {}                  \
820                                                                      \
821     explicit NAME(PARENT other) : PARENT(other) {                    \
822       VIXL_ASSERT(GetSizeInBits() == SIZE);                          \
823     }                                                                \
824                                                                      \
825     PARENT As##PARENT() const { return *this; }                      \
826                                                                      \
827     VIXL_CONSTEXPR int GetSizeInBits() const { return SIZE; }        \
828                                                                      \
829     bool IsValid() const {                                           \
830       return PARENT::IsValid() && (PARENT::GetSizeInBits() == SIZE); \
831     }                                                                \
832   };
833 
834 VIXL_REGISTER_WITH_SIZE_LIST(VIXL_DEFINE_REGISTER_WITH_SIZE)
835 
836 // No*Reg is used to provide default values for unused arguments, error cases
837 // and so on. Note that these (and the default constructors) all compare equal
838 // (using the Is() method).
839 const Register NoReg;
840 const VRegister NoVReg;
841 const CPURegister NoCPUReg;
842 const ZRegister NoZReg;
843 
844 // TODO: Ideally, these would use specialised register types (like XRegister and
845 // so on). However, doing so throws up template overloading problems elsewhere.
846 #define VIXL_DEFINE_REGISTERS(N)       \
847   const Register w##N = WRegister(N);  \
848   const Register x##N = XRegister(N);  \
849   const VRegister b##N = BRegister(N); \
850   const VRegister h##N = HRegister(N); \
851   const VRegister s##N = SRegister(N); \
852   const VRegister d##N = DRegister(N); \
853   const VRegister q##N = QRegister(N); \
854   const VRegister v##N(N);             \
855   const ZRegister z##N(N);
856 AARCH64_REGISTER_CODE_LIST(VIXL_DEFINE_REGISTERS)
857 #undef VIXL_DEFINE_REGISTERS
858 
859 #define VIXL_DEFINE_P_REGISTERS(N) const PRegister p##N(N);
860 AARCH64_P_REGISTER_CODE_LIST(VIXL_DEFINE_P_REGISTERS)
861 #undef VIXL_DEFINE_P_REGISTERS
862 
863 // Most coercions simply invoke the necessary constructor.
864 #define VIXL_CPUREG_COERCION_LIST(U) \
865   U(Register, W, R)                  \
866   U(Register, X, R)                  \
867   U(VRegister, B, V)                 \
868   U(VRegister, H, V)                 \
869   U(VRegister, S, V)                 \
870   U(VRegister, D, V)                 \
871   U(VRegister, Q, V)                 \
872   U(VRegister, V, V)                 \
873   U(ZRegister, Z, V)                 \
874   U(PRegister, P, P)
875 #define VIXL_DEFINE_CPUREG_COERCION(RET_TYPE, CTOR_TYPE, BANK) \
876   RET_TYPE CPURegister::CTOR_TYPE() const {                    \
877     VIXL_ASSERT(GetBank() == k##BANK##RegisterBank);           \
878     return CTOR_TYPE##Register(GetCode());                     \
879   }
880 VIXL_CPUREG_COERCION_LIST(VIXL_DEFINE_CPUREG_COERCION)
881 #undef VIXL_CPUREG_COERCION_LIST
882 #undef VIXL_DEFINE_CPUREG_COERCION
883 
884 // NEON lane-format coercions always return VRegisters.
885 #define VIXL_CPUREG_NEON_COERCION_LIST(V) \
886   V(8, B)                                 \
887   V(16, B)                                \
888   V(2, H)                                 \
889   V(4, H)                                 \
890   V(8, H)                                 \
891   V(2, S)                                 \
892   V(4, S)                                 \
893   V(1, D)                                 \
894   V(2, D)
895 #define VIXL_DEFINE_CPUREG_NEON_COERCION(LANES, LANE_TYPE)             \
896   VRegister VRegister::V##LANES##LANE_TYPE() const {                   \
897     VIXL_ASSERT(IsVRegister());                                        \
898     return VRegister(GetCode(), LANES * k##LANE_TYPE##RegSize, LANES); \
899   }
900 VIXL_CPUREG_NEON_COERCION_LIST(VIXL_DEFINE_CPUREG_NEON_COERCION)
901 #undef VIXL_CPUREG_NEON_COERCION_LIST
902 #undef VIXL_DEFINE_CPUREG_NEON_COERCION
903 
904 // Semantic type coercion for sdot and udot.
905 // TODO: Use the qualifiers_ field to distinguish this from ::S().
906 VRegister VRegister::S4B() const {
907   VIXL_ASSERT(IsVRegister());
908   return SRegister(GetCode());
909 }
910 
911 // VIXL represents 'sp' with a unique code, to tell it apart from 'xzr'.
912 const Register wsp = WRegister(kSPRegInternalCode);
913 const Register sp = XRegister(kSPRegInternalCode);
914 
915 // Standard aliases.
916 const Register ip0 = x16;
917 const Register ip1 = x17;
918 const Register lr = x30;
919 const Register xzr = x31;
920 const Register wzr = w31;
921 
922 std::string CPURegister::GetArchitecturalName() const {
923   std::ostringstream name;
924   if (IsZRegister()) {
925     name << 'z' << GetCode();
926     if (HasLaneSize()) {
927       name << '.' << GetLaneSizeSymbol();
928     }
929   } else if (IsPRegister()) {
930     name << 'p' << GetCode();
931     if (HasLaneSize()) {
932       name << '.' << GetLaneSizeSymbol();
933     }
934     switch (qualifiers_) {
935       case kNoQualifiers:
936         break;
937       case kMerging:
938         name << "/m";
939         break;
940       case kZeroing:
941         name << "/z";
942         break;
943     }
944   } else {
945     VIXL_UNIMPLEMENTED();
946   }
947   return name.str();
948 }
949 
950 unsigned CPURegister::GetMaxCodeFor(CPURegister::RegisterBank bank) {
951   switch (bank) {
952     case kNoRegisterBank:
953       return 0;
954     case kRRegisterBank:
955       return Register::GetMaxCode();
956     case kVRegisterBank:
957 #ifdef VIXL_HAS_CONSTEXPR
958       VIXL_STATIC_ASSERT(VRegister::GetMaxCode() == ZRegister::GetMaxCode());
959 #else
960       VIXL_ASSERT(VRegister::GetMaxCode() == ZRegister::GetMaxCode());
961 #endif
962       return VRegister::GetMaxCode();
963     case kPRegisterBank:
964       return PRegister::GetMaxCode();
965   }
966   VIXL_UNREACHABLE();
967   return 0;
968 }
969 
970 // AreAliased returns true if any of the named registers overlap. Arguments
971 // set to NoReg are ignored. The system stack pointer may be specified.
972 inline
973 bool AreAliased(const CPURegister& reg1,
974                 const CPURegister& reg2,
975                 const CPURegister& reg3 = NoReg,
976                 const CPURegister& reg4 = NoReg,
977                 const CPURegister& reg5 = NoReg,
978                 const CPURegister& reg6 = NoReg,
979                 const CPURegister& reg7 = NoReg,
980                 const CPURegister& reg8 = NoReg) {
981   int number_of_valid_regs = 0;
982   int number_of_valid_vregs = 0;
983   int number_of_valid_pregs = 0;
984 
985   RegList unique_regs = 0;
986   RegList unique_vregs = 0;
987   RegList unique_pregs = 0;
988 
989   const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
990 
991   for (size_t i = 0; i < ArrayLength(regs); i++) {
992     switch (regs[i].GetBank()) {
993       case CPURegister::kRRegisterBank:
994         number_of_valid_regs++;
995         unique_regs |= regs[i].GetBit();
996         break;
997       case CPURegister::kVRegisterBank:
998         number_of_valid_vregs++;
999         unique_vregs |= regs[i].GetBit();
1000         break;
1001       case CPURegister::kPRegisterBank:
1002         number_of_valid_pregs++;
1003         unique_pregs |= regs[i].GetBit();
1004         break;
1005       case CPURegister::kNoRegisterBank:
1006         VIXL_ASSERT(regs[i].IsNone());
1007         break;
1008     }
1009   }
1010 
1011   int number_of_unique_regs = CountSetBits(unique_regs);
1012   int number_of_unique_vregs = CountSetBits(unique_vregs);
1013   int number_of_unique_pregs = CountSetBits(unique_pregs);
1014 
1015   VIXL_ASSERT(number_of_valid_regs >= number_of_unique_regs);
1016   VIXL_ASSERT(number_of_valid_vregs >= number_of_unique_vregs);
1017   VIXL_ASSERT(number_of_valid_pregs >= number_of_unique_pregs);
1018 
1019   return (number_of_valid_regs != number_of_unique_regs) ||
1020          (number_of_valid_vregs != number_of_unique_vregs) ||
1021          (number_of_valid_pregs != number_of_unique_pregs);
1022 }
1023 
1024 // AreSameSizeAndType returns true if all of the specified registers have the
1025 // same size, and are of the same type. The system stack pointer may be
1026 // specified. Arguments set to NoReg are ignored, as are any subsequent
1027 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
1028 inline
1029 bool AreSameSizeAndType(const CPURegister& reg1,
1030                         const CPURegister& reg2,
1031                         const CPURegister& reg3 = NoCPUReg,
1032                         const CPURegister& reg4 = NoCPUReg,
1033                         const CPURegister& reg5 = NoCPUReg,
1034                         const CPURegister& reg6 = NoCPUReg,
1035                         const CPURegister& reg7 = NoCPUReg,
1036                         const CPURegister& reg8 = NoCPUReg) {
1037   VIXL_ASSERT(reg1.IsValid());
1038   bool match = true;
1039   match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
1040   match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
1041   match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
1042   match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
1043   match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
1044   match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
1045   match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
1046   return match;
1047 }
1048 
1049 // AreEven returns true if all of the specified registers have even register
1050 // indices. Arguments set to NoReg are ignored, as are any subsequent
1051 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
1052 inline
1053 bool AreEven(const CPURegister& reg1,
1054              const CPURegister& reg2,
1055              const CPURegister& reg3 = NoReg,
1056              const CPURegister& reg4 = NoReg,
1057              const CPURegister& reg5 = NoReg,
1058              const CPURegister& reg6 = NoReg,
1059              const CPURegister& reg7 = NoReg,
1060              const CPURegister& reg8 = NoReg) {
1061   VIXL_ASSERT(reg1.IsValid());
1062   bool even = (reg1.GetCode() % 2) == 0;
1063   even &= !reg2.IsValid() || ((reg2.GetCode() % 2) == 0);
1064   even &= !reg3.IsValid() || ((reg3.GetCode() % 2) == 0);
1065   even &= !reg4.IsValid() || ((reg4.GetCode() % 2) == 0);
1066   even &= !reg5.IsValid() || ((reg5.GetCode() % 2) == 0);
1067   even &= !reg6.IsValid() || ((reg6.GetCode() % 2) == 0);
1068   even &= !reg7.IsValid() || ((reg7.GetCode() % 2) == 0);
1069   even &= !reg8.IsValid() || ((reg8.GetCode() % 2) == 0);
1070   return even;
1071 }
1072 
1073 // AreConsecutive returns true if all of the specified registers are
1074 // consecutive in the register file. Arguments set to NoReg are ignored, as are
1075 // any subsequent arguments. At least one argument (reg1) must be valid
1076 // (not NoCPUReg).
1077 inline
1078 bool AreConsecutive(const CPURegister& reg1,
1079                     const CPURegister& reg2,
1080                     const CPURegister& reg3 = NoCPUReg,
1081                     const CPURegister& reg4 = NoCPUReg) {
1082   VIXL_ASSERT(reg1.IsValid());
1083 
1084   if (!reg2.IsValid()) {
1085     return true;
1086   } else if (reg2.GetCode() !=
1087              ((reg1.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
1088     return false;
1089   }
1090 
1091   if (!reg3.IsValid()) {
1092     return true;
1093   } else if (reg3.GetCode() !=
1094              ((reg2.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
1095     return false;
1096   }
1097 
1098   if (!reg4.IsValid()) {
1099     return true;
1100   } else if (reg4.GetCode() !=
1101              ((reg3.GetCode() + 1) % (reg1.GetMaxCode() + 1))) {
1102     return false;
1103   }
1104 
1105   return true;
1106 }
1107 
1108 // AreSameFormat returns true if all of the specified registers have the same
1109 // vector format. Arguments set to NoReg are ignored, as are any subsequent
1110 // arguments. At least one argument (reg1) must be valid (not NoVReg).
1111 inline
1112 bool AreSameFormat(const CPURegister& reg1,
1113                    const CPURegister& reg2,
1114                    const CPURegister& reg3 = NoCPUReg,
1115                    const CPURegister& reg4 = NoCPUReg) {
1116   VIXL_ASSERT(reg1.IsValid());
1117   bool match = true;
1118   match &= !reg2.IsValid() || reg2.IsSameFormat(reg1);
1119   match &= !reg3.IsValid() || reg3.IsSameFormat(reg1);
1120   match &= !reg4.IsValid() || reg4.IsSameFormat(reg1);
1121   return match;
1122 }
1123 
1124 // AreSameLaneSize returns true if all of the specified registers have the same
1125 // element lane size, B, H, S or D. It doesn't compare the type of registers.
1126 // Arguments set to NoReg are ignored, as are any subsequent arguments.
1127 // At least one argument (reg1) must be valid (not NoVReg).
1128 // TODO: Remove this, and replace its uses with AreSameFormat.
1129 inline
1130 bool AreSameLaneSize(const CPURegister& reg1,
1131                      const CPURegister& reg2,
1132                      const CPURegister& reg3 = NoCPUReg,
1133                      const CPURegister& reg4 = NoCPUReg) {
1134   VIXL_ASSERT(reg1.IsValid());
1135   bool match = true;
1136   match &=
1137       !reg2.IsValid() || (reg2.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
1138   match &=
1139       !reg3.IsValid() || (reg3.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
1140   match &=
1141       !reg4.IsValid() || (reg4.GetLaneSizeInBits() == reg1.GetLaneSizeInBits());
1142   return match;
1143 }
1144 }  // namespace aarch64
1145 }  // namespace vixl
1146 
1147 #endif  // VIXL_AARCH64_REGISTERS_AARCH64_H_
1148