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