1 /*
2  * Copyright (C) 2017 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_OPTIMIZING_DATA_TYPE_H_
18 #define ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
19 
20 #include <iosfwd>
21 
22 #include <android-base/logging.h>
23 
24 #include "base/bit_utils.h"
25 
26 namespace art {
27 
28 class DataType {
29  public:
30   enum class Type : uint8_t {
31     kReference = 0,
32     kBool,
33     kUint8,
34     kInt8,
35     kUint16,
36     kInt16,
37     kUint32,
38     kInt32,
39     kUint64,
40     kInt64,
41     kFloat32,
42     kFloat64,
43     kVoid,
44     kLast = kVoid
45   };
46 
47   static constexpr Type FromShorty(char type);
48   static constexpr char TypeId(DataType::Type type);
49 
SizeShift(Type type)50   static constexpr size_t SizeShift(Type type) {
51     switch (type) {
52       case Type::kVoid:
53       case Type::kBool:
54       case Type::kUint8:
55       case Type::kInt8:
56         return 0;
57       case Type::kUint16:
58       case Type::kInt16:
59         return 1;
60       case Type::kUint32:
61       case Type::kInt32:
62       case Type::kFloat32:
63         return 2;
64       case Type::kUint64:
65       case Type::kInt64:
66       case Type::kFloat64:
67         return 3;
68       case Type::kReference:
69         return WhichPowerOf2(kObjectReferenceSize);
70       default:
71         LOG(FATAL) << "Invalid type " << static_cast<int>(type);
72         return 0;
73     }
74   }
75 
Size(Type type)76   static constexpr size_t Size(Type type) {
77     switch (type) {
78       case Type::kVoid:
79         return 0;
80       case Type::kBool:
81       case Type::kUint8:
82       case Type::kInt8:
83         return 1;
84       case Type::kUint16:
85       case Type::kInt16:
86         return 2;
87       case Type::kUint32:
88       case Type::kInt32:
89       case Type::kFloat32:
90         return 4;
91       case Type::kUint64:
92       case Type::kInt64:
93       case Type::kFloat64:
94         return 8;
95       case Type::kReference:
96         return kObjectReferenceSize;
97       default:
98         LOG(FATAL) << "Invalid type " << static_cast<int>(type);
99         return 0;
100     }
101   }
102 
IsFloatingPointType(Type type)103   static bool IsFloatingPointType(Type type) {
104     return type == Type::kFloat32 || type == Type::kFloat64;
105   }
106 
IsIntegralType(Type type)107   static bool IsIntegralType(Type type) {
108     // The Java language does not allow treating boolean as an integral type but
109     // our bit representation makes it safe.
110     switch (type) {
111       case Type::kBool:
112       case Type::kUint8:
113       case Type::kInt8:
114       case Type::kUint16:
115       case Type::kInt16:
116       case Type::kUint32:
117       case Type::kInt32:
118       case Type::kUint64:
119       case Type::kInt64:
120         return true;
121       default:
122         return false;
123     }
124   }
125 
IsIntOrLongType(Type type)126   static bool IsIntOrLongType(Type type) {
127     return type == Type::kInt32 || type == Type::kInt64;
128   }
129 
Is64BitType(Type type)130   static bool Is64BitType(Type type) {
131     return type == Type::kUint64 || type == Type::kInt64 || type == Type::kFloat64;
132   }
133 
Is8BitType(Type type)134   static bool Is8BitType(Type type) {
135     return type == Type::kInt8 || type == Type::kUint8 || type == Type::kBool;
136   }
137 
IsUnsignedType(Type type)138   static bool IsUnsignedType(Type type) {
139     return type == Type::kBool || type == Type::kUint8 || type == Type::kUint16 ||
140         type == Type::kUint32 || type == Type::kUint64;
141   }
142 
143   // Return the general kind of `type`, fusing integer-like types as Type::kInt.
Kind(Type type)144   static Type Kind(Type type) {
145     switch (type) {
146       case Type::kBool:
147       case Type::kUint8:
148       case Type::kInt8:
149       case Type::kUint16:
150       case Type::kInt16:
151       case Type::kUint32:
152       case Type::kInt32:
153         return Type::kInt32;
154       case Type::kUint64:
155       case Type::kInt64:
156         return Type::kInt64;
157       default:
158         return type;
159     }
160   }
161 
MinValueOfIntegralType(Type type)162   static int64_t MinValueOfIntegralType(Type type) {
163     switch (type) {
164       case Type::kBool:
165         return std::numeric_limits<bool>::min();
166       case Type::kUint8:
167         return std::numeric_limits<uint8_t>::min();
168       case Type::kInt8:
169         return std::numeric_limits<int8_t>::min();
170       case Type::kUint16:
171         return std::numeric_limits<uint16_t>::min();
172       case Type::kInt16:
173         return std::numeric_limits<int16_t>::min();
174       case Type::kUint32:
175         return std::numeric_limits<uint32_t>::min();
176       case Type::kInt32:
177         return std::numeric_limits<int32_t>::min();
178       case Type::kUint64:
179         return std::numeric_limits<uint64_t>::min();
180       case Type::kInt64:
181         return std::numeric_limits<int64_t>::min();
182       default:
183         LOG(FATAL) << "non integral type";
184     }
185     return 0;
186   }
187 
MaxValueOfIntegralType(Type type)188   static int64_t MaxValueOfIntegralType(Type type) {
189     switch (type) {
190       case Type::kBool:
191         return std::numeric_limits<bool>::max();
192       case Type::kUint8:
193         return std::numeric_limits<uint8_t>::max();
194       case Type::kInt8:
195         return std::numeric_limits<int8_t>::max();
196       case Type::kUint16:
197         return std::numeric_limits<uint16_t>::max();
198       case Type::kInt16:
199         return std::numeric_limits<int16_t>::max();
200       case Type::kUint32:
201         return std::numeric_limits<uint32_t>::max();
202       case Type::kInt32:
203         return std::numeric_limits<int32_t>::max();
204       case Type::kUint64:
205         return std::numeric_limits<uint64_t>::max();
206       case Type::kInt64:
207         return std::numeric_limits<int64_t>::max();
208       default:
209         LOG(FATAL) << "non integral type";
210     }
211     return 0;
212   }
213 
214   static bool IsTypeConversionImplicit(Type input_type, Type result_type);
215   static bool IsTypeConversionImplicit(int64_t value, Type result_type);
216 
IsZeroExtension(Type input_type,Type result_type)217   static bool IsZeroExtension(Type input_type, Type result_type) {
218     return IsIntOrLongType(result_type) &&
219         IsUnsignedType(input_type) &&
220         Size(result_type) > Size(input_type);
221   }
222 
ToSigned(Type type)223   static Type ToSigned(Type type) {
224     switch (type) {
225       case Type::kUint8:
226         return Type::kInt8;
227       case Type::kUint16:
228         return Type::kInt16;
229       case Type::kUint32:
230         return Type::kInt32;
231       case Type::kUint64:
232         return Type::kInt64;
233       default:
234         return type;
235     }
236   }
237 
ToUnsigned(Type type)238   static Type ToUnsigned(Type type) {
239     switch (type) {
240       case Type::kInt8:
241         return Type::kUint8;
242       case Type::kInt16:
243         return Type::kUint16;
244       case Type::kInt32:
245         return Type::kUint32;
246       case Type::kInt64:
247         return Type::kUint64;
248       default:
249         return type;
250     }
251   }
252 
253   static const char* PrettyDescriptor(Type type);
254 
255  private:
256   static constexpr size_t kObjectReferenceSize = 4u;
257 };
258 std::ostream& operator<<(std::ostream& os, DataType::Type data_type);
259 
260 // Defined outside DataType to have the operator<< available for DCHECK_NE().
IsTypeConversionImplicit(Type input_type,Type result_type)261 inline bool DataType::IsTypeConversionImplicit(Type input_type, Type result_type) {
262   DCHECK_NE(DataType::Type::kVoid, result_type);
263   DCHECK_NE(DataType::Type::kVoid, input_type);
264 
265   // Invariant: We should never generate a conversion to a Boolean value.
266   DCHECK_NE(DataType::Type::kBool, result_type);
267 
268   // Besides conversion to the same type, integral conversions to non-Int64 types
269   // are implicit if the result value range covers the input value range, i.e.
270   // widening conversions that do not need to trim the sign bits.
271   return result_type == input_type ||
272          (result_type != Type::kInt64 &&
273           IsIntegralType(input_type) &&
274           IsIntegralType(result_type) &&
275           MinValueOfIntegralType(input_type) >= MinValueOfIntegralType(result_type) &&
276           MaxValueOfIntegralType(input_type) <= MaxValueOfIntegralType(result_type));
277 }
278 
IsTypeConversionImplicit(int64_t value,Type result_type)279 inline bool DataType::IsTypeConversionImplicit(int64_t value, Type result_type) {
280   if (IsIntegralType(result_type) && result_type != Type::kInt64) {
281     // If the constant value falls in the range of the result_type, type
282     // conversion isn't needed.
283     return value >= MinValueOfIntegralType(result_type) &&
284            value <= MaxValueOfIntegralType(result_type);
285   }
286   // Conversion isn't implicit if it's into non-integer types, or 64-bit int
287   // which may have different number of registers.
288   return false;
289 }
290 
291 }  // namespace art
292 
293 #endif  // ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
294