• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_HYDROGEN_FLOW_ENGINE_H_
29 #define V8_HYDROGEN_FLOW_ENGINE_H_
30 
31 #include "hydrogen.h"
32 #include "hydrogen-instructions.h"
33 #include "zone.h"
34 
35 namespace v8 {
36 namespace internal {
37 
38 // An example implementation of effects that doesn't collect anything.
39 class NoEffects : public ZoneObject {
40  public:
NoEffects(Zone * zone)41   explicit NoEffects(Zone* zone) { }
42 
Disabled()43   inline bool Disabled() {
44     return true;  // Nothing to do.
45   }
46   template <class State>
Apply(State * state)47   inline void Apply(State* state) {
48     // do nothing.
49   }
Process(HInstruction * value,Zone * zone)50   inline void Process(HInstruction* value, Zone* zone) {
51     // do nothing.
52   }
Union(NoEffects * other,Zone * zone)53   inline void Union(NoEffects* other, Zone* zone) {
54     // do nothing.
55   }
56 };
57 
58 
59 // An example implementation of state that doesn't track anything.
60 class NoState {
61  public:
Copy(HBasicBlock * succ,Zone * zone)62   inline NoState* Copy(HBasicBlock* succ, Zone* zone) {
63     return this;
64   }
Process(HInstruction * value,Zone * zone)65   inline NoState* Process(HInstruction* value, Zone* zone) {
66     return this;
67   }
Merge(HBasicBlock * succ,NoState * other,Zone * zone)68   inline NoState* Merge(HBasicBlock* succ, NoState* other, Zone* zone) {
69     return this;
70   }
71 };
72 
73 
74 // This class implements an engine that can drive flow-sensitive analyses
75 // over a graph of basic blocks, either one block at a time (local analysis)
76 // or over the entire graph (global analysis). The flow engine is parameterized
77 // by the type of the state and the effects collected while walking over the
78 // graph.
79 //
80 // The "State" collects which facts are known while passing over instructions
81 // in control flow order, and the "Effects" collect summary information about
82 // which facts could be invalidated on other control flow paths. The effects
83 // are necessary to correctly handle loops in the control flow graph without
84 // doing a fixed-point iteration. Thus the flow engine is guaranteed to visit
85 // each block at most twice; once for state, and optionally once for effects.
86 //
87 // The flow engine requires the State and Effects classes to implement methods
88 // like the example NoState and NoEffects above. It's not necessary to provide
89 // an effects implementation for local analysis.
90 template <class State, class Effects>
91 class HFlowEngine {
92  public:
HFlowEngine(HGraph * graph,Zone * zone)93   HFlowEngine(HGraph* graph, Zone* zone)
94     : graph_(graph),
95       zone_(zone),
96 #if DEBUG
97       pred_counts_(graph->blocks()->length(), zone),
98 #endif
99       block_states_(graph->blocks()->length(), zone),
100       loop_effects_(graph->blocks()->length(), zone) {
101     loop_effects_.AddBlock(NULL, graph_->blocks()->length(), zone);
102   }
103 
104   // Local analysis. Iterates over the instructions in the given block.
AnalyzeOneBlock(HBasicBlock * block,State * state)105   State* AnalyzeOneBlock(HBasicBlock* block, State* state) {
106     // Go through all instructions of the current block, updating the state.
107     for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
108       state = state->Process(it.Current(), zone_);
109     }
110     return state;
111   }
112 
113   // Global analysis. Iterates over all blocks that are dominated by the given
114   // block, starting with the initial state. Computes effects for nested loops.
AnalyzeDominatedBlocks(HBasicBlock * root,State * initial)115   void AnalyzeDominatedBlocks(HBasicBlock* root, State* initial) {
116     InitializeStates();
117     SetStateAt(root, initial);
118 
119     // Iterate all dominated blocks starting from the given start block.
120     for (int i = root->block_id(); i < graph_->blocks()->length(); i++) {
121       HBasicBlock* block = graph_->blocks()->at(i);
122 
123       // Skip blocks not dominated by the root node.
124       if (SkipNonDominatedBlock(root, block)) continue;
125       State* state = StateAt(block);
126 
127       if (block->IsLoopHeader()) {
128         // Apply loop effects before analyzing loop body.
129         ComputeLoopEffects(block)->Apply(state);
130       } else {
131         // Must have visited all predecessors before this block.
132         CheckPredecessorCount(block);
133       }
134 
135       // Go through all instructions of the current block, updating the state.
136       for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
137         state = state->Process(it.Current(), zone_);
138       }
139 
140       // Propagate the block state forward to all successor blocks.
141       int max = block->end()->SuccessorCount();
142       for (int i = 0; i < max; i++) {
143         HBasicBlock* succ = block->end()->SuccessorAt(i);
144         IncrementPredecessorCount(succ);
145         if (StateAt(succ) == NULL) {
146           // This is the first state to reach the successor.
147           if (max == 1 && succ->predecessors()->length() == 1) {
148             // Optimization: successor can inherit this state.
149             SetStateAt(succ, state);
150           } else {
151             // Successor needs a copy of the state.
152             SetStateAt(succ, state->Copy(succ, zone_));
153           }
154         } else {
155           // Merge the current state with the state already at the successor.
156           SetStateAt(succ, state->Merge(succ, StateAt(succ), zone_));
157         }
158       }
159     }
160   }
161 
162  private:
163   // Computes and caches the loop effects for the loop which has the given
164   // block as its loop header.
ComputeLoopEffects(HBasicBlock * block)165   Effects* ComputeLoopEffects(HBasicBlock* block) {
166     ASSERT(block->IsLoopHeader());
167     Effects* effects = loop_effects_[block->block_id()];
168     if (effects != NULL) return effects;  // Already analyzed this loop.
169 
170     effects = new(zone_) Effects(zone_);
171     loop_effects_[block->block_id()] = effects;
172     if (effects->Disabled()) return effects;  // No effects for this analysis.
173 
174     HLoopInformation* loop = block->loop_information();
175     int end = loop->GetLastBackEdge()->block_id();
176     // Process the blocks between the header and the end.
177     for (int i = block->block_id(); i <= end; i++) {
178       HBasicBlock* member = graph_->blocks()->at(i);
179       if (i != block->block_id() && member->IsLoopHeader()) {
180         // Recursively compute and cache the effects of the nested loop.
181         ASSERT(member->loop_information()->parent_loop() == loop);
182         Effects* nested = ComputeLoopEffects(member);
183         effects->Union(nested, zone_);
184         // Skip the nested loop's blocks.
185         i = member->loop_information()->GetLastBackEdge()->block_id();
186       } else {
187         // Process all the effects of the block.
188         ASSERT(member->current_loop() == loop);
189         for (HInstructionIterator it(member); !it.Done(); it.Advance()) {
190           effects->Process(it.Current(), zone_);
191         }
192       }
193     }
194     return effects;
195   }
196 
SkipNonDominatedBlock(HBasicBlock * root,HBasicBlock * other)197   inline bool SkipNonDominatedBlock(HBasicBlock* root, HBasicBlock* other) {
198     if (root->block_id() == 0) return false;  // Visit the whole graph.
199     if (root == other) return false;          // Always visit the root.
200     return !root->Dominates(other);           // Only visit dominated blocks.
201   }
202 
StateAt(HBasicBlock * block)203   inline State* StateAt(HBasicBlock* block) {
204     return block_states_.at(block->block_id());
205   }
206 
SetStateAt(HBasicBlock * block,State * state)207   inline void SetStateAt(HBasicBlock* block, State* state) {
208     block_states_.Set(block->block_id(), state);
209   }
210 
InitializeStates()211   inline void InitializeStates() {
212 #if DEBUG
213     pred_counts_.Rewind(0);
214     pred_counts_.AddBlock(0, graph_->blocks()->length(), zone_);
215 #endif
216     block_states_.Rewind(0);
217     block_states_.AddBlock(NULL, graph_->blocks()->length(), zone_);
218   }
219 
CheckPredecessorCount(HBasicBlock * block)220   inline void CheckPredecessorCount(HBasicBlock* block) {
221     ASSERT(block->predecessors()->length() == pred_counts_[block->block_id()]);
222   }
223 
IncrementPredecessorCount(HBasicBlock * block)224   inline void IncrementPredecessorCount(HBasicBlock* block) {
225 #if DEBUG
226     pred_counts_[block->block_id()]++;
227 #endif
228   }
229 
230   HGraph* graph_;                    // The hydrogen graph.
231   Zone* zone_;                       // Temporary zone.
232 #if DEBUG
233   ZoneList<int> pred_counts_;        // Finished predecessors (by block id).
234 #endif
235   ZoneList<State*> block_states_;    // Block states (by block id).
236   ZoneList<Effects*> loop_effects_;  // Loop effects (by block id).
237 };
238 
239 
240 } }  // namespace v8::internal
241 
242 #endif  // V8_HYDROGEN_FLOW_ENGINE_H_
243