• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015, 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
10 //     notice, this list of conditions and the following disclaimer in the
11 //     documentation and/or other materials provided with the distribution.
12 //   * Neither the name of ARM Limited nor the names of its contributors may
13 //     be used to endorse or promote products derived from this software
14 //     without 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
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 // POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef VIXL_AARCH32_OPERANDS_AARCH32_H_
29 #define VIXL_AARCH32_OPERANDS_AARCH32_H_
30 
31 #include "aarch32/instructions-aarch32.h"
32 
33 namespace vixl {
34 namespace aarch32 {
35 
36 // Operand represents generic set of arguments to pass to an instruction.
37 //
38 //   Usage: <instr> <Rd> , <Operand>
39 //
40 //   where <instr> is the instruction to use (e.g., Mov(), Rsb(), etc.)
41 //         <Rd> is the destination register
42 //         <Operand> is the rest of the arguments to the instruction
43 //
44 //   <Operand> can be one of:
45 //
46 //   #<imm> - an unsigned 32-bit immediate value
47 //   <Rm>, <shift> <#amount> - immediate shifted register
48 //   <Rm>, <shift> <Rs> - register shifted register
49 //
50 class Operand {
51  public:
52   // { #<immediate> }
53   // where <immediate> is uint32_t.
54   // This is allowed to be an implicit constructor because Operand is
55   // a wrapper class that doesn't normally perform any type conversion.
Operand(uint32_t immediate)56   Operand(uint32_t immediate)  // NOLINT(runtime/explicit)
57       : imm_(immediate),
58         rm_(NoReg),
59         shift_(LSL),
60         amount_(0),
61         rs_(NoReg) {}
Operand(int32_t immediate)62   Operand(int32_t immediate)  // NOLINT(runtime/explicit)
63       : imm_(immediate),
64         rm_(NoReg),
65         shift_(LSL),
66         amount_(0),
67         rs_(NoReg) {}
68 
69   // rm
70   // where rm is the base register
71   // This is allowed to be an implicit constructor because Operand is
72   // a wrapper class that doesn't normally perform any type conversion.
Operand(Register rm)73   Operand(Register rm)  // NOLINT(runtime/explicit)
74       : imm_(0),
75         rm_(rm),
76         shift_(LSL),
77         amount_(0),
78         rs_(NoReg) {
79     VIXL_ASSERT(rm_.IsValid());
80   }
81 
82   // rm, <shift>
83   // where rm is the base register, and
84   //       <shift> is RRX
Operand(Register rm,Shift shift)85   Operand(Register rm, Shift shift)
86       : imm_(0), rm_(rm), shift_(shift), amount_(0), rs_(NoReg) {
87     VIXL_ASSERT(rm_.IsValid());
88     VIXL_ASSERT(shift_.IsRRX());
89   }
90 
91   // rm, <shift> #<amount>
92   // where rm is the base register, and
93   //       <shift> is one of {LSL, LSR, ASR, ROR}, and
94   //       <amount> is uint6_t.
Operand(Register rm,Shift shift,uint32_t amount)95   Operand(Register rm, Shift shift, uint32_t amount)
96       : imm_(0), rm_(rm), shift_(shift), amount_(amount), rs_(NoReg) {
97     VIXL_ASSERT(rm_.IsValid());
98     VIXL_ASSERT(!shift_.IsRRX());
99 #ifdef VIXL_DEBUG
100     switch (shift_.GetType()) {
101       case LSL:
102         VIXL_ASSERT(amount_ <= 31);
103         break;
104       case ROR:
105         VIXL_ASSERT(amount_ <= 31);
106         break;
107       case LSR:
108       case ASR:
109         VIXL_ASSERT(amount_ <= 32);
110         break;
111       case RRX:
112       default:
113         VIXL_UNREACHABLE();
114         break;
115     }
116 #endif
117   }
118 
119   // rm, <shift> rs
120   // where rm is the base register, and
121   //       <shift> is one of {LSL, LSR, ASR, ROR}, and
122   //       rs is the shifted register
Operand(Register rm,Shift shift,Register rs)123   Operand(Register rm, Shift shift, Register rs)
124       : imm_(0), rm_(rm), shift_(shift), amount_(0), rs_(rs) {
125     VIXL_ASSERT(rm_.IsValid() && rs_.IsValid());
126     VIXL_ASSERT(!shift_.IsRRX());
127   }
128 
129   // Factory methods creating operands from any integral or pointer type. The
130   // source must fit into 32 bits.
131   template <typename T>
From(T immediate)132   static Operand From(T immediate) {
133 #if __cplusplus >= 201103L
134     VIXL_STATIC_ASSERT_MESSAGE(std::is_integral<T>::value,
135                                "An integral type is required to build an "
136                                "immediate operand.");
137 #endif
138     // Allow both a signed or unsigned 32 bit integer to be passed, but store it
139     // as a uint32_t. The signedness information will be lost. We have to add a
140     // static_cast to make sure the compiler does not complain about implicit 64
141     // to 32 narrowing. It's perfectly acceptable for the user to pass a 64-bit
142     // value, as long as it can be encoded in 32 bits.
143     VIXL_ASSERT(IsInt32(immediate) || IsUint32(immediate));
144     return Operand(static_cast<uint32_t>(immediate));
145   }
146 
147   template <typename T>
From(T * address)148   static Operand From(T* address) {
149     uintptr_t address_as_integral = reinterpret_cast<uintptr_t>(address);
150     VIXL_ASSERT(IsUint32(address_as_integral));
151     return Operand(static_cast<uint32_t>(address_as_integral));
152   }
153 
IsImmediate()154   bool IsImmediate() const { return !rm_.IsValid(); }
155 
IsPlainRegister()156   bool IsPlainRegister() const {
157     return rm_.IsValid() && !shift_.IsRRX() && !rs_.IsValid() && (amount_ == 0);
158   }
159 
IsImmediateShiftedRegister()160   bool IsImmediateShiftedRegister() const {
161     return rm_.IsValid() && !rs_.IsValid();
162   }
163 
IsRegisterShiftedRegister()164   bool IsRegisterShiftedRegister() const {
165     return rm_.IsValid() && rs_.IsValid();
166   }
167 
GetImmediate()168   uint32_t GetImmediate() const {
169     VIXL_ASSERT(IsImmediate());
170     return imm_;
171   }
172 
GetSignedImmediate()173   int32_t GetSignedImmediate() const {
174     VIXL_ASSERT(IsImmediate());
175     int32_t result;
176     memcpy(&result, &imm_, sizeof(result));
177     return result;
178   }
179 
GetBaseRegister()180   Register GetBaseRegister() const {
181     VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister());
182     return rm_;
183   }
184 
GetShift()185   Shift GetShift() const {
186     VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister());
187     return shift_;
188   }
189 
GetShiftAmount()190   uint32_t GetShiftAmount() const {
191     VIXL_ASSERT(IsImmediateShiftedRegister());
192     return amount_;
193   }
194 
GetShiftRegister()195   Register GetShiftRegister() const {
196     VIXL_ASSERT(IsRegisterShiftedRegister());
197     return rs_;
198   }
199 
GetTypeEncodingValue()200   uint32_t GetTypeEncodingValue() const {
201     return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue();
202   }
203 
204  private:
205 // Forbid implicitely creating operands around types that cannot be encoded
206 // into a uint32_t without loss.
207 #if __cplusplus >= 201103L
208   Operand(int64_t) = delete;   // NOLINT(runtime/explicit)
209   Operand(uint64_t) = delete;  // NOLINT(runtime/explicit)
210   Operand(float) = delete;     // NOLINT(runtime/explicit)
211   Operand(double) = delete;    // NOLINT(runtime/explicit)
212 #else
213   VIXL_NO_RETURN_IN_DEBUG_MODE Operand(int64_t) {  // NOLINT(runtime/explicit)
214     VIXL_UNREACHABLE();
215   }
216   VIXL_NO_RETURN_IN_DEBUG_MODE Operand(uint64_t) {  // NOLINT(runtime/explicit)
217     VIXL_UNREACHABLE();
218   }
219   VIXL_NO_RETURN_IN_DEBUG_MODE Operand(float) {  // NOLINT
220     VIXL_UNREACHABLE();
221   }
222   VIXL_NO_RETURN_IN_DEBUG_MODE Operand(double) {  // NOLINT
223     VIXL_UNREACHABLE();
224   }
225 #endif
226 
227   uint32_t imm_;
228   Register rm_;
229   Shift shift_;
230   uint32_t amount_;
231   Register rs_;
232 };
233 
234 std::ostream& operator<<(std::ostream& os, const Operand& operand);
235 
236 class NeonImmediate {
237   template <typename T>
238   struct DataTypeIdentity {
239     T data_type_;
240   };
241 
242  public:
243   // { #<immediate> }
244   // where <immediate> is 32 bit number.
245   // This is allowed to be an implicit constructor because NeonImmediate is
246   // a wrapper class that doesn't normally perform any type conversion.
NeonImmediate(uint32_t immediate)247   NeonImmediate(uint32_t immediate)  // NOLINT(runtime/explicit)
248       : imm_(immediate),
249         immediate_type_(I32) {}
NeonImmediate(int immediate)250   NeonImmediate(int immediate)  // NOLINT(runtime/explicit)
251       : imm_(immediate),
252         immediate_type_(I32) {}
253 
254   // { #<immediate> }
255   // where <immediate> is a 64 bit number
256   // This is allowed to be an implicit constructor because NeonImmediate is
257   // a wrapper class that doesn't normally perform any type conversion.
NeonImmediate(int64_t immediate)258   NeonImmediate(int64_t immediate)  // NOLINT(runtime/explicit)
259       : imm_(immediate),
260         immediate_type_(I64) {}
NeonImmediate(uint64_t immediate)261   NeonImmediate(uint64_t immediate)  // NOLINT(runtime/explicit)
262       : imm_(immediate),
263         immediate_type_(I64) {}
264 
265   // { #<immediate> }
266   // where <immediate> is a non zero floating point number which can be encoded
267   // as an 8 bit floating point (checked by the constructor).
268   // This is allowed to be an implicit constructor because NeonImmediate is
269   // a wrapper class that doesn't normally perform any type conversion.
NeonImmediate(float immediate)270   NeonImmediate(float immediate)  // NOLINT(runtime/explicit)
271       : imm_(immediate),
272         immediate_type_(F32) {}
NeonImmediate(double immediate)273   NeonImmediate(double immediate)  // NOLINT(runtime/explicit)
274       : imm_(immediate),
275         immediate_type_(F64) {}
276 
NeonImmediate(const NeonImmediate & src)277   NeonImmediate(const NeonImmediate& src)
278       : imm_(src.imm_), immediate_type_(src.immediate_type_) {}
279 
280   template <typename T>
GetImmediate()281   T GetImmediate() const {
282     return GetImmediate(DataTypeIdentity<T>());
283   }
284 
285   template <typename T>
GetImmediate(const DataTypeIdentity<T> &)286   T GetImmediate(const DataTypeIdentity<T>&) const {
287     VIXL_ASSERT(sizeof(T) <= sizeof(uint32_t));
288     VIXL_ASSERT(CanConvert<T>());
289     if (immediate_type_.Is(I64))
290       return static_cast<T>(imm_.u64_ & static_cast<T>(-1));
291     if (immediate_type_.Is(F64) || immediate_type_.Is(F32)) return 0;
292     return static_cast<T>(imm_.u32_ & static_cast<T>(-1));
293   }
294 
GetImmediate(const DataTypeIdentity<uint64_t> &)295   uint64_t GetImmediate(const DataTypeIdentity<uint64_t>&) const {
296     VIXL_ASSERT(CanConvert<uint64_t>());
297     if (immediate_type_.Is(I32)) return imm_.u32_;
298     if (immediate_type_.Is(F64) || immediate_type_.Is(F32)) return 0;
299     return imm_.u64_;
300   }
GetImmediate(const DataTypeIdentity<float> &)301   float GetImmediate(const DataTypeIdentity<float>&) const {
302     VIXL_ASSERT(CanConvert<float>());
303     if (immediate_type_.Is(F64)) return static_cast<float>(imm_.d_);
304     return imm_.f_;
305   }
GetImmediate(const DataTypeIdentity<double> &)306   double GetImmediate(const DataTypeIdentity<double>&) const {
307     VIXL_ASSERT(CanConvert<double>());
308     if (immediate_type_.Is(F32)) return static_cast<double>(imm_.f_);
309     return imm_.d_;
310   }
311 
IsInteger32()312   bool IsInteger32() const { return immediate_type_.Is(I32); }
IsInteger64()313   bool IsInteger64() const { return immediate_type_.Is(I64); }
IsInteger()314   bool IsInteger() const { return IsInteger32() | IsInteger64(); }
IsFloat()315   bool IsFloat() const { return immediate_type_.Is(F32); }
IsDouble()316   bool IsDouble() const { return immediate_type_.Is(F64); }
IsFloatZero()317   bool IsFloatZero() const {
318     if (immediate_type_.Is(F32)) return imm_.f_ == 0.0f;
319     if (immediate_type_.Is(F64)) return imm_.d_ == 0.0;
320     return false;
321   }
322 
323   template <typename T>
CanConvert()324   bool CanConvert() const {
325     return CanConvert(DataTypeIdentity<T>());
326   }
327 
328   template <typename T>
CanConvert(const DataTypeIdentity<T> &)329   bool CanConvert(const DataTypeIdentity<T>&) const {
330     VIXL_ASSERT(sizeof(T) < sizeof(uint32_t));
331     return (immediate_type_.Is(I32) && ((imm_.u32_ >> (8 * sizeof(T))) == 0)) ||
332            (immediate_type_.Is(I64) && ((imm_.u64_ >> (8 * sizeof(T))) == 0)) ||
333            (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) ||
334            (immediate_type_.Is(F64) && (imm_.d_ == 0.0));
335   }
CanConvert(const DataTypeIdentity<uint32_t> &)336   bool CanConvert(const DataTypeIdentity<uint32_t>&) const {
337     return immediate_type_.Is(I32) ||
338            (immediate_type_.Is(I64) && ((imm_.u64_ >> 32) == 0)) ||
339            (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) ||
340            (immediate_type_.Is(F64) && (imm_.d_ == 0.0));
341   }
CanConvert(const DataTypeIdentity<uint64_t> &)342   bool CanConvert(const DataTypeIdentity<uint64_t>&) const {
343     return IsInteger() || CanConvert<uint32_t>();
344   }
CanConvert(const DataTypeIdentity<float> &)345   bool CanConvert(const DataTypeIdentity<float>&) const {
346     return IsFloat() || IsDouble();
347   }
CanConvert(const DataTypeIdentity<double> &)348   bool CanConvert(const DataTypeIdentity<double>&) const {
349     return IsFloat() || IsDouble();
350   }
351   friend std::ostream& operator<<(std::ostream& os,
352                                   const NeonImmediate& operand);
353 
354  private:
355   union NeonImmediateType {
356     uint64_t u64_;
357     double d_;
358     uint32_t u32_;
359     float f_;
NeonImmediateType(uint64_t u)360     NeonImmediateType(uint64_t u) : u64_(u) {}
NeonImmediateType(int64_t u)361     NeonImmediateType(int64_t u) : u64_(u) {}
NeonImmediateType(uint32_t u)362     NeonImmediateType(uint32_t u) : u32_(u) {}
NeonImmediateType(int32_t u)363     NeonImmediateType(int32_t u) : u32_(u) {}
NeonImmediateType(double d)364     NeonImmediateType(double d) : d_(d) {}
NeonImmediateType(float f)365     NeonImmediateType(float f) : f_(f) {}
NeonImmediateType(const NeonImmediateType & ref)366     NeonImmediateType(const NeonImmediateType& ref) : u64_(ref.u64_) {}
367   } imm_;
368 
369   DataType immediate_type_;
370 };
371 
372 std::ostream& operator<<(std::ostream& os, const NeonImmediate& operand);
373 
374 class NeonOperand {
375  public:
NeonOperand(int32_t immediate)376   NeonOperand(int32_t immediate)  // NOLINT(runtime/explicit)
377       : imm_(immediate),
378         rm_(NoDReg) {}
NeonOperand(uint32_t immediate)379   NeonOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
380       : imm_(immediate),
381         rm_(NoDReg) {}
NeonOperand(int64_t immediate)382   NeonOperand(int64_t immediate)  // NOLINT(runtime/explicit)
383       : imm_(immediate),
384         rm_(NoDReg) {}
NeonOperand(uint64_t immediate)385   NeonOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
386       : imm_(immediate),
387         rm_(NoDReg) {}
NeonOperand(float immediate)388   NeonOperand(float immediate)  // NOLINT(runtime/explicit)
389       : imm_(immediate),
390         rm_(NoDReg) {}
NeonOperand(double immediate)391   NeonOperand(double immediate)  // NOLINT(runtime/explicit)
392       : imm_(immediate),
393         rm_(NoDReg) {}
NeonOperand(const NeonImmediate & imm)394   NeonOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
395       : imm_(imm),
396         rm_(NoDReg) {}
NeonOperand(const VRegister & rm)397   NeonOperand(const VRegister& rm)  // NOLINT(runtime/explicit)
398       : imm_(0),
399         rm_(rm) {
400     VIXL_ASSERT(rm_.IsValid());
401   }
402 
IsImmediate()403   bool IsImmediate() const { return !rm_.IsValid(); }
IsRegister()404   bool IsRegister() const { return rm_.IsValid(); }
IsFloatZero()405   bool IsFloatZero() const {
406     VIXL_ASSERT(IsImmediate());
407     return imm_.IsFloatZero();
408   }
409 
GetNeonImmediate()410   const NeonImmediate& GetNeonImmediate() const { return imm_; }
411 
GetRegister()412   VRegister GetRegister() const {
413     VIXL_ASSERT(IsRegister());
414     return rm_;
415   }
416 
417  protected:
418   NeonImmediate imm_;
419   VRegister rm_;
420 };
421 
422 std::ostream& operator<<(std::ostream& os, const NeonOperand& operand);
423 
424 // SOperand represents either an immediate or a SRegister.
425 class SOperand : public NeonOperand {
426  public:
427   // #<immediate>
428   // where <immediate> is 32bit int
429   // This is allowed to be an implicit constructor because SOperand is
430   // a wrapper class that doesn't normally perform any type conversion.
SOperand(int32_t immediate)431   SOperand(int32_t immediate)  // NOLINT(runtime/explicit)
432       : NeonOperand(immediate) {}
SOperand(uint32_t immediate)433   SOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
434       : NeonOperand(immediate) {}
435   // #<immediate>
436   // where <immediate> is 32bit float
SOperand(float immediate)437   SOperand(float immediate)  // NOLINT(runtime/explicit)
438       : NeonOperand(immediate) {}
439   // where <immediate> is 64bit float
SOperand(double immediate)440   SOperand(double immediate)  // NOLINT(runtime/explicit)
441       : NeonOperand(immediate) {}
442 
SOperand(const NeonImmediate & imm)443   SOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
444       : NeonOperand(imm) {}
445 
446   // rm
447   // This is allowed to be an implicit constructor because SOperand is
448   // a wrapper class that doesn't normally perform any type conversion.
SOperand(SRegister rm)449   SOperand(SRegister rm)  // NOLINT(runtime/explicit)
450       : NeonOperand(rm) {}
GetRegister()451   SRegister GetRegister() const {
452     VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kSRegister));
453     return SRegister(rm_.GetCode());
454   }
455 };
456 
457 // DOperand represents either an immediate or a DRegister.
458 std::ostream& operator<<(std::ostream& os, const SOperand& operand);
459 
460 class DOperand : public NeonOperand {
461  public:
462   // #<immediate>
463   // where <immediate> is uint32_t.
464   // This is allowed to be an implicit constructor because DOperand is
465   // a wrapper class that doesn't normally perform any type conversion.
DOperand(int32_t immediate)466   DOperand(int32_t immediate)  // NOLINT(runtime/explicit)
467       : NeonOperand(immediate) {}
DOperand(uint32_t immediate)468   DOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
469       : NeonOperand(immediate) {}
DOperand(int64_t immediate)470   DOperand(int64_t immediate)  // NOLINT(runtime/explicit)
471       : NeonOperand(immediate) {}
DOperand(uint64_t immediate)472   DOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
473       : NeonOperand(immediate) {}
474 
475   // #<immediate>
476   // where <immediate> is a non zero floating point number which can be encoded
477   // as an 8 bit floating point (checked by the constructor).
478   // This is allowed to be an implicit constructor because DOperand is
479   // a wrapper class that doesn't normally perform any type conversion.
DOperand(float immediate)480   DOperand(float immediate)  // NOLINT(runtime/explicit)
481       : NeonOperand(immediate) {}
DOperand(double immediate)482   DOperand(double immediate)  // NOLINT(runtime/explicit)
483       : NeonOperand(immediate) {}
484 
DOperand(const NeonImmediate & imm)485   DOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
486       : NeonOperand(imm) {}
487   // rm
488   // This is allowed to be an implicit constructor because DOperand is
489   // a wrapper class that doesn't normally perform any type conversion.
DOperand(DRegister rm)490   DOperand(DRegister rm)  // NOLINT(runtime/explicit)
491       : NeonOperand(rm) {}
492 
GetRegister()493   DRegister GetRegister() const {
494     VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kDRegister));
495     return DRegister(rm_.GetCode());
496   }
497 };
498 
499 std::ostream& operator<<(std::ostream& os, const DOperand& operand);
500 
501 // QOperand represents either an immediate or a QRegister.
502 class QOperand : public NeonOperand {
503  public:
504   // #<immediate>
505   // where <immediate> is uint32_t.
506   // This is allowed to be an implicit constructor because QOperand is
507   // a wrapper class that doesn't normally perform any type conversion.
QOperand(int32_t immediate)508   QOperand(int32_t immediate)  // NOLINT(runtime/explicit)
509       : NeonOperand(immediate) {}
QOperand(uint32_t immediate)510   QOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
511       : NeonOperand(immediate) {}
QOperand(int64_t immediate)512   QOperand(int64_t immediate)  // NOLINT(runtime/explicit)
513       : NeonOperand(immediate) {}
QOperand(uint64_t immediate)514   QOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
515       : NeonOperand(immediate) {}
QOperand(float immediate)516   QOperand(float immediate)  // NOLINT(runtime/explicit)
517       : NeonOperand(immediate) {}
QOperand(double immediate)518   QOperand(double immediate)  // NOLINT(runtime/explicit)
519       : NeonOperand(immediate) {}
520 
QOperand(const NeonImmediate & imm)521   QOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
522       : NeonOperand(imm) {}
523 
524   // rm
525   // This is allowed to be an implicit constructor because QOperand is
526   // a wrapper class that doesn't normally perform any type conversion.
QOperand(QRegister rm)527   QOperand(QRegister rm)  // NOLINT(runtime/explicit)
528       : NeonOperand(rm) {
529     VIXL_ASSERT(rm_.IsValid());
530   }
531 
GetRegister()532   QRegister GetRegister() const {
533     VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kQRegister));
534     return QRegister(rm_.GetCode());
535   }
536 };
537 
538 std::ostream& operator<<(std::ostream& os, const QOperand& operand);
539 
540 class ImmediateVFP : public EncodingValue {
541   template <typename T>
542   struct FloatType {
543     typedef T base_type;
544   };
545 
546  public:
ImmediateVFP(const NeonImmediate & neon_imm)547   explicit ImmediateVFP(const NeonImmediate& neon_imm) {
548     if (neon_imm.IsFloat()) {
549       const float imm = neon_imm.GetImmediate<float>();
550       if (VFP::IsImmFP32(imm)) {
551         SetEncodingValue(VFP::FP32ToImm8(imm));
552       }
553     } else if (neon_imm.IsDouble()) {
554       const double imm = neon_imm.GetImmediate<double>();
555       if (VFP::IsImmFP64(imm)) {
556         SetEncodingValue(VFP::FP64ToImm8(imm));
557       }
558     }
559   }
560 
561   template <typename T>
Decode(uint32_t v)562   static T Decode(uint32_t v) {
563     return Decode(v, FloatType<T>());
564   }
565 
Decode(uint32_t imm8,const FloatType<float> &)566   static float Decode(uint32_t imm8, const FloatType<float>&) {
567     return VFP::Imm8ToFP32(imm8);
568   }
569 
Decode(uint32_t imm8,const FloatType<double> &)570   static double Decode(uint32_t imm8, const FloatType<double>&) {
571     return VFP::Imm8ToFP64(imm8);
572   }
573 };
574 
575 
576 class ImmediateVbic : public EncodingValueAndImmediate {
577  public:
578   ImmediateVbic(DataType dt, const NeonImmediate& neon_imm);
579   static DataType DecodeDt(uint32_t cmode);
580   static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate);
581 };
582 
583 class ImmediateVand : public ImmediateVbic {
584  public:
ImmediateVand(DataType dt,const NeonImmediate neon_imm)585   ImmediateVand(DataType dt, const NeonImmediate neon_imm)
586       : ImmediateVbic(dt, neon_imm) {
587     if (IsValid()) {
588       SetEncodedImmediate(~GetEncodedImmediate() & 0xff);
589     }
590   }
591 };
592 
593 class ImmediateVmov : public EncodingValueAndImmediate {
594  public:
595   ImmediateVmov(DataType dt, const NeonImmediate& neon_imm);
596   static DataType DecodeDt(uint32_t cmode);
597   static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate);
598 };
599 
600 class ImmediateVmvn : public EncodingValueAndImmediate {
601  public:
602   ImmediateVmvn(DataType dt, const NeonImmediate& neon_imm);
603   static DataType DecodeDt(uint32_t cmode);
604   static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate);
605 };
606 
607 class ImmediateVorr : public EncodingValueAndImmediate {
608  public:
609   ImmediateVorr(DataType dt, const NeonImmediate& neon_imm);
610   static DataType DecodeDt(uint32_t cmode);
611   static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate);
612 };
613 
614 class ImmediateVorn : public ImmediateVorr {
615  public:
ImmediateVorn(DataType dt,const NeonImmediate & neon_imm)616   ImmediateVorn(DataType dt, const NeonImmediate& neon_imm)
617       : ImmediateVorr(dt, neon_imm) {
618     if (IsValid()) {
619       SetEncodedImmediate(~GetEncodedImmediate() & 0xff);
620     }
621   }
622 };
623 
624 // MemOperand represents the addressing mode of a load or store instruction.
625 //
626 //   Usage: <instr> <Rt> , <MemOperand>
627 //
628 //   where <instr> is the instruction to use (e.g., Ldr(), Str(), etc.),
629 //         <Rt> is general purpose register to be transferred,
630 //         <MemOperand> is the rest of the arguments to the instruction
631 //
632 //   <MemOperand> can be in one of 3 addressing modes:
633 //
634 //   [ <Rn>, <offset> ]   ==  offset addressing
635 //   [ <Rn>, <offset> ]!  ==  pre-indexed addressing
636 //   [ <Rn> ], <offset>   ==  post-indexed addressing
637 //
638 //   where <offset> can be one of:
639 //     - an immediate constant, such as <imm8>, <imm12>
640 //     - an index register <Rm>
641 //     - a shifted index register <Rm>, <shift> #<amount>
642 //
643 //   The index register may have an associated {+/-} sign,
644 //   which if ommitted, defaults to + .
645 //
646 //   We have two constructors for the offset:
647 //
648 //   One with a signed value offset parameter. The value of sign_ is
649 //   "sign_of(constructor's offset parameter) and the value of offset_ is
650 //   "constructor's offset parameter".
651 //
652 //   The other with a sign and a positive value offset parameters. The value of
653 //   sign_ is "constructor's sign parameter" and the value of offset_ is
654 //   "constructor's sign parameter * constructor's offset parameter".
655 //
656 //   The value of offset_ reflects the effective offset. For an offset_ of 0,
657 //   sign_ can be positive or negative. Otherwise, sign_ always agrees with
658 //   the sign of offset_.
659 class MemOperand {
660  public:
661   // rn
662   // where rn is the general purpose base register only
663   explicit MemOperand(Register rn, AddrMode addrmode = Offset)
rn_(rn)664       : rn_(rn),
665         offset_(0),
666         sign_(plus),
667         rm_(NoReg),
668         shift_(LSL),
669         shift_amount_(0),
670         addrmode_(addrmode | kMemOperandRegisterOnly) {
671     VIXL_ASSERT(rn_.IsValid());
672   }
673 
674   // rn, #<imm>
675   // where rn is the general purpose base register,
676   //       <imm> is a 32-bit offset to add to rn
677   //
678   // Note: if rn is PC, then this form is equivalent to a "label"
679   // Note: the second constructor allow minus zero (-0).
680   MemOperand(Register rn, int32_t offset, AddrMode addrmode = Offset)
rn_(rn)681       : rn_(rn),
682         offset_(offset),
683         sign_((offset < 0) ? minus : plus),
684         rm_(NoReg),
685         shift_(LSL),
686         shift_amount_(0),
687         addrmode_(addrmode) {
688     VIXL_ASSERT(rn_.IsValid());
689   }
690   MemOperand(Register rn, Sign sign, int32_t offset, AddrMode addrmode = Offset)
rn_(rn)691       : rn_(rn),
692         offset_(sign.IsPlus() ? offset : -offset),
693         sign_(sign),
694         rm_(NoReg),
695         shift_(LSL),
696         shift_amount_(0),
697         addrmode_(addrmode) {
698     VIXL_ASSERT(rn_.IsValid());
699     // With this constructor, the sign must only be specified by "sign".
700     VIXL_ASSERT(offset >= 0);
701   }
702 
703   // rn, {+/-}rm
704   // where rn is the general purpose base register,
705   //       {+/-} is the sign of the index register,
706   //       rm is the general purpose index register,
707   MemOperand(Register rn, Sign sign, Register rm, AddrMode addrmode = Offset)
rn_(rn)708       : rn_(rn),
709         offset_(0),
710         sign_(sign),
711         rm_(rm),
712         shift_(LSL),
713         shift_amount_(0),
714         addrmode_(addrmode) {
715     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
716   }
717 
718   // rn, rm
719   // where rn is the general purpose base register,
720   //       rm is the general purpose index register,
721   MemOperand(Register rn, Register rm, AddrMode addrmode = Offset)
rn_(rn)722       : rn_(rn),
723         offset_(0),
724         sign_(plus),
725         rm_(rm),
726         shift_(LSL),
727         shift_amount_(0),
728         addrmode_(addrmode) {
729     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
730   }
731 
732   // rn, {+/-}rm, <shift>
733   // where rn is the general purpose base register,
734   //       {+/-} is the sign of the index register,
735   //       rm is the general purpose index register,
736   //       <shift> is RRX, applied to value from rm
737   MemOperand(Register rn,
738              Sign sign,
739              Register rm,
740              Shift shift,
741              AddrMode addrmode = Offset)
rn_(rn)742       : rn_(rn),
743         offset_(0),
744         sign_(sign),
745         rm_(rm),
746         shift_(shift),
747         shift_amount_(0),
748         addrmode_(addrmode) {
749     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
750     VIXL_ASSERT(shift_.IsRRX());
751   }
752 
753   // rn, rm, <shift>
754   // where rn is the general purpose base register,
755   //       rm is the general purpose index register,
756   //       <shift> is RRX, applied to value from rm
757   MemOperand(Register rn, Register rm, Shift shift, AddrMode addrmode = Offset)
rn_(rn)758       : rn_(rn),
759         offset_(0),
760         sign_(plus),
761         rm_(rm),
762         shift_(shift),
763         shift_amount_(0),
764         addrmode_(addrmode) {
765     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
766     VIXL_ASSERT(shift_.IsRRX());
767   }
768 
769   // rn, {+/-}rm, <shift> #<amount>
770   // where rn is the general purpose base register,
771   //       {+/-} is the sign of the index register,
772   //       rm is the general purpose index register,
773   //       <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm
774   //       <shift_amount> is optional size to apply to value from rm
775   MemOperand(Register rn,
776              Sign sign,
777              Register rm,
778              Shift shift,
779              uint32_t shift_amount,
780              AddrMode addrmode = Offset)
rn_(rn)781       : rn_(rn),
782         offset_(0),
783         sign_(sign),
784         rm_(rm),
785         shift_(shift),
786         shift_amount_(shift_amount),
787         addrmode_(addrmode) {
788     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
789     CheckShift();
790   }
791 
792   // rn, rm, <shift> #<amount>
793   // where rn is the general purpose base register,
794   //       rm is the general purpose index register,
795   //       <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm
796   //       <shift_amount> is optional size to apply to value from rm
797   MemOperand(Register rn,
798              Register rm,
799              Shift shift,
800              uint32_t shift_amount,
801              AddrMode addrmode = Offset)
rn_(rn)802       : rn_(rn),
803         offset_(0),
804         sign_(plus),
805         rm_(rm),
806         shift_(shift),
807         shift_amount_(shift_amount),
808         addrmode_(addrmode) {
809     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
810     CheckShift();
811   }
812 
GetBaseRegister()813   Register GetBaseRegister() const { return rn_; }
GetOffsetImmediate()814   int32_t GetOffsetImmediate() const { return offset_; }
815   bool IsOffsetImmediateWithinRange(int min,
816                                     int max,
817                                     int multiple_of = 1) const {
818     return (offset_ >= min) && (offset_ <= max) &&
819            ((offset_ % multiple_of) == 0);
820   }
GetSign()821   Sign GetSign() const { return sign_; }
GetOffsetRegister()822   Register GetOffsetRegister() const { return rm_; }
GetShift()823   Shift GetShift() const { return shift_; }
GetShiftAmount()824   unsigned GetShiftAmount() const { return shift_amount_; }
GetAddrMode()825   AddrMode GetAddrMode() const {
826     return static_cast<AddrMode>(addrmode_ & kMemOperandAddrModeMask);
827   }
IsRegisterOnly()828   bool IsRegisterOnly() const {
829     return (addrmode_ & kMemOperandRegisterOnly) != 0;
830   }
831 
IsImmediate()832   bool IsImmediate() const { return !rm_.IsValid(); }
IsImmediateZero()833   bool IsImmediateZero() const { return !rm_.IsValid() && (offset_ == 0); }
IsPlainRegister()834   bool IsPlainRegister() const {
835     return rm_.IsValid() && shift_.IsLSL() && (shift_amount_ == 0);
836   }
IsShiftedRegister()837   bool IsShiftedRegister() const { return rm_.IsValid(); }
IsImmediateOffset()838   bool IsImmediateOffset() const {
839     return (GetAddrMode() == Offset) && !rm_.IsValid();
840   }
IsImmediateZeroOffset()841   bool IsImmediateZeroOffset() const {
842     return (GetAddrMode() == Offset) && !rm_.IsValid() && (offset_ == 0);
843   }
IsRegisterOffset()844   bool IsRegisterOffset() const {
845     return (GetAddrMode() == Offset) && rm_.IsValid() && shift_.IsLSL() &&
846            (shift_amount_ == 0);
847   }
IsShiftedRegisterOffset()848   bool IsShiftedRegisterOffset() const {
849     return (GetAddrMode() == Offset) && rm_.IsValid();
850   }
GetTypeEncodingValue()851   uint32_t GetTypeEncodingValue() const {
852     return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue();
853   }
IsOffset()854   bool IsOffset() const { return GetAddrMode() == Offset; }
IsPreIndex()855   bool IsPreIndex() const { return GetAddrMode() == PreIndex; }
IsPostIndex()856   bool IsPostIndex() const { return GetAddrMode() == PostIndex; }
IsShiftValid()857   bool IsShiftValid() const { return shift_.IsValidAmount(shift_amount_); }
858 
859  private:
860   static const int kMemOperandRegisterOnly = 0x1000;
861   static const int kMemOperandAddrModeMask = 0xfff;
CheckShift()862   void CheckShift() {
863 #ifdef VIXL_DEBUG
864     // Disallow any zero shift other than RRX #0 and LSL #0 .
865     if ((shift_amount_ == 0) && shift_.IsRRX()) return;
866     if ((shift_amount_ == 0) && !shift_.IsLSL()) {
867       VIXL_ABORT_WITH_MSG(
868           "A shift by 0 is only accepted in "
869           "the case of lsl and will be treated as "
870           "no shift.\n");
871     }
872     switch (shift_.GetType()) {
873       case LSL:
874         VIXL_ASSERT(shift_amount_ <= 31);
875         break;
876       case ROR:
877         VIXL_ASSERT(shift_amount_ <= 31);
878         break;
879       case LSR:
880       case ASR:
881         VIXL_ASSERT(shift_amount_ <= 32);
882         break;
883       case RRX:
884       default:
885         VIXL_UNREACHABLE();
886         break;
887     }
888 #endif
889   }
890   Register rn_;
891   int32_t offset_;
892   Sign sign_;
893   Register rm_;
894   Shift shift_;
895   uint32_t shift_amount_;
896   uint32_t addrmode_;
897 };
898 
899 std::ostream& operator<<(std::ostream& os, const MemOperand& operand);
900 
901 class AlignedMemOperand : public MemOperand {
902  public:
903   AlignedMemOperand(Register rn, Alignment align, AddrMode addrmode = Offset)
MemOperand(rn,addrmode)904       : MemOperand(rn, addrmode), align_(align) {
905     VIXL_ASSERT(addrmode != PreIndex);
906   }
907 
AlignedMemOperand(Register rn,Alignment align,Register rm,AddrMode addrmode)908   AlignedMemOperand(Register rn,
909                     Alignment align,
910                     Register rm,
911                     AddrMode addrmode)
912       : MemOperand(rn, rm, addrmode), align_(align) {
913     VIXL_ASSERT(addrmode != PreIndex);
914   }
915 
GetAlignment()916   Alignment GetAlignment() const { return align_; }
917 
918  private:
919   Alignment align_;
920 };
921 
922 std::ostream& operator<<(std::ostream& os, const AlignedMemOperand& operand);
923 
924 }  // namespace aarch32
925 }  // namespace vixl
926 
927 #endif  // VIXL_AARCH32_OPERANDS_AARCH32_H_
928