Home | History | Annotate | Download | only in aarch32
      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.
     56   Operand(uint32_t immediate)  // NOLINT(runtime/explicit)
     57       : imm_(immediate),
     58         rm_(NoReg),
     59         shift_(LSL),
     60         amount_(0),
     61         rs_(NoReg) {}
     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.
     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
     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.
     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
    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>
    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>
    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 
    154   bool IsImmediate() const { return !rm_.IsValid(); }
    155 
    156   bool IsPlainRegister() const {
    157     return rm_.IsValid() && !shift_.IsRRX() && !rs_.IsValid() && (amount_ == 0);
    158   }
    159 
    160   bool IsImmediateShiftedRegister() const {
    161     return rm_.IsValid() && !rs_.IsValid();
    162   }
    163 
    164   bool IsRegisterShiftedRegister() const {
    165     return rm_.IsValid() && rs_.IsValid();
    166   }
    167 
    168   uint32_t GetImmediate() const {
    169     VIXL_ASSERT(IsImmediate());
    170     return imm_;
    171   }
    172 
    173   int32_t GetSignedImmediate() const {
    174     VIXL_ASSERT(IsImmediate());
    175     int32_t result;
    176     memcpy(&result, &imm_, sizeof(result));
    177     return result;
    178   }
    179 
    180   Register GetBaseRegister() const {
    181     VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister());
    182     return rm_;
    183   }
    184 
    185   Shift GetShift() const {
    186     VIXL_ASSERT(IsImmediateShiftedRegister() || IsRegisterShiftedRegister());
    187     return shift_;
    188   }
    189 
    190   uint32_t GetShiftAmount() const {
    191     VIXL_ASSERT(IsImmediateShiftedRegister());
    192     return amount_;
    193   }
    194 
    195   Register GetShiftRegister() const {
    196     VIXL_ASSERT(IsRegisterShiftedRegister());
    197     return rs_;
    198   }
    199 
    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.
    247   NeonImmediate(uint32_t immediate)  // NOLINT(runtime/explicit)
    248       : imm_(immediate),
    249         immediate_type_(I32) {}
    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.
    258   NeonImmediate(int64_t immediate)  // NOLINT(runtime/explicit)
    259       : imm_(immediate),
    260         immediate_type_(I64) {}
    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.
    270   NeonImmediate(float immediate)  // NOLINT(runtime/explicit)
    271       : imm_(immediate),
    272         immediate_type_(F32) {}
    273   NeonImmediate(double immediate)  // NOLINT(runtime/explicit)
    274       : imm_(immediate),
    275         immediate_type_(F64) {}
    276 
    277   NeonImmediate(const NeonImmediate& src)
    278       : imm_(src.imm_), immediate_type_(src.immediate_type_) {}
    279 
    280   template <typename T>
    281   T GetImmediate() const {
    282     return GetImmediate(DataTypeIdentity<T>());
    283   }
    284 
    285   template <typename 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 
    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   }
    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   }
    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 
    312   bool IsInteger32() const { return immediate_type_.Is(I32); }
    313   bool IsInteger64() const { return immediate_type_.Is(I64); }
    314   bool IsInteger() const { return IsInteger32() | IsInteger64(); }
    315   bool IsFloat() const { return immediate_type_.Is(F32); }
    316   bool IsDouble() const { return immediate_type_.Is(F64); }
    317 
    318   template <typename T>
    319   bool CanConvert() const {
    320     return CanConvert(DataTypeIdentity<T>());
    321   }
    322 
    323   template <typename 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   }
    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   }
    337   bool CanConvert(const DataTypeIdentity<uint64_t>&) const {
    338     return IsInteger() || CanConvert<uint32_t>();
    339   }
    340   bool CanConvert(const DataTypeIdentity<float>&) const {
    341     return IsFloat() || IsDouble();
    342   }
    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_;
    355     NeonImmediateType(uint64_t u) : u64_(u) {}
    356     NeonImmediateType(int64_t u) : u64_(u) {}
    357     NeonImmediateType(uint32_t u) : u32_(u) {}
    358     NeonImmediateType(int32_t u) : u32_(u) {}
    359     NeonImmediateType(double d) : d_(d) {}
    360     NeonImmediateType(float f) : f_(f) {}
    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:
    371   NeonOperand(int32_t immediate)  // NOLINT(runtime/explicit)
    372       : imm_(immediate),
    373         rm_(NoDReg) {}
    374   NeonOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
    375       : imm_(immediate),
    376         rm_(NoDReg) {}
    377   NeonOperand(int64_t immediate)  // NOLINT(runtime/explicit)
    378       : imm_(immediate),
    379         rm_(NoDReg) {}
    380   NeonOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
    381       : imm_(immediate),
    382         rm_(NoDReg) {}
    383   NeonOperand(float immediate)  // NOLINT(runtime/explicit)
    384       : imm_(immediate),
    385         rm_(NoDReg) {}
    386   NeonOperand(double immediate)  // NOLINT(runtime/explicit)
    387       : imm_(immediate),
    388         rm_(NoDReg) {}
    389   NeonOperand(const NeonImmediate& imm)  // NOLINT(runtime/explicit)
    390       : imm_(imm),
    391         rm_(NoDReg) {}
    392   NeonOperand(const VRegister& rm)  // NOLINT(runtime/explicit)
    393       : imm_(0),
    394         rm_(rm) {
    395     VIXL_ASSERT(rm_.IsValid());
    396   }
    397 
    398   bool IsImmediate() const { return !rm_.IsValid(); }
    399   bool IsRegister() const { return rm_.IsValid(); }
    400 
    401   const NeonImmediate& GetNeonImmediate() const { return imm_; }
    402 
    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.
    422   SOperand(int32_t immediate)  // NOLINT(runtime/explicit)
    423       : NeonOperand(immediate) {}
    424   SOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
    425       : NeonOperand(immediate) {}
    426   // #<immediate>
    427   // where <immediate> is 32bit float
    428   SOperand(float immediate)  // NOLINT(runtime/explicit)
    429       : NeonOperand(immediate) {}
    430 
    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.
    437   SOperand(SRegister rm)  // NOLINT(runtime/explicit)
    438       : NeonOperand(rm) {}
    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.
    454   DOperand(int32_t immediate)  // NOLINT(runtime/explicit)
    455       : NeonOperand(immediate) {}
    456   DOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
    457       : NeonOperand(immediate) {}
    458   DOperand(int64_t immediate)  // NOLINT(runtime/explicit)
    459       : NeonOperand(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.
    468   DOperand(float immediate)  // NOLINT(runtime/explicit)
    469       : NeonOperand(immediate) {}
    470   DOperand(double immediate)  // NOLINT(runtime/explicit)
    471       : NeonOperand(immediate) {}
    472 
    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.
    478   DOperand(DRegister rm)  // NOLINT(runtime/explicit)
    479       : NeonOperand(rm) {}
    480 
    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.
    496   QOperand(int32_t immediate)  // NOLINT(runtime/explicit)
    497       : NeonOperand(immediate) {}
    498   QOperand(uint32_t immediate)  // NOLINT(runtime/explicit)
    499       : NeonOperand(immediate) {}
    500   QOperand(int64_t immediate)  // NOLINT(runtime/explicit)
    501       : NeonOperand(immediate) {}
    502   QOperand(uint64_t immediate)  // NOLINT(runtime/explicit)
    503       : NeonOperand(immediate) {}
    504   QOperand(float immediate)  // NOLINT(runtime/explicit)
    505       : NeonOperand(immediate) {}
    506   QOperand(double immediate)  // NOLINT(runtime/explicit)
    507       : NeonOperand(immediate) {}
    508 
    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.
    515   QOperand(QRegister rm)  // NOLINT(runtime/explicit)
    516       : NeonOperand(rm) {
    517     VIXL_ASSERT(rm_.IsValid());
    518   }
    519 
    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:
    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>
    550   static T Decode(uint32_t v) {
    551     return Decode(v, FloatType<T>());
    552   }
    553 
    554   static float Decode(uint32_t imm8, const FloatType<float>&) {
    555     return VFP::Imm8ToFP32(imm8);
    556   }
    557 
    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:
    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:
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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 
    801   Register GetBaseRegister() const { return rn_; }
    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   }
    809   Sign GetSign() const { return sign_; }
    810   Register GetOffsetRegister() const { return rm_; }
    811   Shift GetShift() const { return shift_; }
    812   unsigned GetShiftAmount() const { return shift_amount_; }
    813   AddrMode GetAddrMode() const {
    814     return static_cast<AddrMode>(addrmode_ & kMemOperandAddrModeMask);
    815   }
    816   bool IsRegisterOnly() const {
    817     return (addrmode_ & kMemOperandRegisterOnly) != 0;
    818   }
    819 
    820   bool IsImmediate() const { return !rm_.IsValid(); }
    821   bool IsImmediateZero() const { return !rm_.IsValid() && (offset_ == 0); }
    822   bool IsPlainRegister() const {
    823     return rm_.IsValid() && shift_.IsLSL() && (shift_amount_ == 0);
    824   }
    825   bool IsShiftedRegister() const { return rm_.IsValid(); }
    826   bool IsImmediateOffset() const {
    827     return (GetAddrMode() == Offset) && !rm_.IsValid();
    828   }
    829   bool IsImmediateZeroOffset() const {
    830     return (GetAddrMode() == Offset) && !rm_.IsValid() && (offset_ == 0);
    831   }
    832   bool IsRegisterOffset() const {
    833     return (GetAddrMode() == Offset) && rm_.IsValid() && shift_.IsLSL() &&
    834            (shift_amount_ == 0);
    835   }
    836   bool IsShiftedRegisterOffset() const {
    837     return (GetAddrMode() == Offset) && rm_.IsValid();
    838   }
    839   uint32_t GetTypeEncodingValue() const {
    840     return shift_.IsRRX() ? kRRXEncodedValue : shift_.GetValue();
    841   }
    842   bool IsOffset() const { return GetAddrMode() == Offset; }
    843   bool IsPreIndex() const { return GetAddrMode() == PreIndex; }
    844   bool IsPostIndex() const { return GetAddrMode() == PostIndex; }
    845   bool IsShiftValid() const { return shift_.IsValidAmount(shift_amount_); }
    846 
    847  private:
    848   static const int kMemOperandRegisterOnly = 0x1000;
    849   static const int kMemOperandAddrModeMask = 0xfff;
    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)
    892       : MemOperand(rn, addrmode), align_(align) {
    893     VIXL_ASSERT(addrmode != PreIndex);
    894   }
    895 
    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 
    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