Chromium Code Reviews| 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, disable_simd_inline, false, | |
|
srdjan
2013/07/25 17:02:14
Think positive, rename flag enable_simd_inline, de
| |
| 40 "Disable 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_disable_simd_inline; | |
|
srdjan
2013/07/25 17:02:14
Why don't you use the ifdef on flag definition?
Cutch
2013/07/25 17:08:13
Because enabling it on MIPS will cause a crash.
| |
| 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 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1121 new ShiftMintOpInstr(op_kind, new Value(left), new Value(right), | 1142 new ShiftMintOpInstr(op_kind, new Value(left), new Value(right), |
| 1122 call->deopt_id()); | 1143 call->deopt_id()); |
| 1123 ReplaceCall(call, shift_op); | 1144 ReplaceCall(call, shift_op); |
| 1124 } else { | 1145 } else { |
| 1125 BinaryMintOpInstr* bin_op = | 1146 BinaryMintOpInstr* bin_op = |
| 1126 new BinaryMintOpInstr(op_kind, new Value(left), new Value(right), | 1147 new BinaryMintOpInstr(op_kind, new Value(left), new Value(right), |
| 1127 call->deopt_id()); | 1148 call->deopt_id()); |
| 1128 ReplaceCall(call, bin_op); | 1149 ReplaceCall(call, bin_op); |
| 1129 } | 1150 } |
| 1130 } else if (operands_type == kFloat32x4Cid) { | 1151 } else if (operands_type == kFloat32x4Cid) { |
| 1131 // Type check left. | 1152 return InlineFloat32x4BinaryOp(call, op_kind); |
| 1132 AddCheckClass(left, | |
| 1133 ICData::ZoneHandle( | |
| 1134 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 1135 call->deopt_id(), | |
| 1136 call->env(), | |
| 1137 call); | |
| 1138 // Type check right. | |
| 1139 AddCheckClass(right, | |
| 1140 ICData::ZoneHandle( | |
| 1141 call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1142 call->deopt_id(), | |
| 1143 call->env(), | |
| 1144 call); | |
| 1145 // Replace call. | |
| 1146 BinaryFloat32x4OpInstr* float32x4_bin_op = | |
| 1147 new BinaryFloat32x4OpInstr(op_kind, new Value(left), new Value(right), | |
| 1148 call->deopt_id()); | |
| 1149 ReplaceCall(call, float32x4_bin_op); | |
| 1150 } else if (operands_type == kUint32x4Cid) { | 1153 } else if (operands_type == kUint32x4Cid) { |
| 1151 // Type check left. | 1154 return InlineUint32x4BinaryOp(call, op_kind); |
| 1152 AddCheckClass(left, | |
| 1153 ICData::ZoneHandle( | |
| 1154 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 1155 call->deopt_id(), | |
| 1156 call->env(), | |
| 1157 call); | |
| 1158 // Type check right. | |
| 1159 AddCheckClass(right, | |
| 1160 ICData::ZoneHandle( | |
| 1161 call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1162 call->deopt_id(), | |
| 1163 call->env(), | |
| 1164 call); | |
| 1165 // Replace call. | |
| 1166 BinaryUint32x4OpInstr* uint32x4_bin_op = | |
| 1167 new BinaryUint32x4OpInstr(op_kind, new Value(left), new Value(right), | |
| 1168 call->deopt_id()); | |
| 1169 ReplaceCall(call, uint32x4_bin_op); | |
| 1170 } else if (op_kind == Token::kMOD) { | 1155 } else if (op_kind == Token::kMOD) { |
| 1171 // TODO(vegorov): implement fast path code for modulo. | 1156 // TODO(vegorov): implement fast path code for modulo. |
| 1172 ASSERT(operands_type == kSmiCid); | 1157 ASSERT(operands_type == kSmiCid); |
| 1173 if (!right->IsConstant()) return false; | 1158 if (!right->IsConstant()) return false; |
| 1174 const Object& obj = right->AsConstant()->value(); | 1159 const Object& obj = right->AsConstant()->value(); |
| 1175 if (!obj.IsSmi()) return false; | 1160 if (!obj.IsSmi()) return false; |
| 1176 const intptr_t value = Smi::Cast(obj).Value(); | 1161 const intptr_t value = Smi::Cast(obj).Value(); |
| 1177 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; | 1162 if ((value <= 0) || !Utils::IsPowerOfTwo(value)) return false; |
| 1178 | 1163 |
| 1179 // Insert smi check and attach a copy of the original environment | 1164 // Insert smi check and attach a copy of the original environment |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1455 return GrowableObjectArray::length_offset(); | 1440 return GrowableObjectArray::length_offset(); |
| 1456 default: | 1441 default: |
| 1457 UNREACHABLE(); | 1442 UNREACHABLE(); |
| 1458 return 0; | 1443 return 0; |
| 1459 } | 1444 } |
| 1460 } | 1445 } |
| 1461 | 1446 |
| 1462 | 1447 |
| 1463 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, | 1448 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, |
| 1464 MethodRecognizer::Kind getter) { | 1449 MethodRecognizer::Kind getter) { |
| 1450 if (!ShouldInlineSimd()) { | |
| 1451 return false; | |
| 1452 } | |
| 1465 AddCheckClass(call->ArgumentAt(0), | 1453 AddCheckClass(call->ArgumentAt(0), |
| 1466 ICData::ZoneHandle( | 1454 ICData::ZoneHandle( |
| 1467 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1455 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1468 call->deopt_id(), | 1456 call->deopt_id(), |
| 1469 call->env(), | 1457 call->env(), |
| 1470 call); | 1458 call); |
| 1471 intptr_t mask = 0; | 1459 intptr_t mask = 0; |
| 1472 if (getter == MethodRecognizer::kFloat32x4Shuffle) { | 1460 if (getter == MethodRecognizer::kFloat32x4Shuffle) { |
| 1473 ASSERT(call->ArgumentCount() == 2); | 1461 ASSERT(call->ArgumentCount() == 2); |
| 1474 // Extract shuffle mask. | 1462 // Extract shuffle mask. |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1486 new Value(call->ArgumentAt(0)), | 1474 new Value(call->ArgumentAt(0)), |
| 1487 mask, | 1475 mask, |
| 1488 call->deopt_id()); | 1476 call->deopt_id()); |
| 1489 ReplaceCall(call, instr); | 1477 ReplaceCall(call, instr); |
| 1490 return true; | 1478 return true; |
| 1491 } | 1479 } |
| 1492 | 1480 |
| 1493 | 1481 |
| 1494 bool FlowGraphOptimizer::InlineUint32x4Getter(InstanceCallInstr* call, | 1482 bool FlowGraphOptimizer::InlineUint32x4Getter(InstanceCallInstr* call, |
| 1495 MethodRecognizer::Kind getter) { | 1483 MethodRecognizer::Kind getter) { |
| 1484 if (!ShouldInlineSimd()) { | |
| 1485 return false; | |
| 1486 } | |
| 1496 AddCheckClass(call->ArgumentAt(0), | 1487 AddCheckClass(call->ArgumentAt(0), |
| 1497 ICData::ZoneHandle( | 1488 ICData::ZoneHandle( |
| 1498 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1489 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1499 call->deopt_id(), | 1490 call->deopt_id(), |
| 1500 call->env(), | 1491 call->env(), |
| 1501 call); | 1492 call); |
| 1502 Uint32x4GetFlagInstr* instr = new Uint32x4GetFlagInstr( | 1493 Uint32x4GetFlagInstr* instr = new Uint32x4GetFlagInstr( |
| 1503 getter, | 1494 getter, |
| 1504 new Value(call->ArgumentAt(0)), | 1495 new Value(call->ArgumentAt(0)), |
| 1505 call->deopt_id()); | 1496 call->deopt_id()); |
| 1506 ReplaceCall(call, instr); | 1497 ReplaceCall(call, instr); |
| 1507 return true; | 1498 return true; |
| 1508 } | 1499 } |
| 1509 | 1500 |
| 1510 | 1501 |
| 1502 bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | |
| 1503 Token::Kind op_kind) { | |
| 1504 if (!ShouldInlineSimd()) { | |
| 1505 return false; | |
| 1506 } | |
| 1507 ASSERT(call->ArgumentCount() == 2); | |
| 1508 Definition* left = call->ArgumentAt(0); | |
| 1509 Definition* right = call->ArgumentAt(1); | |
| 1510 // Type check left. | |
| 1511 AddCheckClass(left, | |
| 1512 ICData::ZoneHandle( | |
| 1513 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 1514 call->deopt_id(), | |
| 1515 call->env(), | |
| 1516 call); | |
| 1517 // Type check right. | |
| 1518 AddCheckClass(right, | |
| 1519 ICData::ZoneHandle( | |
| 1520 call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1521 call->deopt_id(), | |
| 1522 call->env(), | |
| 1523 call); | |
| 1524 // Replace call. | |
| 1525 BinaryFloat32x4OpInstr* float32x4_bin_op = | |
| 1526 new BinaryFloat32x4OpInstr(op_kind, new Value(left), new Value(right), | |
| 1527 call->deopt_id()); | |
| 1528 ReplaceCall(call, float32x4_bin_op); | |
| 1529 | |
| 1530 return true; | |
| 1531 } | |
| 1532 | |
| 1533 | |
| 1534 bool FlowGraphOptimizer::InlineUint32x4BinaryOp(InstanceCallInstr* call, | |
| 1535 Token::Kind op_kind) { | |
| 1536 if (!ShouldInlineSimd()) { | |
| 1537 return false; | |
| 1538 } | |
| 1539 ASSERT(call->ArgumentCount() == 2); | |
| 1540 Definition* left = call->ArgumentAt(0); | |
| 1541 Definition* right = call->ArgumentAt(1); | |
| 1542 // Type check left. | |
| 1543 AddCheckClass(left, | |
| 1544 ICData::ZoneHandle( | |
| 1545 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
| 1546 call->deopt_id(), | |
| 1547 call->env(), | |
| 1548 call); | |
| 1549 // Type check right. | |
| 1550 AddCheckClass(right, | |
| 1551 ICData::ZoneHandle( | |
| 1552 call->ic_data()->AsUnaryClassChecksForArgNr(1)), | |
| 1553 call->deopt_id(), | |
| 1554 call->env(), | |
| 1555 call); | |
| 1556 // Replace call. | |
| 1557 BinaryUint32x4OpInstr* uint32x4_bin_op = | |
| 1558 new BinaryUint32x4OpInstr(op_kind, new Value(left), new Value(right), | |
| 1559 call->deopt_id()); | |
| 1560 ReplaceCall(call, uint32x4_bin_op); | |
| 1561 return true; | |
| 1562 } | |
| 1563 | |
| 1564 | |
| 1511 // Only unique implicit instance getters can be currently handled. | 1565 // Only unique implicit instance getters can be currently handled. |
| 1512 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { | 1566 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
| 1513 ASSERT(call->HasICData()); | 1567 ASSERT(call->HasICData()); |
| 1514 const ICData& ic_data = *call->ic_data(); | 1568 const ICData& ic_data = *call->ic_data(); |
| 1515 if (ic_data.NumberOfChecks() == 0) { | 1569 if (ic_data.NumberOfChecks() == 0) { |
| 1516 // No type feedback collected. | 1570 // No type feedback collected. |
| 1517 return false; | 1571 return false; |
| 1518 } | 1572 } |
| 1519 Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 1573 Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
| 1520 if (target.kind() == RawFunction::kImplicitGetter) { | 1574 if (target.kind() == RawFunction::kImplicitGetter) { |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1891 return TryInlineFloat32x4Method(call, recognized_kind); | 1945 return TryInlineFloat32x4Method(call, recognized_kind); |
| 1892 } | 1946 } |
| 1893 | 1947 |
| 1894 if ((class_ids[0] == kUint32x4Cid) && (ic_data.NumberOfChecks() == 1)) { | 1948 if ((class_ids[0] == kUint32x4Cid) && (ic_data.NumberOfChecks() == 1)) { |
| 1895 return TryInlineUint32x4Method(call, recognized_kind); | 1949 return TryInlineUint32x4Method(call, recognized_kind); |
| 1896 } | 1950 } |
| 1897 return false; | 1951 return false; |
| 1898 } | 1952 } |
| 1899 | 1953 |
| 1900 | 1954 |
| 1955 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( | |
| 1956 StaticCallInstr* call, | |
| 1957 MethodRecognizer::Kind recognized_kind) { | |
| 1958 if (!ShouldInlineSimd()) { | |
| 1959 return false; | |
| 1960 } | |
| 1961 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | |
| 1962 Float32x4ZeroInstr* zero = new Float32x4ZeroInstr(call->deopt_id()); | |
| 1963 ReplaceCall(call, zero); | |
| 1964 return true; | |
| 1965 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | |
| 1966 Float32x4SplatInstr* splat = | |
| 1967 new Float32x4SplatInstr(new Value(call->ArgumentAt(1)), | |
| 1968 call->deopt_id()); | |
| 1969 ReplaceCall(call, splat); | |
| 1970 return true; | |
| 1971 } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) { | |
| 1972 Float32x4ConstructorInstr* con = | |
| 1973 new Float32x4ConstructorInstr(new Value(call->ArgumentAt(1)), | |
| 1974 new Value(call->ArgumentAt(2)), | |
| 1975 new Value(call->ArgumentAt(3)), | |
| 1976 new Value(call->ArgumentAt(4)), | |
| 1977 call->deopt_id()); | |
| 1978 ReplaceCall(call, con); | |
| 1979 return true; | |
| 1980 } | |
| 1981 return false; | |
| 1982 } | |
| 1983 | |
| 1984 | |
| 1985 bool FlowGraphOptimizer::TryInlineUint32x4Constructor( | |
| 1986 StaticCallInstr* call, | |
| 1987 MethodRecognizer::Kind recognized_kind) { | |
| 1988 if (!ShouldInlineSimd()) { | |
| 1989 return false; | |
| 1990 } | |
| 1991 if (recognized_kind == MethodRecognizer::kUint32x4BoolConstructor) { | |
| 1992 Uint32x4BoolConstructorInstr* con = new Uint32x4BoolConstructorInstr( | |
| 1993 new Value(call->ArgumentAt(1)), | |
| 1994 new Value(call->ArgumentAt(2)), | |
| 1995 new Value(call->ArgumentAt(3)), | |
| 1996 new Value(call->ArgumentAt(4)), | |
| 1997 call->deopt_id()); | |
| 1998 ReplaceCall(call, con); | |
| 1999 return true; | |
| 2000 } | |
| 2001 return false; | |
| 2002 } | |
| 2003 | |
| 2004 | |
| 1901 bool FlowGraphOptimizer::TryInlineFloat32x4Method( | 2005 bool FlowGraphOptimizer::TryInlineFloat32x4Method( |
| 1902 InstanceCallInstr* call, | 2006 InstanceCallInstr* call, |
| 1903 MethodRecognizer::Kind recognized_kind) { | 2007 MethodRecognizer::Kind recognized_kind) { |
| 2008 if (!ShouldInlineSimd()) { | |
| 2009 return false; | |
| 2010 } | |
| 1904 ASSERT(call->HasICData()); | 2011 ASSERT(call->HasICData()); |
| 1905 switch (recognized_kind) { | 2012 switch (recognized_kind) { |
| 1906 case MethodRecognizer::kFloat32x4Equal: | 2013 case MethodRecognizer::kFloat32x4Equal: |
| 1907 case MethodRecognizer::kFloat32x4GreaterThan: | 2014 case MethodRecognizer::kFloat32x4GreaterThan: |
| 1908 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: | 2015 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: |
| 1909 case MethodRecognizer::kFloat32x4LessThan: | 2016 case MethodRecognizer::kFloat32x4LessThan: |
| 1910 case MethodRecognizer::kFloat32x4LessThanOrEqual: | 2017 case MethodRecognizer::kFloat32x4LessThanOrEqual: |
| 1911 case MethodRecognizer::kFloat32x4NotEqual: { | 2018 case MethodRecognizer::kFloat32x4NotEqual: { |
| 1912 Definition* left = call->ArgumentAt(0); | 2019 Definition* left = call->ArgumentAt(0); |
| 1913 Definition* right = call->ArgumentAt(1); | 2020 Definition* right = call->ArgumentAt(1); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2050 } | 2157 } |
| 2051 default: | 2158 default: |
| 2052 return false; | 2159 return false; |
| 2053 } | 2160 } |
| 2054 } | 2161 } |
| 2055 | 2162 |
| 2056 | 2163 |
| 2057 bool FlowGraphOptimizer::TryInlineUint32x4Method( | 2164 bool FlowGraphOptimizer::TryInlineUint32x4Method( |
| 2058 InstanceCallInstr* call, | 2165 InstanceCallInstr* call, |
| 2059 MethodRecognizer::Kind recognized_kind) { | 2166 MethodRecognizer::Kind recognized_kind) { |
| 2167 if (!ShouldInlineSimd()) { | |
| 2168 return false; | |
| 2169 } | |
| 2060 ASSERT(call->HasICData()); | 2170 ASSERT(call->HasICData()); |
| 2061 switch (recognized_kind) { | 2171 switch (recognized_kind) { |
| 2062 case MethodRecognizer::kUint32x4Select: { | 2172 case MethodRecognizer::kUint32x4Select: { |
| 2063 Definition* mask = call->ArgumentAt(0); | 2173 Definition* mask = call->ArgumentAt(0); |
| 2064 Definition* trueValue = call->ArgumentAt(1); | 2174 Definition* trueValue = call->ArgumentAt(1); |
| 2065 Definition* falseValue = call->ArgumentAt(2); | 2175 Definition* falseValue = call->ArgumentAt(2); |
| 2066 // Type check left. | 2176 // Type check left. |
| 2067 AddCheckClass(mask, | 2177 AddCheckClass(mask, |
| 2068 ICData::ZoneHandle( | 2178 ICData::ZoneHandle( |
| 2069 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 2179 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2116 default: | 2226 default: |
| 2117 return false; | 2227 return false; |
| 2118 } | 2228 } |
| 2119 } | 2229 } |
| 2120 | 2230 |
| 2121 | 2231 |
| 2122 bool FlowGraphOptimizer::BuildByteArrayViewLoad( | 2232 bool FlowGraphOptimizer::BuildByteArrayViewLoad( |
| 2123 InstanceCallInstr* call, | 2233 InstanceCallInstr* call, |
| 2124 intptr_t receiver_cid, | 2234 intptr_t receiver_cid, |
| 2125 intptr_t view_cid) { | 2235 intptr_t view_cid) { |
| 2236 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { | |
| 2237 return false; | |
| 2238 } | |
| 2239 | |
| 2126 Definition* array = call->ArgumentAt(0); | 2240 Definition* array = call->ArgumentAt(0); |
| 2127 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); | 2241 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); |
| 2128 | 2242 |
| 2129 // Optimistically build a smi-checked load for Int32 and Uint32 | 2243 // Optimistically build a smi-checked load for Int32 and Uint32 |
| 2130 // loads on ia32 like we do for normal array loads, and only revert to | 2244 // loads on ia32 like we do for normal array loads, and only revert to |
| 2131 // mint case after deoptimizing here. | 2245 // mint case after deoptimizing here. |
| 2132 intptr_t deopt_id = Isolate::kNoDeoptId; | 2246 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 2133 if ((view_cid == kTypedDataInt32ArrayCid || | 2247 if ((view_cid == kTypedDataInt32ArrayCid || |
| 2134 view_cid == kTypedDataUint32ArrayCid) && | 2248 view_cid == kTypedDataUint32ArrayCid) && |
| 2135 call->ic_data()->deopt_reason() == kDeoptUnknown) { | 2249 call->ic_data()->deopt_reason() == kDeoptUnknown) { |
| 2136 deopt_id = call->deopt_id(); | 2250 deopt_id = call->deopt_id(); |
| 2137 } | 2251 } |
| 2138 Definition* byte_index = call->ArgumentAt(1); | 2252 Definition* byte_index = call->ArgumentAt(1); |
| 2139 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), | 2253 LoadIndexedInstr* array_op = new LoadIndexedInstr(new Value(array), |
| 2140 new Value(byte_index), | 2254 new Value(byte_index), |
| 2141 1, // Index scale. | 2255 1, // Index scale. |
| 2142 view_cid, | 2256 view_cid, |
| 2143 deopt_id); | 2257 deopt_id); |
| 2144 ReplaceCall(call, array_op); | 2258 ReplaceCall(call, array_op); |
| 2145 return true; | 2259 return true; |
| 2146 } | 2260 } |
| 2147 | 2261 |
| 2148 | 2262 |
| 2149 bool FlowGraphOptimizer::BuildByteArrayViewStore( | 2263 bool FlowGraphOptimizer::BuildByteArrayViewStore( |
| 2150 InstanceCallInstr* call, | 2264 InstanceCallInstr* call, |
| 2151 intptr_t receiver_cid, | 2265 intptr_t receiver_cid, |
| 2152 intptr_t view_cid) { | 2266 intptr_t view_cid) { |
| 2267 if ((view_cid == kTypedDataFloat32x4ArrayCid) && !ShouldInlineSimd()) { | |
| 2268 return false; | |
|
srdjan
2013/07/25 17:02:14
Bad indentation.
Cutch
2013/07/25 17:08:13
Done.
| |
| 2269 } | |
| 2153 Definition* array = call->ArgumentAt(0); | 2270 Definition* array = call->ArgumentAt(0); |
| 2154 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); | 2271 PrepareByteArrayViewOp(call, receiver_cid, view_cid, &array); |
| 2155 ICData& value_check = ICData::ZoneHandle(); | 2272 ICData& value_check = ICData::ZoneHandle(); |
| 2156 switch (view_cid) { | 2273 switch (view_cid) { |
| 2157 case kTypedDataInt8ArrayCid: | 2274 case kTypedDataInt8ArrayCid: |
| 2158 case kTypedDataUint8ArrayCid: | 2275 case kTypedDataUint8ArrayCid: |
| 2159 case kTypedDataUint8ClampedArrayCid: | 2276 case kTypedDataUint8ClampedArrayCid: |
| 2160 case kExternalTypedDataUint8ArrayCid: | 2277 case kExternalTypedDataUint8ArrayCid: |
| 2161 case kExternalTypedDataUint8ClampedArrayCid: | 2278 case kExternalTypedDataUint8ClampedArrayCid: |
| 2162 case kTypedDataInt16ArrayCid: | 2279 case kTypedDataInt16ArrayCid: |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2493 } | 2610 } |
| 2494 | 2611 |
| 2495 | 2612 |
| 2496 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2613 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 2497 MethodRecognizer::Kind recognized_kind = | 2614 MethodRecognizer::Kind recognized_kind = |
| 2498 MethodRecognizer::RecognizeKind(call->function()); | 2615 MethodRecognizer::RecognizeKind(call->function()); |
| 2499 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 2616 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 2500 MathSqrtInstr* sqrt = | 2617 MathSqrtInstr* sqrt = |
| 2501 new MathSqrtInstr(new Value(call->ArgumentAt(0)), call->deopt_id()); | 2618 new MathSqrtInstr(new Value(call->ArgumentAt(0)), call->deopt_id()); |
| 2502 ReplaceCall(call, sqrt); | 2619 ReplaceCall(call, sqrt); |
| 2503 } else if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | 2620 } else if ((recognized_kind == MethodRecognizer::kFloat32x4Zero) || |
| 2504 Float32x4ZeroInstr* zero = new Float32x4ZeroInstr(call->deopt_id()); | 2621 (recognized_kind == MethodRecognizer::kFloat32x4Splat) || |
| 2505 ReplaceCall(call, zero); | 2622 (recognized_kind == MethodRecognizer::kFloat32x4Constructor)) { |
| 2506 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | 2623 TryInlineFloat32x4Constructor(call, recognized_kind); |
| 2507 Float32x4SplatInstr* splat = | |
| 2508 new Float32x4SplatInstr(new Value(call->ArgumentAt(1)), | |
| 2509 call->deopt_id()); | |
| 2510 ReplaceCall(call, splat); | |
| 2511 } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) { | |
| 2512 Float32x4ConstructorInstr* con = | |
| 2513 new Float32x4ConstructorInstr(new Value(call->ArgumentAt(1)), | |
| 2514 new Value(call->ArgumentAt(2)), | |
| 2515 new Value(call->ArgumentAt(3)), | |
| 2516 new Value(call->ArgumentAt(4)), | |
| 2517 call->deopt_id()); | |
| 2518 ReplaceCall(call, con); | |
| 2519 } else if (recognized_kind == MethodRecognizer::kUint32x4BoolConstructor) { | 2624 } else if (recognized_kind == MethodRecognizer::kUint32x4BoolConstructor) { |
| 2520 Uint32x4BoolConstructorInstr* con = new Uint32x4BoolConstructorInstr( | 2625 TryInlineUint32x4Constructor(call, recognized_kind); |
| 2521 new Value(call->ArgumentAt(1)), | |
| 2522 new Value(call->ArgumentAt(2)), | |
| 2523 new Value(call->ArgumentAt(3)), | |
| 2524 new Value(call->ArgumentAt(4)), | |
| 2525 call->deopt_id()); | |
| 2526 ReplaceCall(call, con); | |
| 2527 } else if (recognized_kind == MethodRecognizer::kObjectConstructor) { | 2626 } else if (recognized_kind == MethodRecognizer::kObjectConstructor) { |
| 2528 // Remove the original push arguments. | 2627 // Remove the original push arguments. |
| 2529 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 2628 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 2530 PushArgumentInstr* push = call->PushArgumentAt(i); | 2629 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 2531 push->ReplaceUsesWith(push->value()->definition()); | 2630 push->ReplaceUsesWith(push->value()->definition()); |
| 2532 push->RemoveFromGraph(); | 2631 push->RemoveFromGraph(); |
| 2533 } | 2632 } |
| 2534 // Manually replace call with global null constant. ReplaceCall can't | 2633 // Manually replace call with global null constant. ReplaceCall can't |
| 2535 // be used for definitions that are already in the graph. | 2634 // be used for definitions that are already in the graph. |
| 2536 call->ReplaceUsesWith(flow_graph_->constant_null()); | 2635 call->ReplaceUsesWith(flow_graph_->constant_null()); |
| (...skipping 4704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7241 | 7340 |
| 7242 // Insert materializations at environment uses. | 7341 // Insert materializations at environment uses. |
| 7243 const Class& cls = Class::Handle(alloc->constructor().Owner()); | 7342 const Class& cls = Class::Handle(alloc->constructor().Owner()); |
| 7244 for (intptr_t i = 0; i < exits.length(); i++) { | 7343 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7245 CreateMaterializationAt(exits[i], alloc, cls, *fields); | 7344 CreateMaterializationAt(exits[i], alloc, cls, *fields); |
| 7246 } | 7345 } |
| 7247 } | 7346 } |
| 7248 | 7347 |
| 7249 | 7348 |
| 7250 } // namespace dart | 7349 } // namespace dart |
| OLD | NEW |