Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
| 10 #include "vm/hash_map.h" | 10 #include "vm/hash_map.h" |
| (...skipping 1016 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1027 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr, | 1027 HandleEqualityCompare(this, comparison->AsEqualityCompare(), instr, |
| 1028 current_iterator()); | 1028 current_iterator()); |
| 1029 } else { | 1029 } else { |
| 1030 ASSERT(comparison->IsStrictCompare()); | 1030 ASSERT(comparison->IsStrictCompare()); |
| 1031 // Nothing to do. | 1031 // Nothing to do. |
| 1032 } | 1032 } |
| 1033 } | 1033 } |
| 1034 | 1034 |
| 1035 | 1035 |
| 1036 // SminessPropagator ensures that CheckSmis are eliminated across phis. | 1036 // SminessPropagator ensures that CheckSmis are eliminated across phis. |
| 1037 class SminessPropagator { | 1037 class SminessPropagator : public ValueObject { |
| 1038 public: | 1038 public: |
| 1039 explicit SminessPropagator(FlowGraph* flow_graph) | 1039 explicit SminessPropagator(FlowGraph* flow_graph) |
| 1040 : flow_graph_(flow_graph), | 1040 : flow_graph_(flow_graph), |
| 1041 known_smis_(new BitVector(flow_graph_->current_ssa_temp_index())), | 1041 known_smis_(new BitVector(flow_graph_->current_ssa_temp_index())), |
| 1042 rollback_checks_(10), | 1042 rollback_checks_(10), |
| 1043 in_worklist_(NULL), | 1043 in_worklist_(NULL), |
| 1044 worklist_(0) { } | 1044 worklist_(0) { } |
| 1045 | 1045 |
| 1046 void Propagate(); | 1046 void Propagate(); |
| 1047 | 1047 |
| 1048 private: | 1048 private: |
| 1049 void PropagateSminessRecursive(BlockEntryInstr* block); | 1049 void PropagateSminessRecursive(BlockEntryInstr* block); |
| 1050 void AddToWorklist(PhiInstr* phi); | 1050 void AddToWorklist(PhiInstr* phi); |
| 1051 PhiInstr* RemoveLastFromWorklist(); | 1051 PhiInstr* RemoveLastFromWorklist(); |
| 1052 void ProcessPhis(); | 1052 void ProcessPhis(); |
| 1053 | 1053 |
| 1054 FlowGraph* flow_graph_; | 1054 FlowGraph* flow_graph_; |
| 1055 | 1055 |
| 1056 BitVector* known_smis_; | 1056 BitVector* known_smis_; |
| 1057 GrowableArray<intptr_t> rollback_checks_; | 1057 GrowableArray<intptr_t> rollback_checks_; |
| 1058 | 1058 |
| 1059 BitVector* in_worklist_; | 1059 BitVector* in_worklist_; |
| 1060 GrowableArray<PhiInstr*> worklist_; | 1060 GrowableArray<PhiInstr*> worklist_; |
| 1061 | |
| 1062 DISALLOW_COPY_AND_ASSIGN(SminessPropagator); | |
| 1061 }; | 1063 }; |
| 1062 | 1064 |
| 1063 | 1065 |
| 1064 void SminessPropagator::AddToWorklist(PhiInstr* phi) { | 1066 void SminessPropagator::AddToWorklist(PhiInstr* phi) { |
| 1065 if (in_worklist_ == NULL) { | 1067 if (in_worklist_ == NULL) { |
| 1066 in_worklist_ = new BitVector(flow_graph_->current_ssa_temp_index()); | 1068 in_worklist_ = new BitVector(flow_graph_->current_ssa_temp_index()); |
| 1067 } | 1069 } |
| 1068 if (!in_worklist_->Contains(phi->ssa_temp_index())) { | 1070 if (!in_worklist_->Contains(phi->ssa_temp_index())) { |
| 1069 in_worklist_->Add(phi->ssa_temp_index()); | 1071 in_worklist_->Add(phi->ssa_temp_index()); |
| 1070 worklist_.Add(phi); | 1072 worklist_.Add(phi); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1197 ProcessPhis(); | 1199 ProcessPhis(); |
| 1198 } | 1200 } |
| 1199 | 1201 |
| 1200 | 1202 |
| 1201 void FlowGraphOptimizer::PropagateSminess() { | 1203 void FlowGraphOptimizer::PropagateSminess() { |
| 1202 SminessPropagator propagator(flow_graph_); | 1204 SminessPropagator propagator(flow_graph_); |
| 1203 propagator.Propagate(); | 1205 propagator.Propagate(); |
| 1204 } | 1206 } |
| 1205 | 1207 |
| 1206 | 1208 |
| 1209 // Range analysis for smi values. | |
| 1210 class RangeAnalysis : public ValueObject { | |
| 1211 public: | |
| 1212 explicit RangeAnalysis(FlowGraph* flow_graph) : flow_graph_(flow_graph) { } | |
| 1213 | |
| 1214 // Infer ranges for all values and remove overflow checks from binary smi | |
| 1215 // operations when proven redundant. | |
| 1216 void Analyze(); | |
| 1217 | |
| 1218 private: | |
| 1219 // Collect all values that were proven to be smi in smi_values_ array and all | |
| 1220 // CheckSmi instructions in smi_check_ array. | |
| 1221 void CollectSmiValues(); | |
| 1222 | |
| 1223 // Iterate over smi values and constrain them at branch successors. | |
| 1224 // Additionally constraint values after CheckSmi instructions. | |
| 1225 void InsertConstraints(); | |
| 1226 | |
| 1227 // Iterate over uses of the given definition and discover branches that | |
| 1228 // constrain it. Insert appropriate Constraint instructions at true | |
| 1229 // and false successor and rename all dominated uses to refer to a | |
| 1230 // Constraint instead of this definition. | |
| 1231 void InsertConstraintsFor(Definition* defn); | |
| 1232 | |
| 1233 // Create a constraint for defn, insert it after given instruction and | |
| 1234 // rename all uses that are dominated by it. | |
| 1235 ConstraintInstr* InsertConstraintFor(Definition* defn, | |
| 1236 Range* constraint, | |
| 1237 Instruction* after); | |
| 1238 | |
| 1239 // Replace uses of the definition def that are dominated by instruction dom | |
| 1240 // with uses of other definition. | |
| 1241 void RenameDominatedUses(Definition* def, | |
| 1242 Instruction* dom, | |
| 1243 Definition* other); | |
| 1244 | |
| 1245 // Propagate range information until fix-point is reached. | |
| 1246 void InferRanges(); | |
| 1247 | |
| 1248 // Walk the dominator tree, initialize ranges for smi values and place them | |
| 1249 // to the worklist. | |
| 1250 void InitializeRangesRecursive(BlockEntryInstr* block); | |
| 1251 | |
| 1252 // Remove artificial Constraint instructions and replace them with actual | |
| 1253 // unconstrained definitions. | |
| 1254 void RemoveConstraints(); | |
| 1255 | |
| 1256 void CreateWorklists(); | |
| 1257 | |
| 1258 void AddToWorklist(Definition* value) { | |
| 1259 const intptr_t index = value->ssa_temp_index(); | |
| 1260 if (!in_inactive_worklist_->Contains(index)) { | |
| 1261 in_inactive_worklist_->Add(index); | |
| 1262 inactive_worklist_->Add(value); | |
| 1263 } | |
| 1264 } | |
| 1265 | |
| 1266 bool IsWorklistEmpty() const { | |
| 1267 return active_worklist_->is_empty(); | |
| 1268 } | |
| 1269 | |
| 1270 void SwapWorklists(); | |
| 1271 | |
| 1272 FlowGraph* flow_graph_; | |
| 1273 | |
| 1274 GrowableArray<Definition*> smi_values_; // Value that are known to be smi. | |
| 1275 GrowableArray<CheckSmiInstr*> smi_checks_; // All CheckSmi instructions. | |
| 1276 | |
| 1277 // All Constraints inserted during InsertConstraints phase. They are treated | |
| 1278 // as smi values. | |
| 1279 GrowableArray<ConstraintInstr*> constraints_; | |
| 1280 | |
| 1281 // Bitvector for a quick filtering of known smi values. | |
| 1282 BitVector* smi_definitions_; | |
| 1283 | |
| 1284 // Worklists using during range propagation. | |
|
ngeoffray
2012/09/24 21:44:15
using -> used
| |
| 1285 ZoneGrowableArray<Definition*>* active_worklist_; | |
| 1286 ZoneGrowableArray<Definition*>* inactive_worklist_; | |
| 1287 BitVector* in_inactive_worklist_; | |
| 1288 | |
| 1289 DISALLOW_COPY_AND_ASSIGN(RangeAnalysis); | |
| 1290 }; | |
| 1291 | |
| 1292 | |
| 1293 void RangeAnalysis::Analyze() { | |
| 1294 CollectSmiValues(); | |
| 1295 InsertConstraints(); | |
| 1296 InferRanges(); | |
| 1297 RemoveConstraints(); | |
| 1298 } | |
| 1299 | |
| 1300 | |
| 1301 void RangeAnalysis::CollectSmiValues() { | |
| 1302 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | |
| 1303 !block_it.Done(); | |
| 1304 block_it.Advance()) { | |
| 1305 BlockEntryInstr* block = block_it.Current(); | |
| 1306 for (ForwardInstructionIterator instr_it(block); | |
| 1307 !instr_it.Done(); | |
| 1308 instr_it.Advance()) { | |
| 1309 Instruction* current = instr_it.Current(); | |
| 1310 Definition* defn = current->AsDefinition(); | |
| 1311 if (defn != NULL) { | |
| 1312 if (defn->GetPropagatedCid() == kSmiCid) smi_values_.Add(defn); | |
| 1313 } else if (current->IsCheckSmi()) { | |
| 1314 smi_checks_.Add(current->AsCheckSmi()); | |
| 1315 } | |
| 1316 } | |
| 1317 | |
| 1318 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 1319 if (join != NULL) { | |
| 1320 for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) { | |
| 1321 PhiInstr* current = phi_it.Current(); | |
| 1322 if (current->GetPropagatedCid() == kSmiCid) { | |
| 1323 smi_values_.Add(current); | |
| 1324 } | |
| 1325 } | |
| 1326 } | |
| 1327 } | |
| 1328 } | |
| 1329 | |
| 1330 | |
| 1331 // Returns true if use is dominated by the given instruction. | |
| 1332 // Note: uses that occur at instruction itself are not dominated by it. | |
| 1333 static bool IsDominatedUse(Instruction* dom, Value* use) { | |
| 1334 BlockEntryInstr* dom_block = dom->GetBlock(); | |
| 1335 | |
| 1336 Instruction* instr = use->instruction(); | |
| 1337 | |
| 1338 PhiInstr* phi = instr->AsPhi(); | |
| 1339 if (phi != NULL) { | |
| 1340 return dom_block->Dominates(phi->block()->PredecessorAt(use->use_index())); | |
| 1341 } | |
| 1342 | |
| 1343 BlockEntryInstr* use_block = instr->GetBlock(); | |
| 1344 if (use_block == dom_block) { | |
| 1345 // Fast path for the case of block entry. | |
| 1346 if (dom_block == dom) return true; | |
| 1347 | |
| 1348 for (Instruction* curr = dom->next(); curr != NULL; curr = curr->next()) { | |
| 1349 if (curr == instr) return true; | |
| 1350 } | |
| 1351 | |
| 1352 return false; | |
| 1353 } | |
| 1354 | |
| 1355 return dom_block->Dominates(use_block); | |
| 1356 } | |
| 1357 | |
| 1358 | |
| 1359 void RangeAnalysis::RenameDominatedUses(Definition* def, | |
| 1360 Instruction* dom, | |
| 1361 Definition* other) { | |
| 1362 Value* next_use = NULL; | |
| 1363 Value* prev_use = NULL; | |
| 1364 for (Value* use = def->input_use_list(); | |
| 1365 use != NULL; | |
| 1366 use = next_use) { | |
| 1367 next_use = use->next_use(); | |
| 1368 | |
| 1369 // Skip dead phis. | |
| 1370 if (use->instruction()->IsPhi() && | |
| 1371 !use->instruction()->AsPhi()->is_alive()) { | |
| 1372 prev_use = use; | |
| 1373 continue; | |
| 1374 } | |
| 1375 | |
| 1376 if (IsDominatedUse(dom, use)) { | |
| 1377 if (prev_use != NULL) { | |
| 1378 prev_use->set_next_use(next_use); | |
| 1379 } else { | |
| 1380 def->set_input_use_list(next_use); | |
| 1381 } | |
| 1382 use->set_definition(other); | |
| 1383 use->AddToInputUseList(); | |
| 1384 } else { | |
| 1385 prev_use = use; | |
| 1386 } | |
| 1387 } | |
| 1388 } | |
| 1389 | |
| 1390 | |
| 1391 // For a comparison operation return an operation for the equivalent flipped | |
| 1392 // comparison: a (op) b === b (op') a. | |
| 1393 static Token::Kind FlipComparison(Token::Kind op) { | |
| 1394 switch (op) { | |
| 1395 case Token::kEQ: return Token::kEQ; | |
| 1396 case Token::kNE: return Token::kNE; | |
| 1397 case Token::kLT: return Token::kGT; | |
| 1398 case Token::kGT: return Token::kLT; | |
| 1399 case Token::kLTE: return Token::kGTE; | |
| 1400 case Token::kGTE: return Token::kLTE; | |
| 1401 default: | |
| 1402 UNREACHABLE(); | |
| 1403 return Token::kILLEGAL; | |
| 1404 } | |
| 1405 } | |
| 1406 | |
| 1407 // For a comparison operation return an operation for the negated comparison: | |
| 1408 // !(a (op) b) === a (op') b | |
| 1409 static Token::Kind NegateComparison(Token::Kind op) { | |
| 1410 switch (op) { | |
| 1411 case Token::kEQ: return Token::kNE; | |
| 1412 case Token::kNE: return Token::kEQ; | |
| 1413 case Token::kLT: return Token::kGTE; | |
| 1414 case Token::kGT: return Token::kLTE; | |
| 1415 case Token::kLTE: return Token::kGT; | |
| 1416 case Token::kGTE: return Token::kLT; | |
| 1417 default: | |
| 1418 UNREACHABLE(); | |
| 1419 return Token::kILLEGAL; | |
| 1420 } | |
| 1421 } | |
| 1422 | |
| 1423 | |
| 1424 // Given a boundary (right operand) and a comparison operation return | |
| 1425 // a symbolic range constraint for the left operand of the comparison assuming | |
| 1426 // that it evaluated to true. | |
| 1427 // For example for the comparison a < b symbol a is constrained with range | |
| 1428 // [Smi::kMinValue, b - 1]. | |
| 1429 static Range* ConstraintRange(Token::Kind op, Definition* boundary) { | |
| 1430 switch (op) { | |
| 1431 case Token::kEQ: | |
| 1432 return new Range(RangeBoundary::FromDefinition(boundary), | |
| 1433 RangeBoundary::FromDefinition(boundary)); | |
| 1434 case Token::kNE: | |
| 1435 return Range::Unknown(); | |
| 1436 case Token::kLT: | |
| 1437 return new Range(RangeBoundary::MinSmi(), | |
| 1438 RangeBoundary::FromDefinition(boundary, -1)); | |
| 1439 case Token::kGT: | |
| 1440 return new Range(RangeBoundary::FromDefinition(boundary, 1), | |
| 1441 RangeBoundary::MaxSmi()); | |
| 1442 case Token::kLTE: | |
| 1443 return new Range(RangeBoundary::MinSmi(), | |
| 1444 RangeBoundary::FromDefinition(boundary)); | |
| 1445 case Token::kGTE: | |
| 1446 return new Range(RangeBoundary::FromDefinition(boundary), | |
| 1447 RangeBoundary::MaxSmi()); | |
| 1448 default: | |
| 1449 UNREACHABLE(); | |
| 1450 return Range::Unknown(); | |
| 1451 } | |
| 1452 } | |
| 1453 | |
| 1454 | |
| 1455 ConstraintInstr* RangeAnalysis::InsertConstraintFor(Definition* defn, | |
| 1456 Range* constraint_range, | |
|
ngeoffray
2012/09/24 21:44:15
Weird indentation.
| |
| 1457 Instruction* after) { | |
| 1458 // No need to constrain constants. | |
| 1459 if (defn->IsConstant()) return NULL; | |
| 1460 | |
| 1461 ConstraintInstr* constraint = | |
| 1462 new ConstraintInstr(new Value(defn), constraint_range); | |
| 1463 constraint->InsertAfter(after); | |
| 1464 constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | |
| 1465 RenameDominatedUses(defn, after, constraint); | |
| 1466 constraints_.Add(constraint); | |
| 1467 constraint->value()->set_instruction(constraint); | |
| 1468 constraint->value()->set_use_index(0); | |
| 1469 constraint->value()->AddToInputUseList(); | |
| 1470 return constraint; | |
| 1471 } | |
| 1472 | |
| 1473 | |
| 1474 void RangeAnalysis::InsertConstraintsFor(Definition* defn) { | |
| 1475 for (Value* use = defn->input_use_list(); | |
| 1476 use != NULL; | |
| 1477 use = use->next_use()) { | |
| 1478 if (use->instruction()->IsBranch()) { | |
| 1479 BranchInstr* branch = use->instruction()->AsBranch(); | |
| 1480 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); | |
| 1481 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { | |
| 1482 // Found comparison of two smis. Constrain defn at true and false | |
| 1483 // successors using the other operand as a boundary. | |
| 1484 Definition* boundary; | |
| 1485 Token::Kind op_kind; | |
| 1486 if (use->use_index() == 0) { // Left operand. | |
| 1487 boundary = rel_op->InputAt(1)->definition(); | |
| 1488 op_kind = rel_op->kind(); | |
| 1489 } else { | |
| 1490 ASSERT(use->use_index() == 1); // Right operand. | |
| 1491 boundary = rel_op->InputAt(0)->definition(); | |
| 1492 // InsertConstraintFor assumes that defn is left operand of a | |
| 1493 // comparison if it is right operand flip the comparison. | |
| 1494 op_kind = FlipComparison(rel_op->kind()); | |
| 1495 } | |
| 1496 | |
| 1497 // Constrain definition at the true successor. | |
| 1498 ConstraintInstr* true_constraint = | |
| 1499 InsertConstraintFor(defn, | |
| 1500 ConstraintRange(op_kind, boundary), | |
| 1501 branch->true_successor()); | |
| 1502 // Mark true_constraint an artificial use of boundary. This ensures | |
| 1503 // that constraint's range is recalculated if boundary's range changes. | |
| 1504 if (true_constraint != NULL) true_constraint->AddDependency(boundary); | |
| 1505 | |
| 1506 // Constrain definition with a negated condition at the false successor. | |
| 1507 ConstraintInstr* false_constraint = | |
| 1508 InsertConstraintFor( | |
| 1509 defn, | |
| 1510 ConstraintRange(NegateComparison(op_kind), boundary), | |
| 1511 branch->false_successor()); | |
| 1512 // Mark false_constraint an artificial use of boundary. This ensures | |
| 1513 // that constraint's range is recalculated if boundary's range changes. | |
| 1514 if (false_constraint != NULL) false_constraint->AddDependency(boundary); | |
| 1515 } | |
| 1516 } | |
| 1517 } | |
| 1518 } | |
| 1519 | |
| 1520 | |
| 1521 void RangeAnalysis::InsertConstraints() { | |
| 1522 for (intptr_t i = 0; i < smi_checks_.length(); i++) { | |
| 1523 CheckSmiInstr* check = smi_checks_[i]; | |
| 1524 ConstraintInstr* constraint = | |
| 1525 InsertConstraintFor(check->value()->definition(), | |
| 1526 Range::Unknown(), | |
| 1527 check); | |
| 1528 InsertConstraintsFor(constraint); // Constrain uses further. | |
| 1529 } | |
| 1530 | |
| 1531 for (intptr_t i = 0; i < smi_values_.length(); i++) { | |
| 1532 InsertConstraintsFor(smi_values_[i]); | |
| 1533 } | |
| 1534 } | |
| 1535 | |
| 1536 | |
| 1537 void RangeAnalysis::InitializeRangesRecursive(BlockEntryInstr* block) { | |
| 1538 JoinEntryInstr* join = block->AsJoinEntry(); | |
| 1539 if ((join != NULL) && (join->phis() != NULL)) { | |
| 1540 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | |
| 1541 PhiInstr* phi = (*join->phis())[i]; | |
| 1542 if (phi == NULL) continue; | |
| 1543 if (smi_definitions_->Contains(phi->ssa_temp_index())) { | |
| 1544 phi->InferRange(); | |
| 1545 AddToWorklist(phi); | |
| 1546 } | |
| 1547 } | |
| 1548 } | |
| 1549 | |
| 1550 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 1551 Definition* defn = it.Current()->AsDefinition(); | |
| 1552 if ((defn != NULL) && | |
| 1553 (defn->ssa_temp_index() != -1) && | |
| 1554 smi_definitions_->Contains(defn->ssa_temp_index())) { | |
| 1555 defn->InferRange(); | |
| 1556 AddToWorklist(defn); | |
| 1557 } | |
| 1558 } | |
| 1559 | |
| 1560 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { | |
| 1561 InitializeRangesRecursive(block->dominated_blocks()[i]); | |
| 1562 } | |
| 1563 } | |
| 1564 | |
| 1565 | |
| 1566 void RangeAnalysis::CreateWorklists() { | |
| 1567 active_worklist_ = new ZoneGrowableArray<Definition*>(10); | |
| 1568 inactive_worklist_ = new ZoneGrowableArray<Definition*>(10); | |
| 1569 in_inactive_worklist_ = new BitVector( | |
| 1570 flow_graph_->current_ssa_temp_index()); | |
| 1571 } | |
| 1572 | |
| 1573 | |
| 1574 void RangeAnalysis::SwapWorklists() { | |
| 1575 ZoneGrowableArray<Definition*>* temp = active_worklist_; | |
| 1576 active_worklist_ = inactive_worklist_; | |
| 1577 inactive_worklist_ = temp; | |
| 1578 inactive_worklist_->Clear(); | |
| 1579 in_inactive_worklist_->Clear(); | |
| 1580 } | |
| 1581 | |
| 1582 | |
| 1583 void RangeAnalysis::InferRanges() { | |
| 1584 CreateWorklists(); | |
| 1585 | |
| 1586 // Initialize bitvector for quick filtering of smi values. | |
| 1587 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); | |
| 1588 for (intptr_t i = 0; i < smi_values_.length(); i++) { | |
| 1589 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); | |
| 1590 } | |
| 1591 for (intptr_t i = 0; i < constraints_.length(); i++) { | |
| 1592 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); | |
| 1593 } | |
| 1594 | |
| 1595 // Infer initial values of ranges. | |
| 1596 InitializeRangesRecursive(flow_graph_->graph_entry()); | |
| 1597 | |
| 1598 // Active worklist is empty, inactive now contains all smi values. | |
| 1599 SwapWorklists(); | |
| 1600 | |
| 1601 // Iterate until fix point is reached. | |
| 1602 while (!IsWorklistEmpty()) { | |
| 1603 for (intptr_t i = 0; i < active_worklist_->length(); i++) { | |
| 1604 Definition* defn = (*active_worklist_)[i]; | |
| 1605 if (defn->InferRange()) { // Update the range. | |
| 1606 // Range change. Place all uses to the worklist. | |
| 1607 for (Value* use = defn->input_use_list(); | |
| 1608 use != NULL; | |
| 1609 use = use->next_use()) { | |
| 1610 Definition* use_defn = use->instruction()->AsDefinition(); | |
| 1611 if ((use_defn != NULL) && | |
| 1612 (use_defn->ssa_temp_index() != -1) && | |
| 1613 smi_definitions_->Contains(use_defn->ssa_temp_index())) { | |
| 1614 AddToWorklist(use_defn); | |
| 1615 } | |
| 1616 } | |
| 1617 } | |
| 1618 } | |
| 1619 | |
| 1620 // Active worklist has been processed. Inactive contains all values which | |
| 1621 // can be affected by changed ranges. | |
| 1622 SwapWorklists(); | |
| 1623 } | |
| 1624 } | |
| 1625 | |
| 1626 | |
| 1627 void RangeAnalysis::RemoveConstraints() { | |
| 1628 for (intptr_t i = 0; i < constraints_.length(); i++) { | |
| 1629 Definition* def = constraints_[i]->value()->definition(); | |
| 1630 // Some constraints might be constraining constraints. Unwind the chain of | |
| 1631 // constraints until we reach the actual definition. | |
| 1632 while (def->IsConstraint()) { | |
| 1633 def = def->AsConstraint()->value()->definition(); | |
| 1634 } | |
| 1635 constraints_[i]->ReplaceUsesWith(def); | |
| 1636 constraints_[i]->RemoveDependency(); | |
| 1637 constraints_[i]->RemoveFromGraph(); | |
| 1638 } | |
| 1639 } | |
| 1640 | |
| 1641 | |
| 1642 void FlowGraphOptimizer::InferSmiRanges() { | |
| 1643 RangeAnalysis range_analysis(flow_graph_); | |
| 1644 range_analysis.Analyze(); | |
| 1645 } | |
| 1646 | |
| 1647 | |
| 1207 void FlowGraphTypePropagator::VisitBlocks() { | 1648 void FlowGraphTypePropagator::VisitBlocks() { |
| 1208 ASSERT(current_iterator_ == NULL); | 1649 ASSERT(current_iterator_ == NULL); |
| 1209 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 1650 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 1210 BlockEntryInstr* entry = block_order_[i]; | 1651 BlockEntryInstr* entry = block_order_[i]; |
| 1211 entry->Accept(this); | 1652 entry->Accept(this); |
| 1212 ForwardInstructionIterator it(entry); | 1653 ForwardInstructionIterator it(entry); |
| 1213 current_iterator_ = ⁢ | 1654 current_iterator_ = ⁢ |
| 1214 for (; !it.Done(); it.Advance()) { | 1655 for (; !it.Done(); it.Advance()) { |
| 1215 Instruction* current = it.Current(); | 1656 Instruction* current = it.Current(); |
| 1216 // No need to propagate the input types of the instruction, as long as | 1657 // No need to propagate the input types of the instruction, as long as |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1500 // instruction and set the correct deopt_id. | 1941 // instruction and set the correct deopt_id. |
| 1501 ASSERT(last->env() != NULL); | 1942 ASSERT(last->env() != NULL); |
| 1502 last->env()->DeepCopyTo(current); | 1943 last->env()->DeepCopyTo(current); |
| 1503 current->deopt_id_ = last->GetDeoptId(); | 1944 current->deopt_id_ = last->GetDeoptId(); |
| 1504 } | 1945 } |
| 1505 | 1946 |
| 1506 | 1947 |
| 1507 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, | 1948 void LICM::TryHoistCheckSmiThroughPhi(ForwardInstructionIterator* it, |
| 1508 BlockEntryInstr* header, | 1949 BlockEntryInstr* header, |
| 1509 BlockEntryInstr* pre_header, | 1950 BlockEntryInstr* pre_header, |
| 1510 Instruction* current) { | 1951 CheckSmiInstr* current) { |
| 1511 PhiInstr* phi = current->InputAt(0)->definition()->AsPhi(); | 1952 PhiInstr* phi = current->InputAt(0)->definition()->AsPhi(); |
| 1512 if (!header->loop_info()->Contains(phi->block()->preorder_number())) { | 1953 if (!header->loop_info()->Contains(phi->block()->preorder_number())) { |
| 1513 return; | 1954 return; |
| 1514 } | 1955 } |
| 1515 | 1956 |
| 1516 if (phi->GetPropagatedCid() == kSmiCid) { | 1957 if (phi->GetPropagatedCid() == kSmiCid) { |
| 1517 it->RemoveCurrentFromGraph(); | 1958 it->RemoveCurrentFromGraph(); |
| 1518 return; | 1959 return; |
| 1519 } | 1960 } |
| 1520 | 1961 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1535 } | 1976 } |
| 1536 } | 1977 } |
| 1537 | 1978 |
| 1538 if ((non_smi_input == kNotFound) || | 1979 if ((non_smi_input == kNotFound) || |
| 1539 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { | 1980 (phi->block()->PredecessorAt(non_smi_input) != pre_header)) { |
| 1540 return; | 1981 return; |
| 1541 } | 1982 } |
| 1542 | 1983 |
| 1543 // Host CheckSmi instruction and make this phi smi one. | 1984 // Host CheckSmi instruction and make this phi smi one. |
| 1544 Hoist(it, pre_header, current); | 1985 Hoist(it, pre_header, current); |
| 1545 current->SetInputAt(0, phi->InputAt(non_smi_input)); | 1986 |
| 1987 // Replace value we are checking with phi's input. Maintain use lists. | |
| 1988 Definition* non_smi_input_defn = phi->InputAt(non_smi_input)->definition(); | |
| 1989 current->value()->RemoveFromInputUseList(); | |
| 1990 current->value()->set_definition(non_smi_input_defn); | |
| 1991 current->value()->AddToInputUseList(); | |
| 1992 | |
| 1546 phi->SetPropagatedCid(kSmiCid); | 1993 phi->SetPropagatedCid(kSmiCid); |
| 1547 } | 1994 } |
| 1548 | 1995 |
| 1549 | 1996 |
| 1550 void LICM::Optimize(FlowGraph* flow_graph) { | 1997 void LICM::Optimize(FlowGraph* flow_graph) { |
| 1551 GrowableArray<BlockEntryInstr*> loop_headers; | 1998 GrowableArray<BlockEntryInstr*> loop_headers; |
| 1552 flow_graph->ComputeLoops(&loop_headers); | 1999 flow_graph->ComputeLoops(&loop_headers); |
| 1553 | 2000 |
| 1554 for (intptr_t i = 0; i < loop_headers.length(); ++i) { | 2001 for (intptr_t i = 0; i < loop_headers.length(); ++i) { |
| 1555 BlockEntryInstr* header = loop_headers[i]; | 2002 BlockEntryInstr* header = loop_headers[i]; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 1571 Definition* input_def = current->InputAt(i)->definition(); | 2018 Definition* input_def = current->InputAt(i)->definition(); |
| 1572 if (!input_def->GetBlock()->Dominates(pre_header)) { | 2019 if (!input_def->GetBlock()->Dominates(pre_header)) { |
| 1573 inputs_loop_invariant = false; | 2020 inputs_loop_invariant = false; |
| 1574 break; | 2021 break; |
| 1575 } | 2022 } |
| 1576 } | 2023 } |
| 1577 if (inputs_loop_invariant) { | 2024 if (inputs_loop_invariant) { |
| 1578 Hoist(&it, pre_header, current); | 2025 Hoist(&it, pre_header, current); |
| 1579 } else if (current->IsCheckSmi() && | 2026 } else if (current->IsCheckSmi() && |
| 1580 current->InputAt(0)->definition()->IsPhi()) { | 2027 current->InputAt(0)->definition()->IsPhi()) { |
| 1581 TryHoistCheckSmiThroughPhi(&it, header, pre_header, current); | 2028 TryHoistCheckSmiThroughPhi( |
| 2029 &it, header, pre_header, current->AsCheckSmi()); | |
| 1582 } | 2030 } |
| 1583 } | 2031 } |
| 1584 } | 2032 } |
| 1585 } | 2033 } |
| 1586 } | 2034 } |
| 1587 } | 2035 } |
| 1588 | 2036 |
| 1589 | 2037 |
| 1590 static intptr_t NumberLoadExpressions(FlowGraph* graph) { | 2038 static intptr_t NumberLoadExpressions(FlowGraph* graph) { |
| 1591 DirectChainedHashMap<Definition*> map; | 2039 DirectChainedHashMap<Definition*> map; |
| (...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2317 void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { | 2765 void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { |
| 2318 // Nothing to do. Has no value. | 2766 // Nothing to do. Has no value. |
| 2319 } | 2767 } |
| 2320 | 2768 |
| 2321 | 2769 |
| 2322 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { | 2770 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { |
| 2323 SetValue(instr, instr->value()); | 2771 SetValue(instr, instr->value()); |
| 2324 } | 2772 } |
| 2325 | 2773 |
| 2326 | 2774 |
| 2775 void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { | |
| 2776 // Should not be used outside of range analysis. | |
| 2777 UNREACHABLE(); | |
| 2778 } | |
| 2779 | |
| 2780 | |
| 2327 void ConstantPropagator::VisitCheckEitherNonSmi(CheckEitherNonSmiInstr* instr) { | 2781 void ConstantPropagator::VisitCheckEitherNonSmi(CheckEitherNonSmiInstr* instr) { |
| 2328 // Nothing to do. Not a value. | 2782 // Nothing to do. Not a value. |
| 2329 } | 2783 } |
| 2330 | 2784 |
| 2331 | 2785 |
| 2332 void ConstantPropagator::VisitUnboxedDoubleBinaryOp( | 2786 void ConstantPropagator::VisitUnboxedDoubleBinaryOp( |
| 2333 UnboxedDoubleBinaryOpInstr* instr) { | 2787 UnboxedDoubleBinaryOpInstr* instr) { |
| 2334 const Object& left = instr->left()->definition()->constant_value(); | 2788 const Object& left = instr->left()->definition()->constant_value(); |
| 2335 const Object& right = instr->right()->definition()->constant_value(); | 2789 const Object& right = instr->right()->definition()->constant_value(); |
| 2336 if (IsNonConstant(left) || IsNonConstant(right)) { | 2790 if (IsNonConstant(left) || IsNonConstant(right)) { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2488 it.Advance()) { | 2942 it.Advance()) { |
| 2489 JoinEntryInstr* join = it.Current()->AsJoinEntry(); | 2943 JoinEntryInstr* join = it.Current()->AsJoinEntry(); |
| 2490 if (join != NULL) join->EliminateUnreachablePhiInputs(); | 2944 if (join != NULL) join->EliminateUnreachablePhiInputs(); |
| 2491 } | 2945 } |
| 2492 | 2946 |
| 2493 graph_->ComputeUseLists(); | 2947 graph_->ComputeUseLists(); |
| 2494 } | 2948 } |
| 2495 | 2949 |
| 2496 | 2950 |
| 2497 } // namespace dart | 2951 } // namespace dart |
| OLD | NEW |