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