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.
RegStorage(RegStorageKind rs_kind,int reg)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   }
RegStorage(RegStorageKind rs_kind,int low_reg,int high_reg)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   }
RegStorage(uint16_t val)123   constexpr explicit RegStorage(uint16_t val) : reg_(val) {}
RegStorage()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 
ExactlyEquals(const RegStorage & rhs)133   bool ExactlyEquals(const RegStorage& rhs) const {
134     return (reg_ == rhs.GetRawBits());
135   }
136 
NotExactlyEquals(const RegStorage & rhs)137   bool NotExactlyEquals(const RegStorage& rhs) const {
138     return (reg_ != rhs.GetRawBits());
139   }
140 
Valid()141   constexpr bool Valid() const {
142     return ((reg_ & kValidMask) == kValid);
143   }
144 
Is32Bit()145   constexpr bool Is32Bit() const {
146     return ((reg_ & kShapeMask) == k32BitSolo);
147   }
148 
Is64Bit()149   constexpr bool Is64Bit() const {
150     return ((reg_ & k64BitMask) == k64Bits);
151   }
152 
GetWideKind()153   constexpr WideKind GetWideKind() const {
154     return Is64Bit() ? kWide : kNotWide;
155   }
156 
Is64BitSolo()157   constexpr bool Is64BitSolo() const {
158     return ((reg_ & kShapeMask) == k64BitSolo);
159   }
160 
IsPair()161   constexpr bool IsPair() const {
162     return ((reg_ & kShapeMask) == k64BitPair);
163   }
164 
IsFloat()165   constexpr bool IsFloat() const {
166     return
167         DCHECK_CONSTEXPR(Valid(), , false)
168         ((reg_ & kFloatingPoint) == kFloatingPoint);
169   }
170 
IsDouble()171   constexpr bool IsDouble() const {
172     return
173         DCHECK_CONSTEXPR(Valid(), , false)
174         (reg_ & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
175   }
176 
IsSingle()177   constexpr bool IsSingle() const {
178     return
179         DCHECK_CONSTEXPR(Valid(), , false)
180         (reg_ & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
181   }
182 
IsFloat(uint16_t reg)183   static constexpr bool IsFloat(uint16_t reg) {
184     return ((reg & kFloatingPoint) == kFloatingPoint);
185   }
186 
IsDouble(uint16_t reg)187   static constexpr bool IsDouble(uint16_t reg) {
188     return (reg & (kFloatingPoint | k64BitMask)) == (kFloatingPoint | k64Bits);
189   }
190 
IsSingle(uint16_t reg)191   static constexpr bool IsSingle(uint16_t reg) {
192     return (reg & (kFloatingPoint | k64BitMask)) == kFloatingPoint;
193   }
194 
Is32Bit(uint16_t reg)195   static constexpr bool Is32Bit(uint16_t reg) {
196     return ((reg & kShapeMask) == k32BitSolo);
197   }
198 
Is64Bit(uint16_t reg)199   static constexpr bool Is64Bit(uint16_t reg) {
200     return ((reg & k64BitMask) == k64Bits);
201   }
202 
Is64BitSolo(uint16_t reg)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.
GetReg()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.
SetReg(int reg)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.
SetLowReg(int reg)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.
GetLowReg()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.
GetLow()233   RegStorage GetLow() const {
234     DCHECK(IsPair());
235     return RegStorage(k32BitSolo, reg_ & kRegTypeMask);
236   }
237 
238   // Retrieve the most significant register of a pair.
GetHighReg()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.
GetHigh()245   RegStorage GetHigh() const {
246     DCHECK(IsPair());
247     return RegStorage(kValid | GetHighReg());
248   }
249 
SetHighReg(int reg)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.
GetRegNum()256   constexpr int GetRegNum() const {
257     return reg_ & kRegNumMask;
258   }
259 
260   // Is register number in 0..7?
Low8()261   constexpr bool Low8() const {
262     return GetRegNum() < 8;
263   }
264 
265   // Is register number in 0..3?
Low4()266   constexpr bool Low4() const {
267     return GetRegNum() < 4;
268   }
269 
270   // Combine 2 32-bit solo regs into a pair.
MakeRegPair(RegStorage low,RegStorage high)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 
SameRegType(RegStorage reg1,RegStorage reg2)279   static constexpr bool SameRegType(RegStorage reg1, RegStorage reg2) {
280     return ((reg1.reg_ & kShapeTypeMask) == (reg2.reg_ & kShapeTypeMask));
281   }
282 
SameRegType(int reg1,int reg2)283   static constexpr bool SameRegType(int reg1, int reg2) {
284     return ((reg1 & kShapeTypeMask) == (reg2 & kShapeTypeMask));
285   }
286 
287   // Create a 32-bit solo.
Solo32(int reg_num)288   static RegStorage Solo32(int reg_num) {
289     return RegStorage(k32BitSolo, reg_num & kRegTypeMask);
290   }
291 
292   // Create a floating point 32-bit solo.
FloatSolo32(int reg_num)293   static constexpr RegStorage FloatSolo32(int reg_num) {
294     return RegStorage(k32BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
295   }
296 
297   // Create a 128-bit solo.
Solo128(int reg_num)298   static constexpr RegStorage Solo128(int reg_num) {
299     return RegStorage(k128BitSolo, reg_num & kRegTypeMask);
300   }
301 
302   // Create a 64-bit solo.
Solo64(int reg_num)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.
FloatSolo64(int reg_num)308   static RegStorage FloatSolo64(int reg_num) {
309     return RegStorage(k64BitSolo, (reg_num & kRegNumMask) | kFloatingPoint);
310   }
311 
InvalidReg()312   static constexpr RegStorage InvalidReg() {
313     return RegStorage(kInvalid);
314   }
315 
RegNum(int raw_reg_bits)316   static constexpr uint16_t RegNum(int raw_reg_bits) {
317     return raw_reg_bits & kRegNumMask;
318   }
319 
GetRawBits()320   constexpr int GetRawBits() const {
321     return reg_;
322   }
323 
StorageSize()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