| 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/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); | 29 DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis."); |
| 30 DEFINE_FLAG(bool, trace_constant_propagation, false, | 30 DEFINE_FLAG(bool, trace_constant_propagation, false, |
| 31 "Print constant propagation and useless code elimination."); | 31 "Print constant propagation and useless code elimination."); |
| 32 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | 32 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); |
| 33 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); | 33 DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress"); |
| 34 DEFINE_FLAG(bool, truncating_left_shift, true, | 34 DEFINE_FLAG(bool, truncating_left_shift, true, |
| 35 "Optimize left shift to truncate if possible"); | 35 "Optimize left shift to truncate if possible"); |
| 36 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); | 36 DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis."); |
| 37 DEFINE_FLAG(bool, trace_load_optimization, false, | 37 DEFINE_FLAG(bool, trace_load_optimization, false, |
| 38 "Print live sets for load optimization pass."); | 38 "Print live sets for load optimization pass."); |
| 39 DEFINE_FLAG(bool, enable_simd_inline, true, |
| 40 "Enable inlining of SIMD related method calls."); |
| 39 DECLARE_FLAG(bool, eliminate_type_checks); | 41 DECLARE_FLAG(bool, eliminate_type_checks); |
| 40 DECLARE_FLAG(bool, enable_type_checks); | 42 DECLARE_FLAG(bool, enable_type_checks); |
| 41 DECLARE_FLAG(bool, trace_type_check_elimination); | 43 DECLARE_FLAG(bool, trace_type_check_elimination); |
| 42 | 44 |
| 43 | 45 |
| 46 static bool ShouldInlineSimd() { |
| 47 #if defined(TARGET_ARCH_MIPS) |
| 48 return false; |
| 49 #endif |
| 50 return FLAG_enable_simd_inline; |
| 51 } |
| 52 |
| 53 |
| 44 // Optimize instance calls using ICData. | 54 // Optimize instance calls using ICData. |
| 45 void FlowGraphOptimizer::ApplyICData() { | 55 void FlowGraphOptimizer::ApplyICData() { |
| 46 VisitBlocks(); | 56 VisitBlocks(); |
| 47 } | 57 } |
| 48 | 58 |
| 49 | 59 |
| 50 // Optimize instance calls using cid. | 60 // Optimize instance calls using cid. |
| 51 // Attempts to convert an instance call (IC call) using propagated class-ids, | 61 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 52 // e.g., receiver class id, guarded-cid. | 62 // e.g., receiver class id, guarded-cid. |
| 53 void FlowGraphOptimizer::ApplyClassIds() { | 63 void FlowGraphOptimizer::ApplyClassIds() { |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 // Returns true if phi's representation was changed. | 443 // Returns true if phi's representation was changed. |
| 434 static bool UnboxPhi(PhiInstr* phi) { | 444 static bool UnboxPhi(PhiInstr* phi) { |
| 435 Representation current = phi->representation(); | 445 Representation current = phi->representation(); |
| 436 Representation unboxed = current; | 446 Representation unboxed = current; |
| 437 | 447 |
| 438 switch (phi->Type()->ToCid()) { | 448 switch (phi->Type()->ToCid()) { |
| 439 case kDoubleCid: | 449 case kDoubleCid: |
| 440 unboxed = kUnboxedDouble; | 450 unboxed = kUnboxedDouble; |
| 441 break; | 451 break; |
| 442 case kFloat32x4Cid: | 452 case kFloat32x4Cid: |
| 443 unboxed = kUnboxedFloat32x4; | 453 if (ShouldInlineSimd()) { |
| 454 unboxed = kUnboxedFloat32x4; |
| 455 } |
| 444 break; | 456 break; |
| 445 case kUint32x4Cid: | 457 case kUint32x4Cid: |
| 446 unboxed = kUnboxedUint32x4; | 458 if (ShouldInlineSimd()) { |
| 459 unboxed = kUnboxedUint32x4; |
| 460 } |
| 447 break; | 461 break; |
| 448 } | 462 } |
| 449 | 463 |
| 450 if (unboxed != current) { | 464 if (unboxed != current) { |
| 451 phi->set_representation(unboxed); | 465 phi->set_representation(unboxed); |
| 452 return true; | 466 return true; |
| 453 } | 467 } |
| 454 | 468 |
| 455 return false; | 469 return false; |
| 456 } | 470 } |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 813 case kTypedDataFloat64ArrayCid: { | 827 case kTypedDataFloat64ArrayCid: { |
| 814 // Check that value is always double. | 828 // Check that value is always double. |
| 815 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 829 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 816 if ((value_check.NumberOfChecks() != 1) || | 830 if ((value_check.NumberOfChecks() != 1) || |
| 817 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { | 831 (value_check.GetReceiverClassIdAt(0) != kDoubleCid)) { |
| 818 return false; | 832 return false; |
| 819 } | 833 } |
| 820 break; | 834 break; |
| 821 } | 835 } |
| 822 case kTypedDataFloat32x4ArrayCid: { | 836 case kTypedDataFloat32x4ArrayCid: { |
| 837 if (!ShouldInlineSimd()) { |
| 838 return false; |
| 839 } |
| 823 // Check that value is always a Float32x4. | 840 // Check that value is always a Float32x4. |
| 824 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); | 841 value_check = call->ic_data()->AsUnaryClassChecksForArgNr(2); |
| 825 if ((value_check.NumberOfChecks() != 1) || | 842 if ((value_check.NumberOfChecks() != 1) || |
| 826 (value_check.GetReceiverClassIdAt(0) != kFloat32x4Cid)) { | 843 (value_check.GetReceiverClassIdAt(0) != kFloat32x4Cid)) { |
| 827 return false; | 844 return false; |
| 828 } | 845 } |
| 829 } | 846 } |
| 830 break; | 847 break; |
| 831 default: | 848 default: |
| 832 // TODO(fschneider): Add support for other array types. | 849 // TODO(fschneider): Add support for other array types. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 962 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 946 const intptr_t class_id = ReceiverClassId(call); | 963 const intptr_t class_id = ReceiverClassId(call); |
| 947 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. | 964 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. |
| 948 intptr_t deopt_id = Isolate::kNoDeoptId; | 965 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 949 switch (class_id) { | 966 switch (class_id) { |
| 950 case kArrayCid: | 967 case kArrayCid: |
| 951 case kImmutableArrayCid: | 968 case kImmutableArrayCid: |
| 952 case kGrowableObjectArrayCid: | 969 case kGrowableObjectArrayCid: |
| 953 case kTypedDataFloat32ArrayCid: | 970 case kTypedDataFloat32ArrayCid: |
| 954 case kTypedDataFloat64ArrayCid: | 971 case kTypedDataFloat64ArrayCid: |
| 955 case kTypedDataFloat32x4ArrayCid: | |
| 956 case kTypedDataInt8ArrayCid: | 972 case kTypedDataInt8ArrayCid: |
| 957 case kTypedDataUint8ArrayCid: | 973 case kTypedDataUint8ArrayCid: |
| 958 case kTypedDataUint8ClampedArrayCid: | 974 case kTypedDataUint8ClampedArrayCid: |
| 959 case kExternalTypedDataUint8ArrayCid: | 975 case kExternalTypedDataUint8ArrayCid: |
| 960 case kExternalTypedDataUint8ClampedArrayCid: | 976 case kExternalTypedDataUint8ClampedArrayCid: |
| 961 case kTypedDataInt16ArrayCid: | 977 case kTypedDataInt16ArrayCid: |
| 962 case kTypedDataUint16ArrayCid: | 978 case kTypedDataUint16ArrayCid: |
| 963 break; | 979 break; |
| 980 case kTypedDataFloat32x4ArrayCid: |
| 981 if (!ShouldInlineSimd()) { |
| 982 return false; |
| 983 } |
| 984 break; |
| 964 case kTypedDataInt32ArrayCid: | 985 case kTypedDataInt32ArrayCid: |
| 965 case kTypedDataUint32ArrayCid: { | 986 case kTypedDataUint32ArrayCid: { |
| 966 if (!CanUnboxInt32()) return false; | 987 if (!CanUnboxInt32()) return false; |
| 967 | 988 |
| 968 // Set deopt_id if we can optimistically assume that the result is Smi. | 989 // Set deopt_id if we can optimistically assume that the result is Smi. |
| 969 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | 990 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
| 970 ASSERT(call->HasICData()); | 991 ASSERT(call->HasICData()); |
| 971 const ICData& ic_data = *call->ic_data(); | 992 const ICData& ic_data = *call->ic_data(); |
| 972 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | 993 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| 973 call->deopt_id() : Isolate::kNoDeoptId; | 994 call->deopt_id() : Isolate::kNoDeoptId; |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 new ShiftMintOpInstr(op_kind, new Value(left), new Value(right), | 1145 new ShiftMintOpInstr(op_kind, new Value(left), new Value(right), |
| 1125 call->deopt_id()); | 1146 call->deopt_id()); |
| 1126 ReplaceCall(call, shift_op); | 1147 ReplaceCall(call, shift_op); |
| 1127 } else { | 1148 } else { |
| 1128 BinaryMintOpInstr* bin_op = | 1149 BinaryMintOpInstr* bin_op = |
| 1129 new BinaryMintOpInstr(op_kind, new Value(left), new Value(right), | 1150 new BinaryMintOpInstr(op_kind, new Value(left), new Value(right), |
| 1130 call->deopt_id()); | 1151 call->deopt_id()); |
| 1131 ReplaceCall(call, bin_op); | 1152 ReplaceCall(call, bin_op); |
| 1132 } | 1153 } |
| 1133 } else if (operands_type == kFloat32x4Cid) { | 1154 } else if (operands_type == kFloat32x4Cid) { |
| 1134 // Type check left. | 1155 return InlineFloat32x4BinaryOp(call, op_kind); |
| 1135 AddCheckClass(left, | |
| 1136 ICData::ZoneHandle( | |
| 1137 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 1138 call->deopt_id(), | |
| 1139 call->env(), | |
| 1140 call); | |
| 1141 // Type check right. | |
| 1142 AddCheckClass(right, | |
| 1143 ICData::ZoneHandle( | |
| 1144 call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1145 call->deopt_id(), | |
| 1146 call->env(), | |
| 1147 call); | |
| 1148 // Replace call. | |
| 1149 BinaryFloat32x4OpInstr* float32x4_bin_op = | |
| 1150 new BinaryFloat32x4OpInstr(op_kind, new Value(left), new Value(right), | |
| 1151 call->deopt_id()); | |
| 1152 ReplaceCall(call, float32x4_bin_op); | |
| 1153 } else if (operands_type == kUint32x4Cid) { | 1156 } else if (operands_type == kUint32x4Cid) { |
| 1154 // Type check left. | 1157 return InlineUint32x4BinaryOp(call, op_kind); |
| 1155 AddCheckClass(left, | |
| 1156 ICData::ZoneHandle( | |
| 1157 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 1158 call->deopt_id(), | |
| 1159 call->env(), | |
| 1160 call); | |
| 1161 // Type check right. | |
| 1162 AddCheckClass(right, | |
| 1163 ICData::ZoneHandle( | |
| 1164 call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1165 call->deopt_id(), | |
| 1166 call->env(), | |
| 1167 call); | |
| 1168 // Replace call. | |
| 1169 BinaryUint32x4OpInstr* uint32x4_bin_op = | |
| 1170 new BinaryUint32x4OpInstr(op_kind, new Value(left), new Value(right), | |
| 1171 call->deopt_id()); | |
| 1172 ReplaceCall(call, uint32x4_bin_op); | |
| 1173 } else if (op_kind == Token::kMOD) { | 1158 } else if (op_kind == Token::kMOD) { |
| 1174 // TODO(vegorov): implement fast path code for modulo. | 1159 // TODO(vegorov): implement fast path code for modulo. |
| 1175 ASSERT(operands_type == kSmiCid); | 1160 ASSERT(operands_type == kSmiCid); |
| 1176 if (!right->IsConstant()) return false; | 1161 if (!right->IsConstant()) return false; |
| 1177 const Object& obj = right->AsConstant()->value(); | 1162 const Object& obj = right->AsConstant()->value(); |
| 1178 if (!obj.IsSmi()) return false; | 1163 if (!obj.IsSmi()) return false; |
| 1179 const intptr_t value = Smi::Cast(obj).Value(); | 1164 const intptr_t value = Smi::Cast(obj).Value(); |
| 1180 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; | 1165 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; |
| 1181 | 1166 |
| 1182 // Insert smi check and attach a copy of the original environment | 1167 // Insert smi check and attach a copy of the original environment |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1458 return GrowableObjectArray::length_offset(); | 1443 return GrowableObjectArray::length_offset(); |
| 1459 default: | 1444 default: |
| 1460 UNREACHABLE(); | 1445 UNREACHABLE(); |
| 1461 return 0; | 1446 return 0; |
| 1462 } | 1447 } |
| 1463 } | 1448 } |
| 1464 | 1449 |
| 1465 | 1450 |
| 1466 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, | 1451 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, |
| 1467 MethodRecognizer::Kind getter) { | 1452 MethodRecognizer::Kind getter) { |
| 1453 if (!ShouldInlineSimd()) { |
| 1454 return false; |
| 1455 } |
| 1468 AddCheckClass(call->ArgumentAt(0), | 1456 AddCheckClass(call->ArgumentAt(0), |
| 1469 ICData::ZoneHandle( | 1457 ICData::ZoneHandle( |
| 1470 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1458 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1471 call->deopt_id(), | 1459 call->deopt_id(), |
| 1472 call->env(), | 1460 call->env(), |
| 1473 call); | 1461 call); |
| 1474 intptr_t mask = 0; | 1462 intptr_t mask = 0; |
| 1475 if (getter == MethodRecognizer::kFloat32x4Shuffle) { | 1463 if (getter == MethodRecognizer::kFloat32x4Shuffle) { |
| 1476 ASSERT(call->ArgumentCount() == 2); | 1464 ASSERT(call->ArgumentCount() == 2); |
| 1477 // Extract shuffle mask. | 1465 // Extract shuffle mask. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1489 new Value(call->ArgumentAt(0)), | 1477 new Value(call->ArgumentAt(0)), |
| 1490 mask, | 1478 mask, |
| 1491 call->deopt_id()); | 1479 call->deopt_id()); |
| 1492 ReplaceCall(call, instr); | 1480 ReplaceCall(call, instr); |
| 1493 return true; | 1481 return true; |
| 1494 } | 1482 } |
| 1495 | 1483 |
| 1496 | 1484 |
| 1497 bool FlowGraphOptimizer::InlineUint32x4Getter(InstanceCallInstr* call, | 1485 bool FlowGraphOptimizer::InlineUint32x4Getter(InstanceCallInstr* call, |
| 1498 MethodRecognizer::Kind getter) { | 1486 MethodRecognizer::Kind getter) { |
| 1487 if (!ShouldInlineSimd()) { |
| 1488 return false; |
| 1489 } |
| 1499 AddCheckClass(call->ArgumentAt(0), | 1490 AddCheckClass(call->ArgumentAt(0), |
| 1500 ICData::ZoneHandle( | 1491 ICData::ZoneHandle( |
| 1501 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1492 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1502 call->deopt_id(), | 1493 call->deopt_id(), |
| 1503 call->env(), | 1494 call->env(), |
| 1504 call); | 1495 call); |
| 1505 Uint32x4GetFlagInstr* instr = new Uint32x4GetFlagInstr( | 1496 Uint32x4GetFlagInstr* instr = new Uint32x4GetFlagInstr( |
| 1506 getter, | 1497 getter, |
| 1507 new Value(call->ArgumentAt(0)), | 1498 new Value(call->ArgumentAt(0)), |
| 1508 call->deopt_id()); | 1499 call->deopt_id()); |
| 1509 ReplaceCall(call, instr); | 1500 ReplaceCall(call, instr); |
| 1510 return true; | 1501 return true; |
| 1511 } | 1502 } |
| 1512 | 1503 |
| 1513 | 1504 |
| 1505 bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
| 1506 Token::Kind op_kind) { |
| 1507 if (!ShouldInlineSimd()) { |
| 1508 return false; |
| 1509 } |
| 1510 ASSERT(call->ArgumentCount() == 2); |
| 1511 Definition* left = call->ArgumentAt(0); |
| 1512 Definition* right = call->ArgumentAt(1); |
| 1513 // Type check left. |
| 1514 AddCheckClass(left, |
| 1515 ICData::ZoneHandle( |
| 1516 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1517 call->deopt_id(), |
| 1518 call->env(), |
| 1519 call); |
| 1520 // Type check right. |
| 1521 AddCheckClass(right, |
| 1522 ICData::ZoneHandle( |
| 1523 call->ic_data()->AsUnaryClassChecksForArgNr(1)), |
| 1524 call->deopt_id(), |
| 1525 call->env(), |
| 1526 call); |
| 1527 // Replace call. |
| 1528 BinaryFloat32x4OpInstr* float32x4_bin_op = |
| 1529 new BinaryFloat32x4OpInstr(op_kind, new Value(left), new Value(right), |
| 1530 call->deopt_id()); |
| 1531 ReplaceCall(call, float32x4_bin_op); |
| 1532 |
| 1533 return true; |
| 1534 } |
| 1535 |
| 1536 |
| 1537 bool FlowGraphOptimizer::InlineUint32x4BinaryOp(InstanceCallInstr* call, |
| 1538 Token::Kind op_kind) { |
| 1539 if (!ShouldInlineSimd()) { |
| 1540 return false; |
| 1541 } |
| 1542 ASSERT(call->ArgumentCount() == 2); |
| 1543 Definition* left = call->ArgumentAt(0); |
| 1544 Definition* right = call->ArgumentAt(1); |
| 1545 // Type check left. |
| 1546 AddCheckClass(left, |
| 1547 ICData::ZoneHandle( |
| 1548 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1549 call->deopt_id(), |
| 1550 call->env(), |
| 1551 call); |
| 1552 // Type check right. |
| 1553 AddCheckClass(right, |
| 1554 ICData::ZoneHandle( |
| 1555 call->ic_data()->AsUnaryClassChecksForArgNr(1)), |
| 1556 call->deopt_id(), |
| 1557 call->env(), |
| 1558 call); |
| 1559 // Replace call. |
| 1560 BinaryUint32x4OpInstr* uint32x4_bin_op = |
| 1561 new BinaryUint32x4OpInstr(op_kind, new Value(left), new Value(right), |
| 1562 call->deopt_id()); |
| 1563 ReplaceCall(call, uint32x4_bin_op); |
| 1564 return true; |
| 1565 } |
| 1566 |
| 1567 |
| 1514 // Only unique implicit instance getters can be currently handled. | 1568 // Only unique implicit instance getters can be currently handled. |
| 1515 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { | 1569 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
| 1516 ASSERT(call->HasICData()); | 1570 ASSERT(call->HasICData()); |
| 1517 const ICData& ic_data = *call->ic_data(); | 1571 const ICData& ic_data = *call->ic_data(); |
| 1518 if (ic_data.NumberOfChecks() == 0) { | 1572 if (ic_data.NumberOfChecks() == 0) { |
| 1519 // No type feedback collected. | 1573 // No type feedback collected. |
| 1520 return false; | 1574 return false; |
| 1521 } | 1575 } |
| 1522 Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 1576 Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
| 1523 if (target.kind() == RawFunction::kImplicitGetter) { | 1577 if (target.kind() == RawFunction::kImplicitGetter) { |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1894 return TryInlineFloat32x4Method(call, recognized_kind); | 1948 return TryInlineFloat32x4Method(call, recognized_kind); |
| 1895 } | 1949 } |
| 1896 | 1950 |
| 1897 if ((class_ids[0] == kUint32x4Cid) && (ic_data.NumberOfChecks() == 1)) { | 1951 if ((class_ids[0] == kUint32x4Cid) && (ic_data.NumberOfChecks() == 1)) { |
| 1898 return TryInlineUint32x4Method(call, recognized_kind); | 1952 return TryInlineUint32x4Method(call, recognized_kind); |
| 1899 } | 1953 } |
| 1900 return false; | 1954 return false; |
| 1901 } | 1955 } |
| 1902 | 1956 |
| 1903 | 1957 |
| 1958 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( |
| 1959 StaticCallInstr* call, |
| 1960 MethodRecognizer::Kind recognized_kind) { |
| 1961 if (!ShouldInlineSimd()) { |
| 1962 return false; |
| 1963 } |
| 1964 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { |
| 1965 Float32x4ZeroInstr* zero = new Float32x4ZeroInstr(call->deopt_id()); |
| 1966 ReplaceCall(call, zero); |
| 1967 return true; |
| 1968 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { |
| 1969 Float32x4SplatInstr* splat = |
| 1970 new Float32x4SplatInstr(new Value(call->ArgumentAt(1)), |
| 1971 call->deopt_id()); |
| 1972 ReplaceCall(call, splat); |
| 1973 return true; |
| 1974 } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) { |
| 1975 Float32x4ConstructorInstr* con = |
| 1976 new Float32x4ConstructorInstr(new Value(call->ArgumentAt(1)), |
| 1977 new Value(call->ArgumentAt(2)), |
| 1978 new Value(call->ArgumentAt(3)), |
| 1979 new Value(call->ArgumentAt(4)), |
| 1980 call->deopt_id()); |
| 1981 ReplaceCall(call, con); |
| 1982 return true; |
| 1983 } |
| 1984 return false; |
| 1985 } |
| 1986 |
| 1987 |
| 1988 bool FlowGraphOptimizer::TryInlineUint32x4Constructor( |
| 1989 StaticCallInstr* call, |
| 1990 MethodRecognizer::Kind recognized_kind) { |
| 1991 if (!ShouldInlineSimd()) { |
| 1992 return false; |
| 1993 } |
| 1994 if (recognized_kind == MethodRecognizer::kUint32x4BoolConstructor) { |
| 1995 Uint32x4BoolConstructorInstr* con = new Uint32x4BoolConstructorInstr( |
| 1996 new Value(call->ArgumentAt(1)), |
| 1997 new Value(call->ArgumentAt(2)), |
| 1998 new Value(call->ArgumentAt(3)), |
| 1999 new Value(call->ArgumentAt(4)), |
| 2000 call->deopt_id()); |
| 2001 ReplaceCall(call, con); |
| 2002 return true; |
| 2003 } |
| 2004 return false; |
| 2005 } |
| 2006 |
| 2007 |
| 1904 bool FlowGraphOptimizer::TryInlineFloat32x4Method( | 2008 bool FlowGraphOptimizer::TryInlineFloat32x4Method( |
| 1905 InstanceCallInstr* call, | 2009 InstanceCallInstr* call, |
| 1906 MethodRecognizer::Kind recognized_kind) { | 2010 MethodRecognizer::Kind recognized_kind) { |
| 2011 if (!ShouldInlineSimd()) { |
| 2012 return false; |
| 2013 } |
| 1907 ASSERT(call->HasICData()); | 2014 ASSERT(call->HasICData()); |
| 1908 switch (recognized_kind) { | 2015 switch (recognized_kind) { |
| 1909 case MethodRecognizer::kFloat32x4Equal: | 2016 case MethodRecognizer::kFloat32x4Equal: |
| 1910 case MethodRecognizer::kFloat32x4GreaterThan: | 2017 case MethodRecognizer::kFloat32x4GreaterThan: |
| 1911 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: | 2018 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: |
| 1912 case MethodRecognizer::kFloat32x4LessThan: | 2019 case MethodRecognizer::kFloat32x4LessThan: |
| 1913 case MethodRecognizer::kFloat32x4LessThanOrEqual: | 2020 case MethodRecognizer::kFloat32x4LessThanOrEqual: |
| 1914 case MethodRecognizer::kFloat32x4NotEqual: { | 2021 case MethodRecognizer::kFloat32x4NotEqual: { |
| 1915 Definition* left = call->ArgumentAt(0); | 2022 Definition* left = call->ArgumentAt(0); |
| 1916 Definition* right = call->ArgumentAt(1); | 2023 Definition* right = call->ArgumentAt(1); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2053 } | 2160 } |
| 2054 default: | 2161 default: |
| 2055 return false; | 2162 return false; |
| 2056 } | 2163 } |
| 2057 } | 2164 } |
| 2058 | 2165 |
| 2059 | 2166 |
| 2060 bool FlowGraphOptimizer::TryInlineUint32x4Method( | 2167 bool FlowGraphOptimizer::TryInlineUint32x4Method( |
| 2061 InstanceCallInstr* call, | 2168 InstanceCallInstr* call, |
| 2062 MethodRecognizer::Kind recognized_kind) { | 2169 MethodRecognizer::Kind recognized_kind) { |
| 2170 if (!ShouldInlineSimd()) { |
| 2171 return false; |
| 2172 } |
| 2063 ASSERT(call->HasICData()); | 2173 ASSERT(call->HasICData()); |
| 2064 switch (recognized_kind) { | 2174 switch (recognized_kind) { |
| 2065 case MethodRecognizer::kUint32x4Select: { | 2175 case MethodRecognizer::kUint32x4Select: { |
| 2066 Definition* mask = call->ArgumentAt(0); | 2176 Definition* mask = call->ArgumentAt(0); |
| 2067 Definition* trueValue = call->ArgumentAt(1); | 2177 Definition* trueValue = call->ArgumentAt(1); |
| 2068 Definition* falseValue = call->ArgumentAt(2); | 2178 Definition* falseValue = call->ArgumentAt(2); |
| 2069 // Type check left. | 2179 // Type check left. |
| 2070 AddCheckClass(mask, | 2180 AddCheckClass(mask, |
| 2071 ICData::ZoneHandle( | 2181 ICData::ZoneHandle( |
| 2072 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 2182 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2119 default: | 2229 default: |
| 2120 return false; | 2230 return false; |
| 2121 } | 2231 } |
| 2122 } | 2232 } |
| 2123 | 2233 |
| 2124 | 2234 |
| 2125 bool FlowGraphOptimizer::BuildByteArrayViewLoad( | 2235 bool FlowGraphOptimizer::BuildByteArrayViewLoad( |
| 2126 InstanceCallInstr* call, | 2236 InstanceCallInstr* call, |
| 2127 intptr_t receiver_cid, | 2237 intptr_t receiver_cid, |
| 2128 intptr_t view_cid) { | 2238 intptr_t view_cid) { |
| 2239 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { |
| 2240 return false; |
| 2241 } |
| 2242 |
| 2129 Definition* array = call->ArgumentAt(0); | 2243 Definition* array = call->ArgumentAt(0); |
| 2130 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); | 2244 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); |
| 2131 | 2245 |
| 2132 // Optimistically build a smi-checked load for Int32 and Uint32 | 2246 // Optimistically build a smi-checked load for Int32 and Uint32 |
| 2133 // loads on ia32 like we do for normal array loads, and only revert to | 2247 // loads on ia32 like we do for normal array loads, and only revert to |
| 2134 // mint case after deoptimizing here. | 2248 // mint case after deoptimizing here. |
| 2135 intptr_t deopt_id = Isolate::kNoDeoptId; | 2249 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 2136 if ((view_cid == kTypedDataInt32ArrayCid || | 2250 if ((view_cid == kTypedDataInt32ArrayCid || |
| 2137 view_cid == kTypedDataUint32ArrayCid) && | 2251 view_cid == kTypedDataUint32ArrayCid) && |
| 2138 call->ic_data()->deopt_reason() == kDeoptUnknown) { | 2252 call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 2139 deopt_id = call->deopt_id(); | 2253 deopt_id = call->deopt_id(); |
| 2140 } | 2254 } |
| 2141 Definition* byte_index = call->ArgumentAt(1); | 2255 Definition* byte_index = call->ArgumentAt(1); |
| 2142 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), | 2256 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), |
| 2143 new Value(byte_index), | 2257 new Value(byte_index), |
| 2144 1, // Index scale. | 2258 1, // Index scale. |
| 2145 view_cid, | 2259 view_cid, |
| 2146 deopt_id); | 2260 deopt_id); |
| 2147 ReplaceCall(call, array_op); | 2261 ReplaceCall(call, array_op); |
| 2148 return true; | 2262 return true; |
| 2149 } | 2263 } |
| 2150 | 2264 |
| 2151 | 2265 |
| 2152 bool FlowGraphOptimizer::BuildByteArrayViewStore( | 2266 bool FlowGraphOptimizer::BuildByteArrayViewStore( |
| 2153 InstanceCallInstr* call, | 2267 InstanceCallInstr* call, |
| 2154 intptr_t receiver_cid, | 2268 intptr_t receiver_cid, |
| 2155 intptr_t view_cid) { | 2269 intptr_t view_cid) { |
| 2270 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { |
| 2271 return false; |
| 2272 } |
| 2156 Definition* array = call->ArgumentAt(0); | 2273 Definition* array = call->ArgumentAt(0); |
| 2157 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); | 2274 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); |
| 2158 ICData& value_check = ICData::ZoneHandle(); | 2275 ICData& value_check = ICData::ZoneHandle(); |
| 2159 switch (view_cid) { | 2276 switch (view_cid) { |
| 2160 case kTypedDataInt8ArrayCid: | 2277 case kTypedDataInt8ArrayCid: |
| 2161 case kTypedDataUint8ArrayCid: | 2278 case kTypedDataUint8ArrayCid: |
| 2162 case kTypedDataUint8ClampedArrayCid: | 2279 case kTypedDataUint8ClampedArrayCid: |
| 2163 case kExternalTypedDataUint8ArrayCid: | 2280 case kExternalTypedDataUint8ArrayCid: |
| 2164 case kExternalTypedDataUint8ClampedArrayCid: | 2281 case kExternalTypedDataUint8ClampedArrayCid: |
| 2165 case kTypedDataInt16ArrayCid: | 2282 case kTypedDataInt16ArrayCid: |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2496 } | 2613 } |
| 2497 | 2614 |
| 2498 | 2615 |
| 2499 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2616 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 2500 MethodRecognizer::Kind recognized_kind = | 2617 MethodRecognizer::Kind recognized_kind = |
| 2501 MethodRecognizer::RecognizeKind(call->function()); | 2618 MethodRecognizer::RecognizeKind(call->function()); |
| 2502 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 2619 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 2503 MathSqrtInstr* sqrt = | 2620 MathSqrtInstr* sqrt = |
| 2504 new MathSqrtInstr(new Value(call->ArgumentAt(0)), call->deopt_id()); | 2621 new MathSqrtInstr(new Value(call->ArgumentAt(0)), call->deopt_id()); |
| 2505 ReplaceCall(call, sqrt); | 2622 ReplaceCall(call, sqrt); |
| 2506 } else if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | 2623 } else if ((recognized_kind == MethodRecognizer::kFloat32x4Zero) || |
| 2507 Float32x4ZeroInstr* zero = new Float32x4ZeroInstr(call->deopt_id()); | 2624 (recognized_kind == MethodRecognizer::kFloat32x4Splat) || |
| 2508 ReplaceCall(call, zero); | 2625 (recognized_kind == MethodRecognizer::kFloat32x4Constructor)) { |
| 2509 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | 2626 TryInlineFloat32x4Constructor(call, recognized_kind); |
| 2510 Float32x4SplatInstr* splat = | |
| 2511 new Float32x4SplatInstr(new Value(call->ArgumentAt(1)), | |
| 2512 call->deopt_id()); | |
| 2513 ReplaceCall(call, splat); | |
| 2514 } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) { | |
| 2515 Float32x4ConstructorInstr* con = | |
| 2516 new Float32x4ConstructorInstr(new Value(call->ArgumentAt(1)), | |
| 2517 new Value(call->ArgumentAt(2)), | |
| 2518 new Value(call->ArgumentAt(3)), | |
| 2519 new Value(call->ArgumentAt(4)), | |
| 2520 call->deopt_id()); | |
| 2521 ReplaceCall(call, con); | |
| 2522 } else if (recognized_kind == MethodRecognizer::kUint32x4BoolConstructor) { | 2627 } else if (recognized_kind == MethodRecognizer::kUint32x4BoolConstructor) { |
| 2523 Uint32x4BoolConstructorInstr* con = new Uint32x4BoolConstructorInstr( | 2628 TryInlineUint32x4Constructor(call, recognized_kind); |
| 2524 new Value(call->ArgumentAt(1)), | |
| 2525 new Value(call->ArgumentAt(2)), | |
| 2526 new Value(call->ArgumentAt(3)), | |
| 2527 new Value(call->ArgumentAt(4)), | |
| 2528 call->deopt_id()); | |
| 2529 ReplaceCall(call, con); | |
| 2530 } else if (recognized_kind == MethodRecognizer::kObjectConstructor) { | 2629 } else if (recognized_kind == MethodRecognizer::kObjectConstructor) { |
| 2531 // Remove the original push arguments. | 2630 // Remove the original push arguments. |
| 2532 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 2631 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 2533 PushArgumentInstr* push = call->PushArgumentAt(i); | 2632 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 2534 push->ReplaceUsesWith(push->value()->definition()); | 2633 push->ReplaceUsesWith(push->value()->definition()); |
| 2535 push->RemoveFromGraph(); | 2634 push->RemoveFromGraph(); |
| 2536 } | 2635 } |
| 2537 // Manually replace call with global null constant. ReplaceCall can't | 2636 // Manually replace call with global null constant. ReplaceCall can't |
| 2538 // be used for definitions that are already in the graph. | 2637 // be used for definitions that are already in the graph. |
| 2539 call->ReplaceUsesWith(flow_graph_->constant_null()); | 2638 call->ReplaceUsesWith(flow_graph_->constant_null()); |
| (...skipping 4704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7244 | 7343 |
| 7245 // Insert materializations at environment uses. | 7344 // Insert materializations at environment uses. |
| 7246 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 7345 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 7247 for (intptr_t i = 0; i < exits.length(); i++) { | 7346 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7248 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 7347 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 7249 } | 7348 } |
| 7250 } | 7349 } |
| 7251 | 7350 |
| 7252 | 7351 |
| 7253 } // namespace dart | 7352 } // namespace dart |
| OLD | NEW |