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