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