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