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