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 constraint them at branch successors. | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
constraint ==> constrain wherever used as a verb.
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1224 // Additionally constraint values after CheckSmi instructions. | |
| 1225 void InsertConstraints(); | |
| 1226 | |
| 1227 // Iterate over uses of the given definition and discover branches that | |
| 1228 // constraint 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* ConstraintValue(Definition* defn, | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
ConstraintValue ==> ConstrainValue
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 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. | |
| 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() { | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
It seems more straightforward to directly insert c
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Agreed. I am going to commit as is and refactor it
| |
| 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 instructions that are outside of the graph and | |
| 1370 // dead phis. | |
| 1371 if (use->instruction()->WasEliminated() && | |
|
Florian Schneider
2012/09/21 08:56:44
Why do you need to skip those?
Kevin Millikin (Google)
2012/09/21 08:59:33
Can live phis be WasEliminated? That's weird.
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
I don't want to compute ranges for things that are
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Our WasEliminated check just checks if previous()
| |
| 1372 !(use->instruction()->IsPhi() && | |
| 1373 use->instruction()->AsPhi()->is_alive())) { | |
| 1374 prev_use = use; | |
| 1375 continue; | |
| 1376 } | |
| 1377 | |
| 1378 if (IsDominatedUse(dom, use)) { | |
| 1379 if (prev_use != NULL) { | |
| 1380 prev_use->set_next_use(next_use); | |
| 1381 } else { | |
| 1382 def->set_input_use_list(next_use); | |
| 1383 } | |
| 1384 use->set_definition(other); | |
| 1385 use->AddToInputUseList(); | |
| 1386 } else { | |
| 1387 prev_use = use; | |
| 1388 } | |
| 1389 } | |
| 1390 } | |
| 1391 | |
| 1392 | |
| 1393 // For a comparison operation return an operation for the equivalent flipped | |
| 1394 // comparison: a (op) b === b (op') a. | |
| 1395 static Token::Kind FlipComparison(Token::Kind op) { | |
| 1396 switch (op) { | |
| 1397 case Token::kEQ: return Token::kEQ; | |
| 1398 case Token::kNE: return Token::kNE; | |
| 1399 case Token::kLT: return Token::kGT; | |
| 1400 case Token::kGT: return Token::kLT; | |
| 1401 case Token::kLTE: return Token::kGTE; | |
| 1402 case Token::kGTE: return Token::kLTE; | |
| 1403 default: | |
| 1404 UNREACHABLE(); | |
| 1405 return Token::kILLEGAL; | |
| 1406 } | |
| 1407 } | |
| 1408 | |
| 1409 // For a comparison operation return an operation for the negated comparison: | |
| 1410 // !(a (op) b) === a (op') b | |
| 1411 static Token::Kind NegateComparison(Token::Kind op) { | |
| 1412 switch (op) { | |
| 1413 case Token::kEQ: return Token::kNE; | |
| 1414 case Token::kNE: return Token::kEQ; | |
| 1415 case Token::kLT: return Token::kGTE; | |
| 1416 case Token::kGT: return Token::kLTE; | |
| 1417 case Token::kLTE: return Token::kGT; | |
| 1418 case Token::kGTE: return Token::kLT; | |
| 1419 default: | |
| 1420 UNREACHABLE(); | |
| 1421 return Token::kILLEGAL; | |
| 1422 } | |
| 1423 } | |
| 1424 | |
| 1425 | |
| 1426 // Given a boundary (right operand) and a comparison operation return | |
| 1427 // a symbolic range constraint for the left operand of the comparison assuming | |
| 1428 // that it evaluated to true. | |
| 1429 // For example for the comparison a < b symbol a is constrained with range | |
| 1430 // [Smi::kMinValue, b - 1]. | |
| 1431 static Range* ConstraintRange(Token::Kind op, Definition* boundary) { | |
| 1432 switch (op) { | |
| 1433 case Token::kEQ: | |
| 1434 return new Range(RangeBoundary::FromDefinition(boundary), | |
| 1435 RangeBoundary::FromDefinition(boundary)); | |
| 1436 case Token::kNE: | |
| 1437 return Range::Unknown(); | |
| 1438 case Token::kLT: | |
| 1439 return new Range(RangeBoundary::MinSmi(), | |
| 1440 RangeBoundary::FromDefinition(boundary, -1)); | |
| 1441 case Token::kGT: | |
| 1442 return new Range(RangeBoundary::FromDefinition(boundary, 1), | |
| 1443 RangeBoundary::MaxSmi()); | |
| 1444 case Token::kLTE: | |
| 1445 return new Range(RangeBoundary::MinSmi(), | |
| 1446 RangeBoundary::FromDefinition(boundary)); | |
| 1447 case Token::kGTE: | |
| 1448 return new Range(RangeBoundary::FromDefinition(boundary), | |
| 1449 RangeBoundary::MaxSmi()); | |
| 1450 default: | |
| 1451 UNREACHABLE(); | |
| 1452 return Range::Unknown(); | |
| 1453 } | |
| 1454 } | |
| 1455 | |
| 1456 | |
| 1457 ConstraintInstr* RangeAnalysis::ConstraintValue(Definition* defn, | |
|
Florian Schneider
2012/09/21 08:56:44
Suggested better name: InsertConstraintFor
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1458 Range* constraint_range, | |
| 1459 Instruction* after) { | |
|
Florian Schneider
2012/09/21 08:56:44
Maybe assert that Definition defn dominates Instru
| |
| 1460 // No need to constraint constants. | |
|
Florian Schneider
2012/09/21 08:56:44
s/constraint/constrain/
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1461 if (defn->IsConstant()) return NULL; | |
| 1462 | |
| 1463 ConstraintInstr* constraint = | |
| 1464 new ConstraintInstr(new Value(defn), constraint_range); | |
| 1465 constraint->InsertAfter(after); | |
| 1466 constraint->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index()); | |
| 1467 RenameDominatedUses(defn, after, constraint); | |
| 1468 constraints_.Add(constraint); | |
| 1469 constraint->value()->set_instruction(constraint); | |
| 1470 constraint->value()->set_use_index(0); | |
| 1471 constraint->value()->AddToInputUseList(); | |
| 1472 return constraint; | |
| 1473 } | |
| 1474 | |
| 1475 | |
| 1476 void RangeAnalysis::InsertConstraintsFor(Definition* defn) { | |
| 1477 for (Value* use = defn->input_use_list(); | |
| 1478 use != NULL; | |
| 1479 use = use->next_use()) { | |
| 1480 if (use->instruction()->IsBranch()) { | |
| 1481 BranchInstr* branch = use->instruction()->AsBranch(); | |
| 1482 RelationalOpInstr* rel_op = branch->comparison()->AsRelationalOp(); | |
| 1483 if ((rel_op != NULL) && (rel_op->operands_class_id() == kSmiCid)) { | |
| 1484 // Found comparison of two smis. Constrain defn at true and false | |
| 1485 // successors using the other operand as a boundary. | |
| 1486 Definition* boundary = | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
Since you test use_index() anyway, it's clearer to
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1487 rel_op->InputAt(1 - use->use_index())->definition(); | |
| 1488 | |
| 1489 // ConstraintValue assumes that defn is left operand of a comparison | |
| 1490 // if it is right operand flip the comparison. | |
| 1491 const Token::Kind op_kind = | |
| 1492 (use->use_index() == 0) ? rel_op->kind() | |
| 1493 : FlipComparison(rel_op->kind()); | |
| 1494 | |
| 1495 // Constrain definition at the true successor. | |
| 1496 ConstraintInstr* true_constraint = | |
| 1497 ConstraintValue(defn, | |
| 1498 ConstraintRange(op_kind, boundary), | |
| 1499 branch->true_successor()); | |
| 1500 // Mark true_constraint an artificial use of boundary. This ensures | |
| 1501 // that constraints range is recalculated if boundary's range changes. | |
| 1502 if (true_constraint != NULL) true_constraint->AddDependency(boundary); | |
| 1503 | |
| 1504 // Constrain definition with a negated condition at the false successor. | |
| 1505 ConstraintInstr* false_constraint = | |
| 1506 ConstraintValue( | |
| 1507 defn, | |
| 1508 ConstraintRange(NegateComparison(op_kind), boundary), | |
| 1509 branch->false_successor()); | |
| 1510 // Mark false_constraint an artificial use of boundary. This ensures | |
| 1511 // that constraints range is recalculated if boundary's range changes. | |
| 1512 if (false_constraint != NULL) false_constraint->AddDependency(boundary); | |
| 1513 } | |
| 1514 } | |
| 1515 } | |
| 1516 } | |
| 1517 | |
| 1518 | |
| 1519 void RangeAnalysis::InsertConstraints() { | |
| 1520 for (intptr_t i = 0; i < smi_checks_.length(); i++) { | |
| 1521 CheckSmiInstr* check = smi_checks_[i]; | |
| 1522 ConstraintInstr* constraint = | |
| 1523 ConstraintValue(check->value()->definition(), | |
| 1524 Range::Unknown(), | |
| 1525 check); | |
| 1526 InsertConstraintsFor(constraint); // Constraint uses further. | |
| 1527 } | |
| 1528 | |
| 1529 for (intptr_t i = 0; i < smi_values_.length(); i++) { | |
| 1530 InsertConstraintsFor(smi_values_[i]); | |
| 1531 } | |
| 1532 } | |
| 1533 | |
| 1534 | |
| 1535 void RangeAnalysis::InitializeRangesRecursive(BlockEntryInstr* block) { | |
| 1536 JoinEntryInstr* join = block->AsJoinEntry(); | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
It also seems like we could do this in the same wa
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
See above comment. I am going to commit as is now.
| |
| 1537 if ((join != NULL) && (join->phis() != NULL)) { | |
| 1538 for (intptr_t i = 0; i < join->phis()->length(); ++i) { | |
| 1539 PhiInstr* phi = (*join->phis())[i]; | |
| 1540 if (phi == NULL) continue; | |
| 1541 if (smi_definitions_->Contains(phi->ssa_temp_index())) { | |
| 1542 phi->InferRange(); | |
| 1543 AddToWorklist(phi); | |
| 1544 } | |
| 1545 } | |
| 1546 } | |
| 1547 | |
| 1548 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | |
| 1549 Definition* defn = it.Current()->AsDefinition(); | |
| 1550 if ((defn != NULL) && | |
| 1551 (defn->ssa_temp_index() != -1) && | |
| 1552 smi_definitions_->Contains(defn->ssa_temp_index())) { | |
| 1553 defn->InferRange(); | |
| 1554 AddToWorklist(defn); | |
| 1555 } | |
| 1556 } | |
| 1557 | |
| 1558 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) { | |
| 1559 InitializeRangesRecursive(block->dominated_blocks()[i]); | |
| 1560 } | |
| 1561 } | |
| 1562 | |
| 1563 | |
| 1564 void RangeAnalysis::CreateWorklists() { | |
| 1565 active_worklist_ = new ZoneGrowableArray<Definition*>(10); | |
| 1566 inactive_worklist_ = new ZoneGrowableArray<Definition*>(10); | |
| 1567 in_inactive_worklist_ = new BitVector( | |
| 1568 flow_graph_->current_ssa_temp_index()); | |
| 1569 } | |
| 1570 | |
| 1571 | |
| 1572 void RangeAnalysis::SwapWorklists() { | |
| 1573 ZoneGrowableArray<Definition*>* temp = active_worklist_; | |
| 1574 active_worklist_ = inactive_worklist_; | |
| 1575 inactive_worklist_ = temp; | |
| 1576 inactive_worklist_->Clear(); | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
This worklist is assumed empty here, right?
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
We don't pop anything from the worklist. We just p
| |
| 1577 in_inactive_worklist_->Clear(); | |
| 1578 } | |
| 1579 | |
| 1580 | |
| 1581 void RangeAnalysis::InferRanges() { | |
| 1582 CreateWorklists(); | |
| 1583 | |
| 1584 // Initialize bitvector for quick filtering of smi values. | |
| 1585 smi_definitions_ = new BitVector(flow_graph_->current_ssa_temp_index()); | |
| 1586 for (intptr_t i = 0; i < smi_values_.length(); i++) { | |
| 1587 smi_definitions_->Add(smi_values_[i]->ssa_temp_index()); | |
| 1588 } | |
| 1589 for (intptr_t i = 0; i < constraints_.length(); i++) { | |
| 1590 smi_definitions_->Add(constraints_[i]->ssa_temp_index()); | |
| 1591 } | |
| 1592 | |
| 1593 // Infer initial values of ranges. | |
| 1594 InitializeRangesRecursive(flow_graph_->graph_entry()); | |
| 1595 | |
| 1596 // Active worklist is empty, inactive now contains all smi values. | |
| 1597 SwapWorklists(); | |
| 1598 | |
| 1599 // Iterate until fix point is reached. | |
| 1600 while (!IsWorklistEmpty()) { | |
| 1601 for (intptr_t i = 0; i < active_worklist_->length(); i++) { | |
| 1602 Definition* defn = (*active_worklist_)[i]; | |
| 1603 if (defn->InferRange()) { // Update the range. | |
| 1604 // Range change. Place all uses to the worklist. | |
| 1605 for (Value* use = defn->input_use_list(); | |
| 1606 use != NULL; | |
| 1607 use = use->next_use()) { | |
| 1608 Definition* use_defn = use->instruction()->AsDefinition(); | |
| 1609 if ((use_defn != NULL) && | |
| 1610 (use_defn->ssa_temp_index() != -1) && | |
|
Florian Schneider
2012/09/21 08:56:44
Can we still have a Definition with an ssa_index =
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Yes, unfortunately we do. For example StoreIndexed
| |
| 1611 smi_definitions_->Contains(use_defn->ssa_temp_index())) { | |
| 1612 AddToWorklist(use_defn); | |
|
Kevin Millikin (Google)
2012/09/21 08:59:33
The operation of the worklist is not clear. Here
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Worklist contains definition for which InferRange
| |
| 1613 } | |
| 1614 } | |
| 1615 } | |
| 1616 } | |
| 1617 | |
| 1618 // Active worklist has been processed. Inactive contains all values which | |
| 1619 // can be affected by changed ranges. | |
| 1620 SwapWorklists(); | |
| 1621 } | |
| 1622 } | |
| 1623 | |
| 1624 | |
| 1625 void RangeAnalysis::RemoveConstraints() { | |
| 1626 for (intptr_t i = 0; i < constraints_.length(); i++) { | |
| 1627 Definition* def = constraints_[i]->value()->definition(); | |
| 1628 // Some constraints might be constraining constraints. Unwind the chain of | |
| 1629 // constraints until | |
|
Florian Schneider
2012/09/21 08:56:44
Until what?
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 1630 while (def->IsConstraint()) { | |
| 1631 def = def->AsConstraint()->value()->definition(); | |
| 1632 } | |
| 1633 constraints_[i]->ReplaceUsesWith(def); | |
| 1634 constraints_[i]->RemoveDependency(); | |
| 1635 constraints_[i]->RemoveFromGraph(); | |
| 1636 } | |
| 1637 } | |
| 1638 | |
| 1639 | |
| 1640 void FlowGraphOptimizer::InferSmiRanges() { | |
| 1641 RangeAnalysis range_analysis(flow_graph_); | |
| 1642 range_analysis.Analyze(); | |
| 1643 } | |
| 1644 | |
| 1645 | |
| 1207 void FlowGraphTypePropagator::VisitBlocks() { | 1646 void FlowGraphTypePropagator::VisitBlocks() { |
| 1208 ASSERT(current_iterator_ == NULL); | 1647 ASSERT(current_iterator_ == NULL); |
| 1209 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 1648 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 1210 BlockEntryInstr* entry = block_order_[i]; | 1649 BlockEntryInstr* entry = block_order_[i]; |
| 1211 entry->Accept(this); | 1650 entry->Accept(this); |
| 1212 ForwardInstructionIterator it(entry); | 1651 ForwardInstructionIterator it(entry); |
| 1213 current_iterator_ = ⁢ | 1652 current_iterator_ = ⁢ |
| 1214 for (; !it.Done(); it.Advance()) { | 1653 for (; !it.Done(); it.Advance()) { |
| 1215 Instruction* current = it.Current(); | 1654 Instruction* current = it.Current(); |
| 1216 // No need to propagate the input types of the instruction, as long as | 1655 // No need to propagate the input types of the instruction, as long as |
| (...skipping 1100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2317 void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { | 2756 void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { |
| 2318 // Nothing to do. Has no value. | 2757 // Nothing to do. Has no value. |
| 2319 } | 2758 } |
| 2320 | 2759 |
| 2321 | 2760 |
| 2322 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { | 2761 void ConstantPropagator::VisitConstant(ConstantInstr* instr) { |
| 2323 SetValue(instr, instr->value()); | 2762 SetValue(instr, instr->value()); |
| 2324 } | 2763 } |
| 2325 | 2764 |
| 2326 | 2765 |
| 2766 void ConstantPropagator::VisitConstraint(ConstraintInstr* instr) { | |
| 2767 // Nothing to do. Is not used outside of range analysis. | |
|
Florian Schneider
2012/09/21 08:56:44
Maybe also make it UNREACHABLE()?
Vyacheslav Egorov (Google)
2012/09/21 20:08:07
Done.
| |
| 2768 } | |
| 2769 | |
| 2770 | |
| 2327 void ConstantPropagator::VisitCheckEitherNonSmi(CheckEitherNonSmiInstr* instr) { | 2771 void ConstantPropagator::VisitCheckEitherNonSmi(CheckEitherNonSmiInstr* instr) { |
| 2328 // Nothing to do. Not a value. | 2772 // Nothing to do. Not a value. |
| 2329 } | 2773 } |
| 2330 | 2774 |
| 2331 | 2775 |
| 2332 void ConstantPropagator::VisitUnboxedDoubleBinaryOp( | 2776 void ConstantPropagator::VisitUnboxedDoubleBinaryOp( |
| 2333 UnboxedDoubleBinaryOpInstr* instr) { | 2777 UnboxedDoubleBinaryOpInstr* instr) { |
| 2334 const Object& left = instr->left()->definition()->constant_value(); | 2778 const Object& left = instr->left()->definition()->constant_value(); |
| 2335 const Object& right = instr->right()->definition()->constant_value(); | 2779 const Object& right = instr->right()->definition()->constant_value(); |
| 2336 if (IsNonConstant(left) || IsNonConstant(right)) { | 2780 if (IsNonConstant(left) || IsNonConstant(right)) { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2488 it.Advance()) { | 2932 it.Advance()) { |
| 2489 JoinEntryInstr* join = it.Current()->AsJoinEntry(); | 2933 JoinEntryInstr* join = it.Current()->AsJoinEntry(); |
| 2490 if (join != NULL) join->EliminateUnreachablePhiInputs(); | 2934 if (join != NULL) join->EliminateUnreachablePhiInputs(); |
| 2491 } | 2935 } |
| 2492 | 2936 |
| 2493 graph_->ComputeUseLists(); | 2937 graph_->ComputeUseLists(); |
| 2494 } | 2938 } |
| 2495 | 2939 |
| 2496 | 2940 |
| 2497 } // namespace dart | 2941 } // namespace dart |
| OLD | NEW |