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