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