Home | History | Annotate | Download | only in dex
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_COMPILER_DEX_REG_STORAGE_H_
     18 #define ART_COMPILER_DEX_REG_STORAGE_H_
     19 
     20 #include "base/logging.h"
     21 #include "compiler_enums.h"  // For WideKind
     22 
     23 namespace art {
     24 
     25 /*
     26  * 16-bit representation of the physical register container holding a Dalvik value.
     27  * The encoding allows up to 64 physical elements per storage class, and supports eight
     28  * register container shapes.
     29  *
     30  * [V] [HHHHH] [SSS] [F] [LLLLLL]
     31  *
     32  * [LLLLLL]
     33  *  Physical register number for the low or solo register.
     34  *    0..63
     35  *
     36  * [F]
     37  *  Describes type of the [LLLLL] register.
     38  *    0: Core
     39  *    1: Floating point
     40  *
     41  * [SSS]
     42  *  Shape of the register container.
     43  *    000: Invalid
     44  *    001: 32-bit solo register
     45  *    010: 64-bit solo register
     46  *    011: 64-bit pair consisting of two 32-bit solo registers
     47  *    100: 128-bit solo register
     48  *    101: 256-bit solo register
     49  *    110: 512-bit solo register
     50  *    111: 1024-bit solo register
     51  *
     52  * [HHHHH]
     53  *  Physical register number of the high register (valid only for register pair).
     54  *    0..31
     55  *
     56  * [V]
     57  *    0 -> Invalid
     58  *    1 -> Valid
     59  *
     60  * Note that in all non-invalid cases, we can determine if the storage is floating point
     61  * by testing bit 7.  Note also that a register pair is effectively limited to a pair of
     62  * physical register numbers in the 0..31 range.
     63  *
     64  * On some target architectures, the same underlying physical register container can be given
     65  * different views.  For example, Arm's 32-bit single-precision floating point registers
     66  * s2 and s3 map to the low and high halves of double-precision d1.  Similarly, X86's xmm3
     67  * vector register can be viewed as 32-bit, 64-bit, 128-bit, etc.  In these cases the use of
     68  * one view will affect the other views.  The RegStorage class does not concern itself
     69  * with potential aliasing.  That will be done using the associated RegisterInfo struct.
     70  * Distinct RegStorage elements should be created for each view of a physical register
     71  * container.  The management of the aliased physical elements will be handled via RegisterInfo
     72  * records.
     73  */
     74 
     75 class RegStorage {
     76  public:
     77   enum RegStorageKind {
     78     kValidMask     = 0x8000,
     79     kValid         = 0x8000,
     80     kInvalid       = 0x0000,
     81     kShapeMask     = 0x0380,
     82     k32BitSolo     = 0x0080,
     83     k64BitSolo     = 0x0100,
     84     k64BitPair     = 0x0180,
     85     k128BitSolo    = 0x0200,
     86     k256BitSolo    = 0x0280,
     87     k512BitSolo    = 0x0300,
     88     k1024BitSolo   = 0x0380,
     89     k64BitMask     = 0x0300,
     90     k64Bits        = 0x0100,
     91     kShapeTypeMask = 0x03c0,
     92     kFloatingPoint = 0x0040,
     93     kCoreRegister  = 0x0000,
     94   };
     95 
     96   static const uint16_t kRegValMask  = 0x03ff;     // Num, type and shape.
     97   static const uint16_t kRegTypeMask = 0x007f;     // Num and type.
     98   static const uint16_t kRegNumMask  = 0x003f;     // Num only.
     99   static const uint16_t kHighRegNumMask = 0x001f;  // 0..31 for high reg
    100   static const uint16_t kMaxRegs     = kRegValMask + 1;
    101   // TODO: deprecate use of kInvalidRegVal and speed up GetReg().  Rely on valid bit instead.
    102   static const uint16_t kInvalidRegVal = 0x03ff;
    103   static const uint16_t kHighRegShift = 10;
    104   static const uint16_t kHighRegMask = (kHighRegNumMask << kHighRegShift);
    105 
    106   // Reg is [F][LLLLL], will override any existing shape and use rs_kind.
    107   constexpr RegStorage(RegStorageKind rs_kind, int reg)
    108       : reg_(
    109           DCHECK_CONSTEXPR(rs_kind != k64BitPair, , 0u)
    110           DCHECK_CONSTEXPR((rs_kind & ~kShapeMask) == 0, , 0u)
    111           kValid | rs_kind | (reg & kRegTypeMask)) {
    112   }
    113   constexpr RegStorage(RegStorageKind rs_kind, int low_reg, int high_reg)
    114       : reg_(
    115           DCHECK_CONSTEXPR(rs_kind == k64BitPair, << rs_kind, 0u)
    116           DCHECK_CONSTEXPR((low_reg & kFloatingPoint) == (high_reg & kFloatingPoint),
    117                            << low_reg << ", " << high_reg, 0u)
    118           DCHECK_CONSTEXPR((high_reg & kRegNumMask) <= kHighRegNumMask,
    119                            << "High reg must be in 0..31: " << high_reg, false)
    120           kValid | rs_kind | ((high_reg & kHighRegNumMask) << kHighRegShift) |
    121                   (low_reg & kRegTypeMask)) {
    122   }
    123   constexpr explicit RegStorage(uint16_t val) : reg_(val) {}
    124   RegStorage() : reg_(kInvalid) {}
    125 
    126   // We do not provide a general operator overload for equality of reg storage, as this is
    127   // dangerous in the case of architectures with multiple views, and the naming ExactEquals
    128   // expresses the exact match expressed here. It is more likely that a comparison between the views
    129   // is intended in most cases. Such code can be found in, for example, Mir2Lir::IsSameReg.
    130   //
    131   // If you know what you are doing, include reg_storage_eq.h, which defines == and != for brevity.
    132 
    133   bool ExactlyEquals(const RegStorage& rhs) const {
    134     return (reg_ == rhs.GetRawBits());
    135   }
    136 
    137   bool NotExactlyEquals(const RegStorage& rhs) const {
    138     return (reg_ != rhs.GetRawBits());
    139   }
    140 
    141   constexpr bool Valid() const {
    142     return ((reg_ & kValidMask) == kValid);
    143   }
    144 
    145   constexpr bool Is32Bit() const {
    146     return ((reg_ & kShapeMask) == k32BitSolo);
    147   }
    148 
    149   constexpr bool Is64Bit() const {
    150     return ((reg_ & k64BitMask) == k64Bits);
    151   }
    152 
    153   constexpr WideKind GetWideKind() const {
    154     return Is64Bit() ? kWide : kNotWide;
    155   }
    156 
    157   constexpr bool Is64BitSolo() const {
    158     return ((reg_ & kShapeMask) == k64BitSolo);
    159   }
    160 
    161   constexpr bool IsPair() const {
    162     return ((reg_ & kShapeMask) == k64BitPair);
    163   }
    164 
    165   constexpr bool IsFloat() const {
    166     return
    167         DCHECK_CONSTEXPR(Valid(), , false)
    168         ((reg_ & kFloatingPoint) == kFloatingPoint);
    169   }
    170 
    171   constexpr bool IsDouble() const {
    172     return
    173         DCHECK_CONSTEXPR(Valid(), , false)
    174         (reg_ & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
    175   }
    176 
    177   constexpr bool IsSingle() const {
    178     return
    179         DCHECK_CONSTEXPR(Valid(), , false)
    180         (reg_ & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
    181   }
    182 
    183   static constexpr bool IsFloat(uint16_t reg) {
    184     return ((reg & kFloatingPoint) == kFloatingPoint);
    185   }
    186 
    187   static constexpr bool IsDouble(uint16_t reg) {
    188     return (reg & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
    189   }
    190 
    191   static constexpr bool IsSingle(uint16_t reg) {
    192     return (reg & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
    193   }
    194 
    195   static constexpr bool Is32Bit(uint16_t reg) {
    196     return ((reg & kShapeMask) == k32BitSolo);
    197   }
    198 
    199   static constexpr bool Is64Bit(uint16_t reg) {
    200     return ((reg & k64BitMask) == k64Bits);
    201   }
    202 
    203   static constexpr bool Is64BitSolo(uint16_t reg) {
    204     return ((reg & kShapeMask) == k64BitSolo);
    205   }
    206 
    207   // Used to retrieve either the low register of a pair, or the only register.
    208   int GetReg() const {
    209     DCHECK(!IsPair()) << "reg_ = 0x" << std::hex << reg_;
    210     return Valid() ? (reg_ & kRegValMask) : kInvalidRegVal;
    211   }
    212 
    213   // Sets shape, type and num of solo.
    214   void SetReg(int reg) {
    215     DCHECK(Valid());
    216     DCHECK(!IsPair());
    217     reg_ = (reg_ & ~kRegValMask) | reg;
    218   }
    219 
    220   // Set the reg number and type only, target remain 64-bit pair.
    221   void SetLowReg(int reg) {
    222     DCHECK(IsPair());
    223     reg_ = (reg_ & ~kRegTypeMask) | (reg & kRegTypeMask);
    224   }
    225 
    226   // Retrieve the least significant register of a pair and return as 32-bit solo.
    227   int GetLowReg() const {
    228     DCHECK(IsPair());
    229     return ((reg_ & kRegTypeMask) | k32BitSolo);
    230   }
    231 
    232   // Create a stand-alone RegStorage from the low reg of a pair.
    233   RegStorage GetLow() const {
    234     DCHECK(IsPair());
    235     return RegStorage(k32BitSolo, reg_ & kRegTypeMask);
    236   }
    237 
    238   // Retrieve the most significant register of a pair.
    239   int GetHighReg() const {
    240     DCHECK(IsPair());
    241     return k32BitSolo | ((reg_ & kHighRegMask) >> kHighRegShift) | (reg_ & kFloatingPoint);
    242   }
    243 
    244   // Create a stand-alone RegStorage from the high reg of a pair.
    245   RegStorage GetHigh() const {
    246     DCHECK(IsPair());
    247     return RegStorage(kValid | GetHighReg());
    248   }
    249 
    250   void SetHighReg(int reg) {
    251     DCHECK(IsPair());
    252     reg_ = (reg_ & ~kHighRegMask) | ((reg & kHighRegNumMask) << kHighRegShift);
    253   }
    254 
    255   // Return the register number of low or solo.
    256   constexpr int GetRegNum() const {
    257     return reg_ & kRegNumMask;
    258   }
    259 
    260   // Is register number in 0..7?
    261   constexpr bool Low8() const {
    262     return GetRegNum() < 8;
    263   }
    264 
    265   // Is register number in 0..3?
    266   constexpr bool Low4() const {
    267     return GetRegNum() < 4;
    268   }
    269 
    270   // Combine 2 32-bit solo regs into a pair.
    271   static RegStorage MakeRegPair(RegStorage low, RegStorage high) {
    272     DCHECK(!low.IsPair());
    273     DCHECK(low.Is32Bit());
    274     DCHECK(!high.IsPair());
    275     DCHECK(high.Is32Bit());
    276     return RegStorage(k64BitPair, low.GetReg(), high.GetReg());
    277   }
    278 
    279   static constexpr bool SameRegType(RegStorage reg1, RegStorage reg2) {
    280     return ((reg1.reg_ & kShapeTypeMask) == (reg2.reg_ & kShapeTypeMask));
    281   }
    282 
    283   static constexpr bool SameRegType(int reg1, int reg2) {
    284     return ((reg1 & kShapeTypeMask) == (reg2 & kShapeTypeMask));
    285   }
    286 
    287   // Create a 32-bit solo.
    288   static RegStorage Solo32(int reg_num) {
    289     return RegStorage(k32BitSolo, reg_num & kRegTypeMask);
    290   }
    291 
    292   // Create a floating point 32-bit solo.
    293   static constexpr RegStorage FloatSolo32(int reg_num) {
    294     return RegStorage(k32BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
    295   }
    296 
    297   // Create a 128-bit solo.
    298   static constexpr RegStorage Solo128(int reg_num) {
    299     return RegStorage(k128BitSolo, reg_num & kRegTypeMask);
    300   }
    301 
    302   // Create a 64-bit solo.
    303   static constexpr RegStorage Solo64(int reg_num) {
    304     return RegStorage(k64BitSolo, reg_num & kRegTypeMask);
    305   }
    306 
    307   // Create a floating point 64-bit solo.
    308   static RegStorage FloatSolo64(int reg_num) {
    309     return RegStorage(k64BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
    310   }
    311 
    312   static constexpr RegStorage InvalidReg() {
    313     return RegStorage(kInvalid);
    314   }
    315 
    316   static constexpr uint16_t RegNum(int raw_reg_bits) {
    317     return raw_reg_bits & kRegNumMask;
    318   }
    319 
    320   constexpr int GetRawBits() const {
    321     return reg_;
    322   }
    323 
    324   size_t StorageSize() const {
    325     switch (reg_ & kShapeMask) {
    326       case kInvalid: return 0;
    327       case k32BitSolo: return 4;
    328       case k64BitSolo: return 8;
    329       case k64BitPair: return 8;  // Is this useful?  Might want to disallow taking size of pair.
    330       case k128BitSolo: return 16;
    331       case k256BitSolo: return 32;
    332       case k512BitSolo: return 64;
    333       case k1024BitSolo: return 128;
    334       default: LOG(FATAL) << "Unexpected shape";
    335     }
    336     return 0;
    337   }
    338 
    339  private:
    340   uint16_t reg_;
    341 };
    342 
    343 }  // namespace art
    344 
    345 #endif  // ART_COMPILER_DEX_REG_STORAGE_H_
    346