• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016, 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_OPERANDS_AARCH64_H_
28 #define VIXL_AARCH64_OPERANDS_AARCH64_H_
29 
30 #include "instructions-aarch64.h"
31 
32 namespace vixl {
33 namespace aarch64 {
34 
35 typedef uint64_t RegList;
36 static const int kRegListSizeInBits = sizeof(RegList) * 8;
37 
38 
39 // Registers.
40 
41 // Some CPURegister methods can return Register or VRegister types, so we need
42 // to declare them in advance.
43 class Register;
44 class VRegister;
45 
46 class CPURegister {
47  public:
48   enum RegisterType {
49     // The kInvalid value is used to detect uninitialized static instances,
50     // which are always zero-initialized before any constructors are called.
51     kInvalid = 0,
52     kRegister,
53     kVRegister,
54     kFPRegister = kVRegister,
55     kNoRegister
56   };
57 
CPURegister()58   CPURegister() : code_(0), size_(0), type_(kNoRegister) {
59     VIXL_ASSERT(!IsValid());
60     VIXL_ASSERT(IsNone());
61   }
62 
CPURegister(unsigned code,unsigned size,RegisterType type)63   CPURegister(unsigned code, unsigned size, RegisterType type)
64       : code_(code), size_(size), type_(type) {
65     VIXL_ASSERT(IsValidOrNone());
66   }
67 
GetCode()68   unsigned GetCode() const {
69     VIXL_ASSERT(IsValid());
70     return code_;
71   }
code()72   VIXL_DEPRECATED("GetCode", unsigned code() const) { return GetCode(); }
73 
GetType()74   RegisterType GetType() const {
75     VIXL_ASSERT(IsValidOrNone());
76     return type_;
77   }
78   VIXL_DEPRECATED("GetType", RegisterType type() const) { return GetType(); }
79 
GetBit()80   RegList GetBit() const {
81     VIXL_ASSERT(code_ < (sizeof(RegList) * 8));
82     return IsValid() ? (static_cast<RegList>(1) << code_) : 0;
83   }
84   VIXL_DEPRECATED("GetBit", RegList Bit() const) { return GetBit(); }
85 
GetSizeInBytes()86   int GetSizeInBytes() const {
87     VIXL_ASSERT(IsValid());
88     VIXL_ASSERT(size_ % 8 == 0);
89     return size_ / 8;
90   }
SizeInBytes()91   VIXL_DEPRECATED("GetSizeInBytes", int SizeInBytes() const) {
92     return GetSizeInBytes();
93   }
94 
GetSizeInBits()95   int GetSizeInBits() const {
96     VIXL_ASSERT(IsValid());
97     return size_;
98   }
size()99   VIXL_DEPRECATED("GetSizeInBits", unsigned size() const) {
100     return GetSizeInBits();
101   }
SizeInBits()102   VIXL_DEPRECATED("GetSizeInBits", int SizeInBits() const) {
103     return GetSizeInBits();
104   }
105 
Is8Bits()106   bool Is8Bits() const {
107     VIXL_ASSERT(IsValid());
108     return size_ == 8;
109   }
110 
Is16Bits()111   bool Is16Bits() const {
112     VIXL_ASSERT(IsValid());
113     return size_ == 16;
114   }
115 
Is32Bits()116   bool Is32Bits() const {
117     VIXL_ASSERT(IsValid());
118     return size_ == 32;
119   }
120 
Is64Bits()121   bool Is64Bits() const {
122     VIXL_ASSERT(IsValid());
123     return size_ == 64;
124   }
125 
Is128Bits()126   bool Is128Bits() const {
127     VIXL_ASSERT(IsValid());
128     return size_ == 128;
129   }
130 
IsValid()131   bool IsValid() const {
132     if (IsValidRegister() || IsValidVRegister()) {
133       VIXL_ASSERT(!IsNone());
134       return true;
135     } else {
136       // This assert is hit when the register has not been properly initialized.
137       // One cause for this can be an initialisation order fiasco. See
138       // https://isocpp.org/wiki/faq/ctors#static-init-order for some details.
139       VIXL_ASSERT(IsNone());
140       return false;
141     }
142   }
143 
IsValidRegister()144   bool IsValidRegister() const {
145     return IsRegister() && ((size_ == kWRegSize) || (size_ == kXRegSize)) &&
146            ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode));
147   }
148 
IsValidVRegister()149   bool IsValidVRegister() const {
150     return IsVRegister() && ((size_ == kBRegSize) || (size_ == kHRegSize) ||
151                              (size_ == kSRegSize) || (size_ == kDRegSize) ||
152                              (size_ == kQRegSize)) &&
153            (code_ < kNumberOfVRegisters);
154   }
155 
IsValidFPRegister()156   bool IsValidFPRegister() const {
157     return IsFPRegister() && (code_ < kNumberOfVRegisters);
158   }
159 
IsNone()160   bool IsNone() const {
161     // kNoRegister types should always have size 0 and code 0.
162     VIXL_ASSERT((type_ != kNoRegister) || (code_ == 0));
163     VIXL_ASSERT((type_ != kNoRegister) || (size_ == 0));
164 
165     return type_ == kNoRegister;
166   }
167 
Aliases(const CPURegister & other)168   bool Aliases(const CPURegister& other) const {
169     VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone());
170     return (code_ == other.code_) && (type_ == other.type_);
171   }
172 
Is(const CPURegister & other)173   bool Is(const CPURegister& other) const {
174     VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone());
175     return Aliases(other) && (size_ == other.size_);
176   }
177 
IsZero()178   bool IsZero() const {
179     VIXL_ASSERT(IsValid());
180     return IsRegister() && (code_ == kZeroRegCode);
181   }
182 
IsSP()183   bool IsSP() const {
184     VIXL_ASSERT(IsValid());
185     return IsRegister() && (code_ == kSPRegInternalCode);
186   }
187 
IsRegister()188   bool IsRegister() const { return type_ == kRegister; }
189 
IsVRegister()190   bool IsVRegister() const { return type_ == kVRegister; }
191 
IsFPRegister()192   bool IsFPRegister() const { return IsS() || IsD(); }
193 
IsW()194   bool IsW() const { return IsValidRegister() && Is32Bits(); }
IsX()195   bool IsX() const { return IsValidRegister() && Is64Bits(); }
196 
197   // These assertions ensure that the size and type of the register are as
198   // described. They do not consider the number of lanes that make up a vector.
199   // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
200   // does not imply Is1D() or Is8B().
201   // Check the number of lanes, ie. the format of the vector, using methods such
202   // as Is8B(), Is1D(), etc. in the VRegister class.
IsV()203   bool IsV() const { return IsVRegister(); }
IsB()204   bool IsB() const { return IsV() && Is8Bits(); }
IsH()205   bool IsH() const { return IsV() && Is16Bits(); }
IsS()206   bool IsS() const { return IsV() && Is32Bits(); }
IsD()207   bool IsD() const { return IsV() && Is64Bits(); }
IsQ()208   bool IsQ() const { return IsV() && Is128Bits(); }
209 
210   // Semantic type for sdot and udot instructions.
IsS4B()211   bool IsS4B() const { return IsS(); }
S4B()212   const VRegister& S4B() const { return S(); }
213 
214   const Register& W() const;
215   const Register& X() const;
216   const VRegister& V() const;
217   const VRegister& B() const;
218   const VRegister& H() const;
219   const VRegister& S() const;
220   const VRegister& D() const;
221   const VRegister& Q() const;
222 
IsSameType(const CPURegister & other)223   bool IsSameType(const CPURegister& other) const {
224     return type_ == other.type_;
225   }
226 
IsSameSizeAndType(const CPURegister & other)227   bool IsSameSizeAndType(const CPURegister& other) const {
228     return (size_ == other.size_) && IsSameType(other);
229   }
230 
231  protected:
232   unsigned code_;
233   int size_;
234   RegisterType type_;
235 
236  private:
IsValidOrNone()237   bool IsValidOrNone() const { return IsValid() || IsNone(); }
238 };
239 
240 
241 class Register : public CPURegister {
242  public:
Register()243   Register() : CPURegister() {}
Register(const CPURegister & other)244   explicit Register(const CPURegister& other)
245       : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()) {
246     VIXL_ASSERT(IsValidRegister());
247   }
Register(unsigned code,unsigned size)248   Register(unsigned code, unsigned size) : CPURegister(code, size, kRegister) {}
249 
IsValid()250   bool IsValid() const {
251     VIXL_ASSERT(IsRegister() || IsNone());
252     return IsValidRegister();
253   }
254 
255   static const Register& GetWRegFromCode(unsigned code);
256   VIXL_DEPRECATED("GetWRegFromCode",
257                   static const Register& WRegFromCode(unsigned code)) {
258     return GetWRegFromCode(code);
259   }
260 
261   static const Register& GetXRegFromCode(unsigned code);
262   VIXL_DEPRECATED("GetXRegFromCode",
263                   static const Register& XRegFromCode(unsigned code)) {
264     return GetXRegFromCode(code);
265   }
266 
267  private:
268   static const Register wregisters[];
269   static const Register xregisters[];
270 };
271 
272 
273 namespace internal {
274 
275 template <int size_in_bits>
276 class FixedSizeRegister : public Register {
277  public:
FixedSizeRegister()278   FixedSizeRegister() : Register() {}
FixedSizeRegister(unsigned code)279   explicit FixedSizeRegister(unsigned code) : Register(code, size_in_bits) {
280     VIXL_ASSERT(IsValidRegister());
281   }
FixedSizeRegister(const Register & other)282   explicit FixedSizeRegister(const Register& other)
283       : Register(other.GetCode(), size_in_bits) {
284     VIXL_ASSERT(other.GetSizeInBits() == size_in_bits);
285     VIXL_ASSERT(IsValidRegister());
286   }
FixedSizeRegister(const CPURegister & other)287   explicit FixedSizeRegister(const CPURegister& other)
288       : Register(other.GetCode(), other.GetSizeInBits()) {
289     VIXL_ASSERT(other.GetType() == kRegister);
290     VIXL_ASSERT(other.GetSizeInBits() == size_in_bits);
291     VIXL_ASSERT(IsValidRegister());
292   }
293 
IsValid()294   bool IsValid() const {
295     return Register::IsValid() && (GetSizeInBits() == size_in_bits);
296   }
297 };
298 
299 }  // namespace internal
300 
301 typedef internal::FixedSizeRegister<kXRegSize> XRegister;
302 typedef internal::FixedSizeRegister<kWRegSize> WRegister;
303 
304 
305 class VRegister : public CPURegister {
306  public:
VRegister()307   VRegister() : CPURegister(), lanes_(1) {}
VRegister(const CPURegister & other)308   explicit VRegister(const CPURegister& other)
309       : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()),
310         lanes_(1) {
311     VIXL_ASSERT(IsValidVRegister());
312     VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16));
313   }
314   VRegister(unsigned code, unsigned size, unsigned lanes = 1)
CPURegister(code,size,kVRegister)315       : CPURegister(code, size, kVRegister), lanes_(lanes) {
316     VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16));
317   }
VRegister(unsigned code,VectorFormat format)318   VRegister(unsigned code, VectorFormat format)
319       : CPURegister(code, RegisterSizeInBitsFromFormat(format), kVRegister),
320         lanes_(IsVectorFormat(format) ? LaneCountFromFormat(format) : 1) {
321     VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16));
322   }
323 
IsValid()324   bool IsValid() const {
325     VIXL_ASSERT(IsVRegister() || IsNone());
326     return IsValidVRegister();
327   }
328 
329   static const VRegister& GetBRegFromCode(unsigned code);
330   VIXL_DEPRECATED("GetBRegFromCode",
331                   static const VRegister& BRegFromCode(unsigned code)) {
332     return GetBRegFromCode(code);
333   }
334 
335   static const VRegister& GetHRegFromCode(unsigned code);
336   VIXL_DEPRECATED("GetHRegFromCode",
337                   static const VRegister& HRegFromCode(unsigned code)) {
338     return GetHRegFromCode(code);
339   }
340 
341   static const VRegister& GetSRegFromCode(unsigned code);
342   VIXL_DEPRECATED("GetSRegFromCode",
343                   static const VRegister& SRegFromCode(unsigned code)) {
344     return GetSRegFromCode(code);
345   }
346 
347   static const VRegister& GetDRegFromCode(unsigned code);
348   VIXL_DEPRECATED("GetDRegFromCode",
349                   static const VRegister& DRegFromCode(unsigned code)) {
350     return GetDRegFromCode(code);
351   }
352 
353   static const VRegister& GetQRegFromCode(unsigned code);
354   VIXL_DEPRECATED("GetQRegFromCode",
355                   static const VRegister& QRegFromCode(unsigned code)) {
356     return GetQRegFromCode(code);
357   }
358 
359   static const VRegister& GetVRegFromCode(unsigned code);
360   VIXL_DEPRECATED("GetVRegFromCode",
361                   static const VRegister& VRegFromCode(unsigned code)) {
362     return GetVRegFromCode(code);
363   }
364 
V8B()365   VRegister V8B() const { return VRegister(code_, kDRegSize, 8); }
V16B()366   VRegister V16B() const { return VRegister(code_, kQRegSize, 16); }
V2H()367   VRegister V2H() const { return VRegister(code_, kSRegSize, 2); }
V4H()368   VRegister V4H() const { return VRegister(code_, kDRegSize, 4); }
V8H()369   VRegister V8H() const { return VRegister(code_, kQRegSize, 8); }
V2S()370   VRegister V2S() const { return VRegister(code_, kDRegSize, 2); }
V4S()371   VRegister V4S() const { return VRegister(code_, kQRegSize, 4); }
V2D()372   VRegister V2D() const { return VRegister(code_, kQRegSize, 2); }
V1D()373   VRegister V1D() const { return VRegister(code_, kDRegSize, 1); }
374 
Is8B()375   bool Is8B() const { return (Is64Bits() && (lanes_ == 8)); }
Is16B()376   bool Is16B() const { return (Is128Bits() && (lanes_ == 16)); }
Is2H()377   bool Is2H() const { return (Is32Bits() && (lanes_ == 2)); }
Is4H()378   bool Is4H() const { return (Is64Bits() && (lanes_ == 4)); }
Is8H()379   bool Is8H() const { return (Is128Bits() && (lanes_ == 8)); }
Is2S()380   bool Is2S() const { return (Is64Bits() && (lanes_ == 2)); }
Is4S()381   bool Is4S() const { return (Is128Bits() && (lanes_ == 4)); }
Is1D()382   bool Is1D() const { return (Is64Bits() && (lanes_ == 1)); }
Is2D()383   bool Is2D() const { return (Is128Bits() && (lanes_ == 2)); }
384 
385   // For consistency, we assert the number of lanes of these scalar registers,
386   // even though there are no vectors of equivalent total size with which they
387   // could alias.
Is1B()388   bool Is1B() const {
389     VIXL_ASSERT(!(Is8Bits() && IsVector()));
390     return Is8Bits();
391   }
Is1H()392   bool Is1H() const {
393     VIXL_ASSERT(!(Is16Bits() && IsVector()));
394     return Is16Bits();
395   }
Is1S()396   bool Is1S() const {
397     VIXL_ASSERT(!(Is32Bits() && IsVector()));
398     return Is32Bits();
399   }
400 
401   // Semantic type for sdot and udot instructions.
Is1S4B()402   bool Is1S4B() const { return Is1S(); }
403 
404 
IsLaneSizeB()405   bool IsLaneSizeB() const { return GetLaneSizeInBits() == kBRegSize; }
IsLaneSizeH()406   bool IsLaneSizeH() const { return GetLaneSizeInBits() == kHRegSize; }
IsLaneSizeS()407   bool IsLaneSizeS() const { return GetLaneSizeInBits() == kSRegSize; }
IsLaneSizeD()408   bool IsLaneSizeD() const { return GetLaneSizeInBits() == kDRegSize; }
409 
GetLanes()410   int GetLanes() const { return lanes_; }
lanes()411   VIXL_DEPRECATED("GetLanes", int lanes() const) { return GetLanes(); }
412 
IsScalar()413   bool IsScalar() const { return lanes_ == 1; }
414 
IsVector()415   bool IsVector() const { return lanes_ > 1; }
416 
IsSameFormat(const VRegister & other)417   bool IsSameFormat(const VRegister& other) const {
418     return (size_ == other.size_) && (lanes_ == other.lanes_);
419   }
420 
GetLaneSizeInBytes()421   unsigned GetLaneSizeInBytes() const { return GetSizeInBytes() / lanes_; }
LaneSizeInBytes()422   VIXL_DEPRECATED("GetLaneSizeInBytes", unsigned LaneSizeInBytes() const) {
423     return GetLaneSizeInBytes();
424   }
425 
GetLaneSizeInBits()426   unsigned GetLaneSizeInBits() const { return GetLaneSizeInBytes() * 8; }
LaneSizeInBits()427   VIXL_DEPRECATED("GetLaneSizeInBits", unsigned LaneSizeInBits() const) {
428     return GetLaneSizeInBits();
429   }
430 
431  private:
432   static const VRegister bregisters[];
433   static const VRegister hregisters[];
434   static const VRegister sregisters[];
435   static const VRegister dregisters[];
436   static const VRegister qregisters[];
437   static const VRegister vregisters[];
438   int lanes_;
439 };
440 
441 
442 // Backward compatibility for FPRegisters.
443 typedef VRegister FPRegister;
444 
445 // No*Reg is used to indicate an unused argument, or an error case. Note that
446 // these all compare equal (using the Is() method). The Register and VRegister
447 // variants are provided for convenience.
448 const Register NoReg;
449 const VRegister NoVReg;
450 const FPRegister NoFPReg;  // For backward compatibility.
451 const CPURegister NoCPUReg;
452 
453 
454 #define DEFINE_REGISTERS(N) \
455   const WRegister w##N(N);  \
456   const XRegister x##N(N);
457 AARCH64_REGISTER_CODE_LIST(DEFINE_REGISTERS)
458 #undef DEFINE_REGISTERS
459 const WRegister wsp(kSPRegInternalCode);
460 const XRegister sp(kSPRegInternalCode);
461 
462 
463 #define DEFINE_VREGISTERS(N)          \
464   const VRegister b##N(N, kBRegSize); \
465   const VRegister h##N(N, kHRegSize); \
466   const VRegister s##N(N, kSRegSize); \
467   const VRegister d##N(N, kDRegSize); \
468   const VRegister q##N(N, kQRegSize); \
469   const VRegister v##N(N, kQRegSize);
470 AARCH64_REGISTER_CODE_LIST(DEFINE_VREGISTERS)
471 #undef DEFINE_VREGISTERS
472 
473 
474 // Register aliases.
475 const XRegister ip0 = x16;
476 const XRegister ip1 = x17;
477 const XRegister lr = x30;
478 const XRegister xzr = x31;
479 const WRegister wzr = w31;
480 
481 
482 // AreAliased returns true if any of the named registers overlap. Arguments
483 // set to NoReg are ignored. The system stack pointer may be specified.
484 bool AreAliased(const CPURegister& reg1,
485                 const CPURegister& reg2,
486                 const CPURegister& reg3 = NoReg,
487                 const CPURegister& reg4 = NoReg,
488                 const CPURegister& reg5 = NoReg,
489                 const CPURegister& reg6 = NoReg,
490                 const CPURegister& reg7 = NoReg,
491                 const CPURegister& reg8 = NoReg);
492 
493 
494 // AreSameSizeAndType returns true if all of the specified registers have the
495 // same size, and are of the same type. The system stack pointer may be
496 // specified. Arguments set to NoReg are ignored, as are any subsequent
497 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
498 bool AreSameSizeAndType(const CPURegister& reg1,
499                         const CPURegister& reg2,
500                         const CPURegister& reg3 = NoCPUReg,
501                         const CPURegister& reg4 = NoCPUReg,
502                         const CPURegister& reg5 = NoCPUReg,
503                         const CPURegister& reg6 = NoCPUReg,
504                         const CPURegister& reg7 = NoCPUReg,
505                         const CPURegister& reg8 = NoCPUReg);
506 
507 // AreEven returns true if all of the specified registers have even register
508 // indices. Arguments set to NoReg are ignored, as are any subsequent
509 // arguments. At least one argument (reg1) must be valid (not NoCPUReg).
510 bool AreEven(const CPURegister& reg1,
511              const CPURegister& reg2,
512              const CPURegister& reg3 = NoReg,
513              const CPURegister& reg4 = NoReg,
514              const CPURegister& reg5 = NoReg,
515              const CPURegister& reg6 = NoReg,
516              const CPURegister& reg7 = NoReg,
517              const CPURegister& reg8 = NoReg);
518 
519 
520 // AreConsecutive returns true if all of the specified registers are
521 // consecutive in the register file. Arguments set to NoReg are ignored, as are
522 // any subsequent arguments. At least one argument (reg1) must be valid
523 // (not NoCPUReg).
524 bool AreConsecutive(const CPURegister& reg1,
525                     const CPURegister& reg2,
526                     const CPURegister& reg3 = NoCPUReg,
527                     const CPURegister& reg4 = NoCPUReg);
528 
529 
530 // AreSameFormat returns true if all of the specified VRegisters have the same
531 // vector format. Arguments set to NoReg are ignored, as are any subsequent
532 // arguments. At least one argument (reg1) must be valid (not NoVReg).
533 bool AreSameFormat(const VRegister& reg1,
534                    const VRegister& reg2,
535                    const VRegister& reg3 = NoVReg,
536                    const VRegister& reg4 = NoVReg);
537 
538 
539 // AreConsecutive returns true if all of the specified VRegisters are
540 // consecutive in the register file. Arguments set to NoReg are ignored, as are
541 // any subsequent arguments. At least one argument (reg1) must be valid
542 // (not NoVReg).
543 bool AreConsecutive(const VRegister& reg1,
544                     const VRegister& reg2,
545                     const VRegister& reg3 = NoVReg,
546                     const VRegister& reg4 = NoVReg);
547 
548 
549 // Lists of registers.
550 class CPURegList {
551  public:
552   explicit CPURegList(CPURegister reg1,
553                       CPURegister reg2 = NoCPUReg,
554                       CPURegister reg3 = NoCPUReg,
555                       CPURegister reg4 = NoCPUReg)
556       : list_(reg1.GetBit() | reg2.GetBit() | reg3.GetBit() | reg4.GetBit()),
557         size_(reg1.GetSizeInBits()),
558         type_(reg1.GetType()) {
559     VIXL_ASSERT(AreSameSizeAndType(reg1, reg2, reg3, reg4));
560     VIXL_ASSERT(IsValid());
561   }
562 
CPURegList(CPURegister::RegisterType type,unsigned size,RegList list)563   CPURegList(CPURegister::RegisterType type, unsigned size, RegList list)
564       : list_(list), size_(size), type_(type) {
565     VIXL_ASSERT(IsValid());
566   }
567 
CPURegList(CPURegister::RegisterType type,unsigned size,unsigned first_reg,unsigned last_reg)568   CPURegList(CPURegister::RegisterType type,
569              unsigned size,
570              unsigned first_reg,
571              unsigned last_reg)
572       : size_(size), type_(type) {
573     VIXL_ASSERT(
574         ((type == CPURegister::kRegister) && (last_reg < kNumberOfRegisters)) ||
575         ((type == CPURegister::kVRegister) &&
576          (last_reg < kNumberOfVRegisters)));
577     VIXL_ASSERT(last_reg >= first_reg);
578     list_ = (UINT64_C(1) << (last_reg + 1)) - 1;
579     list_ &= ~((UINT64_C(1) << first_reg) - 1);
580     VIXL_ASSERT(IsValid());
581   }
582 
GetType()583   CPURegister::RegisterType GetType() const {
584     VIXL_ASSERT(IsValid());
585     return type_;
586   }
587   VIXL_DEPRECATED("GetType", CPURegister::RegisterType type() const) {
588     return GetType();
589   }
590 
591   // Combine another CPURegList into this one. Registers that already exist in
592   // this list are left unchanged. The type and size of the registers in the
593   // 'other' list must match those in this list.
Combine(const CPURegList & other)594   void Combine(const CPURegList& other) {
595     VIXL_ASSERT(IsValid());
596     VIXL_ASSERT(other.GetType() == type_);
597     VIXL_ASSERT(other.GetRegisterSizeInBits() == size_);
598     list_ |= other.GetList();
599   }
600 
601   // Remove every register in the other CPURegList from this one. Registers that
602   // do not exist in this list are ignored. The type and size of the registers
603   // in the 'other' list must match those in this list.
Remove(const CPURegList & other)604   void Remove(const CPURegList& other) {
605     VIXL_ASSERT(IsValid());
606     VIXL_ASSERT(other.GetType() == type_);
607     VIXL_ASSERT(other.GetRegisterSizeInBits() == size_);
608     list_ &= ~other.GetList();
609   }
610 
611   // Variants of Combine and Remove which take a single register.
Combine(const CPURegister & other)612   void Combine(const CPURegister& other) {
613     VIXL_ASSERT(other.GetType() == type_);
614     VIXL_ASSERT(other.GetSizeInBits() == size_);
615     Combine(other.GetCode());
616   }
617 
Remove(const CPURegister & other)618   void Remove(const CPURegister& other) {
619     VIXL_ASSERT(other.GetType() == type_);
620     VIXL_ASSERT(other.GetSizeInBits() == size_);
621     Remove(other.GetCode());
622   }
623 
624   // Variants of Combine and Remove which take a single register by its code;
625   // the type and size of the register is inferred from this list.
Combine(int code)626   void Combine(int code) {
627     VIXL_ASSERT(IsValid());
628     VIXL_ASSERT(CPURegister(code, size_, type_).IsValid());
629     list_ |= (UINT64_C(1) << code);
630   }
631 
Remove(int code)632   void Remove(int code) {
633     VIXL_ASSERT(IsValid());
634     VIXL_ASSERT(CPURegister(code, size_, type_).IsValid());
635     list_ &= ~(UINT64_C(1) << code);
636   }
637 
Union(const CPURegList & list_1,const CPURegList & list_2)638   static CPURegList Union(const CPURegList& list_1, const CPURegList& list_2) {
639     VIXL_ASSERT(list_1.type_ == list_2.type_);
640     VIXL_ASSERT(list_1.size_ == list_2.size_);
641     return CPURegList(list_1.type_, list_1.size_, list_1.list_ | list_2.list_);
642   }
643   static CPURegList Union(const CPURegList& list_1,
644                           const CPURegList& list_2,
645                           const CPURegList& list_3);
646   static CPURegList Union(const CPURegList& list_1,
647                           const CPURegList& list_2,
648                           const CPURegList& list_3,
649                           const CPURegList& list_4);
650 
Intersection(const CPURegList & list_1,const CPURegList & list_2)651   static CPURegList Intersection(const CPURegList& list_1,
652                                  const CPURegList& list_2) {
653     VIXL_ASSERT(list_1.type_ == list_2.type_);
654     VIXL_ASSERT(list_1.size_ == list_2.size_);
655     return CPURegList(list_1.type_, list_1.size_, list_1.list_ & list_2.list_);
656   }
657   static CPURegList Intersection(const CPURegList& list_1,
658                                  const CPURegList& list_2,
659                                  const CPURegList& list_3);
660   static CPURegList Intersection(const CPURegList& list_1,
661                                  const CPURegList& list_2,
662                                  const CPURegList& list_3,
663                                  const CPURegList& list_4);
664 
Overlaps(const CPURegList & other)665   bool Overlaps(const CPURegList& other) const {
666     return (type_ == other.type_) && ((list_ & other.list_) != 0);
667   }
668 
GetList()669   RegList GetList() const {
670     VIXL_ASSERT(IsValid());
671     return list_;
672   }
673   VIXL_DEPRECATED("GetList", RegList list() const) { return GetList(); }
674 
SetList(RegList new_list)675   void SetList(RegList new_list) {
676     VIXL_ASSERT(IsValid());
677     list_ = new_list;
678   }
set_list(RegList new_list)679   VIXL_DEPRECATED("SetList", void set_list(RegList new_list)) {
680     return SetList(new_list);
681   }
682 
683   // Remove all callee-saved registers from the list. This can be useful when
684   // preparing registers for an AAPCS64 function call, for example.
685   void RemoveCalleeSaved();
686 
687   CPURegister PopLowestIndex();
688   CPURegister PopHighestIndex();
689 
690   // AAPCS64 callee-saved registers.
691   static CPURegList GetCalleeSaved(unsigned size = kXRegSize);
692   static CPURegList GetCalleeSavedV(unsigned size = kDRegSize);
693 
694   // AAPCS64 caller-saved registers. Note that this includes lr.
695   // TODO(all): Determine how we handle d8-d15 being callee-saved, but the top
696   // 64-bits being caller-saved.
697   static CPURegList GetCallerSaved(unsigned size = kXRegSize);
698   static CPURegList GetCallerSavedV(unsigned size = kDRegSize);
699 
IsEmpty()700   bool IsEmpty() const {
701     VIXL_ASSERT(IsValid());
702     return list_ == 0;
703   }
704 
IncludesAliasOf(const CPURegister & other)705   bool IncludesAliasOf(const CPURegister& other) const {
706     VIXL_ASSERT(IsValid());
707     return (type_ == other.GetType()) && ((other.GetBit() & list_) != 0);
708   }
709 
IncludesAliasOf(int code)710   bool IncludesAliasOf(int code) const {
711     VIXL_ASSERT(IsValid());
712     return ((code & list_) != 0);
713   }
714 
GetCount()715   int GetCount() const {
716     VIXL_ASSERT(IsValid());
717     return CountSetBits(list_);
718   }
Count()719   VIXL_DEPRECATED("GetCount", int Count()) const { return GetCount(); }
720 
GetRegisterSizeInBits()721   int GetRegisterSizeInBits() const {
722     VIXL_ASSERT(IsValid());
723     return size_;
724   }
RegisterSizeInBits()725   VIXL_DEPRECATED("GetRegisterSizeInBits", int RegisterSizeInBits() const) {
726     return GetRegisterSizeInBits();
727   }
728 
GetRegisterSizeInBytes()729   int GetRegisterSizeInBytes() const {
730     int size_in_bits = GetRegisterSizeInBits();
731     VIXL_ASSERT((size_in_bits % 8) == 0);
732     return size_in_bits / 8;
733   }
RegisterSizeInBytes()734   VIXL_DEPRECATED("GetRegisterSizeInBytes", int RegisterSizeInBytes() const) {
735     return GetRegisterSizeInBytes();
736   }
737 
GetTotalSizeInBytes()738   unsigned GetTotalSizeInBytes() const {
739     VIXL_ASSERT(IsValid());
740     return GetRegisterSizeInBytes() * GetCount();
741   }
TotalSizeInBytes()742   VIXL_DEPRECATED("GetTotalSizeInBytes", unsigned TotalSizeInBytes() const) {
743     return GetTotalSizeInBytes();
744   }
745 
746  private:
747   RegList list_;
748   int size_;
749   CPURegister::RegisterType type_;
750 
751   bool IsValid() const;
752 };
753 
754 
755 // AAPCS64 callee-saved registers.
756 extern const CPURegList kCalleeSaved;
757 extern const CPURegList kCalleeSavedV;
758 
759 
760 // AAPCS64 caller-saved registers. Note that this includes lr.
761 extern const CPURegList kCallerSaved;
762 extern const CPURegList kCallerSavedV;
763 
764 
765 // Operand.
766 class Operand {
767  public:
768   // #<immediate>
769   // where <immediate> is int64_t.
770   // This is allowed to be an implicit constructor because Operand is
771   // a wrapper class that doesn't normally perform any type conversion.
772   Operand(int64_t immediate = 0);  // NOLINT(runtime/explicit)
773 
774   // rm, {<shift> #<shift_amount>}
775   // where <shift> is one of {LSL, LSR, ASR, ROR}.
776   //       <shift_amount> is uint6_t.
777   // This is allowed to be an implicit constructor because Operand is
778   // a wrapper class that doesn't normally perform any type conversion.
779   Operand(Register reg,
780           Shift shift = LSL,
781           unsigned shift_amount = 0);  // NOLINT(runtime/explicit)
782 
783   // rm, {<extend> {#<shift_amount>}}
784   // where <extend> is one of {UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX}.
785   //       <shift_amount> is uint2_t.
786   explicit Operand(Register reg, Extend extend, unsigned shift_amount = 0);
787 
788   bool IsImmediate() const;
789   bool IsPlainRegister() const;
790   bool IsShiftedRegister() const;
791   bool IsExtendedRegister() const;
792   bool IsZero() const;
793 
794   // This returns an LSL shift (<= 4) operand as an equivalent extend operand,
795   // which helps in the encoding of instructions that use the stack pointer.
796   Operand ToExtendedRegister() const;
797 
GetImmediate()798   int64_t GetImmediate() const {
799     VIXL_ASSERT(IsImmediate());
800     return immediate_;
801   }
802   VIXL_DEPRECATED("GetImmediate", int64_t immediate() const) {
803     return GetImmediate();
804   }
805 
GetEquivalentImmediate()806   int64_t GetEquivalentImmediate() const {
807     return IsZero() ? 0 : GetImmediate();
808   }
809 
GetRegister()810   Register GetRegister() const {
811     VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister());
812     return reg_;
813   }
814   VIXL_DEPRECATED("GetRegister", Register reg() const) { return GetRegister(); }
GetBaseRegister()815   Register GetBaseRegister() const { return GetRegister(); }
816 
GetShift()817   Shift GetShift() const {
818     VIXL_ASSERT(IsShiftedRegister());
819     return shift_;
820   }
821   VIXL_DEPRECATED("GetShift", Shift shift() const) { return GetShift(); }
822 
GetExtend()823   Extend GetExtend() const {
824     VIXL_ASSERT(IsExtendedRegister());
825     return extend_;
826   }
827   VIXL_DEPRECATED("GetExtend", Extend extend() const) { return GetExtend(); }
828 
GetShiftAmount()829   unsigned GetShiftAmount() const {
830     VIXL_ASSERT(IsShiftedRegister() || IsExtendedRegister());
831     return shift_amount_;
832   }
shift_amount()833   VIXL_DEPRECATED("GetShiftAmount", unsigned shift_amount() const) {
834     return GetShiftAmount();
835   }
836 
837  private:
838   int64_t immediate_;
839   Register reg_;
840   Shift shift_;
841   Extend extend_;
842   unsigned shift_amount_;
843 };
844 
845 
846 // MemOperand represents the addressing mode of a load or store instruction.
847 class MemOperand {
848  public:
849   // Creates an invalid `MemOperand`.
850   MemOperand();
851   explicit MemOperand(Register base,
852                       int64_t offset = 0,
853                       AddrMode addrmode = Offset);
854   MemOperand(Register base,
855              Register regoffset,
856              Shift shift = LSL,
857              unsigned shift_amount = 0);
858   MemOperand(Register base,
859              Register regoffset,
860              Extend extend,
861              unsigned shift_amount = 0);
862   MemOperand(Register base, const Operand& offset, AddrMode addrmode = Offset);
863 
GetBaseRegister()864   const Register& GetBaseRegister() const { return base_; }
865   VIXL_DEPRECATED("GetBaseRegister", const Register& base() const) {
866     return GetBaseRegister();
867   }
868 
GetRegisterOffset()869   const Register& GetRegisterOffset() const { return regoffset_; }
870   VIXL_DEPRECATED("GetRegisterOffset", const Register& regoffset() const) {
871     return GetRegisterOffset();
872   }
873 
GetOffset()874   int64_t GetOffset() const { return offset_; }
875   VIXL_DEPRECATED("GetOffset", int64_t offset() const) { return GetOffset(); }
876 
GetAddrMode()877   AddrMode GetAddrMode() const { return addrmode_; }
878   VIXL_DEPRECATED("GetAddrMode", AddrMode addrmode() const) {
879     return GetAddrMode();
880   }
881 
GetShift()882   Shift GetShift() const { return shift_; }
883   VIXL_DEPRECATED("GetShift", Shift shift() const) { return GetShift(); }
884 
GetExtend()885   Extend GetExtend() const { return extend_; }
886   VIXL_DEPRECATED("GetExtend", Extend extend() const) { return GetExtend(); }
887 
GetShiftAmount()888   unsigned GetShiftAmount() const { return shift_amount_; }
shift_amount()889   VIXL_DEPRECATED("GetShiftAmount", unsigned shift_amount() const) {
890     return GetShiftAmount();
891   }
892 
893   bool IsImmediateOffset() const;
894   bool IsRegisterOffset() const;
895   bool IsPreIndex() const;
896   bool IsPostIndex() const;
897 
898   void AddOffset(int64_t offset);
899 
IsValid()900   bool IsValid() const {
901     return base_.IsValid() &&
902            ((addrmode_ == Offset) || (addrmode_ == PreIndex) ||
903             (addrmode_ == PostIndex)) &&
904            ((shift_ == NO_SHIFT) || (extend_ == NO_EXTEND)) &&
905            ((offset_ == 0) || !regoffset_.IsValid());
906   }
907 
Equals(const MemOperand & other)908   bool Equals(const MemOperand& other) const {
909     return base_.Is(other.base_) && regoffset_.Is(other.regoffset_) &&
910            (offset_ == other.offset_) && (addrmode_ == other.addrmode_) &&
911            (shift_ == other.shift_) && (extend_ == other.extend_) &&
912            (shift_amount_ == other.shift_amount_);
913   }
914 
915  private:
916   Register base_;
917   Register regoffset_;
918   int64_t offset_;
919   AddrMode addrmode_;
920   Shift shift_;
921   Extend extend_;
922   unsigned shift_amount_;
923 };
924 
925 // This an abstraction that can represent a register or memory location. The
926 // `MacroAssembler` provides helpers to move data between generic operands.
927 class GenericOperand {
928  public:
GenericOperand()929   GenericOperand() { VIXL_ASSERT(!IsValid()); }
930   GenericOperand(const CPURegister& reg);  // NOLINT(runtime/explicit)
931   GenericOperand(const MemOperand& mem_op,
932                  size_t mem_op_size = 0);  // NOLINT(runtime/explicit)
933 
IsValid()934   bool IsValid() const { return cpu_register_.IsValid() != mem_op_.IsValid(); }
935 
936   bool Equals(const GenericOperand& other) const;
937 
IsCPURegister()938   bool IsCPURegister() const {
939     VIXL_ASSERT(IsValid());
940     return cpu_register_.IsValid();
941   }
942 
IsRegister()943   bool IsRegister() const {
944     return IsCPURegister() && cpu_register_.IsRegister();
945   }
946 
IsVRegister()947   bool IsVRegister() const {
948     return IsCPURegister() && cpu_register_.IsVRegister();
949   }
950 
IsSameCPURegisterType(const GenericOperand & other)951   bool IsSameCPURegisterType(const GenericOperand& other) {
952     return IsCPURegister() && other.IsCPURegister() &&
953            GetCPURegister().IsSameType(other.GetCPURegister());
954   }
955 
IsMemOperand()956   bool IsMemOperand() const {
957     VIXL_ASSERT(IsValid());
958     return mem_op_.IsValid();
959   }
960 
GetCPURegister()961   CPURegister GetCPURegister() const {
962     VIXL_ASSERT(IsCPURegister());
963     return cpu_register_;
964   }
965 
GetMemOperand()966   MemOperand GetMemOperand() const {
967     VIXL_ASSERT(IsMemOperand());
968     return mem_op_;
969   }
970 
GetMemOperandSizeInBytes()971   size_t GetMemOperandSizeInBytes() const {
972     VIXL_ASSERT(IsMemOperand());
973     return mem_op_size_;
974   }
975 
GetSizeInBytes()976   size_t GetSizeInBytes() const {
977     return IsCPURegister() ? cpu_register_.GetSizeInBytes()
978                            : GetMemOperandSizeInBytes();
979   }
980 
GetSizeInBits()981   size_t GetSizeInBits() const { return GetSizeInBytes() * kBitsPerByte; }
982 
983  private:
984   CPURegister cpu_register_;
985   MemOperand mem_op_;
986   // The size of the memory region pointed to, in bytes.
987   // We only support sizes up to X/D register sizes.
988   size_t mem_op_size_;
989 };
990 }
991 }  // namespace vixl::aarch64
992 
993 #endif  // VIXL_AARCH64_OPERANDS_AARCH64_H_
994