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
213 static const char* PrettyDescriptor(Type type);
214
215 private:
216 static constexpr size_t kObjectReferenceSize = 4u;
217 };
218 std::ostream& operator<<(std::ostream& os, DataType::Type data_type);
219
220 // Defined outside DataType to have the operator<< available for DCHECK_NE().
IsTypeConversionImplicit(Type input_type,Type result_type)221 inline bool DataType::IsTypeConversionImplicit(Type input_type, Type result_type) {
222 DCHECK_NE(DataType::Type::kVoid, result_type);
223 DCHECK_NE(DataType::Type::kVoid, input_type);
224
225 // Invariant: We should never generate a conversion to a Boolean value.
226 DCHECK_NE(DataType::Type::kBool, result_type);
227
228 // Besides conversion to the same type, integral conversions to non-Int64 types
229 // are implicit if the result value range covers the input value range, i.e.
230 // widening conversions that do not need to trim the sign bits.
231 return result_type == input_type ||
232 (result_type != Type::kInt64 &&
233 IsIntegralType(input_type) &&
234 IsIntegralType(result_type) &&
235 MinValueOfIntegralType(input_type) >= MinValueOfIntegralType(result_type) &&
236 MaxValueOfIntegralType(input_type) <= MaxValueOfIntegralType(result_type));
237 }
238
IsTypeConversionImplicit(int64_t value,Type result_type)239 inline bool DataType::IsTypeConversionImplicit(int64_t value, Type result_type) {
240 if (IsIntegralType(result_type) && result_type != Type::kInt64) {
241 // If the constant value falls in the range of the result_type, type
242 // conversion isn't needed.
243 return value >= MinValueOfIntegralType(result_type) &&
244 value <= MaxValueOfIntegralType(result_type);
245 }
246 // Conversion isn't implicit if it's into non-integer types, or 64-bit int
247 // which may have different number of registers.
248 return false;
249 }
250
251 } // namespace art
252
253 #endif // ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
254