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