• 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     kNoRegister
55   };
56 
CPURegister()57   CPURegister() : code_(0), size_(0), type_(kNoRegister) {
58     VIXL_ASSERT(!IsValid());
59     VIXL_ASSERT(IsNone());
60   }
61 
CPURegister(unsigned code,unsigned size,RegisterType type)62   CPURegister(unsigned code, unsigned size, RegisterType type)
63       : code_(code), size_(size), type_(type) {
64     VIXL_ASSERT(IsValidOrNone());
65   }
66 
GetCode()67   unsigned GetCode() const {
68     VIXL_ASSERT(IsValid());
69     return code_;
70   }
code()71   VIXL_DEPRECATED("GetCode", unsigned code() const) { return GetCode(); }
72 
GetType()73   RegisterType GetType() const {
74     VIXL_ASSERT(IsValidOrNone());
75     return type_;
76   }
77   VIXL_DEPRECATED("GetType", RegisterType type() const) { return GetType(); }
78 
GetBit()79   RegList GetBit() const {
80     VIXL_ASSERT(code_ < (sizeof(RegList) * 8));
81     return IsValid() ? (static_cast<RegList>(1) << code_) : 0;
82   }
83   VIXL_DEPRECATED("GetBit", RegList Bit() const) { return GetBit(); }
84 
GetSizeInBytes()85   int GetSizeInBytes() const {
86     VIXL_ASSERT(IsValid());
87     VIXL_ASSERT(size_ % 8 == 0);
88     return size_ / 8;
89   }
SizeInBytes()90   VIXL_DEPRECATED("GetSizeInBytes", int SizeInBytes() const) {
91     return GetSizeInBytes();
92   }
93 
GetSizeInBits()94   int GetSizeInBits() const {
95     VIXL_ASSERT(IsValid());
96     return size_;
97   }
size()98   VIXL_DEPRECATED("GetSizeInBits", unsigned size() const) {
99     return GetSizeInBits();
100   }
SizeInBits()101   VIXL_DEPRECATED("GetSizeInBits", int SizeInBits() const) {
102     return GetSizeInBits();
103   }
104 
Is8Bits()105   bool Is8Bits() const {
106     VIXL_ASSERT(IsValid());
107     return size_ == 8;
108   }
109 
Is16Bits()110   bool Is16Bits() const {
111     VIXL_ASSERT(IsValid());
112     return size_ == 16;
113   }
114 
Is32Bits()115   bool Is32Bits() const {
116     VIXL_ASSERT(IsValid());
117     return size_ == 32;
118   }
119 
Is64Bits()120   bool Is64Bits() const {
121     VIXL_ASSERT(IsValid());
122     return size_ == 64;
123   }
124 
Is128Bits()125   bool Is128Bits() const {
126     VIXL_ASSERT(IsValid());
127     return size_ == 128;
128   }
129 
IsValid()130   bool IsValid() const {
131     if (IsValidRegister() || IsValidVRegister()) {
132       VIXL_ASSERT(!IsNone());
133       return true;
134     } else {
135       // This assert is hit when the register has not been properly initialized.
136       // One cause for this can be an initialisation order fiasco. See
137       // https://isocpp.org/wiki/faq/ctors#static-init-order for some details.
138       VIXL_ASSERT(IsNone());
139       return false;
140     }
141   }
142 
IsValidRegister()143   bool IsValidRegister() const {
144     return IsRegister() && ((size_ == kWRegSize) || (size_ == kXRegSize)) &&
145            ((code_ < kNumberOfRegisters) || (code_ == kSPRegInternalCode));
146   }
147 
IsValidVRegister()148   bool IsValidVRegister() const {
149     return IsVRegister() && ((size_ == kBRegSize) || (size_ == kHRegSize) ||
150                              (size_ == kSRegSize) || (size_ == kDRegSize) ||
151                              (size_ == kQRegSize)) &&
152            (code_ < kNumberOfVRegisters);
153   }
154 
IsValidFPRegister()155   bool IsValidFPRegister() const {
156     return IsValidVRegister() && IsFPRegister();
157   }
158 
IsNone()159   bool IsNone() const {
160     // kNoRegister types should always have size 0 and code 0.
161     VIXL_ASSERT((type_ != kNoRegister) || (code_ == 0));
162     VIXL_ASSERT((type_ != kNoRegister) || (size_ == 0));
163 
164     return type_ == kNoRegister;
165   }
166 
Aliases(const CPURegister & other)167   bool Aliases(const CPURegister& other) const {
168     VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone());
169     return (code_ == other.code_) && (type_ == other.type_);
170   }
171 
Is(const CPURegister & other)172   bool Is(const CPURegister& other) const {
173     VIXL_ASSERT(IsValidOrNone() && other.IsValidOrNone());
174     return Aliases(other) && (size_ == other.size_);
175   }
176 
IsZero()177   bool IsZero() const {
178     VIXL_ASSERT(IsValid());
179     return IsRegister() && (code_ == kZeroRegCode);
180   }
181 
IsSP()182   bool IsSP() const {
183     VIXL_ASSERT(IsValid());
184     return IsRegister() && (code_ == kSPRegInternalCode);
185   }
186 
IsRegister()187   bool IsRegister() const { return type_ == kRegister; }
188 
IsVRegister()189   bool IsVRegister() const { return type_ == kVRegister; }
190 
191   // CPURegister does not track lanes like VRegister does, so we have to assume
192   // that we have scalar types here.
193   // TODO: Encode lane information in CPURegister so that we can be consistent.
IsFPRegister()194   bool IsFPRegister() const { return IsH() || IsS() || IsD(); }
195 
IsW()196   bool IsW() const { return IsValidRegister() && Is32Bits(); }
IsX()197   bool IsX() const { return IsValidRegister() && Is64Bits(); }
198 
199   // These assertions ensure that the size and type of the register are as
200   // described. They do not consider the number of lanes that make up a vector.
201   // So, for example, Is8B() implies IsD(), and Is1D() implies IsD, but IsD()
202   // does not imply Is1D() or Is8B().
203   // Check the number of lanes, ie. the format of the vector, using methods such
204   // as Is8B(), Is1D(), etc. in the VRegister class.
IsV()205   bool IsV() const { return IsVRegister(); }
IsB()206   bool IsB() const { return IsV() && Is8Bits(); }
IsH()207   bool IsH() const { return IsV() && Is16Bits(); }
IsS()208   bool IsS() const { return IsV() && Is32Bits(); }
IsD()209   bool IsD() const { return IsV() && Is64Bits(); }
IsQ()210   bool IsQ() const { return IsV() && Is128Bits(); }
211 
212   // Semantic type for sdot and udot instructions.
IsS4B()213   bool IsS4B() const { return IsS(); }
S4B()214   const VRegister& S4B() const { return S(); }
215 
216   const Register& W() const;
217   const Register& X() const;
218   const VRegister& V() const;
219   const VRegister& B() const;
220   const VRegister& H() const;
221   const VRegister& S() const;
222   const VRegister& D() const;
223   const VRegister& Q() const;
224 
IsSameType(const CPURegister & other)225   bool IsSameType(const CPURegister& other) const {
226     return type_ == other.type_;
227   }
228 
IsSameSizeAndType(const CPURegister & other)229   bool IsSameSizeAndType(const CPURegister& other) const {
230     return (size_ == other.size_) && IsSameType(other);
231   }
232 
233  protected:
234   unsigned code_;
235   int size_;
236   RegisterType type_;
237 
238  private:
IsValidOrNone()239   bool IsValidOrNone() const { return IsValid() || IsNone(); }
240 };
241 
242 
243 class Register : public CPURegister {
244  public:
Register()245   Register() : CPURegister() {}
Register(const CPURegister & other)246   explicit Register(const CPURegister& other)
247       : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()) {
248     VIXL_ASSERT(IsValidRegister());
249   }
Register(unsigned code,unsigned size)250   Register(unsigned code, unsigned size) : CPURegister(code, size, kRegister) {}
251 
IsValid()252   bool IsValid() const {
253     VIXL_ASSERT(IsRegister() || IsNone());
254     return IsValidRegister();
255   }
256 
257   static const Register& GetWRegFromCode(unsigned code);
258   VIXL_DEPRECATED("GetWRegFromCode",
259                   static const Register& WRegFromCode(unsigned code)) {
260     return GetWRegFromCode(code);
261   }
262 
263   static const Register& GetXRegFromCode(unsigned code);
264   VIXL_DEPRECATED("GetXRegFromCode",
265                   static const Register& XRegFromCode(unsigned code)) {
266     return GetXRegFromCode(code);
267   }
268 
269  private:
270   static const Register wregisters[];
271   static const Register xregisters[];
272 };
273 
274 
275 namespace internal {
276 
277 template <int size_in_bits>
278 class FixedSizeRegister : public Register {
279  public:
FixedSizeRegister()280   FixedSizeRegister() : Register() {}
FixedSizeRegister(unsigned code)281   explicit FixedSizeRegister(unsigned code) : Register(code, size_in_bits) {
282     VIXL_ASSERT(IsValidRegister());
283   }
FixedSizeRegister(const Register & other)284   explicit FixedSizeRegister(const Register& other)
285       : Register(other.GetCode(), size_in_bits) {
286     VIXL_ASSERT(other.GetSizeInBits() == size_in_bits);
287     VIXL_ASSERT(IsValidRegister());
288   }
FixedSizeRegister(const CPURegister & other)289   explicit FixedSizeRegister(const CPURegister& other)
290       : Register(other.GetCode(), other.GetSizeInBits()) {
291     VIXL_ASSERT(other.GetType() == kRegister);
292     VIXL_ASSERT(other.GetSizeInBits() == size_in_bits);
293     VIXL_ASSERT(IsValidRegister());
294   }
295 
IsValid()296   bool IsValid() const {
297     return Register::IsValid() && (GetSizeInBits() == size_in_bits);
298   }
299 };
300 
301 }  // namespace internal
302 
303 typedef internal::FixedSizeRegister<kXRegSize> XRegister;
304 typedef internal::FixedSizeRegister<kWRegSize> WRegister;
305 
306 
307 class VRegister : public CPURegister {
308  public:
VRegister()309   VRegister() : CPURegister(), lanes_(1) {}
VRegister(const CPURegister & other)310   explicit VRegister(const CPURegister& other)
311       : CPURegister(other.GetCode(), other.GetSizeInBits(), other.GetType()),
312         lanes_(1) {
313     VIXL_ASSERT(IsValidVRegister());
314     VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16));
315   }
316   VRegister(unsigned code, unsigned size, unsigned lanes = 1)
CPURegister(code,size,kVRegister)317       : CPURegister(code, size, kVRegister), lanes_(lanes) {
318     VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16));
319   }
VRegister(unsigned code,VectorFormat format)320   VRegister(unsigned code, VectorFormat format)
321       : CPURegister(code, RegisterSizeInBitsFromFormat(format), kVRegister),
322         lanes_(IsVectorFormat(format) ? LaneCountFromFormat(format) : 1) {
323     VIXL_ASSERT(IsPowerOf2(lanes_) && (lanes_ <= 16));
324   }
325 
IsValid()326   bool IsValid() const {
327     VIXL_ASSERT(IsVRegister() || IsNone());
328     return IsValidVRegister();
329   }
330 
331   static const VRegister& GetBRegFromCode(unsigned code);
332   VIXL_DEPRECATED("GetBRegFromCode",
333                   static const VRegister& BRegFromCode(unsigned code)) {
334     return GetBRegFromCode(code);
335   }
336 
337   static const VRegister& GetHRegFromCode(unsigned code);
338   VIXL_DEPRECATED("GetHRegFromCode",
339                   static const VRegister& HRegFromCode(unsigned code)) {
340     return GetHRegFromCode(code);
341   }
342 
343   static const VRegister& GetSRegFromCode(unsigned code);
344   VIXL_DEPRECATED("GetSRegFromCode",
345                   static const VRegister& SRegFromCode(unsigned code)) {
346     return GetSRegFromCode(code);
347   }
348 
349   static const VRegister& GetDRegFromCode(unsigned code);
350   VIXL_DEPRECATED("GetDRegFromCode",
351                   static const VRegister& DRegFromCode(unsigned code)) {
352     return GetDRegFromCode(code);
353   }
354 
355   static const VRegister& GetQRegFromCode(unsigned code);
356   VIXL_DEPRECATED("GetQRegFromCode",
357                   static const VRegister& QRegFromCode(unsigned code)) {
358     return GetQRegFromCode(code);
359   }
360 
361   static const VRegister& GetVRegFromCode(unsigned code);
362   VIXL_DEPRECATED("GetVRegFromCode",
363                   static const VRegister& VRegFromCode(unsigned code)) {
364     return GetVRegFromCode(code);
365   }
366 
V8B()367   VRegister V8B() const { return VRegister(code_, kDRegSize, 8); }
V16B()368   VRegister V16B() const { return VRegister(code_, kQRegSize, 16); }
V2H()369   VRegister V2H() const { return VRegister(code_, kSRegSize, 2); }
V4H()370   VRegister V4H() const { return VRegister(code_, kDRegSize, 4); }
V8H()371   VRegister V8H() const { return VRegister(code_, kQRegSize, 8); }
V2S()372   VRegister V2S() const { return VRegister(code_, kDRegSize, 2); }
V4S()373   VRegister V4S() const { return VRegister(code_, kQRegSize, 4); }
V2D()374   VRegister V2D() const { return VRegister(code_, kQRegSize, 2); }
V1D()375   VRegister V1D() const { return VRegister(code_, kDRegSize, 1); }
376 
Is8B()377   bool Is8B() const { return (Is64Bits() && (lanes_ == 8)); }
Is16B()378   bool Is16B() const { return (Is128Bits() && (lanes_ == 16)); }
Is2H()379   bool Is2H() const { return (Is32Bits() && (lanes_ == 2)); }
Is4H()380   bool Is4H() const { return (Is64Bits() && (lanes_ == 4)); }
Is8H()381   bool Is8H() const { return (Is128Bits() && (lanes_ == 8)); }
Is1S()382   bool Is1S() const { return (Is32Bits() && (lanes_ == 1)); }
Is2S()383   bool Is2S() const { return (Is64Bits() && (lanes_ == 2)); }
Is4S()384   bool Is4S() const { return (Is128Bits() && (lanes_ == 4)); }
Is1D()385   bool Is1D() const { return (Is64Bits() && (lanes_ == 1)); }
Is2D()386   bool Is2D() const { return (Is128Bits() && (lanes_ == 2)); }
387 
388   // For consistency, we assert the number of lanes of these scalar registers,
389   // even though there are no vectors of equivalent total size with which they
390   // could alias.
Is1B()391   bool Is1B() const {
392     VIXL_ASSERT(!(Is8Bits() && IsVector()));
393     return Is8Bits();
394   }
Is1H()395   bool Is1H() const {
396     VIXL_ASSERT(!(Is16Bits() && IsVector()));
397     return Is16Bits();
398   }
399 
400   // Semantic type for sdot and udot instructions.
Is1S4B()401   bool Is1S4B() const { return Is1S(); }
402 
403 
IsLaneSizeB()404   bool IsLaneSizeB() const { return GetLaneSizeInBits() == kBRegSize; }
IsLaneSizeH()405   bool IsLaneSizeH() const { return GetLaneSizeInBits() == kHRegSize; }
IsLaneSizeS()406   bool IsLaneSizeS() const { return GetLaneSizeInBits() == kSRegSize; }
IsLaneSizeD()407   bool IsLaneSizeD() const { return GetLaneSizeInBits() == kDRegSize; }
408 
GetLanes()409   int GetLanes() const { return lanes_; }
lanes()410   VIXL_DEPRECATED("GetLanes", int lanes() const) { return GetLanes(); }
411 
IsFPRegister()412   bool IsFPRegister() const { return Is1H() || Is1S() || Is1D(); }
IsValidFPRegister()413   bool IsValidFPRegister() const {
414     return IsValidVRegister() && IsFPRegister();
415   }
416 
IsScalar()417   bool IsScalar() const { return lanes_ == 1; }
418 
IsVector()419   bool IsVector() const { return lanes_ > 1; }
420 
IsSameFormat(const VRegister & other)421   bool IsSameFormat(const VRegister& other) const {
422     return (size_ == other.size_) && (lanes_ == other.lanes_);
423   }
424 
GetLaneSizeInBytes()425   unsigned GetLaneSizeInBytes() const { return GetSizeInBytes() / lanes_; }
LaneSizeInBytes()426   VIXL_DEPRECATED("GetLaneSizeInBytes", unsigned LaneSizeInBytes() const) {
427     return GetLaneSizeInBytes();
428   }
429 
GetLaneSizeInBits()430   unsigned GetLaneSizeInBits() const { return GetLaneSizeInBytes() * 8; }
LaneSizeInBits()431   VIXL_DEPRECATED("GetLaneSizeInBits", unsigned LaneSizeInBits() const) {
432     return GetLaneSizeInBits();
433   }
434 
435  private:
436   static const VRegister bregisters[];
437   static const VRegister hregisters[];
438   static const VRegister sregisters[];
439   static const VRegister dregisters[];
440   static const VRegister qregisters[];
441   static const VRegister vregisters[];
442   int lanes_;
443 };
444 
445 
446 // No*Reg is used to indicate an unused argument, or an error case. Note that
447 // these all compare equal (using the Is() method). The Register and VRegister
448 // variants are provided for convenience.
449 const Register NoReg;
450 const VRegister NoVReg;
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()) && IncludesAliasOf(other.GetCode());
708   }
709 
IncludesAliasOf(int code)710   bool IncludesAliasOf(int code) const {
711     VIXL_ASSERT(IsValid());
712     return (((static_cast<RegList>(1) << 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 // In assembly syntax, MemOperands are normally denoted by one or more elements
848 // inside or around square brackets.
849 class MemOperand {
850  public:
851   // Creates an invalid `MemOperand`.
852   MemOperand();
853   explicit MemOperand(Register base,
854                       int64_t offset = 0,
855                       AddrMode addrmode = Offset);
856   MemOperand(Register base,
857              Register regoffset,
858              Shift shift = LSL,
859              unsigned shift_amount = 0);
860   MemOperand(Register base,
861              Register regoffset,
862              Extend extend,
863              unsigned shift_amount = 0);
864   MemOperand(Register base, const Operand& offset, AddrMode addrmode = Offset);
865 
GetBaseRegister()866   const Register& GetBaseRegister() const { return base_; }
867 
868   // If the MemOperand has a register offset, return it. (This also applies to
869   // pre- and post-index modes.) Otherwise, return NoReg.
GetRegisterOffset()870   const Register& GetRegisterOffset() const { return regoffset_; }
871 
872   // If the MemOperand has an immediate offset, return it. (This also applies to
873   // pre- and post-index modes.) Otherwise, return 0.
GetOffset()874   int64_t GetOffset() const { return offset_; }
875 
GetAddrMode()876   AddrMode GetAddrMode() const { return addrmode_; }
GetShift()877   Shift GetShift() const { return shift_; }
GetExtend()878   Extend GetExtend() const { return extend_; }
879 
GetShiftAmount()880   unsigned GetShiftAmount() const {
881     // Extend modes can also encode a shift for some instructions.
882     VIXL_ASSERT((GetShift() != NO_SHIFT) || (GetExtend() != NO_EXTEND));
883     return shift_amount_;
884   }
885 
886   // True for immediate-offset (but not indexed) MemOperands.
887   bool IsImmediateOffset() const;
888   // True for register-offset (but not indexed) MemOperands.
889   bool IsRegisterOffset() const;
890 
891   bool IsPreIndex() const;
892   bool IsPostIndex() const;
893 
894   void AddOffset(int64_t offset);
895 
IsValid()896   bool IsValid() const {
897     return base_.IsValid() &&
898            ((addrmode_ == Offset) || (addrmode_ == PreIndex) ||
899             (addrmode_ == PostIndex)) &&
900            ((shift_ == NO_SHIFT) || (extend_ == NO_EXTEND)) &&
901            ((offset_ == 0) || !regoffset_.IsValid());
902   }
903 
Equals(const MemOperand & other)904   bool Equals(const MemOperand& other) const {
905     return base_.Is(other.base_) && regoffset_.Is(other.regoffset_) &&
906            (offset_ == other.offset_) && (addrmode_ == other.addrmode_) &&
907            (shift_ == other.shift_) && (extend_ == other.extend_) &&
908            (shift_amount_ == other.shift_amount_);
909   }
910 
911  private:
912   Register base_;
913   Register regoffset_;
914   int64_t offset_;
915   AddrMode addrmode_;
916   Shift shift_;
917   Extend extend_;
918   unsigned shift_amount_;
919 };
920 
921 // This an abstraction that can represent a register or memory location. The
922 // `MacroAssembler` provides helpers to move data between generic operands.
923 class GenericOperand {
924  public:
GenericOperand()925   GenericOperand() { VIXL_ASSERT(!IsValid()); }
926   GenericOperand(const CPURegister& reg);  // NOLINT(runtime/explicit)
927   GenericOperand(const MemOperand& mem_op,
928                  size_t mem_op_size = 0);  // NOLINT(runtime/explicit)
929 
IsValid()930   bool IsValid() const { return cpu_register_.IsValid() != mem_op_.IsValid(); }
931 
932   bool Equals(const GenericOperand& other) const;
933 
IsCPURegister()934   bool IsCPURegister() const {
935     VIXL_ASSERT(IsValid());
936     return cpu_register_.IsValid();
937   }
938 
IsRegister()939   bool IsRegister() const {
940     return IsCPURegister() && cpu_register_.IsRegister();
941   }
942 
IsVRegister()943   bool IsVRegister() const {
944     return IsCPURegister() && cpu_register_.IsVRegister();
945   }
946 
IsSameCPURegisterType(const GenericOperand & other)947   bool IsSameCPURegisterType(const GenericOperand& other) {
948     return IsCPURegister() && other.IsCPURegister() &&
949            GetCPURegister().IsSameType(other.GetCPURegister());
950   }
951 
IsMemOperand()952   bool IsMemOperand() const {
953     VIXL_ASSERT(IsValid());
954     return mem_op_.IsValid();
955   }
956 
GetCPURegister()957   CPURegister GetCPURegister() const {
958     VIXL_ASSERT(IsCPURegister());
959     return cpu_register_;
960   }
961 
GetMemOperand()962   MemOperand GetMemOperand() const {
963     VIXL_ASSERT(IsMemOperand());
964     return mem_op_;
965   }
966 
GetMemOperandSizeInBytes()967   size_t GetMemOperandSizeInBytes() const {
968     VIXL_ASSERT(IsMemOperand());
969     return mem_op_size_;
970   }
971 
GetSizeInBytes()972   size_t GetSizeInBytes() const {
973     return IsCPURegister() ? cpu_register_.GetSizeInBytes()
974                            : GetMemOperandSizeInBytes();
975   }
976 
GetSizeInBits()977   size_t GetSizeInBits() const { return GetSizeInBytes() * kBitsPerByte; }
978 
979  private:
980   CPURegister cpu_register_;
981   MemOperand mem_op_;
982   // The size of the memory region pointed to, in bytes.
983   // We only support sizes up to X/D register sizes.
984   size_t mem_op_size_;
985 };
986 }
987 }  // namespace vixl::aarch64
988 
989 #endif  // VIXL_AARCH64_OPERANDS_AARCH64_H_
990