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 
IsUnsignedType(Type type)134   static bool IsUnsignedType(Type type) {
135     return type == Type::kBool || type == Type::kUint8 || type == Type::kUint16 ||
136         type == Type::kUint32 || type == Type::kUint64;
137   }
138 
139   // Return the general kind of `type`, fusing integer-like types as Type::kInt.
Kind(Type type)140   static Type Kind(Type type) {
141     switch (type) {
142       case Type::kBool:
143       case Type::kUint8:
144       case Type::kInt8:
145       case Type::kUint16:
146       case Type::kInt16:
147       case Type::kUint32:
148       case Type::kInt32:
149         return Type::kInt32;
150       case Type::kUint64:
151       case Type::kInt64:
152         return Type::kInt64;
153       default:
154         return type;
155     }
156   }
157 
MinValueOfIntegralType(Type type)158   static int64_t MinValueOfIntegralType(Type type) {
159     switch (type) {
160       case Type::kBool:
161         return std::numeric_limits<bool>::min();
162       case Type::kUint8:
163         return std::numeric_limits<uint8_t>::min();
164       case Type::kInt8:
165         return std::numeric_limits<int8_t>::min();
166       case Type::kUint16:
167         return std::numeric_limits<uint16_t>::min();
168       case Type::kInt16:
169         return std::numeric_limits<int16_t>::min();
170       case Type::kUint32:
171         return std::numeric_limits<uint32_t>::min();
172       case Type::kInt32:
173         return std::numeric_limits<int32_t>::min();
174       case Type::kUint64:
175         return std::numeric_limits<uint64_t>::min();
176       case Type::kInt64:
177         return std::numeric_limits<int64_t>::min();
178       default:
179         LOG(FATAL) << "non integral type";
180     }
181     return 0;
182   }
183 
MaxValueOfIntegralType(Type type)184   static int64_t MaxValueOfIntegralType(Type type) {
185     switch (type) {
186       case Type::kBool:
187         return std::numeric_limits<bool>::max();
188       case Type::kUint8:
189         return std::numeric_limits<uint8_t>::max();
190       case Type::kInt8:
191         return std::numeric_limits<int8_t>::max();
192       case Type::kUint16:
193         return std::numeric_limits<uint16_t>::max();
194       case Type::kInt16:
195         return std::numeric_limits<int16_t>::max();
196       case Type::kUint32:
197         return std::numeric_limits<uint32_t>::max();
198       case Type::kInt32:
199         return std::numeric_limits<int32_t>::max();
200       case Type::kUint64:
201         return std::numeric_limits<uint64_t>::max();
202       case Type::kInt64:
203         return std::numeric_limits<int64_t>::max();
204       default:
205         LOG(FATAL) << "non integral type";
206     }
207     return 0;
208   }
209 
210   static bool IsTypeConversionImplicit(Type input_type, Type result_type);
211   static bool IsTypeConversionImplicit(int64_t value, Type result_type);
212 
IsZeroExtension(Type input_type,Type result_type)213   static bool IsZeroExtension(Type input_type, Type result_type) {
214     return IsIntOrLongType(result_type) &&
215         IsUnsignedType(input_type) &&
216         Size(result_type) > Size(input_type);
217   }
218 
ToSigned(Type type)219   static Type ToSigned(Type type) {
220     switch (type) {
221       case Type::kUint8:
222         return Type::kInt8;
223       case Type::kUint16:
224         return Type::kInt16;
225       case Type::kUint32:
226         return Type::kInt32;
227       case Type::kUint64:
228         return Type::kInt64;
229       default:
230         return type;
231     }
232   }
233 
ToUnsigned(Type type)234   static Type ToUnsigned(Type type) {
235     switch (type) {
236       case Type::kInt8:
237         return Type::kUint8;
238       case Type::kInt16:
239         return Type::kUint16;
240       case Type::kInt32:
241         return Type::kUint32;
242       case Type::kInt64:
243         return Type::kUint64;
244       default:
245         return type;
246     }
247   }
248 
249   static const char* PrettyDescriptor(Type type);
250 
251  private:
252   static constexpr size_t kObjectReferenceSize = 4u;
253 };
254 std::ostream& operator<<(std::ostream& os, DataType::Type data_type);
255 
256 // Defined outside DataType to have the operator<< available for DCHECK_NE().
IsTypeConversionImplicit(Type input_type,Type result_type)257 inline bool DataType::IsTypeConversionImplicit(Type input_type, Type result_type) {
258   DCHECK_NE(DataType::Type::kVoid, result_type);
259   DCHECK_NE(DataType::Type::kVoid, input_type);
260 
261   // Invariant: We should never generate a conversion to a Boolean value.
262   DCHECK_NE(DataType::Type::kBool, result_type);
263 
264   // Besides conversion to the same type, integral conversions to non-Int64 types
265   // are implicit if the result value range covers the input value range, i.e.
266   // widening conversions that do not need to trim the sign bits.
267   return result_type == input_type ||
268          (result_type != Type::kInt64 &&
269           IsIntegralType(input_type) &&
270           IsIntegralType(result_type) &&
271           MinValueOfIntegralType(input_type) >= MinValueOfIntegralType(result_type) &&
272           MaxValueOfIntegralType(input_type) <= MaxValueOfIntegralType(result_type));
273 }
274 
IsTypeConversionImplicit(int64_t value,Type result_type)275 inline bool DataType::IsTypeConversionImplicit(int64_t value, Type result_type) {
276   if (IsIntegralType(result_type) && result_type != Type::kInt64) {
277     // If the constant value falls in the range of the result_type, type
278     // conversion isn't needed.
279     return value >= MinValueOfIntegralType(result_type) &&
280            value <= MaxValueOfIntegralType(result_type);
281   }
282   // Conversion isn't implicit if it's into non-integer types, or 64-bit int
283   // which may have different number of registers.
284   return false;
285 }
286 
287 }  // namespace art
288 
289 #endif  // ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
290