• 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); }
317 
318   template <typename T>
CanConvert()319   bool CanConvert() const {
320     return CanConvert(DataTypeIdentity<T>());
321   }
322 
323   template <typename T>
CanConvert(const DataTypeIdentity<T> &)324   bool CanConvert(const DataTypeIdentity<T>&) const {
325     VIXL_ASSERT(sizeof(T) < sizeof(uint32_t));
326     return (immediate_type_.Is(I32) && ((imm_.u32_ >> (8 * sizeof(T))) == 0)) ||
327            (immediate_type_.Is(I64) && ((imm_.u64_ >> (8 * sizeof(T))) == 0)) ||
328            (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) ||
329            (immediate_type_.Is(F64) && (imm_.d_ == 0.0));
330   }
CanConvert(const DataTypeIdentity<uint32_t> &)331   bool CanConvert(const DataTypeIdentity<uint32_t>&) const {
332     return immediate_type_.Is(I32) ||
333            (immediate_type_.Is(I64) && ((imm_.u64_ >> 32) == 0)) ||
334            (immediate_type_.Is(F32) && (imm_.f_ == 0.0f)) ||
335            (immediate_type_.Is(F64) && (imm_.d_ == 0.0));
336   }
CanConvert(const DataTypeIdentity<uint64_t> &)337   bool CanConvert(const DataTypeIdentity<uint64_t>&) const {
338     return IsInteger() || CanConvert<uint32_t>();
339   }
CanConvert(const DataTypeIdentity<float> &)340   bool CanConvert(const DataTypeIdentity<float>&) const {
341     return IsFloat() || IsDouble();
342   }
CanConvert(const DataTypeIdentity<double> &)343   bool CanConvert(const DataTypeIdentity<double>&) const {
344     return IsFloat() || IsDouble();
345   }
346   friend std::ostream& operator<<(std::ostream& os,
347                                   const NeonImmediate& operand);
348 
349  private:
350   union NeonImmediateType {
351     uint64_t u64_;
352     double d_;
353     uint32_t u32_;
354     float f_;
NeonImmediateType(uint64_t u)355     NeonImmediateType(uint64_t u) : u64_(u) {}
NeonImmediateType(int64_t u)356     NeonImmediateType(int64_t u) : u64_(u) {}
NeonImmediateType(uint32_t u)357     NeonImmediateType(uint32_t u) : u32_(u) {}
NeonImmediateType(int32_t u)358     NeonImmediateType(int32_t u) : u32_(u) {}
NeonImmediateType(double d)359     NeonImmediateType(double d) : d_(d) {}
NeonImmediateType(float f)360     NeonImmediateType(float f) : f_(f) {}
NeonImmediateType(const NeonImmediateType & ref)361     NeonImmediateType(const NeonImmediateType& ref) : u64_(ref.u64_) {}
362   } imm_;
363 
364   DataType immediate_type_;
365 };
366 
367 std::ostream& operator<<(std::ostream& os, const NeonImmediate& operand);
368 
369 class NeonOperand {
370  public:
NeonOperand(int32_t immediate)371   NeonOperand(int32_t immediate)  // NOLINT(runtime/explicit)
372       : imm_(immediate),
373         rm_(NoDReg) {}
NeonOperand(uint32_t immediate)374   NeonOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
375       : imm_(immediate),
376         rm_(NoDReg) {}
NeonOperand(int64_t immediate)377   NeonOperand(int64_t immediate)  // NOLINT(runtime/explicit)
378       : imm_(immediate),
379         rm_(NoDReg) {}
NeonOperand(uint64_t immediate)380   NeonOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
381       : imm_(immediate),
382         rm_(NoDReg) {}
NeonOperand(float immediate)383   NeonOperand(float immediate)  // NOLINT(runtime/explicit)
384       : imm_(immediate),
385         rm_(NoDReg) {}
NeonOperand(double immediate)386   NeonOperand(double immediate)  // NOLINT(runtime/explicit)
387       : imm_(immediate),
388         rm_(NoDReg) {}
NeonOperand(const NeonImmediate & imm)389   NeonOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
390       : imm_(imm),
391         rm_(NoDReg) {}
NeonOperand(const VRegister & rm)392   NeonOperand(const VRegister& rm)  // NOLINT(runtime/explicit)
393       : imm_(0),
394         rm_(rm) {
395     VIXL_ASSERT(rm_.IsValid());
396   }
397 
IsImmediate()398   bool IsImmediate() const { return !rm_.IsValid(); }
IsRegister()399   bool IsRegister() const { return rm_.IsValid(); }
400 
GetNeonImmediate()401   const NeonImmediate& GetNeonImmediate() const { return imm_; }
402 
GetRegister()403   VRegister GetRegister() const {
404     VIXL_ASSERT(IsRegister());
405     return rm_;
406   }
407 
408  protected:
409   NeonImmediate imm_;
410   VRegister rm_;
411 };
412 
413 std::ostream& operator<<(std::ostream& os, const NeonOperand& operand);
414 
415 // SOperand represents either an immediate or a SRegister.
416 class SOperand : public NeonOperand {
417  public:
418   // #<immediate>
419   // where <immediate> is 32bit int
420   // This is allowed to be an implicit constructor because SOperand is
421   // a wrapper class that doesn't normally perform any type conversion.
SOperand(int32_t immediate)422   SOperand(int32_t immediate)  // NOLINT(runtime/explicit)
423       : NeonOperand(immediate) {}
SOperand(uint32_t immediate)424   SOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
425       : NeonOperand(immediate) {}
426   // #<immediate>
427   // where <immediate> is 32bit float
SOperand(float immediate)428   SOperand(float immediate)  // NOLINT(runtime/explicit)
429       : NeonOperand(immediate) {}
430 
SOperand(const NeonImmediate & imm)431   SOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
432       : NeonOperand(imm) {}
433 
434   // rm
435   // This is allowed to be an implicit constructor because SOperand is
436   // a wrapper class that doesn't normally perform any type conversion.
SOperand(SRegister rm)437   SOperand(SRegister rm)  // NOLINT(runtime/explicit)
438       : NeonOperand(rm) {}
GetRegister()439   SRegister GetRegister() const {
440     VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kSRegister));
441     return SRegister(rm_.GetCode());
442   }
443 };
444 
445 // DOperand represents either an immediate or a DRegister.
446 std::ostream& operator<<(std::ostream& os, const SOperand& operand);
447 
448 class DOperand : public NeonOperand {
449  public:
450   // #<immediate>
451   // where <immediate> is uint32_t.
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(int32_t immediate)454   DOperand(int32_t immediate)  // NOLINT(runtime/explicit)
455       : NeonOperand(immediate) {}
DOperand(uint32_t immediate)456   DOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
457       : NeonOperand(immediate) {}
DOperand(int64_t immediate)458   DOperand(int64_t immediate)  // NOLINT(runtime/explicit)
459       : NeonOperand(immediate) {}
DOperand(uint64_t immediate)460   DOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
461       : NeonOperand(immediate) {}
462 
463   // #<immediate>
464   // where <immediate> is a non zero floating point number which can be encoded
465   // as an 8 bit floating point (checked by the constructor).
466   // This is allowed to be an implicit constructor because DOperand is
467   // a wrapper class that doesn't normally perform any type conversion.
DOperand(float immediate)468   DOperand(float immediate)  // NOLINT(runtime/explicit)
469       : NeonOperand(immediate) {}
DOperand(double immediate)470   DOperand(double immediate)  // NOLINT(runtime/explicit)
471       : NeonOperand(immediate) {}
472 
DOperand(const NeonImmediate & imm)473   DOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
474       : NeonOperand(imm) {}
475   // rm
476   // This is allowed to be an implicit constructor because DOperand is
477   // a wrapper class that doesn't normally perform any type conversion.
DOperand(DRegister rm)478   DOperand(DRegister rm)  // NOLINT(runtime/explicit)
479       : NeonOperand(rm) {}
480 
GetRegister()481   DRegister GetRegister() const {
482     VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kDRegister));
483     return DRegister(rm_.GetCode());
484   }
485 };
486 
487 std::ostream& operator<<(std::ostream& os, const DOperand& operand);
488 
489 // QOperand represents either an immediate or a QRegister.
490 class QOperand : public NeonOperand {
491  public:
492   // #<immediate>
493   // where <immediate> is uint32_t.
494   // This is allowed to be an implicit constructor because QOperand is
495   // a wrapper class that doesn't normally perform any type conversion.
QOperand(int32_t immediate)496   QOperand(int32_t immediate)  // NOLINT(runtime/explicit)
497       : NeonOperand(immediate) {}
QOperand(uint32_t immediate)498   QOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
499       : NeonOperand(immediate) {}
QOperand(int64_t immediate)500   QOperand(int64_t immediate)  // NOLINT(runtime/explicit)
501       : NeonOperand(immediate) {}
QOperand(uint64_t immediate)502   QOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
503       : NeonOperand(immediate) {}
QOperand(float immediate)504   QOperand(float immediate)  // NOLINT(runtime/explicit)
505       : NeonOperand(immediate) {}
QOperand(double immediate)506   QOperand(double immediate)  // NOLINT(runtime/explicit)
507       : NeonOperand(immediate) {}
508 
QOperand(const NeonImmediate & imm)509   QOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
510       : NeonOperand(imm) {}
511 
512   // rm
513   // This is allowed to be an implicit constructor because QOperand is
514   // a wrapper class that doesn't normally perform any type conversion.
QOperand(QRegister rm)515   QOperand(QRegister rm)  // NOLINT(runtime/explicit)
516       : NeonOperand(rm) {
517     VIXL_ASSERT(rm_.IsValid());
518   }
519 
GetRegister()520   QRegister GetRegister() const {
521     VIXL_ASSERT(IsRegister() && (rm_.GetType() == CPURegister::kQRegister));
522     return QRegister(rm_.GetCode());
523   }
524 };
525 
526 std::ostream& operator<<(std::ostream& os, const QOperand& operand);
527 
528 class ImmediateVFP : public EncodingValue {
529   template <typename T>
530   struct FloatType {
531     typedef T base_type;
532   };
533 
534  public:
ImmediateVFP(const NeonImmediate & neon_imm)535   explicit ImmediateVFP(const NeonImmediate& neon_imm) {
536     if (neon_imm.IsFloat()) {
537       const float imm = neon_imm.GetImmediate<float>();
538       if (VFP::IsImmFP32(imm)) {
539         SetEncodingValue(VFP::FP32ToImm8(imm));
540       }
541     } else if (neon_imm.IsDouble()) {
542       const double imm = neon_imm.GetImmediate<double>();
543       if (VFP::IsImmFP64(imm)) {
544         SetEncodingValue(VFP::FP32ToImm8(imm));
545       }
546     }
547   }
548 
549   template <typename T>
Decode(uint32_t v)550   static T Decode(uint32_t v) {
551     return Decode(v, FloatType<T>());
552   }
553 
Decode(uint32_t imm8,const FloatType<float> &)554   static float Decode(uint32_t imm8, const FloatType<float>&) {
555     return VFP::Imm8ToFP32(imm8);
556   }
557 
Decode(uint32_t imm8,const FloatType<double> &)558   static double Decode(uint32_t imm8, const FloatType<double>&) {
559     return VFP::Imm8ToFP64(imm8);
560   }
561 };
562 
563 
564 class ImmediateVbic : public EncodingValueAndImmediate {
565  public:
566   ImmediateVbic(DataType dt, const NeonImmediate& neon_imm);
567   static DataType DecodeDt(uint32_t cmode);
568   static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate);
569 };
570 
571 class ImmediateVand : public ImmediateVbic {
572  public:
ImmediateVand(DataType dt,const NeonImmediate neon_imm)573   ImmediateVand(DataType dt, const NeonImmediate neon_imm)
574       : ImmediateVbic(dt, neon_imm) {
575     if (IsValid()) {
576       SetEncodedImmediate(~GetEncodedImmediate() & 0xff);
577     }
578   }
579 };
580 
581 class ImmediateVmov : public EncodingValueAndImmediate {
582  public:
583   ImmediateVmov(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 ImmediateVmvn : public EncodingValueAndImmediate {
589  public:
590   ImmediateVmvn(DataType dt, const NeonImmediate& neon_imm);
591   static DataType DecodeDt(uint32_t cmode);
592   static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate);
593 };
594 
595 class ImmediateVorr : public EncodingValueAndImmediate {
596  public:
597   ImmediateVorr(DataType dt, const NeonImmediate& neon_imm);
598   static DataType DecodeDt(uint32_t cmode);
599   static NeonImmediate DecodeImmediate(uint32_t cmode, uint32_t immediate);
600 };
601 
602 class ImmediateVorn : public ImmediateVorr {
603  public:
ImmediateVorn(DataType dt,const NeonImmediate & neon_imm)604   ImmediateVorn(DataType dt, const NeonImmediate& neon_imm)
605       : ImmediateVorr(dt, neon_imm) {
606     if (IsValid()) {
607       SetEncodedImmediate(~GetEncodedImmediate() & 0xff);
608     }
609   }
610 };
611 
612 // MemOperand represents the addressing mode of a load or store instruction.
613 //
614 //   Usage: <instr> <Rt> , <MemOperand>
615 //
616 //   where <instr> is the instruction to use (e.g., Ldr(), Str(), etc.),
617 //         <Rt> is general purpose register to be transferred,
618 //         <MemOperand> is the rest of the arguments to the instruction
619 //
620 //   <MemOperand> can be in one of 3 addressing modes:
621 //
622 //   [ <Rn>, <offset> ]   ==  offset addressing
623 //   [ <Rn>, <offset> ]!  ==  pre-indexed addressing
624 //   [ <Rn> ], <offset>   ==  post-indexed addressing
625 //
626 //   where <offset> can be one of:
627 //     - an immediate constant, such as <imm8>, <imm12>
628 //     - an index register <Rm>
629 //     - a shifted index register <Rm>, <shift> #<amount>
630 //
631 //   The index register may have an associated {+/-} sign,
632 //   which if ommitted, defaults to + .
633 //
634 //   We have two constructors for the offset:
635 //
636 //   One with a signed value offset parameter. The value of sign_ is
637 //   "sign_of(constructor's offset parameter) and the value of offset_ is
638 //   "constructor's offset parameter".
639 //
640 //   The other with a sign and a positive value offset parameters. The value of
641 //   sign_ is "constructor's sign parameter" and the value of offset_ is
642 //   "constructor's sign parameter * constructor's offset parameter".
643 //
644 //   The value of offset_ reflects the effective offset. For an offset_ of 0,
645 //   sign_ can be positive or negative. Otherwise, sign_ always agrees with
646 //   the sign of offset_.
647 class MemOperand {
648  public:
649   // rn
650   // where rn is the general purpose base register only
651   explicit MemOperand(Register rn, AddrMode addrmode = Offset)
rn_(rn)652       : rn_(rn),
653         offset_(0),
654         sign_(plus),
655         rm_(NoReg),
656         shift_(LSL),
657         shift_amount_(0),
658         addrmode_(addrmode | kMemOperandRegisterOnly) {
659     VIXL_ASSERT(rn_.IsValid());
660   }
661 
662   // rn, #<imm>
663   // where rn is the general purpose base register,
664   //       <imm> is a 32-bit offset to add to rn
665   //
666   // Note: if rn is PC, then this form is equivalent to a "label"
667   // Note: the second constructor allow minus zero (-0).
668   MemOperand(Register rn, int32_t offset, AddrMode addrmode = Offset)
rn_(rn)669       : rn_(rn),
670         offset_(offset),
671         sign_((offset < 0) ? minus : plus),
672         rm_(NoReg),
673         shift_(LSL),
674         shift_amount_(0),
675         addrmode_(addrmode) {
676     VIXL_ASSERT(rn_.IsValid());
677   }
678   MemOperand(Register rn, Sign sign, int32_t offset, AddrMode addrmode = Offset)
rn_(rn)679       : rn_(rn),
680         offset_(sign.IsPlus() ? offset : -offset),
681         sign_(sign),
682         rm_(NoReg),
683         shift_(LSL),
684         shift_amount_(0),
685         addrmode_(addrmode) {
686     VIXL_ASSERT(rn_.IsValid());
687     // With this constructor, the sign must only be specified by "sign".
688     VIXL_ASSERT(offset >= 0);
689   }
690 
691   // rn, {+/-}rm
692   // where rn is the general purpose base register,
693   //       {+/-} is the sign of the index register,
694   //       rm is the general purpose index register,
695   MemOperand(Register rn, Sign sign, Register rm, AddrMode addrmode = Offset)
rn_(rn)696       : rn_(rn),
697         offset_(0),
698         sign_(sign),
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
707   // where rn is the general purpose base register,
708   //       rm is the general purpose index register,
709   MemOperand(Register rn, Register rm, AddrMode addrmode = Offset)
rn_(rn)710       : rn_(rn),
711         offset_(0),
712         sign_(plus),
713         rm_(rm),
714         shift_(LSL),
715         shift_amount_(0),
716         addrmode_(addrmode) {
717     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
718   }
719 
720   // rn, {+/-}rm, <shift>
721   // where rn is the general purpose base register,
722   //       {+/-} is the sign of the index register,
723   //       rm is the general purpose index register,
724   //       <shift> is RRX, applied to value from rm
725   MemOperand(Register rn,
726              Sign sign,
727              Register rm,
728              Shift shift,
729              AddrMode addrmode = Offset)
rn_(rn)730       : rn_(rn),
731         offset_(0),
732         sign_(sign),
733         rm_(rm),
734         shift_(shift),
735         shift_amount_(0),
736         addrmode_(addrmode) {
737     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
738     VIXL_ASSERT(shift_.IsRRX());
739   }
740 
741   // rn, rm, <shift>
742   // where rn is the general purpose base register,
743   //       rm is the general purpose index register,
744   //       <shift> is RRX, applied to value from rm
745   MemOperand(Register rn, Register rm, Shift shift, AddrMode addrmode = Offset)
rn_(rn)746       : rn_(rn),
747         offset_(0),
748         sign_(plus),
749         rm_(rm),
750         shift_(shift),
751         shift_amount_(0),
752         addrmode_(addrmode) {
753     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
754     VIXL_ASSERT(shift_.IsRRX());
755   }
756 
757   // rn, {+/-}rm, <shift> #<amount>
758   // where rn is the general purpose base register,
759   //       {+/-} is the sign of the index register,
760   //       rm is the general purpose index register,
761   //       <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm
762   //       <shift_amount> is optional size to apply to value from rm
763   MemOperand(Register rn,
764              Sign sign,
765              Register rm,
766              Shift shift,
767              uint32_t shift_amount,
768              AddrMode addrmode = Offset)
rn_(rn)769       : rn_(rn),
770         offset_(0),
771         sign_(sign),
772         rm_(rm),
773         shift_(shift),
774         shift_amount_(shift_amount),
775         addrmode_(addrmode) {
776     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
777     CheckShift();
778   }
779 
780   // rn, rm, <shift> #<amount>
781   // where rn is the general purpose base register,
782   //       rm is the general purpose index register,
783   //       <shift> is one of {LSL, LSR, ASR, ROR}, applied to value from rm
784   //       <shift_amount> is optional size to apply to value from rm
785   MemOperand(Register rn,
786              Register rm,
787              Shift shift,
788              uint32_t shift_amount,
789              AddrMode addrmode = Offset)
rn_(rn)790       : rn_(rn),
791         offset_(0),
792         sign_(plus),
793         rm_(rm),
794         shift_(shift),
795         shift_amount_(shift_amount),
796         addrmode_(addrmode) {
797     VIXL_ASSERT(rn_.IsValid() && rm_.IsValid());
798     CheckShift();
799   }
800 
GetBaseRegister()801   Register GetBaseRegister() const { return rn_; }
GetOffsetImmediate()802   int32_t GetOffsetImmediate() const { return offset_; }
803   bool IsOffsetImmediateWithinRange(int min,
804                                     int max,
805                                     int multiple_of = 1) const {
806     return (offset_ >= min) && (offset_ <= max) &&
807            ((offset_ % multiple_of) == 0);
808   }
GetSign()809   Sign GetSign() const { return sign_; }
GetOffsetRegister()810   Register GetOffsetRegister() const { return rm_; }
GetShift()811   Shift GetShift() const { return shift_; }
GetShiftAmount()812   unsigned GetShiftAmount() const { return shift_amount_; }
GetAddrMode()813   AddrMode GetAddrMode() const {
814     return static_cast<AddrMode>(addrmode_ & kMemOperandAddrModeMask);
815   }
IsRegisterOnly()816   bool IsRegisterOnly() const {
817     return (addrmode_ & kMemOperandRegisterOnly) != 0;
818   }
819 
IsImmediate()820   bool IsImmediate() const { return !rm_.IsValid(); }
IsImmediateZero()821   bool IsImmediateZero() const { return !rm_.IsValid() && (offset_ == 0); }
IsPlainRegister()822   bool IsPlainRegister() const {
823     return rm_.IsValid() && shift_.IsLSL() && (shift_amount_ == 0);
824   }
IsShiftedRegister()825   bool IsShiftedRegister() const { return rm_.IsValid(); }
IsImmediateOffset()826   bool IsImmediateOffset() const {
827     return (GetAddrMode() == Offset) && !rm_.IsValid();
828   }
IsImmediateZeroOffset()829   bool IsImmediateZeroOffset() const {
830     return (GetAddrMode() == Offset) && !rm_.IsValid() && (offset_ == 0);
831   }
IsRegisterOffset()832   bool IsRegisterOffset() const {
833     return (GetAddrMode() == Offset) && rm_.IsValid() && shift_.IsLSL() &&
834            (shift_amount_ == 0);
835   }
IsShiftedRegisterOffset()836   bool IsShiftedRegisterOffset() const {
837     return (GetAddrMode() == Offset) && rm_.IsValid();
838   }
GetTypeEncodingValue()839   uint32_t GetTypeEncodingValue() const {
840     return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue();
841   }
IsOffset()842   bool IsOffset() const { return GetAddrMode() == Offset; }
IsPreIndex()843   bool IsPreIndex() const { return GetAddrMode() == PreIndex; }
IsPostIndex()844   bool IsPostIndex() const { return GetAddrMode() == PostIndex; }
IsShiftValid()845   bool IsShiftValid() const { return shift_.IsValidAmount(shift_amount_); }
846 
847  private:
848   static const int kMemOperandRegisterOnly = 0x1000;
849   static const int kMemOperandAddrModeMask = 0xfff;
CheckShift()850   void CheckShift() {
851 #ifdef VIXL_DEBUG
852     // Disallow any zero shift other than RRX #0 and LSL #0 .
853     if ((shift_amount_ == 0) && shift_.IsRRX()) return;
854     if ((shift_amount_ == 0) && !shift_.IsLSL()) {
855       VIXL_ABORT_WITH_MSG(
856           "A shift by 0 is only accepted in "
857           "the case of lsl and will be treated as "
858           "no shift.\n");
859     }
860     switch (shift_.GetType()) {
861       case LSL:
862         VIXL_ASSERT(shift_amount_ <= 31);
863         break;
864       case ROR:
865         VIXL_ASSERT(shift_amount_ <= 31);
866         break;
867       case LSR:
868       case ASR:
869         VIXL_ASSERT(shift_amount_ <= 32);
870         break;
871       case RRX:
872       default:
873         VIXL_UNREACHABLE();
874         break;
875     }
876 #endif
877   }
878   Register rn_;
879   int32_t offset_;
880   Sign sign_;
881   Register rm_;
882   Shift shift_;
883   uint32_t shift_amount_;
884   uint32_t addrmode_;
885 };
886 
887 std::ostream& operator<<(std::ostream& os, const MemOperand& operand);
888 
889 class AlignedMemOperand : public MemOperand {
890  public:
891   AlignedMemOperand(Register rn, Alignment align, AddrMode addrmode = Offset)
MemOperand(rn,addrmode)892       : MemOperand(rn, addrmode), align_(align) {
893     VIXL_ASSERT(addrmode != PreIndex);
894   }
895 
AlignedMemOperand(Register rn,Alignment align,Register rm,AddrMode addrmode)896   AlignedMemOperand(Register rn,
897                     Alignment align,
898                     Register rm,
899                     AddrMode addrmode)
900       : MemOperand(rn, rm, addrmode), align_(align) {
901     VIXL_ASSERT(addrmode != PreIndex);
902   }
903 
GetAlignment()904   Alignment GetAlignment() const { return align_; }
905 
906  private:
907   Alignment align_;
908 };
909 
910 std::ostream& operator<<(std::ostream& os, const AlignedMemOperand& operand);
911 
912 }  // namespace aarch32
913 }  // namespace vixl
914 
915 #endif  // VIXL_AARCH32_OPERANDS_AARCH32_H_
916