• 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   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.
215   bool IsValidRegister() const;
216   bool IsValidVRegister() const;
217   bool IsValidFPRegister() const;
218   bool IsValidZRegister() const;
219   bool IsValidPRegister() const;
220 
221   bool IsValid() const;
IsValidOrNone()222   bool IsValidOrNone() const { return IsNone() || IsValid(); }
223 
IsVector()224   bool IsVector() const { return HasLaneSize() && (size_ != lane_size_); }
IsScalar()225   bool IsScalar() const { return HasLaneSize() && (size_ == lane_size_); }
226 
IsSameType(const CPURegister & other)227   bool IsSameType(const CPURegister& other) const {
228     return GetType() == other.GetType();
229   }
230 
IsSameBank(const CPURegister & other)231   bool IsSameBank(const CPURegister& other) const {
232     return GetBank() == other.GetBank();
233   }
234 
235   // Two registers with unknown size are considered to have the same size if
236   // they also have the same type. For example, all Z registers have the same
237   // size, even though we don't know what that is.
IsSameSizeAndType(const CPURegister & other)238   bool IsSameSizeAndType(const CPURegister& other) const {
239     return IsSameType(other) && (size_ == other.size_);
240   }
241 
IsSameFormat(const CPURegister & other)242   bool IsSameFormat(const CPURegister& other) const {
243     return IsSameSizeAndType(other) && (lane_size_ == other.lane_size_);
244   }
245 
246   // Note that NoReg aliases itself, so that 'Is' implies 'Aliases'.
Aliases(const CPURegister & other)247   bool Aliases(const CPURegister& other) const {
248     return IsSameBank(other) && (code_ == other.code_);
249   }
250 
Is(const CPURegister & other)251   bool Is(const CPURegister& other) const {
252     if (IsRegister() || IsVRegister()) {
253       // For core (W, X) and FP/NEON registers, we only consider the code, size
254       // and type. This is legacy behaviour.
255       // TODO: We should probably check every field for all registers.
256       return Aliases(other) && (size_ == other.size_);
257     } else {
258       // For Z and P registers, we require all fields to match exactly.
259       VIXL_ASSERT(IsNone() || IsZRegister() || IsPRegister());
260       return (code_ == other.code_) && (bank_ == other.bank_) &&
261              (size_ == other.size_) && (qualifiers_ == other.qualifiers_) &&
262              (lane_size_ == other.lane_size_);
263     }
264   }
265 
266   // Conversions to specific register types. The result is a register that
267   // aliases the original CPURegister. That is, the original register bank
268   // (`GetBank()`) is checked and the code (`GetCode()`) preserved, but all
269   // other properties are ignored.
270   //
271   // Typical usage:
272   //
273   //     if (reg.GetBank() == kVRegisterBank) {
274   //       DRegister d = reg.D();
275   //       ...
276   //     }
277   //
278   // These could all return types with compile-time guarantees (like XRegister),
279   // but this breaks backwards-compatibility quite severely, particularly with
280   // code like `cond ? reg.W() : reg.X()`, which would have indeterminate type.
281 
282   // Core registers, like "w0".
283   Register W() const;
284   Register X() const;
285   // FP/NEON registers, like "b0".
286   VRegister B() const;
287   VRegister H() const;
288   VRegister S() const;
289   VRegister D() const;
290   VRegister Q() const;
291   VRegister V() const;
292   // SVE registers, like "z0".
293   ZRegister Z() const;
294   PRegister P() const;
295 
296   // Utilities for kRegister types.
297 
IsZero()298   bool IsZero() const { return IsRegister() && (code_ == kZeroRegCode); }
IsSP()299   bool IsSP() const { return IsRegister() && (code_ == kSPRegInternalCode); }
IsW()300   bool IsW() const { return IsRegister() && Is32Bits(); }
IsX()301   bool IsX() const { return IsRegister() && Is64Bits(); }
302 
303   // Utilities for FP/NEON kVRegister types.
304 
305   // These helpers ensure that the size and type of the register are as
306   // described. They do not consider the number of lanes that make up a vector.
307   // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
308   // does not imply Is1D() or Is8B().
309   // Check the number of lanes, ie. the format of the vector, using methods such
310   // as Is8B(), Is1D(), etc.
IsB()311   bool IsB() const { return IsVRegister() && Is8Bits(); }
IsH()312   bool IsH() const { return IsVRegister() && Is16Bits(); }
IsS()313   bool IsS() const { return IsVRegister() && Is32Bits(); }
IsD()314   bool IsD() const { return IsVRegister() && Is64Bits(); }
IsQ()315   bool IsQ() const { return IsVRegister() && Is128Bits(); }
316 
317   // As above, but also check that the register has exactly one lane. For
318   // example, reg.Is1D() implies DRegister(reg).IsValid(), but reg.IsD() does
319   // not.
Is1B()320   bool Is1B() const { return IsB() && IsScalar(); }
Is1H()321   bool Is1H() const { return IsH() && IsScalar(); }
Is1S()322   bool Is1S() const { return IsS() && IsScalar(); }
Is1D()323   bool Is1D() const { return IsD() && IsScalar(); }
Is1Q()324   bool Is1Q() const { return IsQ() && IsScalar(); }
325 
326   // Check the specific NEON format.
Is8B()327   bool Is8B() const { return IsD() && IsLaneSizeB(); }
Is16B()328   bool Is16B() const { return IsQ() && IsLaneSizeB(); }
Is2H()329   bool Is2H() const { return IsS() && IsLaneSizeH(); }
Is4H()330   bool Is4H() const { return IsD() && IsLaneSizeH(); }
Is8H()331   bool Is8H() const { return IsQ() && IsLaneSizeH(); }
Is2S()332   bool Is2S() const { return IsD() && IsLaneSizeS(); }
Is4S()333   bool Is4S() const { return IsQ() && IsLaneSizeS(); }
Is2D()334   bool Is2D() const { return IsQ() && IsLaneSizeD(); }
335 
336   // A semantic alias for sdot and udot (indexed and by element) instructions.
337   // The current CPURegister implementation cannot not tell this from Is1S(),
338   // but it might do later.
339   // TODO: Do this with the qualifiers_ field.
Is1S4B()340   bool Is1S4B() const { return Is1S(); }
341 
342   // Utilities for SVE registers.
343 
IsUnqualified()344   bool IsUnqualified() const { return qualifiers_ == kNoQualifiers; }
IsMerging()345   bool IsMerging() const { return IsPRegister() && (qualifiers_ == kMerging); }
IsZeroing()346   bool IsZeroing() const { return IsPRegister() && (qualifiers_ == kZeroing); }
347 
348   // SVE types have unknown sizes, but within known bounds.
349 
GetMaxSizeInBytes()350   int GetMaxSizeInBytes() const {
351     switch (GetType()) {
352       case kZRegister:
353         return kZRegMaxSizeInBytes;
354       case kPRegister:
355         return kPRegMaxSizeInBytes;
356       default:
357         VIXL_ASSERT(HasSize());
358         return GetSizeInBits();
359     }
360   }
361 
GetMinSizeInBytes()362   int GetMinSizeInBytes() const {
363     switch (GetType()) {
364       case kZRegister:
365         return kZRegMinSizeInBytes;
366       case kPRegister:
367         return kPRegMinSizeInBytes;
368       default:
369         VIXL_ASSERT(HasSize());
370         return GetSizeInBits();
371     }
372   }
373 
GetMaxSizeInBits()374   int GetMaxSizeInBits() const { return GetMaxSizeInBytes() * kBitsPerByte; }
GetMinSizeInBits()375   int GetMinSizeInBits() const { return GetMinSizeInBytes() * kBitsPerByte; }
376 
GetBankFor(RegisterType type)377   static RegisterBank GetBankFor(RegisterType type) {
378     switch (type) {
379       case kNoRegister:
380         return kNoRegisterBank;
381       case kRegister:
382         return kRRegisterBank;
383       case kVRegister:
384       case kZRegister:
385         return kVRegisterBank;
386       case kPRegister:
387         return kPRegisterBank;
388     }
389     VIXL_UNREACHABLE();
390     return kNoRegisterBank;
391   }
392 
GetMaxCodeFor(CPURegister::RegisterType type)393   static unsigned GetMaxCodeFor(CPURegister::RegisterType type) {
394     return GetMaxCodeFor(GetBankFor(type));
395   }
396 
397  protected:
398   enum EncodedSize : uint8_t {
399     // Ensure that kUnknownSize (and therefore kNoRegister) is encoded as zero.
400     kEncodedUnknownSize = 0,
401 
402     // The implementation assumes that the remaining sizes are encoded as
403     // `log2(size) + c`, so the following names must remain in sequence.
404     kEncodedBRegSize,
405     kEncodedHRegSize,
406     kEncodedSRegSize,
407     kEncodedDRegSize,
408     kEncodedQRegSize,
409 
410     kEncodedWRegSize = kEncodedSRegSize,
411     kEncodedXRegSize = kEncodedDRegSize
412   };
413   VIXL_STATIC_ASSERT(kSRegSize == kWRegSize);
414   VIXL_STATIC_ASSERT(kDRegSize == kXRegSize);
415 
GetLaneSizeSymbol()416   char GetLaneSizeSymbol() const {
417     switch (lane_size_) {
418       case kEncodedBRegSize:
419         return 'B';
420       case kEncodedHRegSize:
421         return 'H';
422       case kEncodedSRegSize:
423         return 'S';
424       case kEncodedDRegSize:
425         return 'D';
426       case kEncodedQRegSize:
427         return 'Q';
428       case kEncodedUnknownSize:
429         break;
430     }
431     VIXL_UNREACHABLE();
432     return '?';
433   }
434 
EncodeSizeInBits(int size_in_bits)435   static EncodedSize EncodeSizeInBits(int size_in_bits) {
436     switch (size_in_bits) {
437       case kUnknownSize:
438         return kEncodedUnknownSize;
439       case kBRegSize:
440         return kEncodedBRegSize;
441       case kHRegSize:
442         return kEncodedHRegSize;
443       case kSRegSize:
444         return kEncodedSRegSize;
445       case kDRegSize:
446         return kEncodedDRegSize;
447       case kQRegSize:
448         return kEncodedQRegSize;
449     }
450     VIXL_UNREACHABLE();
451     return kEncodedUnknownSize;
452   }
453 
DecodeSizeInBytesLog2(EncodedSize encoded_size)454   static int DecodeSizeInBytesLog2(EncodedSize encoded_size) {
455     switch (encoded_size) {
456       case kEncodedUnknownSize:
457         // Log2 of B-sized lane in bytes is 0, so we can't just return 0 here.
458         VIXL_UNREACHABLE();
459         return -1;
460       case kEncodedBRegSize:
461         return kBRegSizeInBytesLog2;
462       case kEncodedHRegSize:
463         return kHRegSizeInBytesLog2;
464       case kEncodedSRegSize:
465         return kSRegSizeInBytesLog2;
466       case kEncodedDRegSize:
467         return kDRegSizeInBytesLog2;
468       case kEncodedQRegSize:
469         return kQRegSizeInBytesLog2;
470     }
471     VIXL_UNREACHABLE();
472     return kUnknownSize;
473   }
474 
DecodeSizeInBytes(EncodedSize encoded_size)475   static int DecodeSizeInBytes(EncodedSize encoded_size) {
476     if (encoded_size == kEncodedUnknownSize) {
477       return kUnknownSize;
478     }
479     return 1 << DecodeSizeInBytesLog2(encoded_size);
480   }
481 
DecodeSizeInBits(EncodedSize encoded_size)482   static int DecodeSizeInBits(EncodedSize encoded_size) {
483     VIXL_STATIC_ASSERT(kUnknownSize == 0);
484     return DecodeSizeInBytes(encoded_size) * kBitsPerByte;
485   }
486 
487   static unsigned GetMaxCodeFor(CPURegister::RegisterBank bank);
488 
489   enum Qualifiers : uint8_t {
490     kNoQualifiers = 0,
491     // Used by P registers.
492     kMerging,
493     kZeroing
494   };
495 
496   // An unchecked constructor, for use by derived classes.
497   CPURegister(int code,
498               EncodedSize size,
499               RegisterBank bank,
500               EncodedSize lane_size,
501               Qualifiers qualifiers = kNoQualifiers)
code_(code)502       : code_(code),
503         bank_(bank),
504         size_(size),
505         qualifiers_(qualifiers),
506         lane_size_(lane_size) {}
507 
508   // TODO: Check that access to these fields is reasonably efficient.
509   uint8_t code_;
510   RegisterBank bank_;
511   EncodedSize size_;
512   Qualifiers qualifiers_;
513   EncodedSize lane_size_;
514 };
515 // Ensure that CPURegisters can fit in a single (64-bit) register. This is a
516 // proxy for being "cheap to pass by value", which is hard to check directly.
517 VIXL_STATIC_ASSERT(sizeof(CPURegister) <= sizeof(uint64_t));
518 
519 // TODO: Add constexpr constructors.
520 #define VIXL_DECLARE_REGISTER_COMMON(NAME, REGISTER_TYPE, PARENT_TYPE) \
521   VIXL_CONSTEXPR NAME() : PARENT_TYPE() {}                             \
522                                                                        \
523   explicit NAME(CPURegister other) : PARENT_TYPE(other) {              \
524     VIXL_ASSERT(IsValid());                                            \
525   }                                                                    \
526                                                                        \
527   VIXL_CONSTEXPR static unsigned GetMaxCode() {                        \
528     return kNumberOf##REGISTER_TYPE##s - 1;                            \
529   }
530 
531 // Any W or X register, including the zero register and the stack pointer.
532 class Register : public CPURegister {
533  public:
VIXL_DECLARE_REGISTER_COMMON(Register,Register,CPURegister)534   VIXL_DECLARE_REGISTER_COMMON(Register, Register, CPURegister)
535 
536   Register(int code, int size_in_bits)
537       : CPURegister(code, size_in_bits, kRegister) {
538     VIXL_ASSERT(IsValidRegister());
539   }
540 
IsValid()541   bool IsValid() const { return IsValidRegister(); }
542 };
543 
544 // Any FP or NEON V register, including vector (V.<T>) and scalar forms
545 // (B, H, S, D, Q).
546 class VRegister : public CPURegister {
547  public:
VIXL_DECLARE_REGISTER_COMMON(VRegister,VRegister,CPURegister)548   VIXL_DECLARE_REGISTER_COMMON(VRegister, VRegister, CPURegister)
549 
550   // For historical reasons, VRegister(0) returns v0.1Q (or equivalently, q0).
551   explicit VRegister(int code, int size_in_bits = kQRegSize, int lanes = 1)
552       : CPURegister(code,
553                     EncodeSizeInBits(size_in_bits),
554                     kVRegisterBank,
555                     EncodeLaneSizeInBits(size_in_bits, lanes)) {
556     VIXL_ASSERT(IsValidVRegister());
557   }
558 
VRegister(int code,VectorFormat format)559   VRegister(int code, VectorFormat format)
560       : CPURegister(code,
561                     EncodeSizeInBits(RegisterSizeInBitsFromFormat(format)),
562                     kVRegisterBank,
563                     EncodeSizeInBits(LaneSizeInBitsFromFormat(format)),
564                     kNoQualifiers) {
565     VIXL_ASSERT(IsValid());
566   }
567 
568   VRegister V8B() const;
569   VRegister V16B() const;
570   VRegister V2H() const;
571   VRegister V4H() const;
572   VRegister V8H() const;
573   VRegister V2S() const;
574   VRegister V4S() const;
575   VRegister V1D() const;
576   VRegister V2D() const;
577   VRegister S4B() const;
578 
IsValid()579   bool IsValid() const { return IsValidVRegister(); }
580 
581  protected:
EncodeLaneSizeInBits(int size_in_bits,int lanes)582   static EncodedSize EncodeLaneSizeInBits(int size_in_bits, int lanes) {
583     VIXL_ASSERT(lanes >= 1);
584     VIXL_ASSERT((size_in_bits % lanes) == 0);
585     return EncodeSizeInBits(size_in_bits / lanes);
586   }
587 };
588 
589 // Any SVE Z register, with or without a lane size specifier.
590 class ZRegister : public CPURegister {
591  public:
VIXL_DECLARE_REGISTER_COMMON(ZRegister,ZRegister,CPURegister)592   VIXL_DECLARE_REGISTER_COMMON(ZRegister, ZRegister, CPURegister)
593 
594   explicit ZRegister(int code, int lane_size_in_bits = kUnknownSize)
595       : CPURegister(code,
596                     kEncodedUnknownSize,
597                     kVRegisterBank,
598                     EncodeSizeInBits(lane_size_in_bits)) {
599     VIXL_ASSERT(IsValid());
600   }
601 
ZRegister(int code,VectorFormat format)602   ZRegister(int code, VectorFormat format)
603       : CPURegister(code,
604                     kEncodedUnknownSize,
605                     kVRegisterBank,
606                     EncodeSizeInBits(LaneSizeInBitsFromFormat(format)),
607                     kNoQualifiers) {
608     VIXL_ASSERT(IsValid());
609   }
610 
611   // Return a Z register with a known lane size (like "z0.B").
VnB()612   ZRegister VnB() const { return ZRegister(GetCode(), kBRegSize); }
VnH()613   ZRegister VnH() const { return ZRegister(GetCode(), kHRegSize); }
VnS()614   ZRegister VnS() const { return ZRegister(GetCode(), kSRegSize); }
VnD()615   ZRegister VnD() const { return ZRegister(GetCode(), kDRegSize); }
VnQ()616   ZRegister VnQ() const { return ZRegister(GetCode(), kQRegSize); }
617 
618   template <typename T>
WithLaneSize(T format)619   ZRegister WithLaneSize(T format) const {
620     return ZRegister(GetCode(), format);
621   }
622 
WithSameLaneSizeAs(const CPURegister & other)623   ZRegister WithSameLaneSizeAs(const CPURegister& other) const {
624     VIXL_ASSERT(other.HasLaneSize());
625     return this->WithLaneSize(other.GetLaneSizeInBits());
626   }
627 
IsValid()628   bool IsValid() const { return IsValidZRegister(); }
629 };
630 
631 // Any SVE P register, with or without a qualifier or lane size specifier.
632 class PRegister : public CPURegister {
633  public:
VIXL_DECLARE_REGISTER_COMMON(PRegister,PRegister,CPURegister)634   VIXL_DECLARE_REGISTER_COMMON(PRegister, PRegister, CPURegister)
635 
636   explicit PRegister(int code) : CPURegister(code, kUnknownSize, kPRegister) {
637     VIXL_ASSERT(IsValid());
638   }
639 
IsValid()640   bool IsValid() const {
641     return IsValidPRegister() && !HasLaneSize() && IsUnqualified();
642   }
643 
644   // Return a P register with a known lane size (like "p0.B").
645   PRegisterWithLaneSize VnB() const;
646   PRegisterWithLaneSize VnH() const;
647   PRegisterWithLaneSize VnS() const;
648   PRegisterWithLaneSize VnD() const;
649 
650   template <typename T>
651   PRegisterWithLaneSize WithLaneSize(T format) const;
652 
653   PRegisterWithLaneSize WithSameLaneSizeAs(const CPURegister& other) const;
654 
655   // SVE predicates are specified (in normal assembly) with a "/z" (zeroing) or
656   // "/m" (merging) suffix. These methods are VIXL's equivalents.
657   PRegisterZ Zeroing() const;
658   PRegisterM Merging() const;
659 
660  protected:
661   // Unchecked constructors, for use by derived classes.
PRegister(int code,EncodedSize encoded_lane_size)662   PRegister(int code, EncodedSize encoded_lane_size)
663       : CPURegister(code,
664                     kEncodedUnknownSize,
665                     kPRegisterBank,
666                     encoded_lane_size,
667                     kNoQualifiers) {}
668 
PRegister(int code,Qualifiers qualifiers)669   PRegister(int code, Qualifiers qualifiers)
670       : CPURegister(code,
671                     kEncodedUnknownSize,
672                     kPRegisterBank,
673                     kEncodedUnknownSize,
674                     qualifiers) {}
675 };
676 
677 // Any SVE P register with a known lane size (like "p0.B").
678 class PRegisterWithLaneSize : public PRegister {
679  public:
VIXL_DECLARE_REGISTER_COMMON(PRegisterWithLaneSize,PRegister,PRegister)680   VIXL_DECLARE_REGISTER_COMMON(PRegisterWithLaneSize, PRegister, PRegister)
681 
682   PRegisterWithLaneSize(int code, int lane_size_in_bits)
683       : PRegister(code, EncodeSizeInBits(lane_size_in_bits)) {
684     VIXL_ASSERT(IsValid());
685   }
686 
PRegisterWithLaneSize(int code,VectorFormat format)687   PRegisterWithLaneSize(int code, VectorFormat format)
688       : PRegister(code, EncodeSizeInBits(LaneSizeInBitsFromFormat(format))) {
689     VIXL_ASSERT(IsValid());
690   }
691 
IsValid()692   bool IsValid() const {
693     return IsValidPRegister() && HasLaneSize() && IsUnqualified();
694   }
695 
696   // Overload lane size accessors so we can assert `HasLaneSize()`. This allows
697   // tools such as clang-tidy to prove that the result of GetLaneSize* is
698   // non-zero.
699 
700   // TODO: Make these return 'int'.
GetLaneSizeInBits()701   unsigned GetLaneSizeInBits() const {
702     VIXL_ASSERT(HasLaneSize());
703     return PRegister::GetLaneSizeInBits();
704   }
705 
GetLaneSizeInBytes()706   unsigned GetLaneSizeInBytes() const {
707     VIXL_ASSERT(HasLaneSize());
708     return PRegister::GetLaneSizeInBytes();
709   }
710 };
711 
712 // Any SVE P register with the zeroing qualifier (like "p0/z").
713 class PRegisterZ : public PRegister {
714  public:
VIXL_DECLARE_REGISTER_COMMON(PRegisterZ,PRegister,PRegister)715   VIXL_DECLARE_REGISTER_COMMON(PRegisterZ, PRegister, PRegister)
716 
717   explicit PRegisterZ(int code) : PRegister(code, kZeroing) {
718     VIXL_ASSERT(IsValid());
719   }
720 
IsValid()721   bool IsValid() const {
722     return IsValidPRegister() && !HasLaneSize() && IsZeroing();
723   }
724 };
725 
726 // Any SVE P register with the merging qualifier (like "p0/m").
727 class PRegisterM : public PRegister {
728  public:
VIXL_DECLARE_REGISTER_COMMON(PRegisterM,PRegister,PRegister)729   VIXL_DECLARE_REGISTER_COMMON(PRegisterM, PRegister, PRegister)
730 
731   explicit PRegisterM(int code) : PRegister(code, kMerging) {
732     VIXL_ASSERT(IsValid());
733   }
734 
IsValid()735   bool IsValid() const {
736     return IsValidPRegister() && !HasLaneSize() && IsMerging();
737   }
738 };
739 
VnB()740 inline PRegisterWithLaneSize PRegister::VnB() const {
741   return PRegisterWithLaneSize(GetCode(), kBRegSize);
742 }
VnH()743 inline PRegisterWithLaneSize PRegister::VnH() const {
744   return PRegisterWithLaneSize(GetCode(), kHRegSize);
745 }
VnS()746 inline PRegisterWithLaneSize PRegister::VnS() const {
747   return PRegisterWithLaneSize(GetCode(), kSRegSize);
748 }
VnD()749 inline PRegisterWithLaneSize PRegister::VnD() const {
750   return PRegisterWithLaneSize(GetCode(), kDRegSize);
751 }
752 
753 template <typename T>
WithLaneSize(T format)754 inline PRegisterWithLaneSize PRegister::WithLaneSize(T format) const {
755   return PRegisterWithLaneSize(GetCode(), format);
756 }
757 
WithSameLaneSizeAs(const CPURegister & other)758 inline PRegisterWithLaneSize PRegister::WithSameLaneSizeAs(
759     const CPURegister& other) const {
760   VIXL_ASSERT(other.HasLaneSize());
761   return this->WithLaneSize(other.GetLaneSizeInBits());
762 }
763 
Zeroing()764 inline PRegisterZ PRegister::Zeroing() const { return PRegisterZ(GetCode()); }
Merging()765 inline PRegisterM PRegister::Merging() const { return PRegisterM(GetCode()); }
766 
767 #define VIXL_REGISTER_WITH_SIZE_LIST(V) \
768   V(WRegister, kWRegSize, Register)     \
769   V(XRegister, kXRegSize, Register)     \
770   V(QRegister, kQRegSize, VRegister)    \
771   V(DRegister, kDRegSize, VRegister)    \
772   V(SRegister, kSRegSize, VRegister)    \
773   V(HRegister, kHRegSize, VRegister)    \
774   V(BRegister, kBRegSize, VRegister)
775 
776 #define VIXL_DEFINE_REGISTER_WITH_SIZE(NAME, SIZE, PARENT)           \
777   class NAME : public PARENT {                                       \
778    public:                                                           \
779     VIXL_CONSTEXPR NAME() : PARENT() {}                              \
780     explicit NAME(int code) : PARENT(code, SIZE) {}                  \
781                                                                      \
782     explicit NAME(PARENT other) : PARENT(other) {                    \
783       VIXL_ASSERT(GetSizeInBits() == SIZE);                          \
784     }                                                                \
785                                                                      \
786     PARENT As##PARENT() const { return *this; }                      \
787                                                                      \
788     VIXL_CONSTEXPR int GetSizeInBits() const { return SIZE; }        \
789                                                                      \
790     bool IsValid() const {                                           \
791       return PARENT::IsValid() && (PARENT::GetSizeInBits() == SIZE); \
792     }                                                                \
793   };
794 
795 VIXL_REGISTER_WITH_SIZE_LIST(VIXL_DEFINE_REGISTER_WITH_SIZE)
796 
797 // No*Reg is used to provide default values for unused arguments, error cases
798 // and so on. Note that these (and the default constructors) all compare equal
799 // (using the Is() method).
800 const Register NoReg;
801 const VRegister NoVReg;
802 const CPURegister NoCPUReg;
803 const ZRegister NoZReg;
804 
805 // TODO: Ideally, these would use specialised register types (like XRegister and
806 // so on). However, doing so throws up template overloading problems elsewhere.
807 #define VIXL_DEFINE_REGISTERS(N)       \
808   const Register w##N = WRegister(N);  \
809   const Register x##N = XRegister(N);  \
810   const VRegister b##N = BRegister(N); \
811   const VRegister h##N = HRegister(N); \
812   const VRegister s##N = SRegister(N); \
813   const VRegister d##N = DRegister(N); \
814   const VRegister q##N = QRegister(N); \
815   const VRegister v##N(N);             \
816   const ZRegister z##N(N);
817 AARCH64_REGISTER_CODE_LIST(VIXL_DEFINE_REGISTERS)
818 #undef VIXL_DEFINE_REGISTERS
819 
820 #define VIXL_DEFINE_P_REGISTERS(N) const PRegister p##N(N);
821 AARCH64_P_REGISTER_CODE_LIST(VIXL_DEFINE_P_REGISTERS)
822 #undef VIXL_DEFINE_P_REGISTERS
823 
824 // VIXL represents 'sp' with a unique code, to tell it apart from 'xzr'.
825 const Register wsp = WRegister(kSPRegInternalCode);
826 const Register sp = XRegister(kSPRegInternalCode);
827 
828 // Standard aliases.
829 const Register ip0 = x16;
830 const Register ip1 = x17;
831 const Register lr = x30;
832 const Register xzr = x31;
833 const Register wzr = w31;
834 
835 // AreAliased returns true if any of the named registers overlap. Arguments
836 // set to NoReg are ignored. The system stack pointer may be specified.
837 bool AreAliased(const CPURegister& reg1,
838                 const CPURegister& reg2,
839                 const CPURegister& reg3 = NoReg,
840                 const CPURegister& reg4 = NoReg,
841                 const CPURegister& reg5 = NoReg,
842                 const CPURegister& reg6 = NoReg,
843                 const CPURegister& reg7 = NoReg,
844                 const CPURegister& reg8 = NoReg);
845 
846 // AreSameSizeAndType returns true if all of the specified registers have the
847 // same size, and are of the same type. The system stack pointer may be
848 // specified. Arguments set to NoReg are ignored, as are any subsequent
849 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
850 bool AreSameSizeAndType(const CPURegister& reg1,
851                         const CPURegister& reg2,
852                         const CPURegister& reg3 = NoCPUReg,
853                         const CPURegister& reg4 = NoCPUReg,
854                         const CPURegister& reg5 = NoCPUReg,
855                         const CPURegister& reg6 = NoCPUReg,
856                         const CPURegister& reg7 = NoCPUReg,
857                         const CPURegister& reg8 = NoCPUReg);
858 
859 // AreEven returns true if all of the specified registers have even register
860 // indices. Arguments set to NoReg are ignored, as are any subsequent
861 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
862 bool AreEven(const CPURegister& reg1,
863              const CPURegister& reg2,
864              const CPURegister& reg3 = NoReg,
865              const CPURegister& reg4 = NoReg,
866              const CPURegister& reg5 = NoReg,
867              const CPURegister& reg6 = NoReg,
868              const CPURegister& reg7 = NoReg,
869              const CPURegister& reg8 = NoReg);
870 
871 // AreConsecutive returns true if all of the specified registers are
872 // consecutive in the register file. Arguments set to NoReg are ignored, as are
873 // any subsequent arguments. At least one argument (reg1) must be valid
874 // (not NoCPUReg).
875 bool AreConsecutive(const CPURegister& reg1,
876                     const CPURegister& reg2,
877                     const CPURegister& reg3 = NoCPUReg,
878                     const CPURegister& reg4 = NoCPUReg);
879 
880 // AreSameFormat returns true if all of the specified registers have the same
881 // vector format. Arguments set to NoReg are ignored, as are any subsequent
882 // arguments. At least one argument (reg1) must be valid (not NoVReg).
883 bool AreSameFormat(const CPURegister& reg1,
884                    const CPURegister& reg2,
885                    const CPURegister& reg3 = NoCPUReg,
886                    const CPURegister& reg4 = NoCPUReg);
887 
888 // AreSameLaneSize returns true if all of the specified registers have the same
889 // element lane size, B, H, S or D. It doesn't compare the type of registers.
890 // Arguments set to NoReg are ignored, as are any subsequent arguments.
891 // At least one argument (reg1) must be valid (not NoVReg).
892 // TODO: Remove this, and replace its uses with AreSameFormat.
893 bool AreSameLaneSize(const CPURegister& reg1,
894                      const CPURegister& reg2,
895                      const CPURegister& reg3 = NoCPUReg,
896                      const CPURegister& reg4 = NoCPUReg);
897 }
898 }  // namespace vixl::aarch64
899 
900 #endif  // VIXL_AARCH64_REGISTERS_AARCH64_H_
901