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