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