blob: 5a5cbf4a9ffd26566de1b1ab08c0f4067b6f5bf6 [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 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
Yifan Hong52165692016-08-12 18:06:40 -070017#include "ConstantExpression.h"
18
Yifan Hong57886972016-08-17 10:42:15 -070019#include <stdio.h>
20#include <string>
Yifan Hong52165692016-08-12 18:06:40 -070021#include <utils/String8.h>
Yifan Hong57886972016-08-17 10:42:15 -070022#include <android-base/parseint.h>
23#include <android-base/logging.h>
24#include <sstream>
25
26// The macros are really nasty here. Consider removing
27// as many macros as possible.
28
29#define STREQ(__x__, __y__) (strcmp((__x__), (__y__)) == 0)
30#define OPEQ(__y__) STREQ(op, __y__)
31#define COMPUTE_UNARY(__op__) if(OPEQ(#__op__)) return __op__ val;
32#define COMPUTE_BINARY(__op__) if(OPEQ(#__op__)) return lval __op__ rval;
33#define OP_IS_BIN_ARITHMETIC (OPEQ("+") || OPEQ("-") || OPEQ("*") || OPEQ("/") || OPEQ("%"))
34#define OP_IS_BIN_BITFLIP (OPEQ("|") || OPEQ("^") || OPEQ("&"))
35#define OP_IS_BIN_COMP (OPEQ("<") || OPEQ(">") || OPEQ("<=") || OPEQ(">=") || OPEQ("==") || OPEQ("!="))
36#define OP_IS_BIN_SHIFT (OPEQ(">>") || OPEQ("<<"))
37#define OP_IS_BIN_LOGICAL (OPEQ("||") || OPEQ("&&"))
38#define SK(__x__) ScalarType::Kind::KIND_##__x__
39
40#define SWITCH_KIND(__cond__, __action__, __def__) \
41 switch(__cond__) { \
42 case SK(BOOL): __action__(bool) \
43 case SK(UINT8): __action__(uint8_t) \
44 case SK(INT8): __action__(int8_t) \
45 case SK(UINT16): __action__(uint16_t) \
46 case SK(INT16): __action__(int16_t) \
47 case SK(UINT32): __action__(uint32_t) \
48 case SK(INT32): __action__(int32_t) \
49 case SK(UINT64): __action__(uint64_t) \
50 case SK(INT64): __action__(int64_t) \
51 default: __def__ \
52 } \
Yifan Hong52165692016-08-12 18:06:40 -070053
54namespace android {
55
Yifan Hong57886972016-08-17 10:42:15 -070056/* See docs at the end for details on integral promotion. */
57ScalarType::Kind integralPromotion(ScalarType::Kind in) {
58 return SK(INT32) < in ? in : SK(INT32); // note that KIND_INT32 < KIND_UINT32
Yifan Hong52165692016-08-12 18:06:40 -070059}
60
Yifan Hong57886972016-08-17 10:42:15 -070061/* See docs at the end for details on usual arithmetic conversion. */
62ScalarType::Kind usualArithmeticConversion(ScalarType::Kind lft, ScalarType::Kind rgt) {
63 CHECK(SK(BOOL) <= lft && lft <= SK(UINT64)
64 && SK(BOOL) <= rgt && rgt <= SK(UINT64)
65 && lft != SK(OPAQUE) && rgt != SK(OPAQUE)
66 );
67 // Kinds in concern: bool, (u)int[8|16|32|64]
68 if(lft == rgt) return lft; // easy case
69 if(lft == SK(BOOL)) return rgt;
70 if(rgt == SK(BOOL)) return lft;
71 bool isLftSigned = (lft == SK(INT8)) || (lft == SK(INT16))
72 || (lft == SK(INT32)) || (lft == SK(INT64));
73 bool isRgtSigned = (rgt == SK(INT8)) || (rgt == SK(INT16))
74 || (rgt == SK(INT32)) || (rgt == SK(INT64));
75 if(isLftSigned == isRgtSigned) return lft < rgt ? rgt : lft;
76 ScalarType::Kind unsignedRank = isLftSigned ? rgt : lft;
77 ScalarType::Kind signedRank = isLftSigned ? lft : rgt;
78 if(unsignedRank >= signedRank) return unsignedRank;
79 if(signedRank > unsignedRank) return signedRank;
80
81 // Although there is such rule to return "the unsigned counterpart of
82 // the signed operand", it should not reach here in our HIDL grammar.
83 LOG(FATAL) << "Could not do usual arithmetic conversion for type "
84 << lft << "and" << rgt;
85 switch(signedRank) {
86 case SK(INT8): return SK(UINT8);
87 case SK(INT16): return SK(UINT16);
88 case SK(INT32): return SK(UINT32);
89 case SK(INT64): return SK(UINT64);
90 default: return SK(UINT64);
91 }
Yifan Hong52165692016-08-12 18:06:40 -070092}
Yifan Hong57886972016-08-17 10:42:15 -070093
94template <class T>
95T handleUnary(const char *op, T val) {
96 COMPUTE_UNARY(+)
97 COMPUTE_UNARY(-)
98 COMPUTE_UNARY(!)
99 COMPUTE_UNARY(~)
100 // Should not reach here.
101 LOG(FATAL) << "Could not handleUnary for " << op << " " << val;
102 return static_cast<T>(0xdeadbeef);
103}
104
105template <class T>
106T handleBinaryCommon(T lval, const char *op, T rval) {
107 COMPUTE_BINARY(+)
108 COMPUTE_BINARY(-)
109 COMPUTE_BINARY(*)
110 COMPUTE_BINARY(/)
111 COMPUTE_BINARY(%)
112 COMPUTE_BINARY(|)
113 COMPUTE_BINARY(^)
114 COMPUTE_BINARY(&)
115 // comparison operators: return 0 or 1 by nature.
116 COMPUTE_BINARY(==)
117 COMPUTE_BINARY(!=)
118 COMPUTE_BINARY(<)
119 COMPUTE_BINARY(>)
120 COMPUTE_BINARY(<=)
121 COMPUTE_BINARY(>=)
122 // Should not reach here.
123 LOG(FATAL) << "Could not handleBinaryCommon for "
124 << lval << " " << op << " " << rval;
125 return static_cast<T>(0xdeadbeef);
126}
127
128template <class T>
129T handleShift(T lval, const char *op, int64_t rval) {
130 // just cast rval to int64_t and it should fit.
131 COMPUTE_BINARY(>>)
132 COMPUTE_BINARY(<<)
133 // Should not reach here.
134 LOG(FATAL) << "Could not handleShift for"
135 << lval << " " << op << " " << rval;
136 return static_cast<T>(0xdeadbeef);
137}
138
139bool handleLogical(bool lval, const char *op, bool rval) {
140 COMPUTE_BINARY(||);
141 COMPUTE_BINARY(&&);
142 // Should not reach here.
143 LOG(FATAL) << "Could not handleLogical for"
144 << lval << " " << op << " " << rval;
145 return false;
146}
147
148/* Literals. */
149ConstantExpression::ConstantExpression(const char *value,
150 ConstantExpression::ConstExprType type)
151 : mFormatted(value), mType(type) {
152 if(mType == kConstExprUnknown)
153 return;
154 const char* head = value, *tail = head + strlen(value) - 1;
155 bool isLong = false, isUnsigned = false;
156 bool isHex = (value[0] == '0' && (value[1] == 'x' || value[1] == 'X'));
157 while(tail >= head && (*tail == 'u' || *tail == 'U' || *tail == 'l' || *tail == 'L')) {
158 isUnsigned |= *tail == 'u' || *tail == 'U';
159 isLong |= *tail == 'l' || *tail == 'L';
160 tail--;
161 }
162 char *newVal = strndup(value, tail - head + 1);
163 bool parseOK = base::ParseUint(newVal, &mValue);
164 free(newVal);
165 if(!parseOK) {
166 LOG(FATAL) << "Could not parse as integer: " << value;
167 mType = kConstExprUnknown;
168 return;
169 }
170
171 // guess literal type.
172 if(isLong) {
173 if(isUnsigned) // ul
174 mValueKind = SK(UINT64);
175 else // l
176 mValueKind = SK(INT64);
177 } else { // no l suffix
178 if(isUnsigned) { // u
179 if(mValue <= UINT32_MAX)
180 mValueKind = SK(UINT32);
181 else
182 mValueKind = SK(UINT64);
183 } else { // no suffix
184 if(isHex) {
185 if(mValue <= INT32_MAX) // mValue always >= 0
186 mValueKind = SK(INT32);
187 else if(mValue <= UINT32_MAX)
188 mValueKind = SK(UINT32);
189 else if(mValue <= INT64_MAX) // mValue always >= 0
190 mValueKind = SK(INT64);
191 else if(mValue <= UINT64_MAX)
192 mValueKind = SK(UINT64);
193 } else {
194 if(mValue <= INT32_MAX) // mValue always >= 0
195 mValueKind = SK(INT32);
196 else
197 mValueKind = SK(INT64);
198 }
199 }
200 }
201}
202
203/* Unary operations. */
Yifan Hong52165692016-08-12 18:06:40 -0700204ConstantExpression::ConstantExpression(const char *op, const ConstantExpression *value)
Yifan Hong57886972016-08-17 10:42:15 -0700205 : mFormatted(android::String8::format("(%s%s)", op, value->expr()).string()),
206 mType(kConstExprUnary),
207 mValueKind(value->mValueKind) {
208 if(value->mType == kConstExprUnknown) {
209 mType = kConstExprUnknown;
210 return;
211 }
212#define CASE_UNARY(__type__)\
213 mValue = handleUnary(op, static_cast<__type__>(value->mValue)); return;
214
215 SWITCH_KIND(mValueKind, CASE_UNARY, mType = kConstExprUnknown; return;)
Yifan Hong52165692016-08-12 18:06:40 -0700216}
Yifan Hong57886972016-08-17 10:42:15 -0700217
218/* Binary operations. */
219ConstantExpression::ConstantExpression(const ConstantExpression *lval, const char *op, const ConstantExpression* rval)
220 : mFormatted(android::String8::format("(%s %s %s)", lval->expr(), op, rval->expr()).string()),
221 mType(kConstExprBinary)
222{
223 if(lval->mType == kConstExprUnknown || rval->mType == kConstExprUnknown) {
224 mType = kConstExprUnknown;
225 return;
226 }
227
228 bool isArithmeticOrBitflip = OP_IS_BIN_ARITHMETIC || OP_IS_BIN_BITFLIP;
229
230 // CASE 1: + - * / % | ^ & < > <= >= == !=
231 if(isArithmeticOrBitflip || OP_IS_BIN_COMP) {
232 // promoted kind for both operands.
233 ScalarType::Kind promoted = usualArithmeticConversion(
234 integralPromotion(lval->mValueKind),
235 integralPromotion(rval->mValueKind));
236 // result kind.
237 mValueKind = isArithmeticOrBitflip
238 ? promoted // arithmetic or bitflip operators generates promoted type
239 : SK(BOOL); // comparison operators generates bool
240
241#define CASE_BINARY_COMMON(__type__)\
242 mValue = handleBinaryCommon(static_cast<__type__>(lval->mValue), op, static_cast<__type__>(rval->mValue)); return;
243
244 SWITCH_KIND(promoted, CASE_BINARY_COMMON, mType = kConstExprUnknown; return;)
245 }
246
247 // CASE 2: << >>
248 if(OP_IS_BIN_SHIFT) {
249 mValueKind = integralPromotion(lval->mValueKind);
250 // instead of promoting rval, simply casting it to int64 should also be good.
Yifan Hong19ca75a2016-08-31 10:20:03 -0700251 int64_t numBits = rval->cast<int64_t>();
Yifan Hong57886972016-08-17 10:42:15 -0700252 if(numBits < 0) {
253 // shifting with negative number of bits is undefined in C. In HIDL it
254 // is defined as shifting into the other direction.
255 op = OPEQ("<<") ? ">>" : "<<";
256 numBits = -numBits;
257 }
258
259#define CASE_SHIFT(__type__)\
260 mValue = handleShift(static_cast<__type__>(lval->mValue), op, numBits); return;
261
262 SWITCH_KIND(mValueKind, CASE_SHIFT, mType = kConstExprUnknown; return;)
263 }
264
265 // CASE 3: && ||
266 if(OP_IS_BIN_LOGICAL) {
267 mValueKind = SK(BOOL);
268 // easy; everything is bool.
269 mValue = handleLogical(lval->mValue, op, rval->mValue);
270 return;
271 }
272
273 mType = kConstExprUnknown;
274}
275
276/* Ternary ?: operation. */
Yifan Hong52165692016-08-12 18:06:40 -0700277ConstantExpression::ConstantExpression(const ConstantExpression *cond,
278 const ConstantExpression *trueVal,
279 const ConstantExpression *falseVal)
Yifan Hong57886972016-08-17 10:42:15 -0700280 : mFormatted(android::String8::format("(%s?%s:%s)",
281 cond->expr(), trueVal->expr(), falseVal->expr()).string()),
282 mType(kConstExprTernary) {
283 // note: for ?:, unlike arithmetic ops, integral promotion is not necessary.
284 mValueKind = usualArithmeticConversion(trueVal->mValueKind,
285 falseVal->mValueKind);
286
287#define CASE_TERNARY(__type__)\
288 mValue = cond->mValue ? (static_cast<__type__>(trueVal->mValue)) : (static_cast<__type__>(falseVal->mValue)); return;
289
290 SWITCH_KIND(mValueKind, CASE_TERNARY, mType = kConstExprUnknown; return;)
Yifan Hong52165692016-08-12 18:06:40 -0700291}
292
Yifan Hong57886972016-08-17 10:42:15 -0700293const char *ConstantExpression::expr() const {
294 return mFormatted.c_str();
Yifan Hong52165692016-08-12 18:06:40 -0700295}
Yifan Hong57886972016-08-17 10:42:15 -0700296
297const char *ConstantExpression::description() const {
298 static const char *const kName[] = {
299 "bool",
300 "void *",
301 "int8_t",
302 "uint8_t",
303 "int16_t",
304 "uint16_t",
305 "int32_t",
306 "uint32_t",
307 "int64_t",
308 "uint64_t",
309 "float",
310 "double"
311 };
312 if(mType == kConstExprUnknown)
313 return expr();
314 std::ostringstream os;
315 os << "(" << kName[mValueKind] << ")" << expr();
316 return strdup(os.str().c_str());
317}
318
Yifan Hong52165692016-08-12 18:06:40 -0700319const char *ConstantExpression::value() const {
Yifan Hong57886972016-08-17 10:42:15 -0700320 return value0(mValueKind);
Yifan Hong52165692016-08-12 18:06:40 -0700321}
322
Yifan Hong57886972016-08-17 10:42:15 -0700323const char *ConstantExpression::cppValue(ScalarType::Kind castKind) const {
324 std::string literal(value0(castKind));
325 // this is a hack to translate
326 // enum x : int64_t { y = 1l << 63 };
327 // into
328 // enum class x : int64_t { y = (int64_t)-9223372036854775808ull };
329 // by adding the explicit cast.
330 // Because 9223372036854775808 is uint64_t, and
331 // -(uint64_t)9223372036854775808 == 9223372036854775808 could not
332 // be narrowed to int64_t.
333 if(castKind == SK(INT64) && (int64_t)mValue == INT64_MIN) {
334 std::string extra;
335 return strdup(("("
336 + ScalarType(SK(INT64)).getCppType(android::Type::StorageMode_Stack, &extra) // "int64_t"
337 + ")(" + literal + "ull)").c_str());
338 }
339
340 // add suffix if necessary.
341 if(castKind == SK(UINT32) || castKind == SK(UINT64)) literal += "u";
342 if(castKind == SK(UINT64) || castKind == SK(INT64)) literal += "ll";
343 return strdup(literal.c_str());
344}
345
Yifan Hong19ca75a2016-08-31 10:20:03 -0700346const char *ConstantExpression::javaValue(ScalarType::Kind castKind) const {
347 switch(castKind) {
348 case SK(UINT64): return value0(SK(INT64));
349 case SK(UINT32): return value0(SK(INT32));
350 case SK(UINT16): return value0(SK(INT16));
351 case SK(UINT8) : return value0(SK(INT8));
352 case SK(BOOL) :
353 if(mType == kConstExprUnknown)
354 return expr();
355 return this->cast<bool>() ? strdup("true") : strdup("false");
356 default: break;
357 }
358 return value0(castKind);
359}
360
Yifan Hong57886972016-08-17 10:42:15 -0700361const char *ConstantExpression::value0(ScalarType::Kind castKind) const {
362 if(mType == kConstExprUnknown)
363 return expr();
364
Yifan Hong19ca75a2016-08-31 10:20:03 -0700365#define CASE_STR(__type__) return strdup(std::to_string(this->cast<__type__>()).c_str());
Yifan Hong57886972016-08-17 10:42:15 -0700366
367 SWITCH_KIND(castKind, CASE_STR, return expr(); );
368}
369
Yifan Hong19ca75a2016-08-31 10:20:03 -0700370template<typename T>
371T ConstantExpression::cast() const {
Yifan Hong57886972016-08-17 10:42:15 -0700372 CHECK(mType != kConstExprUnknown);
373
Yifan Hong19ca75a2016-08-31 10:20:03 -0700374#define CASE_CAST_T(__type__) return static_cast<T>(static_cast<__type__>(mValue));
Yifan Hong57886972016-08-17 10:42:15 -0700375
Yifan Hong19ca75a2016-08-31 10:20:03 -0700376 SWITCH_KIND(mValueKind, CASE_CAST_T, CHECK(false); return 0; );
Yifan Hong57886972016-08-17 10:42:15 -0700377}
378
379/*
380
381Evaluating expressions in HIDL language
382
383The following rules are mostly like that in:
384http://en.cppreference.com/w/cpp/language/operator_arithmetic
385http://en.cppreference.com/w/cpp/language/operator_logical
386http://en.cppreference.com/w/cpp/language/operator_comparison
387http://en.cppreference.com/w/cpp/language/operator_other
388
389The type of literal is the first type which the value
390can fit from the list of types depending on the suffix and bases.
391
392suffix decimal bases hexadecimal bases
393no suffix int32_t int32_t
394 int64_t uint32_t
395 int64_t
396 uint64_t
397
398u/U uint32_t (same as left)
399 uint64_t
400
401l/L int64_t int64_t
402
403ul/UL/uL/Ul uint64_t uint64_t
404
405
406Note: There are no negative integer literals.
407 -1 is the unary minus applied to 1.
408
409Unary arithmetic and bitwise operators (~ + -):
410 don't change the type of the argument.
411 (so -1u = -(1u) has type uint32_t)
412
413Binary arithmetic and bitwise operators (except shifts) (+ - * / % & | ^):
4141. Integral promotion is first applied on both sides.
4152. If both operands have the same type, no promotion is necessary.
4163. Usual arithmetic conversions.
417
418Integral promotion: if an operand is of a type with less than 32 bits,
419(including bool), it is promoted to int32_t.
420
421Usual arithmetic conversions:
4221. If operands are both signed or both unsigned, lesser conversion rank is
423 converted to greater conversion rank.
4242. Otherwise, if unsigned's rank >= signed's rank, -> unsigned's type
4253. Otherwise, if signed's type can hold all values in unsigned's type,
426 -> signed's type
4274. Otherwise, both converted to the unsigned counterpart of the signed operand's
428 type.
429rank: bool < int8_t < int16_t < int32_t < int64_t
430
431
432Shift operators (<< >>):
4331. Integral promotion is applied on both sides.
4342. For unsigned a, a << b discards bits that shifts out.
435 For signed non-negative a, a << b is legal if no bits shifts out, otherwise error.
436 For signed negative a, a << b gives error.
4373. For unsigned and signed non-negative a, a >> b discards bits that shifts out.
438 For signed negative a, a >> b discards bits that shifts out, and the signed
439 bit gets extended. ("arithmetic right shift")
4404. Shifting with negative number of bits is undefined. (Currently, the
441 parser will shift into the other direction. This behavior may change.)
4425. Shifting with number of bits exceeding the width of the type is undefined.
443 (Currently, 1 << 32 == 1. This behavior may change.)
444
445Logical operators (!, &&, ||):
4461. Convert first operand to bool. (true if non-zero, false otherwise)
4472. If short-circuited, return the result as type bool, value 1 or 0.
4483. Otherwise, convert second operand to bool, evaluate the result, and return
449 the result in the same fashion.
450
451Arithmetic comparison operators (< > <= >= == !=):
4521. Promote operands in the same way as binary arithmetic and bitwise operators.
453 (Integral promotion + Usual arithmetic conversions)
4542. Return type bool, value 0 or 1 the same way as logical operators.
455
456Ternary conditional operator (?:):
4571. Evaluate the conditional and evaluate the operands.
4582. Return type of expression is the type under usual arithmetic conversions on
459 the second and third operand. (No integral promotions necessary.)
460
461*/
462
Yifan Hong52165692016-08-12 18:06:40 -0700463} // namespace android
464