// Copyright 2013 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_CRANKSHAFT_HYDROGEN_FLOW_ENGINE_H_ #define V8_CRANKSHAFT_HYDROGEN_FLOW_ENGINE_H_ #include "src/crankshaft/hydrogen.h" #include "src/crankshaft/hydrogen-instructions.h" #include "src/zone.h" namespace v8 { namespace internal { // An example implementation of effects that doesn't collect anything. class NoEffects : public ZoneObject { public: explicit NoEffects(Zone* zone) { } inline bool Disabled() { return true; // Nothing to do. } template inline void Apply(State* state) { // do nothing. } inline void Process(HInstruction* value, Zone* zone) { // do nothing. } inline void Union(NoEffects* other, Zone* zone) { // do nothing. } }; // An example implementation of state that doesn't track anything. class NoState { public: inline NoState* Copy(HBasicBlock* succ, Zone* zone) { return this; } inline NoState* Process(HInstruction* value, Zone* zone) { return this; } inline NoState* Merge(HBasicBlock* succ, NoState* other, Zone* zone) { return this; } }; // This class implements an engine that can drive flow-sensitive analyses // over a graph of basic blocks, either one block at a time (local analysis) // or over the entire graph (global analysis). The flow engine is parameterized // by the type of the state and the effects collected while walking over the // graph. // // The "State" collects which facts are known while passing over instructions // in control flow order, and the "Effects" collect summary information about // which facts could be invalidated on other control flow paths. The effects // are necessary to correctly handle loops in the control flow graph without // doing a fixed-point iteration. Thus the flow engine is guaranteed to visit // each block at most twice; once for state, and optionally once for effects. // // The flow engine requires the State and Effects classes to implement methods // like the example NoState and NoEffects above. It's not necessary to provide // an effects implementation for local analysis. template class HFlowEngine { public: HFlowEngine(HGraph* graph, Zone* zone) : graph_(graph), zone_(zone), #if DEBUG pred_counts_(graph->blocks()->length(), zone), #endif block_states_(graph->blocks()->length(), zone), loop_effects_(graph->blocks()->length(), zone) { loop_effects_.AddBlock(NULL, graph_->blocks()->length(), zone); } // Local analysis. Iterates over the instructions in the given block. State* AnalyzeOneBlock(HBasicBlock* block, State* state) { // Go through all instructions of the current block, updating the state. for (HInstructionIterator it(block); !it.Done(); it.Advance()) { state = state->Process(it.Current(), zone_); } return state; } // Global analysis. Iterates over all blocks that are dominated by the given // block, starting with the initial state. Computes effects for nested loops. void AnalyzeDominatedBlocks(HBasicBlock* root, State* initial) { InitializeStates(); SetStateAt(root, initial); // Iterate all dominated blocks starting from the given start block. for (int i = root->block_id(); i < graph_->blocks()->length(); i++) { HBasicBlock* block = graph_->blocks()->at(i); // Skip blocks not dominated by the root node. if (SkipNonDominatedBlock(root, block)) continue; State* state = State::Finish(StateAt(block), block, zone_); if (block->IsReachable()) { DCHECK(state != NULL); if (block->IsLoopHeader()) { // Apply loop effects before analyzing loop body. ComputeLoopEffects(block)->Apply(state); } else { // Must have visited all predecessors before this block. CheckPredecessorCount(block); } // Go through all instructions of the current block, updating the state. for (HInstructionIterator it(block); !it.Done(); it.Advance()) { state = state->Process(it.Current(), zone_); } } // Propagate the block state forward to all successor blocks. int max = block->end()->SuccessorCount(); for (int i = 0; i < max; i++) { HBasicBlock* succ = block->end()->SuccessorAt(i); IncrementPredecessorCount(succ); if (max == 1 && succ->predecessors()->length() == 1) { // Optimization: successor can inherit this state. SetStateAt(succ, state); } else { // Merge the current state with the state already at the successor. SetStateAt(succ, State::Merge(StateAt(succ), succ, state, block, zone_)); } } } } private: // Computes and caches the loop effects for the loop which has the given // block as its loop header. Effects* ComputeLoopEffects(HBasicBlock* block) { DCHECK(block->IsLoopHeader()); Effects* effects = loop_effects_[block->block_id()]; if (effects != NULL) return effects; // Already analyzed this loop. effects = new(zone_) Effects(zone_); loop_effects_[block->block_id()] = effects; if (effects->Disabled()) return effects; // No effects for this analysis. HLoopInformation* loop = block->loop_information(); int end = loop->GetLastBackEdge()->block_id(); // Process the blocks between the header and the end. for (int i = block->block_id(); i <= end; i++) { HBasicBlock* member = graph_->blocks()->at(i); if (i != block->block_id() && member->IsLoopHeader()) { // Recursively compute and cache the effects of the nested loop. DCHECK(member->loop_information()->parent_loop() == loop); Effects* nested = ComputeLoopEffects(member); effects->Union(nested, zone_); // Skip the nested loop's blocks. i = member->loop_information()->GetLastBackEdge()->block_id(); } else { // Process all the effects of the block. if (member->IsUnreachable()) continue; DCHECK(member->current_loop() == loop); for (HInstructionIterator it(member); !it.Done(); it.Advance()) { effects->Process(it.Current(), zone_); } } } return effects; } inline bool SkipNonDominatedBlock(HBasicBlock* root, HBasicBlock* other) { if (root->block_id() == 0) return false; // Visit the whole graph. if (root == other) return false; // Always visit the root. return !root->Dominates(other); // Only visit dominated blocks. } inline State* StateAt(HBasicBlock* block) { return block_states_.at(block->block_id()); } inline void SetStateAt(HBasicBlock* block, State* state) { block_states_.Set(block->block_id(), state); } inline void InitializeStates() { #if DEBUG pred_counts_.Rewind(0); pred_counts_.AddBlock(0, graph_->blocks()->length(), zone_); #endif block_states_.Rewind(0); block_states_.AddBlock(NULL, graph_->blocks()->length(), zone_); } inline void CheckPredecessorCount(HBasicBlock* block) { DCHECK(block->predecessors()->length() == pred_counts_[block->block_id()]); } inline void IncrementPredecessorCount(HBasicBlock* block) { #if DEBUG pred_counts_[block->block_id()]++; #endif } HGraph* graph_; // The hydrogen graph. Zone* zone_; // Temporary zone. #if DEBUG ZoneList pred_counts_; // Finished predecessors (by block id). #endif ZoneList block_states_; // Block states (by block id). ZoneList loop_effects_; // Loop effects (by block id). }; } // namespace internal } // namespace v8 #endif // V8_CRANKSHAFT_HYDROGEN_FLOW_ENGINE_H_