OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
6 | 6 |
7 #include "vm/bigint_operations.h" | 7 #include "vm/bigint_operations.h" |
8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
330 | 330 |
331 | 331 |
332 UnboxedConstantInstr::UnboxedConstantInstr(const Object& value) | 332 UnboxedConstantInstr::UnboxedConstantInstr(const Object& value) |
333 : ConstantInstr(value), constant_address_(0) { | 333 : ConstantInstr(value), constant_address_(0) { |
334 // Only doubles supported for now. | 334 // Only doubles supported for now. |
335 ASSERT(value.IsDouble()); | 335 ASSERT(value.IsDouble()); |
336 constant_address_ = | 336 constant_address_ = |
337 FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value()); | 337 FlowGraphBuilder::FindDoubleConstant(Double::Cast(value).value()); |
338 } | 338 } |
339 | 339 |
340 | |
341 bool Value::BindsTo32BitMaskConstant() const { | |
342 if (!definition()->IsUnboxInteger() || !definition()->IsUnboxUint32()) { | |
343 return false; | |
344 } | |
345 // Two cases to consider: UnboxInteger and UnboxUint32. | |
346 if (definition()->IsUnboxInteger()) { | |
347 UnboxIntegerInstr* instr = definition()->AsUnboxInteger(); | |
348 if (!instr->value()->BindsToConstant()) { | |
349 return false; | |
350 } | |
351 const Object& obj = instr->value()->BoundConstant(); | |
352 if (!obj.IsMint()) { | |
353 return false; | |
354 } | |
355 Mint& mint = Mint::Handle(); | |
356 mint ^= obj.raw(); | |
357 return mint.value() == kMaxUint32; | |
358 } else if (definition()->IsUnboxUint32()) { | |
359 UnboxUint32Instr* instr = definition()->AsUnboxUint32(); | |
360 if (!instr->value()->BindsToConstant()) { | |
361 return false; | |
362 } | |
363 const Object& obj = instr->value()->BoundConstant(); | |
364 if (!obj.IsMint()) { | |
365 return false; | |
366 } | |
367 Mint& mint = Mint::Handle(); | |
368 mint ^= obj.raw(); | |
369 return mint.value() == kMaxUint32; | |
370 } | |
371 return false; | |
372 } | |
373 | |
374 | |
340 // Returns true if the value represents a constant. | 375 // Returns true if the value represents a constant. |
341 bool Value::BindsToConstant() const { | 376 bool Value::BindsToConstant() const { |
342 return definition()->IsConstant(); | 377 return definition()->IsConstant(); |
343 } | 378 } |
344 | 379 |
345 | 380 |
346 // Returns true if the value represents constant null. | 381 // Returns true if the value represents constant null. |
347 bool Value::BindsToConstantNull() const { | 382 bool Value::BindsToConstantNull() const { |
348 ConstantInstr* constant = definition()->AsConstant(); | 383 ConstantInstr* constant = definition()->AsConstant(); |
349 return (constant != NULL) && constant->value().IsNull(); | 384 return (constant != NULL) && constant->value().IsNull(); |
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1259 | 1294 |
1260 bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const { | 1295 bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const { |
1261 if (!right()->definition()->IsConstant()) return false; | 1296 if (!right()->definition()->IsConstant()) return false; |
1262 const Object& constant = right()->definition()->AsConstant()->value(); | 1297 const Object& constant = right()->definition()->AsConstant()->value(); |
1263 if (!constant.IsSmi()) return false; | 1298 if (!constant.IsSmi()) return false; |
1264 const intptr_t int_value = Smi::Cast(constant).Value(); | 1299 const intptr_t int_value = Smi::Cast(constant).Value(); |
1265 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); | 1300 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); |
1266 } | 1301 } |
1267 | 1302 |
1268 | 1303 |
1269 static bool ToIntegerConstant(Value* value, intptr_t* result) { | 1304 static bool ToIntegerConstant(Value* value, int64_t* result) { |
1270 if (!value->BindsToConstant()) { | 1305 if (!value->BindsToConstant()) { |
1271 if (value->definition()->IsUnboxDouble()) { | 1306 if (value->definition()->IsUnboxDouble()) { |
1272 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), | 1307 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), |
1273 result); | 1308 result); |
1274 } | 1309 } |
1275 return false; | 1310 return false; |
1276 } | 1311 } |
1277 | 1312 |
1278 const Object& constant = value->BoundConstant(); | 1313 const Object& constant = value->BoundConstant(); |
1279 if (constant.IsDouble()) { | 1314 if (constant.IsDouble()) { |
1280 const Double& double_constant = Double::Cast(constant); | 1315 const Double& double_constant = Double::Cast(constant); |
1281 *result = static_cast<intptr_t>(double_constant.value()); | 1316 *result = static_cast<int64_t>(double_constant.value()); |
1282 return (static_cast<double>(*result) == double_constant.value()); | 1317 return (static_cast<double>(*result) == double_constant.value()); |
1283 } else if (constant.IsSmi()) { | 1318 } else if (constant.IsSmi()) { |
1284 *result = Smi::Cast(constant).Value(); | 1319 *result = Smi::Cast(constant).Value(); |
1285 return true; | 1320 return true; |
1321 } else if (constant.IsMint()) { | |
1322 *result = Mint::Cast(constant).value(); | |
1323 return true; | |
1286 } | 1324 } |
1287 | 1325 |
1288 return false; | 1326 return false; |
1289 } | 1327 } |
1290 | 1328 |
1291 | 1329 |
1292 static Definition* CanonicalizeCommutativeArithmetic(Token::Kind op, | 1330 static Definition* CanonicalizeCommutativeArithmetic( |
1293 intptr_t cid, | 1331 Token::Kind op, |
1294 Value* left, | 1332 intptr_t cid, |
1295 Value* right) { | 1333 Value* left, |
1334 Value* right, | |
1335 int64_t mask = static_cast<int64_t>(0xFFFFFFFFFFFFFFFF)) { | |
1296 ASSERT((cid == kSmiCid) || (cid == kDoubleCid) || (cid == kMintCid)); | 1336 ASSERT((cid == kSmiCid) || (cid == kDoubleCid) || (cid == kMintCid)); |
1297 | 1337 |
1298 intptr_t left_value; | 1338 int64_t left_value; |
1299 if (!ToIntegerConstant(left, &left_value)) { | 1339 if (!ToIntegerConstant(left, &left_value)) { |
1300 return NULL; | 1340 return NULL; |
1301 } | 1341 } |
1302 | 1342 |
1343 // Apply truncation mask to left_value. | |
1344 left_value &= mask; | |
1345 | |
1303 switch (op) { | 1346 switch (op) { |
1304 case Token::kMUL: | 1347 case Token::kMUL: |
1305 if (left_value == 1) { | 1348 if (left_value == 1) { |
1306 if ((cid == kDoubleCid) && | 1349 if ((cid == kDoubleCid) && |
1307 (right->definition()->representation() != kUnboxedDouble)) { | 1350 (right->definition()->representation() != kUnboxedDouble)) { |
1308 // Can't yet apply the equivalence because representation selection | 1351 // Can't yet apply the equivalence because representation selection |
1309 // did not run yet. We need it to guarantee that right value is | 1352 // did not run yet. We need it to guarantee that right value is |
1310 // correctly coerced to double. The second canonicalization pass | 1353 // correctly coerced to double. The second canonicalization pass |
1311 // will apply this equivalence. | 1354 // will apply this equivalence. |
1312 return NULL; | 1355 return NULL; |
(...skipping 10 matching lines...) Expand all Loading... | |
1323 if ((left_value == 0) && (cid != kDoubleCid)) { | 1366 if ((left_value == 0) && (cid != kDoubleCid)) { |
1324 // Can't apply this equivalence to double operations because | 1367 // Can't apply this equivalence to double operations because |
1325 // 0.0 + (-0.0) is 0.0 not -0.0. | 1368 // 0.0 + (-0.0) is 0.0 not -0.0. |
1326 return right->definition(); | 1369 return right->definition(); |
1327 } | 1370 } |
1328 break; | 1371 break; |
1329 case Token::kBIT_AND: | 1372 case Token::kBIT_AND: |
1330 ASSERT(cid != kDoubleCid); | 1373 ASSERT(cid != kDoubleCid); |
1331 if (left_value == 0) { | 1374 if (left_value == 0) { |
1332 return left->definition(); | 1375 return left->definition(); |
1333 } else if (left_value == -1) { | 1376 } else if (left_value == -1) { |
Vyacheslav Egorov (Google)
2014/07/11 16:00:08
I think you should s/-1/mask/ in this function.
Cutch
2014/07/11 22:04:13
Done.
| |
1334 return right->definition(); | 1377 return right->definition(); |
1335 } | 1378 } |
1336 break; | 1379 break; |
1337 case Token::kBIT_OR: | 1380 case Token::kBIT_OR: |
1338 ASSERT(cid != kDoubleCid); | 1381 ASSERT(cid != kDoubleCid); |
1339 if (left_value == 0) { | 1382 if (left_value == 0) { |
1340 return right->definition(); | 1383 return right->definition(); |
1341 } else if (left_value == -1) { | 1384 } else if (left_value == -1) { |
Vyacheslav Egorov (Google)
2014/07/11 16:00:08
ditto
Cutch
2014/07/11 22:04:14
Done.
| |
1342 return left->definition(); | 1385 return left->definition(); |
1343 } | 1386 } |
1344 break; | 1387 break; |
1345 case Token::kBIT_XOR: | 1388 case Token::kBIT_XOR: |
1346 ASSERT(cid != kDoubleCid); | 1389 ASSERT(cid != kDoubleCid); |
1347 if (left_value == 0) { | 1390 if (left_value == 0) { |
1348 return right->definition(); | 1391 return right->definition(); |
1349 } | 1392 } |
1350 break; | 1393 break; |
1351 default: | 1394 default: |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1457 right(), | 1500 right(), |
1458 left()); | 1501 left()); |
1459 if (result != NULL) { | 1502 if (result != NULL) { |
1460 return result; | 1503 return result; |
1461 } | 1504 } |
1462 | 1505 |
1463 return this; | 1506 return this; |
1464 } | 1507 } |
1465 | 1508 |
1466 | 1509 |
1510 static bool IsUint32Mask(BinaryUint32OpInstr* defn) { | |
1511 ASSERT(defn != NULL); | |
1512 if (defn->op_kind() != Token::kBIT_AND) { | |
1513 // Not a mask. | |
1514 return false; | |
1515 } | |
1516 Value* left = defn->left(); | |
1517 Value* right = defn->right(); | |
1518 return left->BindsTo32BitMaskConstant() != right->BindsTo32BitMaskConstant(); | |
1519 } | |
1520 | |
1521 | |
1522 Definition* BinaryUint32OpInstr::Canonicalize(FlowGraph* flow_graph) { | |
1523 // If this is (value & 0xFFFFFFFF) the mask operation can be dropped because | |
1524 // all Uint32 operations are implicitly masked with 0xFFFFFFFF. | |
1525 if (IsUint32Mask(this)) { | |
Vyacheslav Egorov (Google)
2014/07/11 16:00:08
I think this is not needed anymore once you replac
Cutch
2014/07/11 22:04:13
Done.
| |
1526 return NULL; | |
1527 } | |
1528 | |
1529 Definition* result = NULL; | |
1530 | |
1531 const int64_t truncation_mask = static_cast<int64_t>(0xFFFFFFFF); | |
1532 | |
1533 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
1534 kMintCid, | |
1535 left(), | |
1536 right(), | |
1537 truncation_mask); | |
1538 if (result != NULL) { | |
1539 return result; | |
1540 } | |
1541 | |
1542 result = CanonicalizeCommutativeArithmetic(op_kind(), | |
1543 kMintCid, | |
1544 right(), | |
1545 left(), | |
1546 truncation_mask); | |
1547 if (result != NULL) { | |
1548 return result; | |
1549 } | |
1550 | |
1551 return this; | |
1552 } | |
1553 | |
1554 | |
1467 // Optimizations that eliminate or simplify individual instructions. | 1555 // Optimizations that eliminate or simplify individual instructions. |
1468 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { | 1556 Instruction* Instruction::Canonicalize(FlowGraph* flow_graph) { |
1469 return this; | 1557 return this; |
1470 } | 1558 } |
1471 | 1559 |
1472 | 1560 |
1473 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { | 1561 Definition* Definition::Canonicalize(FlowGraph* flow_graph) { |
1474 return this; | 1562 return this; |
1475 } | 1563 } |
1476 | 1564 |
(...skipping 2498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3975 case Token::kTRUNCDIV: return 0; | 4063 case Token::kTRUNCDIV: return 0; |
3976 case Token::kMOD: return 1; | 4064 case Token::kMOD: return 1; |
3977 default: UNIMPLEMENTED(); return -1; | 4065 default: UNIMPLEMENTED(); return -1; |
3978 } | 4066 } |
3979 } | 4067 } |
3980 | 4068 |
3981 | 4069 |
3982 #undef __ | 4070 #undef __ |
3983 | 4071 |
3984 } // namespace dart | 4072 } // namespace dart |
OLD | NEW |