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 |