| 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/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/bootstrap.h" | 8 #include "vm/bootstrap.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/constant_propagator.h" | 10 #include "vm/constant_propagator.h" |
| (...skipping 1313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1324 return can_overflow() || !RangeUtils::IsPositive(right_range()); | 1324 return can_overflow() || !RangeUtils::IsPositive(right_range()); |
| 1325 | 1325 |
| 1326 case Token::kMOD: | 1326 case Token::kMOD: |
| 1327 return RangeUtils::CanBeZero(right_range()); | 1327 return RangeUtils::CanBeZero(right_range()); |
| 1328 | 1328 |
| 1329 default: | 1329 default: |
| 1330 return can_overflow(); | 1330 return can_overflow(); |
| 1331 } | 1331 } |
| 1332 } | 1332 } |
| 1333 | 1333 |
| 1334 bool ShiftMintOpInstr::IsShiftCountInRange() const { | 1334 bool ShiftInt64OpInstr::IsShiftCountInRange() const { |
| 1335 return RangeUtils::IsWithin(shift_range(), 0, kMintShiftCountLimit); | 1335 return RangeUtils::IsWithin(shift_range(), 0, kMintShiftCountLimit); |
| 1336 } | 1336 } |
| 1337 | 1337 |
| 1338 bool BinaryIntegerOpInstr::RightIsPowerOfTwoConstant() const { | 1338 bool BinaryIntegerOpInstr::RightIsPowerOfTwoConstant() const { |
| 1339 if (!right()->definition()->IsConstant()) return false; | 1339 if (!right()->definition()->IsConstant()) return false; |
| 1340 const Object& constant = right()->definition()->AsConstant()->value(); | 1340 const Object& constant = right()->definition()->AsConstant()->value(); |
| 1341 if (!constant.IsSmi()) return false; | 1341 if (!constant.IsSmi()) return false; |
| 1342 const intptr_t int_value = Smi::Cast(constant).Value(); | 1342 const intptr_t int_value = Smi::Cast(constant).Value(); |
| 1343 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); | 1343 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); |
| 1344 } | 1344 } |
| 1345 | 1345 |
| 1346 static intptr_t RepresentationBits(Representation r) { | 1346 static intptr_t RepresentationBits(Representation r) { |
| 1347 switch (r) { | 1347 switch (r) { |
| 1348 case kTagged: | 1348 case kTagged: |
| 1349 return kBitsPerWord - 1; | 1349 return kBitsPerWord - 1; |
| 1350 case kUnboxedInt32: | 1350 case kUnboxedInt32: |
| 1351 case kUnboxedUint32: | 1351 case kUnboxedUint32: |
| 1352 return 32; | 1352 return 32; |
| 1353 case kUnboxedMint: | 1353 case kUnboxedInt64: |
| 1354 return 64; | 1354 return 64; |
| 1355 default: | 1355 default: |
| 1356 UNREACHABLE(); | 1356 UNREACHABLE(); |
| 1357 return 0; | 1357 return 0; |
| 1358 } | 1358 } |
| 1359 } | 1359 } |
| 1360 | 1360 |
| 1361 static int64_t RepresentationMask(Representation r) { | 1361 static int64_t RepresentationMask(Representation r) { |
| 1362 return static_cast<int64_t>(static_cast<uint64_t>(-1) >> | 1362 return static_cast<int64_t>(static_cast<uint64_t>(-1) >> |
| 1363 (64 - RepresentationBits(r))); | 1363 (64 - RepresentationBits(r))); |
| 1364 } | 1364 } |
| 1365 | 1365 |
| 1366 static bool ToIntegerConstant(Value* value, int64_t* result) { | 1366 static bool ToIntegerConstant(Value* value, int64_t* result) { |
| 1367 if (!value->BindsToConstant()) { | 1367 if (!value->BindsToConstant()) { |
| 1368 UnboxInstr* unbox = value->definition()->AsUnbox(); | 1368 UnboxInstr* unbox = value->definition()->AsUnbox(); |
| 1369 if (unbox != NULL) { | 1369 if (unbox != NULL) { |
| 1370 switch (unbox->representation()) { | 1370 switch (unbox->representation()) { |
| 1371 case kUnboxedDouble: | 1371 case kUnboxedDouble: |
| 1372 case kUnboxedMint: | 1372 case kUnboxedInt64: |
| 1373 return ToIntegerConstant(unbox->value(), result); | 1373 return ToIntegerConstant(unbox->value(), result); |
| 1374 | 1374 |
| 1375 case kUnboxedUint32: | 1375 case kUnboxedUint32: |
| 1376 if (ToIntegerConstant(unbox->value(), result)) { | 1376 if (ToIntegerConstant(unbox->value(), result)) { |
| 1377 *result &= RepresentationMask(kUnboxedUint32); | 1377 *result &= RepresentationMask(kUnboxedUint32); |
| 1378 return true; | 1378 return true; |
| 1379 } | 1379 } |
| 1380 break; | 1380 break; |
| 1381 | 1381 |
| 1382 // No need to handle Unbox<Int32>(Constant(C)) because it gets | 1382 // No need to handle Unbox<Int32>(Constant(C)) because it gets |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1514 UnaryIntegerOpInstr* op = NULL; | 1514 UnaryIntegerOpInstr* op = NULL; |
| 1515 switch (representation) { | 1515 switch (representation) { |
| 1516 case kTagged: | 1516 case kTagged: |
| 1517 op = new UnarySmiOpInstr(op_kind, value, deopt_id); | 1517 op = new UnarySmiOpInstr(op_kind, value, deopt_id); |
| 1518 break; | 1518 break; |
| 1519 case kUnboxedInt32: | 1519 case kUnboxedInt32: |
| 1520 return NULL; | 1520 return NULL; |
| 1521 case kUnboxedUint32: | 1521 case kUnboxedUint32: |
| 1522 op = new UnaryUint32OpInstr(op_kind, value, deopt_id); | 1522 op = new UnaryUint32OpInstr(op_kind, value, deopt_id); |
| 1523 break; | 1523 break; |
| 1524 case kUnboxedMint: | 1524 case kUnboxedInt64: |
| 1525 op = new UnaryMintOpInstr(op_kind, value, deopt_id); | 1525 op = new UnaryInt64OpInstr(op_kind, value, deopt_id); |
| 1526 break; | 1526 break; |
| 1527 default: | 1527 default: |
| 1528 UNREACHABLE(); | 1528 UNREACHABLE(); |
| 1529 return NULL; | 1529 return NULL; |
| 1530 } | 1530 } |
| 1531 | 1531 |
| 1532 if (op == NULL) { | 1532 if (op == NULL) { |
| 1533 return op; | 1533 return op; |
| 1534 } | 1534 } |
| 1535 | 1535 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1560 } | 1560 } |
| 1561 op = new BinaryInt32OpInstr(op_kind, left, right, deopt_id); | 1561 op = new BinaryInt32OpInstr(op_kind, left, right, deopt_id); |
| 1562 break; | 1562 break; |
| 1563 case kUnboxedUint32: | 1563 case kUnboxedUint32: |
| 1564 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | 1564 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { |
| 1565 op = new ShiftUint32OpInstr(op_kind, left, right, deopt_id); | 1565 op = new ShiftUint32OpInstr(op_kind, left, right, deopt_id); |
| 1566 } else { | 1566 } else { |
| 1567 op = new BinaryUint32OpInstr(op_kind, left, right, deopt_id); | 1567 op = new BinaryUint32OpInstr(op_kind, left, right, deopt_id); |
| 1568 } | 1568 } |
| 1569 break; | 1569 break; |
| 1570 case kUnboxedMint: | 1570 case kUnboxedInt64: |
| 1571 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | 1571 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { |
| 1572 op = new ShiftMintOpInstr(op_kind, left, right, deopt_id); | 1572 op = new ShiftInt64OpInstr(op_kind, left, right, deopt_id); |
| 1573 } else { | 1573 } else { |
| 1574 op = new BinaryMintOpInstr(op_kind, left, right, deopt_id); | 1574 op = new BinaryInt64OpInstr(op_kind, left, right, deopt_id); |
| 1575 } | 1575 } |
| 1576 break; | 1576 break; |
| 1577 default: | 1577 default: |
| 1578 UNREACHABLE(); | 1578 UNREACHABLE(); |
| 1579 return NULL; | 1579 return NULL; |
| 1580 } | 1580 } |
| 1581 | 1581 |
| 1582 if (!Range::IsUnknown(range)) { | 1582 if (!Range::IsUnknown(range)) { |
| 1583 op->set_range(*range); | 1583 op->set_range(*range); |
| 1584 } | 1584 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1596 switch (rep) { | 1596 switch (rep) { |
| 1597 case kTagged: // Smi case. | 1597 case kTagged: // Smi case. |
| 1598 return value.IsSmi(); | 1598 return value.IsSmi(); |
| 1599 | 1599 |
| 1600 case kUnboxedInt32: | 1600 case kUnboxedInt32: |
| 1601 if (value.IsSmi() || value.IsMint()) { | 1601 if (value.IsSmi() || value.IsMint()) { |
| 1602 return Utils::IsInt(32, value.AsInt64Value()); | 1602 return Utils::IsInt(32, value.AsInt64Value()); |
| 1603 } | 1603 } |
| 1604 return false; | 1604 return false; |
| 1605 | 1605 |
| 1606 case kUnboxedMint: | 1606 case kUnboxedInt64: |
| 1607 return value.IsSmi() || value.IsMint(); | 1607 return value.IsSmi() || value.IsMint(); |
| 1608 | 1608 |
| 1609 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported. | 1609 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported. |
| 1610 default: | 1610 default: |
| 1611 UNREACHABLE(); | 1611 UNREACHABLE(); |
| 1612 } | 1612 } |
| 1613 | 1613 |
| 1614 return false; | 1614 return false; |
| 1615 } | 1615 } |
| 1616 | 1616 |
| (...skipping 711 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2328 | 2328 |
| 2329 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { | 2329 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { |
| 2330 if (!HasUses()) return NULL; | 2330 if (!HasUses()) return NULL; |
| 2331 | 2331 |
| 2332 UnboxedIntConverterInstr* box_defn = | 2332 UnboxedIntConverterInstr* box_defn = |
| 2333 value()->definition()->AsUnboxedIntConverter(); | 2333 value()->definition()->AsUnboxedIntConverter(); |
| 2334 if ((box_defn != NULL) && (box_defn->representation() == from())) { | 2334 if ((box_defn != NULL) && (box_defn->representation() == from())) { |
| 2335 if (box_defn->from() == to()) { | 2335 if (box_defn->from() == to()) { |
| 2336 // Do not erase truncating conversions from 64-bit value to 32-bit values | 2336 // Do not erase truncating conversions from 64-bit value to 32-bit values |
| 2337 // because such conversions erase upper 32 bits. | 2337 // because such conversions erase upper 32 bits. |
| 2338 if ((box_defn->from() == kUnboxedMint) && box_defn->is_truncating()) { | 2338 if ((box_defn->from() == kUnboxedInt64) && box_defn->is_truncating()) { |
| 2339 return this; | 2339 return this; |
| 2340 } | 2340 } |
| 2341 return box_defn->value()->definition(); | 2341 return box_defn->value()->definition(); |
| 2342 } | 2342 } |
| 2343 | 2343 |
| 2344 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( | 2344 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( |
| 2345 box_defn->from(), representation(), box_defn->value()->CopyWithType(), | 2345 box_defn->from(), representation(), box_defn->value()->CopyWithType(), |
| 2346 (to() == kUnboxedInt32) ? GetDeoptId() : Thread::kNoDeoptId); | 2346 (to() == kUnboxedInt32) ? GetDeoptId() : Thread::kNoDeoptId); |
| 2347 if ((representation() == kUnboxedInt32) && is_truncating()) { | 2347 if ((representation() == kUnboxedInt32) && is_truncating()) { |
| 2348 converter->mark_truncating(); | 2348 converter->mark_truncating(); |
| 2349 } | 2349 } |
| 2350 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); | 2350 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
| 2351 return converter; | 2351 return converter; |
| 2352 } | 2352 } |
| 2353 | 2353 |
| 2354 UnboxInt64Instr* unbox_defn = value()->definition()->AsUnboxInt64(); | 2354 UnboxInt64Instr* unbox_defn = value()->definition()->AsUnboxInt64(); |
| 2355 if (unbox_defn != NULL && (from() == kUnboxedMint) && | 2355 if (unbox_defn != NULL && (from() == kUnboxedInt64) && |
| 2356 (to() == kUnboxedInt32) && unbox_defn->HasOnlyInputUse(value())) { | 2356 (to() == kUnboxedInt32) && unbox_defn->HasOnlyInputUse(value())) { |
| 2357 // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter | 2357 // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter |
| 2358 // and code path that unboxes Mint into Int32. We should just schedule | 2358 // and code path that unboxes Mint into Int32. We should just schedule |
| 2359 // these instructions close to each other instead of fusing them. | 2359 // these instructions close to each other instead of fusing them. |
| 2360 Definition* replacement = | 2360 Definition* replacement = |
| 2361 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate | 2361 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate |
| 2362 : UnboxInt32Instr::kNoTruncation, | 2362 : UnboxInt32Instr::kNoTruncation, |
| 2363 unbox_defn->value()->CopyWithType(), GetDeoptId()); | 2363 unbox_defn->value()->CopyWithType(), GetDeoptId()); |
| 2364 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 2364 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
| 2365 return replacement; | 2365 return replacement; |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2705 } | 2705 } |
| 2706 | 2706 |
| 2707 BoxInstr* BoxInstr::Create(Representation from, Value* value) { | 2707 BoxInstr* BoxInstr::Create(Representation from, Value* value) { |
| 2708 switch (from) { | 2708 switch (from) { |
| 2709 case kUnboxedInt32: | 2709 case kUnboxedInt32: |
| 2710 return new BoxInt32Instr(value); | 2710 return new BoxInt32Instr(value); |
| 2711 | 2711 |
| 2712 case kUnboxedUint32: | 2712 case kUnboxedUint32: |
| 2713 return new BoxUint32Instr(value); | 2713 return new BoxUint32Instr(value); |
| 2714 | 2714 |
| 2715 case kUnboxedMint: | 2715 case kUnboxedInt64: |
| 2716 return new BoxInt64Instr(value); | 2716 return new BoxInt64Instr(value); |
| 2717 | 2717 |
| 2718 case kUnboxedDouble: | 2718 case kUnboxedDouble: |
| 2719 case kUnboxedFloat32x4: | 2719 case kUnboxedFloat32x4: |
| 2720 case kUnboxedFloat64x2: | 2720 case kUnboxedFloat64x2: |
| 2721 case kUnboxedInt32x4: | 2721 case kUnboxedInt32x4: |
| 2722 return new BoxInstr(from, value); | 2722 return new BoxInstr(from, value); |
| 2723 | 2723 |
| 2724 default: | 2724 default: |
| 2725 UNREACHABLE(); | 2725 UNREACHABLE(); |
| 2726 return NULL; | 2726 return NULL; |
| 2727 } | 2727 } |
| 2728 } | 2728 } |
| 2729 | 2729 |
| 2730 UnboxInstr* UnboxInstr::Create(Representation to, | 2730 UnboxInstr* UnboxInstr::Create(Representation to, |
| 2731 Value* value, | 2731 Value* value, |
| 2732 intptr_t deopt_id) { | 2732 intptr_t deopt_id) { |
| 2733 switch (to) { | 2733 switch (to) { |
| 2734 case kUnboxedInt32: | 2734 case kUnboxedInt32: |
| 2735 return new UnboxInt32Instr(UnboxInt32Instr::kNoTruncation, value, | 2735 return new UnboxInt32Instr(UnboxInt32Instr::kNoTruncation, value, |
| 2736 deopt_id); | 2736 deopt_id); |
| 2737 | 2737 |
| 2738 case kUnboxedUint32: | 2738 case kUnboxedUint32: |
| 2739 return new UnboxUint32Instr(value, deopt_id); | 2739 return new UnboxUint32Instr(value, deopt_id); |
| 2740 | 2740 |
| 2741 case kUnboxedMint: | 2741 case kUnboxedInt64: |
| 2742 return new UnboxInt64Instr(value, deopt_id); | 2742 return new UnboxInt64Instr(value, deopt_id); |
| 2743 | 2743 |
| 2744 case kUnboxedDouble: | 2744 case kUnboxedDouble: |
| 2745 case kUnboxedFloat32x4: | 2745 case kUnboxedFloat32x4: |
| 2746 case kUnboxedFloat64x2: | 2746 case kUnboxedFloat64x2: |
| 2747 case kUnboxedInt32x4: | 2747 case kUnboxedInt32x4: |
| 2748 return new UnboxInstr(to, value, deopt_id); | 2748 return new UnboxInstr(to, value, deopt_id); |
| 2749 | 2749 |
| 2750 default: | 2750 default: |
| 2751 UNREACHABLE(); | 2751 UNREACHABLE(); |
| 2752 return NULL; | 2752 return NULL; |
| 2753 } | 2753 } |
| 2754 } | 2754 } |
| 2755 | 2755 |
| 2756 bool UnboxInstr::CanConvertSmi() const { | 2756 bool UnboxInstr::CanConvertSmi() const { |
| 2757 switch (representation()) { | 2757 switch (representation()) { |
| 2758 case kUnboxedDouble: | 2758 case kUnboxedDouble: |
| 2759 case kUnboxedMint: | 2759 case kUnboxedInt64: |
| 2760 return true; | 2760 return true; |
| 2761 | 2761 |
| 2762 case kUnboxedFloat32x4: | 2762 case kUnboxedFloat32x4: |
| 2763 case kUnboxedFloat64x2: | 2763 case kUnboxedFloat64x2: |
| 2764 case kUnboxedInt32x4: | 2764 case kUnboxedInt32x4: |
| 2765 return false; | 2765 return false; |
| 2766 | 2766 |
| 2767 default: | 2767 default: |
| 2768 UNREACHABLE(); | 2768 UNREACHABLE(); |
| 2769 return false; | 2769 return false; |
| (...skipping 1287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4057 "native function '%s' (%" Pd " arguments) cannot be found", | 4057 "native function '%s' (%" Pd " arguments) cannot be found", |
| 4058 native_name().ToCString(), function().NumParameters()); | 4058 native_name().ToCString(), function().NumParameters()); |
| 4059 } | 4059 } |
| 4060 set_is_auto_scope(auto_setup_scope); | 4060 set_is_auto_scope(auto_setup_scope); |
| 4061 set_native_c_function(native_function); | 4061 set_native_c_function(native_function); |
| 4062 } | 4062 } |
| 4063 | 4063 |
| 4064 #undef __ | 4064 #undef __ |
| 4065 | 4065 |
| 4066 } // namespace dart | 4066 } // namespace dart |
| OLD | NEW |