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 |