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