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 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.
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.
IsValidRegister()216 bool IsValidRegister() const {
217 return ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode)) &&
218 (bank_ == kRRegisterBank) &&
219 ((size_ == kEncodedWRegSize) || (size_ == kEncodedXRegSize)) &&
220 (qualifiers_ == kNoQualifiers) && (lane_size_ == size_);
221 }
222
IsValidVRegister()223 bool 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
IsValidFPRegister()231 bool IsValidFPRegister() const {
232 return IsValidVRegister() && IsFPRegister();
233 }
234
IsValidZRegister()235 bool 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
IsValidPRegister()243 bool 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
IsValid()253 bool IsValid() const {
254 return IsValidRegister() || IsValidVRegister() || IsValidZRegister() ||
255 IsValidPRegister();
256 }
257
IsValidOrNone()258 bool IsValidOrNone() const { return IsNone() || IsValid(); }
259
IsVector()260 bool IsVector() const { return HasLaneSize() && (size_ != lane_size_); }
IsScalar()261 bool IsScalar() const { return HasLaneSize() && (size_ == lane_size_); }
262
IsSameType(const CPURegister & other)263 bool IsSameType(const CPURegister& other) const {
264 return GetType() == other.GetType();
265 }
266
IsSameBank(const CPURegister & other)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.
IsSameSizeAndType(const CPURegister & other)274 bool IsSameSizeAndType(const CPURegister& other) const {
275 return IsSameType(other) && (size_ == other.size_);
276 }
277
IsSameFormat(const CPURegister & other)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'.
Aliases(const CPURegister & other)283 bool Aliases(const CPURegister& other) const {
284 return IsSameBank(other) && (code_ == other.code_);
285 }
286
Is(const CPURegister & other)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
IsZero()334 bool IsZero() const { return IsRegister() && (code_ == kZeroRegCode); }
IsSP()335 bool IsSP() const { return IsRegister() && (code_ == kSPRegInternalCode); }
IsW()336 bool IsW() const { return IsRegister() && Is32Bits(); }
IsX()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.
IsB()347 bool IsB() const { return IsVRegister() && Is8Bits(); }
IsH()348 bool IsH() const { return IsVRegister() && Is16Bits(); }
IsS()349 bool IsS() const { return IsVRegister() && Is32Bits(); }
IsD()350 bool IsD() const { return IsVRegister() && Is64Bits(); }
IsQ()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.
Is1B()356 bool Is1B() const { return IsB() && IsScalar(); }
Is1H()357 bool Is1H() const { return IsH() && IsScalar(); }
Is1S()358 bool Is1S() const { return IsS() && IsScalar(); }
Is1D()359 bool Is1D() const { return IsD() && IsScalar(); }
Is1Q()360 bool Is1Q() const { return IsQ() && IsScalar(); }
361
362 // Check the specific NEON format.
Is8B()363 bool Is8B() const { return IsD() && IsLaneSizeB(); }
Is16B()364 bool Is16B() const { return IsQ() && IsLaneSizeB(); }
Is2H()365 bool Is2H() const { return IsS() && IsLaneSizeH(); }
Is4H()366 bool Is4H() const { return IsD() && IsLaneSizeH(); }
Is8H()367 bool Is8H() const { return IsQ() && IsLaneSizeH(); }
Is2S()368 bool Is2S() const { return IsD() && IsLaneSizeS(); }
Is4S()369 bool Is4S() const { return IsQ() && IsLaneSizeS(); }
Is2D()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.
Is1S4B()376 bool Is1S4B() const { return Is1S(); }
377
378 // Utilities for SVE registers.
379
IsUnqualified()380 bool IsUnqualified() const { return qualifiers_ == kNoQualifiers; }
IsMerging()381 bool IsMerging() const { return IsPRegister() && (qualifiers_ == kMerging); }
IsZeroing()382 bool IsZeroing() const { return IsPRegister() && (qualifiers_ == kZeroing); }
383
384 // SVE types have unknown sizes, but within known bounds.
385
GetMaxSizeInBytes()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
GetMinSizeInBytes()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
GetMaxSizeInBits()410 int GetMaxSizeInBits() const { return GetMaxSizeInBytes() * kBitsPerByte; }
GetMinSizeInBits()411 int GetMinSizeInBits() const { return GetMinSizeInBytes() * kBitsPerByte; }
412
GetBankFor(RegisterType type)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
GetMaxCodeFor(CPURegister::RegisterType type)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
GetLaneSizeSymbol()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
EncodeSizeInBits(int size_in_bits)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
DecodeSizeInBytesLog2(EncodedSize encoded_size)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
DecodeSizeInBytes(EncodedSize encoded_size)511 static int DecodeSizeInBytes(EncodedSize encoded_size) {
512 if (encoded_size == kEncodedUnknownSize) {
513 return kUnknownSize;
514 }
515 return 1 << DecodeSizeInBytesLog2(encoded_size);
516 }
517
DecodeSizeInBits(EncodedSize encoded_size)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)
code_(code)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.
553 VIXL_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.
568 class Register : public CPURegister {
569 public:
VIXL_DECLARE_REGISTER_COMMON(Register,Register,CPURegister)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
IsValid()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).
582 class VRegister : public CPURegister {
583 public:
VIXL_DECLARE_REGISTER_COMMON(VRegister,VRegister,CPURegister)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
VRegister(int code,VectorFormat format)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
IsValid()618 bool IsValid() const { return IsValidVRegister(); }
619
620 protected:
EncodeLaneSizeInBits(int size_in_bits,int lanes)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.
629 class ZRegister : public CPURegister {
630 public:
VIXL_DECLARE_REGISTER_COMMON(ZRegister,ZRegister,CPURegister)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
ZRegister(int code,VectorFormat format)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").
VnB()651 ZRegister VnB() const { return ZRegister(GetCode(), kBRegSize); }
VnH()652 ZRegister VnH() const { return ZRegister(GetCode(), kHRegSize); }
VnS()653 ZRegister VnS() const { return ZRegister(GetCode(), kSRegSize); }
VnD()654 ZRegister VnD() const { return ZRegister(GetCode(), kDRegSize); }
VnQ()655 ZRegister VnQ() const { return ZRegister(GetCode(), kQRegSize); }
656
657 template <typename T>
WithLaneSize(T format)658 ZRegister WithLaneSize(T format) const {
659 return ZRegister(GetCode(), format);
660 }
661
WithSameLaneSizeAs(const CPURegister & other)662 ZRegister WithSameLaneSizeAs(const CPURegister& other) const {
663 VIXL_ASSERT(other.HasLaneSize());
664 return this->WithLaneSize(other.GetLaneSizeInBits());
665 }
666
IsValid()667 bool IsValid() const { return IsValidZRegister(); }
668 };
669
670 // Any SVE P register, with or without a qualifier or lane size specifier.
671 class PRegister : public CPURegister {
672 public:
VIXL_DECLARE_REGISTER_COMMON(PRegister,PRegister,CPURegister)673 VIXL_DECLARE_REGISTER_COMMON(PRegister, PRegister, CPURegister)
674
675 explicit PRegister(int code) : CPURegister(code, kUnknownSize, kPRegister) {
676 VIXL_ASSERT(IsValid());
677 }
678
IsValid()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.
PRegister(int code,EncodedSize encoded_lane_size)701 PRegister(int code, EncodedSize encoded_lane_size)
702 : CPURegister(code,
703 kEncodedUnknownSize,
704 kPRegisterBank,
705 encoded_lane_size,
706 kNoQualifiers) {}
707
PRegister(int code,Qualifiers qualifiers)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").
717 class PRegisterWithLaneSize : public PRegister {
718 public:
VIXL_DECLARE_REGISTER_COMMON(PRegisterWithLaneSize,PRegister,PRegister)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
PRegisterWithLaneSize(int code,VectorFormat format)726 PRegisterWithLaneSize(int code, VectorFormat format)
727 : PRegister(code, EncodeSizeInBits(LaneSizeInBitsFromFormat(format))) {
728 VIXL_ASSERT(IsValid());
729 }
730
IsValid()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'.
GetLaneSizeInBits()740 unsigned GetLaneSizeInBits() const {
741 VIXL_ASSERT(HasLaneSize());
742 return PRegister::GetLaneSizeInBits();
743 }
744
GetLaneSizeInBytes()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").
752 class PRegisterZ : public PRegister {
753 public:
VIXL_DECLARE_REGISTER_COMMON(PRegisterZ,PRegister,PRegister)754 VIXL_DECLARE_REGISTER_COMMON(PRegisterZ, PRegister, PRegister)
755
756 explicit PRegisterZ(int code) : PRegister(code, kZeroing) {
757 VIXL_ASSERT(IsValid());
758 }
759
IsValid()760 bool IsValid() const {
761 return IsValidPRegister() && !HasLaneSize() && IsZeroing();
762 }
763 };
764
765 // Any SVE P register with the merging qualifier (like "p0/m").
766 class PRegisterM : public PRegister {
767 public:
VIXL_DECLARE_REGISTER_COMMON(PRegisterM,PRegister,PRegister)768 VIXL_DECLARE_REGISTER_COMMON(PRegisterM, PRegister, PRegister)
769
770 explicit PRegisterM(int code) : PRegister(code, kMerging) {
771 VIXL_ASSERT(IsValid());
772 }
773
IsValid()774 bool IsValid() const {
775 return IsValidPRegister() && !HasLaneSize() && IsMerging();
776 }
777 };
778
VnB()779 inline PRegisterWithLaneSize PRegister::VnB() const {
780 return PRegisterWithLaneSize(GetCode(), kBRegSize);
781 }
VnH()782 inline PRegisterWithLaneSize PRegister::VnH() const {
783 return PRegisterWithLaneSize(GetCode(), kHRegSize);
784 }
VnS()785 inline PRegisterWithLaneSize PRegister::VnS() const {
786 return PRegisterWithLaneSize(GetCode(), kSRegSize);
787 }
VnD()788 inline PRegisterWithLaneSize PRegister::VnD() const {
789 return PRegisterWithLaneSize(GetCode(), kDRegSize);
790 }
791
792 template <typename T>
WithLaneSize(T format)793 inline PRegisterWithLaneSize PRegister::WithLaneSize(T format) const {
794 return PRegisterWithLaneSize(GetCode(), format);
795 }
796
WithSameLaneSizeAs(const CPURegister & other)797 inline PRegisterWithLaneSize PRegister::WithSameLaneSizeAs(
798 const CPURegister& other) const {
799 VIXL_ASSERT(other.HasLaneSize());
800 return this->WithLaneSize(other.GetLaneSizeInBits());
801 }
802
Zeroing()803 inline PRegisterZ PRegister::Zeroing() const { return PRegisterZ(GetCode()); }
Merging()804 inline 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
834 VIXL_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).
839 const Register NoReg;
840 const VRegister NoVReg;
841 const CPURegister NoCPUReg;
842 const 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);
856 AARCH64_REGISTER_CODE_LIST(VIXL_DEFINE_REGISTERS)
857 #undef VIXL_DEFINE_REGISTERS
858
859 #define VIXL_DEFINE_P_REGISTERS(N) const PRegister p##N(N);
AARCH64_P_REGISTER_CODE_LIST(VIXL_DEFINE_P_REGISTERS)860 AARCH64_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 }
880 VIXL_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 }
900 VIXL_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().
906 VRegister 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'.
912 const Register wsp = WRegister(kSPRegInternalCode);
913 const Register sp = XRegister(kSPRegInternalCode);
914
915 // Standard aliases.
916 const Register ip0 = x16;
917 const Register ip1 = x17;
918 const Register lr = x30;
919 const Register xzr = x31;
920 const Register wzr = w31;
921
GetArchitecturalName()922 std::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
GetMaxCodeFor(CPURegister::RegisterBank bank)950 unsigned 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.
972 inline
973 bool 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).
1028 inline
1029 bool 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).
1052 inline
1053 bool 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).
1077 inline
1078 bool 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).
1111 inline
1112 bool 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.
1129 inline
1130 bool 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