Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1346 }; | 1346 }; |
| 1347 | 1347 |
| 1348 | 1348 |
| 1349 class HGlobalValueNumberer BASE_EMBEDDED { | 1349 class HGlobalValueNumberer BASE_EMBEDDED { |
| 1350 public: | 1350 public: |
| 1351 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) | 1351 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) |
| 1352 : graph_(graph), | 1352 : graph_(graph), |
| 1353 info_(info), | 1353 info_(info), |
| 1354 removed_side_effects_(false), | 1354 removed_side_effects_(false), |
| 1355 block_side_effects_(graph->blocks()->length()), | 1355 block_side_effects_(graph->blocks()->length()), |
| 1356 block_depends_on_(graph->blocks()->length()), | |
| 1356 loop_side_effects_(graph->blocks()->length()), | 1357 loop_side_effects_(graph->blocks()->length()), |
| 1357 visited_on_paths_(graph->zone(), graph->blocks()->length()) { | 1358 visited_on_paths_(graph->zone(), graph->blocks()->length()) { |
| 1358 ASSERT(info->isolate()->heap()->allow_allocation(false)); | 1359 ASSERT(info->isolate()->heap()->allow_allocation(false)); |
| 1359 block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length()); | 1360 block_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length()); |
| 1361 block_depends_on_.AddBlock(GVNFlagSet(), graph_->blocks()->length()); | |
| 1360 loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length()); | 1362 loop_side_effects_.AddBlock(GVNFlagSet(), graph_->blocks()->length()); |
| 1361 } | 1363 } |
| 1362 ~HGlobalValueNumberer() { | 1364 ~HGlobalValueNumberer() { |
| 1363 ASSERT(!info_->isolate()->heap()->allow_allocation(true)); | 1365 ASSERT(!info_->isolate()->heap()->allow_allocation(true)); |
| 1364 } | 1366 } |
| 1365 | 1367 |
| 1366 // Returns true if values with side effects are removed. | 1368 // Returns true if values with side effects are removed. |
| 1367 bool Analyze(); | 1369 bool Analyze(); |
| 1368 | 1370 |
| 1369 private: | 1371 private: |
| 1370 GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( | 1372 GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( |
| 1371 HBasicBlock* dominator, | 1373 HBasicBlock* dominator, |
| 1372 HBasicBlock* dominated); | 1374 HBasicBlock* dominated); |
| 1373 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); | 1375 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); |
| 1374 void ComputeBlockSideEffects(); | 1376 void ComputeBlockSideEffects(); |
| 1375 void LoopInvariantCodeMotion(); | 1377 void LoopInvariantCodeMotion(); |
| 1376 void ProcessLoopBlock(HBasicBlock* block, | 1378 void ProcessLoopBlock(HBasicBlock* block, |
| 1377 HBasicBlock* before_loop, | 1379 HBasicBlock* before_loop, |
| 1378 GVNFlagSet loop_kills); | 1380 GVNFlagSet loop_kills, |
| 1381 GVNFlagSet conservative_first_time_depends, | |
| 1382 GVNFlagSet* accumulated_first_time_depends); | |
| 1379 bool AllowCodeMotion(); | 1383 bool AllowCodeMotion(); |
| 1380 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); | 1384 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); |
| 1381 | 1385 |
| 1382 HGraph* graph() { return graph_; } | 1386 HGraph* graph() { return graph_; } |
| 1383 CompilationInfo* info() { return info_; } | 1387 CompilationInfo* info() { return info_; } |
| 1384 Zone* zone() { return graph_->zone(); } | 1388 Zone* zone() { return graph_->zone(); } |
| 1385 | 1389 |
| 1386 HGraph* graph_; | 1390 HGraph* graph_; |
| 1387 CompilationInfo* info_; | 1391 CompilationInfo* info_; |
| 1388 bool removed_side_effects_; | 1392 bool removed_side_effects_; |
| 1389 | 1393 |
| 1390 // A map of block IDs to their side effects. | 1394 // A map of block IDs to their side effects. |
| 1391 ZoneList<GVNFlagSet> block_side_effects_; | 1395 ZoneList<GVNFlagSet> block_side_effects_; |
| 1396 ZoneList<GVNFlagSet> block_depends_on_; | |
| 1392 | 1397 |
| 1393 // A map of loop header block IDs to their loop's side effects. | 1398 // A map of loop header block IDs to their loop's side effects. |
| 1394 ZoneList<GVNFlagSet> loop_side_effects_; | 1399 ZoneList<GVNFlagSet> loop_side_effects_; |
| 1395 | 1400 |
| 1396 // Used when collecting side effects on paths from dominator to | 1401 // Used when collecting side effects on paths from dominator to |
| 1397 // dominated. | 1402 // dominated. |
| 1398 SparseSet visited_on_paths_; | 1403 SparseSet visited_on_paths_; |
| 1399 }; | 1404 }; |
| 1400 | 1405 |
| 1401 | 1406 |
| 1402 bool HGlobalValueNumberer::Analyze() { | 1407 bool HGlobalValueNumberer::Analyze() { |
| 1408 removed_side_effects_ = false; | |
| 1403 ComputeBlockSideEffects(); | 1409 ComputeBlockSideEffects(); |
| 1404 if (FLAG_loop_invariant_code_motion) { | 1410 if (FLAG_loop_invariant_code_motion) { |
| 1405 LoopInvariantCodeMotion(); | 1411 LoopInvariantCodeMotion(); |
| 1406 } | 1412 } |
| 1407 HValueMap* map = new(zone()) HValueMap(); | 1413 HValueMap* map = new(zone()) HValueMap(); |
| 1408 AnalyzeBlock(graph_->entry_block(), map); | 1414 AnalyzeBlock(graph_->entry_block(), map); |
| 1409 return removed_side_effects_; | 1415 return removed_side_effects_; |
| 1410 } | 1416 } |
| 1411 | 1417 |
| 1412 | 1418 |
| 1413 void HGlobalValueNumberer::ComputeBlockSideEffects() { | 1419 void HGlobalValueNumberer::ComputeBlockSideEffects() { |
| 1420 for (int i = 0; i < loop_side_effects_.length(); ++i) { | |
| 1421 loop_side_effects_[i].RemoveAll(); | |
| 1422 } | |
| 1414 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | 1423 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { |
| 1415 // Compute side effects for the block. | 1424 // Compute side effects for the block. |
| 1416 HBasicBlock* block = graph_->blocks()->at(i); | 1425 HBasicBlock* block = graph_->blocks()->at(i); |
| 1417 HInstruction* instr = block->first(); | 1426 HInstruction* instr = block->first(); |
| 1418 int id = block->block_id(); | 1427 int id = block->block_id(); |
| 1419 GVNFlagSet side_effects; | 1428 GVNFlagSet side_effects; |
| 1429 GVNFlagSet depends; | |
| 1420 while (instr != NULL) { | 1430 while (instr != NULL) { |
| 1421 side_effects.Add(instr->ChangesFlags()); | 1431 side_effects.Add(instr->ChangesFlags()); |
| 1432 depends.Add(instr->DependsOnFlags()); | |
| 1422 instr = instr->next(); | 1433 instr = instr->next(); |
| 1423 } | 1434 } |
| 1424 block_side_effects_[id].Add(side_effects); | 1435 block_side_effects_[id].Add(side_effects); |
| 1436 block_depends_on_[id].Add(depends); | |
| 1425 | 1437 |
| 1426 // Loop headers are part of their loop. | 1438 // Loop headers are part of their loop. |
| 1427 if (block->IsLoopHeader()) { | 1439 if (block->IsLoopHeader()) { |
| 1428 loop_side_effects_[id].Add(side_effects); | 1440 loop_side_effects_[id].Add(side_effects); |
| 1429 } | 1441 } |
| 1430 | 1442 |
| 1431 // Propagate loop side effects upwards. | 1443 // Propagate loop side effects upwards. |
| 1432 if (block->HasParentLoopHeader()) { | 1444 if (block->HasParentLoopHeader()) { |
| 1433 int header_id = block->parent_loop_header()->block_id(); | 1445 int header_id = block->parent_loop_header()->block_id(); |
| 1434 loop_side_effects_[header_id].Add(block->IsLoopHeader() | 1446 loop_side_effects_[header_id].Add(block->IsLoopHeader() |
| 1435 ? loop_side_effects_[id] | 1447 ? loop_side_effects_[id] |
| 1436 : side_effects); | 1448 : side_effects); |
| 1437 } | 1449 } |
| 1438 } | 1450 } |
| 1439 } | 1451 } |
| 1440 | 1452 |
| 1441 | 1453 |
| 1442 void HGlobalValueNumberer::LoopInvariantCodeMotion() { | 1454 void HGlobalValueNumberer::LoopInvariantCodeMotion() { |
| 1443 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | 1455 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { |
| 1444 HBasicBlock* block = graph_->blocks()->at(i); | 1456 HBasicBlock* block = graph_->blocks()->at(i); |
| 1445 if (block->IsLoopHeader()) { | 1457 if (block->IsLoopHeader()) { |
| 1446 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; | 1458 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; |
| 1447 TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n", | 1459 TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n", |
| 1448 block->block_id(), | 1460 block->block_id(), |
| 1449 side_effects.ToIntegral()); | 1461 side_effects.ToIntegral()); |
| 1450 | 1462 |
| 1463 GVNFlagSet accumulated_first_time_depends; | |
| 1451 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); | 1464 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); |
| 1465 int outstanding_sucsessors = 0; | |
| 1452 for (int j = block->block_id(); j <= last->block_id(); ++j) { | 1466 for (int j = block->block_id(); j <= last->block_id(); ++j) { |
| 1453 ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects); | 1467 GVNFlagSet conservative_first_time_depends = |
| 1468 accumulated_first_time_depends; | |
| 1469 HBasicBlock* analyze_block = graph_->blocks()->at(j); | |
| 1470 if (analyze_block != block) { | |
| 1471 outstanding_sucsessors -= analyze_block->predecessors()->length(); | |
| 1472 } | |
| 1473 if (outstanding_sucsessors != 0) { | |
| 1474 // If more successors than predecessors have been seen in the loop up | |
| 1475 // to now, it's not possible to guarantee that the current block | |
| 1476 // dominates all of the blocks with higher IDs. In this case, assume | |
| 1477 // conservatively that those paths through loop that don't go through | |
| 1478 // the current block contain all of the loop's dependencies. | |
|
fschneider
2012/02/01 10:54:14
I don't think this works in general: e.g. in a sim
danno
2012/02/01 16:53:15
Done.
| |
| 1479 conservative_first_time_depends.Add( | |
| 1480 block_depends_on_[analyze_block->block_id()]); | |
| 1481 } | |
| 1482 ProcessLoopBlock(analyze_block, block, side_effects, | |
| 1483 conservative_first_time_depends, | |
| 1484 &accumulated_first_time_depends); | |
| 1485 outstanding_sucsessors += analyze_block->end()->SuccessorCount(); | |
| 1454 } | 1486 } |
| 1455 } | 1487 } |
| 1456 } | 1488 } |
| 1457 } | 1489 } |
| 1458 | 1490 |
| 1459 | 1491 |
| 1460 void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block, | 1492 void HGlobalValueNumberer::ProcessLoopBlock( |
| 1461 HBasicBlock* loop_header, | 1493 HBasicBlock* block, |
| 1462 GVNFlagSet loop_kills) { | 1494 HBasicBlock* loop_header, |
| 1495 GVNFlagSet loop_kills, | |
| 1496 GVNFlagSet conservative_first_time_depends, | |
| 1497 GVNFlagSet* accumulated_first_time_depends) { | |
| 1463 HBasicBlock* pre_header = loop_header->predecessors()->at(0); | 1498 HBasicBlock* pre_header = loop_header->predecessors()->at(0); |
| 1464 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); | 1499 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); |
| 1465 TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", | 1500 TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", |
| 1466 block->block_id(), | 1501 block->block_id(), |
| 1467 depends_flags.ToIntegral()); | 1502 depends_flags.ToIntegral()); |
| 1468 HInstruction* instr = block->first(); | 1503 HInstruction* instr = block->first(); |
| 1469 while (instr != NULL) { | 1504 while (instr != NULL) { |
| 1470 HInstruction* next = instr->next(); | 1505 HInstruction* next = instr->next(); |
| 1471 if (instr->CheckFlag(HValue::kUseGVN) && | 1506 bool hoisted = false; |
| 1472 !instr->gvn_flags().ContainsAnyOf(depends_flags)) { | 1507 if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1473 TraceGVN("Checking instruction %d (%s)\n", | 1508 TraceGVN("Checking instruction %d (%s) instruction GVN flags 0x%X, " |
| 1509 "conservative depends 0x%X, loop kills 0x%X\n", | |
| 1474 instr->id(), | 1510 instr->id(), |
| 1475 instr->Mnemonic()); | 1511 instr->Mnemonic(), |
| 1476 bool inputs_loop_invariant = true; | 1512 instr->gvn_flags().ToIntegral(), |
| 1477 for (int i = 0; i < instr->OperandCount(); ++i) { | 1513 (conservative_first_time_depends).ToIntegral(), |
| 1478 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { | 1514 depends_flags.ToIntegral()); |
| 1479 inputs_loop_invariant = false; | 1515 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); |
| 1516 if (!can_hoist && | |
| 1517 !instr->HasObservableSideEffects() && | |
| 1518 instr->HasOneTimeSideEffects()) { | |
| 1519 // It's only possible to hoist one time side effects if there are no | |
| 1520 // dependencies on their changes from the loop header to the current | |
| 1521 // instruction. | |
| 1522 GVNFlagSet converted_changes = | |
| 1523 HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); | |
| 1524 TraceGVN("Checking dependencies on one-time instruction %d (%s) " | |
| 1525 "converted changes 0x%X, conservative depends 0x%X\n", | |
| 1526 instr->id(), | |
| 1527 instr->Mnemonic(), | |
| 1528 converted_changes.ToIntegral(), | |
| 1529 (conservative_first_time_depends).ToIntegral()); | |
| 1530 can_hoist = | |
| 1531 !conservative_first_time_depends.ContainsAnyOf(converted_changes); | |
| 1532 } | |
| 1533 | |
| 1534 if (can_hoist) { | |
| 1535 bool inputs_loop_invariant = true; | |
| 1536 for (int i = 0; i < instr->OperandCount(); ++i) { | |
| 1537 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { | |
| 1538 inputs_loop_invariant = false; | |
| 1539 } | |
| 1540 } | |
| 1541 | |
| 1542 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { | |
| 1543 TraceGVN("Found loop invariant instruction %d\n", instr->id()); | |
| 1544 // Move the instruction out of the loop. | |
| 1545 instr->Unlink(); | |
| 1546 instr->InsertBefore(pre_header->end()); | |
| 1547 if (instr->HasSideEffects()) removed_side_effects_ = true; | |
| 1548 hoisted = true; | |
| 1480 } | 1549 } |
| 1481 } | 1550 } |
| 1482 | 1551 } |
| 1483 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { | 1552 if (!hoisted) { |
| 1484 TraceGVN("Found loop invariant instruction %d\n", instr->id()); | 1553 // Hoisting an instruction to the preheader causes its DependsOn flags to |
| 1485 // Move the instruction out of the loop. | 1554 // not prevent hosting OneTimeSideEffecct instructions. |
| 1486 instr->Unlink(); | 1555 accumulated_first_time_depends->Add(instr->DependsOnFlags()); |
| 1487 instr->InsertBefore(pre_header->end()); | |
| 1488 } | |
| 1489 } | 1556 } |
| 1490 instr = next; | 1557 instr = next; |
| 1491 } | 1558 } |
| 1492 } | 1559 } |
| 1493 | 1560 |
| 1494 | 1561 |
| 1495 bool HGlobalValueNumberer::AllowCodeMotion() { | 1562 bool HGlobalValueNumberer::AllowCodeMotion() { |
| 1496 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; | 1563 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; |
| 1497 } | 1564 } |
| 1498 | 1565 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1540 while (instr != NULL) { | 1607 while (instr != NULL) { |
| 1541 HInstruction* next = instr->next(); | 1608 HInstruction* next = instr->next(); |
| 1542 GVNFlagSet flags = instr->ChangesFlags(); | 1609 GVNFlagSet flags = instr->ChangesFlags(); |
| 1543 if (!flags.IsEmpty()) { | 1610 if (!flags.IsEmpty()) { |
| 1544 // Clear all instructions in the map that are affected by side effects. | 1611 // Clear all instructions in the map that are affected by side effects. |
| 1545 map->Kill(flags); | 1612 map->Kill(flags); |
| 1546 TraceGVN("Instruction %d kills\n", instr->id()); | 1613 TraceGVN("Instruction %d kills\n", instr->id()); |
| 1547 } | 1614 } |
| 1548 if (instr->CheckFlag(HValue::kUseGVN)) { | 1615 if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1549 ASSERT(!instr->HasObservableSideEffects()); | 1616 ASSERT(!instr->HasObservableSideEffects()); |
| 1617 ASSERT(!instr->HasSideEffects() || instr->HasOneTimeSideEffects()); | |
| 1550 HValue* other = map->Lookup(instr); | 1618 HValue* other = map->Lookup(instr); |
| 1551 if (other != NULL) { | 1619 if (other != NULL) { |
| 1552 ASSERT(instr->Equals(other) && other->Equals(instr)); | 1620 ASSERT(instr->Equals(other) && other->Equals(instr)); |
| 1553 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", | 1621 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", |
| 1554 instr->id(), | 1622 instr->id(), |
| 1555 instr->Mnemonic(), | 1623 instr->Mnemonic(), |
| 1556 other->id(), | 1624 other->id(), |
| 1557 other->Mnemonic()); | 1625 other->Mnemonic()); |
| 1558 if (instr->HasSideEffects()) removed_side_effects_ = true; | 1626 if (instr->HasSideEffects()) removed_side_effects_ = true; |
| 1559 instr->DeleteAndReplaceWith(other); | 1627 instr->DeleteAndReplaceWith(other); |
| (...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2387 | 2455 |
| 2388 // Perform common subexpression elimination and loop-invariant code motion. | 2456 // Perform common subexpression elimination and loop-invariant code motion. |
| 2389 if (FLAG_use_gvn) { | 2457 if (FLAG_use_gvn) { |
| 2390 HPhase phase("Global value numbering", graph()); | 2458 HPhase phase("Global value numbering", graph()); |
| 2391 HGlobalValueNumberer gvn(graph(), info()); | 2459 HGlobalValueNumberer gvn(graph(), info()); |
| 2392 bool removed_side_effects = gvn.Analyze(); | 2460 bool removed_side_effects = gvn.Analyze(); |
| 2393 // Trigger a second analysis pass to further eliminate duplicate values that | 2461 // Trigger a second analysis pass to further eliminate duplicate values that |
| 2394 // could only be discovered by removing side-effect-generating instructions | 2462 // could only be discovered by removing side-effect-generating instructions |
| 2395 // during the first pass. | 2463 // during the first pass. |
| 2396 if (FLAG_smi_only_arrays && removed_side_effects) { | 2464 if (FLAG_smi_only_arrays && removed_side_effects) { |
| 2397 gvn.Analyze(); | 2465 removed_side_effects = gvn.Analyze(); |
| 2466 ASSERT(!removed_side_effects); | |
| 2398 } | 2467 } |
| 2399 } | 2468 } |
| 2400 | 2469 |
| 2401 if (FLAG_use_range) { | 2470 if (FLAG_use_range) { |
| 2402 HRangeAnalysis rangeAnalysis(graph()); | 2471 HRangeAnalysis rangeAnalysis(graph()); |
| 2403 rangeAnalysis.Analyze(); | 2472 rangeAnalysis.Analyze(); |
| 2404 } | 2473 } |
| 2405 graph()->ComputeMinusZeroChecks(); | 2474 graph()->ComputeMinusZeroChecks(); |
| 2406 | 2475 |
| 2407 // Eliminate redundant stack checks on backwards branches. | 2476 // Eliminate redundant stack checks on backwards branches. |
| (...skipping 5047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7455 } | 7524 } |
| 7456 } | 7525 } |
| 7457 | 7526 |
| 7458 #ifdef DEBUG | 7527 #ifdef DEBUG |
| 7459 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7528 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 7460 if (allocator_ != NULL) allocator_->Verify(); | 7529 if (allocator_ != NULL) allocator_->Verify(); |
| 7461 #endif | 7530 #endif |
| 7462 } | 7531 } |
| 7463 | 7532 |
| 7464 } } // namespace v8::internal | 7533 } } // namespace v8::internal |
| OLD | NEW |