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 1359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1370 | 1370 |
| 1371 private: | 1371 private: |
| 1372 GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( | 1372 GVNFlagSet CollectSideEffectsOnPathsToDominatedBlock( |
| 1373 HBasicBlock* dominator, | 1373 HBasicBlock* dominator, |
| 1374 HBasicBlock* dominated); | 1374 HBasicBlock* dominated); |
| 1375 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); | 1375 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); |
| 1376 void ComputeBlockSideEffects(); | 1376 void ComputeBlockSideEffects(); |
| 1377 void LoopInvariantCodeMotion(); | 1377 void LoopInvariantCodeMotion(); |
| 1378 void ProcessLoopBlock(HBasicBlock* block, | 1378 void ProcessLoopBlock(HBasicBlock* block, |
| 1379 HBasicBlock* before_loop, | 1379 HBasicBlock* before_loop, |
| 1380 GVNFlagSet loop_kills); | 1380 GVNFlagSet loop_kills, |
| 1381 GVNFlagSet* preceeding_loop_depends); | |
| 1381 bool AllowCodeMotion(); | 1382 bool AllowCodeMotion(); |
| 1382 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); | 1383 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); |
| 1383 | 1384 |
| 1384 HGraph* graph() { return graph_; } | 1385 HGraph* graph() { return graph_; } |
| 1385 CompilationInfo* info() { return info_; } | 1386 CompilationInfo* info() { return info_; } |
| 1386 Zone* zone() { return graph_->zone(); } | 1387 Zone* zone() { return graph_->zone(); } |
| 1387 | 1388 |
| 1388 HGraph* graph_; | 1389 HGraph* graph_; |
| 1389 CompilationInfo* info_; | 1390 CompilationInfo* info_; |
| 1390 bool removed_side_effects_; | 1391 bool removed_side_effects_; |
| 1391 | 1392 |
| 1392 // A map of block IDs to their side effects. | 1393 // A map of block IDs to their side effects. |
| 1393 ZoneList<GVNFlagSet> block_side_effects_; | 1394 ZoneList<GVNFlagSet> block_side_effects_; |
| 1394 | 1395 |
| 1395 // A map of loop header block IDs to their loop's side effects. | 1396 // A map of loop header block IDs to their loop's side effects. |
| 1396 ZoneList<GVNFlagSet> loop_side_effects_; | 1397 ZoneList<GVNFlagSet> loop_side_effects_; |
| 1397 | 1398 |
| 1398 // Used when collecting side effects on paths from dominator to | 1399 // Used when collecting side effects on paths from dominator to |
| 1399 // dominated. | 1400 // dominated. |
| 1400 SparseSet visited_on_paths_; | 1401 SparseSet visited_on_paths_; |
| 1401 }; | 1402 }; |
| 1402 | 1403 |
| 1403 | 1404 |
| 1404 bool HGlobalValueNumberer::Analyze() { | 1405 bool HGlobalValueNumberer::Analyze() { |
| 1406 removed_side_effects_ = false; | |
| 1405 ComputeBlockSideEffects(); | 1407 ComputeBlockSideEffects(); |
| 1406 if (FLAG_loop_invariant_code_motion) { | 1408 if (FLAG_loop_invariant_code_motion) { |
| 1407 LoopInvariantCodeMotion(); | 1409 LoopInvariantCodeMotion(); |
| 1408 } | 1410 } |
| 1409 HValueMap* map = new(zone()) HValueMap(); | 1411 HValueMap* map = new(zone()) HValueMap(); |
| 1410 AnalyzeBlock(graph_->entry_block(), map); | 1412 AnalyzeBlock(graph_->entry_block(), map); |
| 1411 return removed_side_effects_; | 1413 return removed_side_effects_; |
| 1412 } | 1414 } |
| 1413 | 1415 |
| 1414 | 1416 |
| 1415 void HGlobalValueNumberer::ComputeBlockSideEffects() { | 1417 void HGlobalValueNumberer::ComputeBlockSideEffects() { |
| 1418 for (int i = 0; i < loop_side_effects_.length(); ++i) { | |
| 1419 loop_side_effects_[i].RemoveAll(); | |
| 1420 } | |
| 1416 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | 1421 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { |
| 1417 // Compute side effects for the block. | 1422 // Compute side effects for the block. |
| 1418 HBasicBlock* block = graph_->blocks()->at(i); | 1423 HBasicBlock* block = graph_->blocks()->at(i); |
| 1419 HInstruction* instr = block->first(); | 1424 HInstruction* instr = block->first(); |
| 1420 int id = block->block_id(); | 1425 int id = block->block_id(); |
| 1421 GVNFlagSet side_effects; | 1426 GVNFlagSet side_effects; |
| 1422 while (instr != NULL) { | 1427 while (instr != NULL) { |
| 1423 side_effects.Add(instr->ChangesFlags()); | 1428 side_effects.Add(instr->ChangesFlags()); |
| 1424 instr = instr->next(); | 1429 instr = instr->next(); |
| 1425 } | 1430 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1443 | 1448 |
| 1444 void HGlobalValueNumberer::LoopInvariantCodeMotion() { | 1449 void HGlobalValueNumberer::LoopInvariantCodeMotion() { |
| 1445 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { | 1450 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { |
| 1446 HBasicBlock* block = graph_->blocks()->at(i); | 1451 HBasicBlock* block = graph_->blocks()->at(i); |
| 1447 if (block->IsLoopHeader()) { | 1452 if (block->IsLoopHeader()) { |
| 1448 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; | 1453 GVNFlagSet side_effects = loop_side_effects_[block->block_id()]; |
| 1449 TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n", | 1454 TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n", |
| 1450 block->block_id(), | 1455 block->block_id(), |
| 1451 side_effects.ToIntegral()); | 1456 side_effects.ToIntegral()); |
| 1452 | 1457 |
| 1458 GVNFlagSet preceeding_loop_depends; | |
| 1453 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); | 1459 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); |
| 1454 for (int j = block->block_id(); j <= last->block_id(); ++j) { | 1460 for (int j = block->block_id(); j <= last->block_id(); ++j) { |
| 1455 ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects); | 1461 ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects, |
| 1462 &preceeding_loop_depends); | |
| 1456 } | 1463 } |
| 1457 } | 1464 } |
| 1458 } | 1465 } |
| 1459 } | 1466 } |
| 1460 | 1467 |
| 1461 | 1468 |
| 1462 void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block, | 1469 void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block, |
| 1463 HBasicBlock* loop_header, | 1470 HBasicBlock* loop_header, |
| 1464 GVNFlagSet loop_kills) { | 1471 GVNFlagSet loop_kills, |
| 1472 GVNFlagSet* preceeding_loop_depends) { | |
| 1465 HBasicBlock* pre_header = loop_header->predecessors()->at(0); | 1473 HBasicBlock* pre_header = loop_header->predecessors()->at(0); |
| 1466 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); | 1474 GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); |
| 1467 TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", | 1475 TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", |
| 1468 block->block_id(), | 1476 block->block_id(), |
| 1469 depends_flags.ToIntegral()); | 1477 depends_flags.ToIntegral()); |
| 1470 HInstruction* instr = block->first(); | 1478 HInstruction* instr = block->first(); |
| 1471 while (instr != NULL) { | 1479 while (instr != NULL) { |
| 1472 HInstruction* next = instr->next(); | 1480 HInstruction* next = instr->next(); |
| 1473 if (instr->CheckFlag(HValue::kUseGVN) && | 1481 bool hoisted = false; |
| 1474 !instr->gvn_flags().ContainsAnyOf(depends_flags)) { | 1482 if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1475 TraceGVN("Checking instruction %d (%s)\n", | 1483 TraceGVN("Checking instruction %d (%s) instr 0x%X, block 0x%X\n", |
| 1476 instr->id(), | 1484 instr->id(), |
| 1477 instr->Mnemonic()); | 1485 instr->Mnemonic(), |
| 1478 bool inputs_loop_invariant = true; | 1486 instr->gvn_flags().ToIntegral(), |
| 1479 for (int i = 0; i < instr->OperandCount(); ++i) { | 1487 depends_flags.ToIntegral() ); |
| 1480 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { | 1488 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); |
| 1481 inputs_loop_invariant = false; | 1489 if (!can_hoist && |
| 1490 !instr->HasObservableSideEffects() && | |
| 1491 instr->HasOneTimeSideEffects()) { | |
| 1492 // It's only possible to hoist one time side effects if there are no | |
| 1493 // dependencies on their changes from the loop header to the current | |
| 1494 // instruction. | |
|
fschneider
2012/01/25 00:04:57
In general a path from the header to the current i
danno
2012/01/31 15:38:26
I'm not sure that's true. We're careful to order t
| |
| 1495 can_hoist = | |
|
fschneider
2012/01/25 00:04:57
Please add a unit test that covers the two cases t
danno
2012/01/31 15:38:26
Done.
| |
| 1496 !preceeding_loop_depends->ContainsAnyOf( | |
| 1497 HValue::ConvertChangesToDependsFlags(instr->ChangesFlags())); | |
| 1498 } | |
| 1499 | |
| 1500 if (can_hoist) { | |
| 1501 bool inputs_loop_invariant = true; | |
| 1502 for (int i = 0; i < instr->OperandCount(); ++i) { | |
| 1503 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { | |
| 1504 inputs_loop_invariant = false; | |
| 1505 } | |
| 1506 } | |
| 1507 | |
| 1508 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { | |
| 1509 TraceGVN("Found loop invariant instruction %d\n", instr->id()); | |
| 1510 // Move the instruction out of the loop. | |
| 1511 instr->Unlink(); | |
| 1512 instr->InsertBefore(pre_header->end()); | |
| 1513 if (instr->HasSideEffects()) removed_side_effects_ = true; | |
| 1514 hoisted = true; | |
| 1482 } | 1515 } |
| 1483 } | 1516 } |
| 1484 | 1517 } |
| 1485 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { | 1518 if (!hoisted) { |
| 1486 TraceGVN("Found loop invariant instruction %d\n", instr->id()); | 1519 // Hoisting an instruction to the preheader causes its DependsOn flags to |
| 1487 // Move the instruction out of the loop. | 1520 // not prevent hosting OneTimeSideEffecct instructions. |
| 1488 instr->Unlink(); | 1521 preceeding_loop_depends->Add(instr->DependsOnFlags()); |
| 1489 instr->InsertBefore(pre_header->end()); | |
| 1490 } | |
| 1491 } | 1522 } |
| 1492 instr = next; | 1523 instr = next; |
| 1493 } | 1524 } |
| 1494 } | 1525 } |
| 1495 | 1526 |
| 1496 | 1527 |
| 1497 bool HGlobalValueNumberer::AllowCodeMotion() { | 1528 bool HGlobalValueNumberer::AllowCodeMotion() { |
| 1498 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; | 1529 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; |
| 1499 } | 1530 } |
| 1500 | 1531 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1542 while (instr != NULL) { | 1573 while (instr != NULL) { |
| 1543 HInstruction* next = instr->next(); | 1574 HInstruction* next = instr->next(); |
| 1544 GVNFlagSet flags = instr->ChangesFlags(); | 1575 GVNFlagSet flags = instr->ChangesFlags(); |
| 1545 if (!flags.IsEmpty()) { | 1576 if (!flags.IsEmpty()) { |
| 1546 // Clear all instructions in the map that are affected by side effects. | 1577 // Clear all instructions in the map that are affected by side effects. |
| 1547 map->Kill(flags); | 1578 map->Kill(flags); |
| 1548 TraceGVN("Instruction %d kills\n", instr->id()); | 1579 TraceGVN("Instruction %d kills\n", instr->id()); |
| 1549 } | 1580 } |
| 1550 if (instr->CheckFlag(HValue::kUseGVN)) { | 1581 if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1551 ASSERT(!instr->HasObservableSideEffects()); | 1582 ASSERT(!instr->HasObservableSideEffects()); |
| 1583 ASSERT(!instr->HasSideEffects() || instr->HasOneTimeSideEffects()); | |
| 1552 HValue* other = map->Lookup(instr); | 1584 HValue* other = map->Lookup(instr); |
| 1553 if (other != NULL) { | 1585 if (other != NULL) { |
| 1554 ASSERT(instr->Equals(other) && other->Equals(instr)); | 1586 ASSERT(instr->Equals(other) && other->Equals(instr)); |
| 1555 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", | 1587 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", |
| 1556 instr->id(), | 1588 instr->id(), |
| 1557 instr->Mnemonic(), | 1589 instr->Mnemonic(), |
| 1558 other->id(), | 1590 other->id(), |
| 1559 other->Mnemonic()); | 1591 other->Mnemonic()); |
| 1560 if (instr->HasSideEffects()) removed_side_effects_ = true; | 1592 if (instr->HasSideEffects()) removed_side_effects_ = true; |
| 1561 instr->DeleteAndReplaceWith(other); | 1593 instr->DeleteAndReplaceWith(other); |
| (...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2385 graph()->Canonicalize(); | 2417 graph()->Canonicalize(); |
| 2386 | 2418 |
| 2387 // Perform common subexpression elimination and loop-invariant code motion. | 2419 // Perform common subexpression elimination and loop-invariant code motion. |
| 2388 if (FLAG_use_gvn) { | 2420 if (FLAG_use_gvn) { |
| 2389 HPhase phase("Global value numbering", graph()); | 2421 HPhase phase("Global value numbering", graph()); |
| 2390 HGlobalValueNumberer gvn(graph(), info()); | 2422 HGlobalValueNumberer gvn(graph(), info()); |
| 2391 bool removed_side_effects = gvn.Analyze(); | 2423 bool removed_side_effects = gvn.Analyze(); |
| 2392 // Trigger a second analysis pass to further eliminate duplicate values that | 2424 // Trigger a second analysis pass to further eliminate duplicate values that |
| 2393 // could only be discovered by removing side-effect-generating instructions | 2425 // could only be discovered by removing side-effect-generating instructions |
| 2394 // during the first pass. | 2426 // during the first pass. |
| 2395 if (FLAG_smi_only_arrays && removed_side_effects) { | 2427 if (FLAG_smi_only_arrays) { |
| 2396 gvn.Analyze(); | 2428 if (removed_side_effects) { |
| 2429 removed_side_effects = gvn.Analyze(); | |
| 2430 } | |
| 2431 ASSERT(!removed_side_effects); | |
| 2397 } | 2432 } |
| 2398 } | 2433 } |
| 2399 | 2434 |
| 2400 if (FLAG_use_range) { | 2435 if (FLAG_use_range) { |
| 2401 HRangeAnalysis rangeAnalysis(graph()); | 2436 HRangeAnalysis rangeAnalysis(graph()); |
| 2402 rangeAnalysis.Analyze(); | 2437 rangeAnalysis.Analyze(); |
| 2403 } | 2438 } |
| 2404 graph()->ComputeMinusZeroChecks(); | 2439 graph()->ComputeMinusZeroChecks(); |
| 2405 | 2440 |
| 2406 // Eliminate redundant stack checks on backwards branches. | 2441 // Eliminate redundant stack checks on backwards branches. |
| (...skipping 5005 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7412 } | 7447 } |
| 7413 } | 7448 } |
| 7414 | 7449 |
| 7415 #ifdef DEBUG | 7450 #ifdef DEBUG |
| 7416 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 7451 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 7417 if (allocator_ != NULL) allocator_->Verify(); | 7452 if (allocator_ != NULL) allocator_->Verify(); |
| 7418 #endif | 7453 #endif |
| 7419 } | 7454 } |
| 7420 | 7455 |
| 7421 } } // namespace v8::internal | 7456 } } // namespace v8::internal |
| OLD | NEW |