3 import Analysis.CallGraph.*;
4 import Analysis.OwnershipAnalysis.*;
12 public class MLPAnalysis {
14 // data from the compiler
16 private TypeUtil typeUtil;
17 private CallGraph callGraph;
18 private OwnershipAnalysis ownAnalysis;
20 private SESENode rootTree;
21 private FlatSESEEnterNode rootSESE;
22 private FlatSESEExitNode rootExit;
24 private Hashtable< FlatNode, Stack<FlatSESEEnterNode> > seseStacks;
25 private Hashtable< FlatNode, Set<TempDescriptor> > livenessResults;
26 private Hashtable< FlatNode, VarSrcTokTable > variableResults;
27 private Hashtable< FlatNode, String > codePlan;
30 public MLPAnalysis( State state,
33 OwnershipAnalysis ownAnalysis
36 double timeStartAnalysis = (double) System.nanoTime();
40 this.callGraph = callGraph;
41 this.ownAnalysis = ownAnalysis;
43 // initialize analysis data structures
44 seseStacks = new Hashtable< FlatNode, Stack<FlatSESEEnterNode> >();
45 livenessResults = new Hashtable< FlatNode, Set<TempDescriptor> >();
46 variableResults = new Hashtable< FlatNode, VarSrcTokTable >();
47 codePlan = new Hashtable< FlatNode, String >();
50 // build an implicit root SESE to wrap contents of main method
51 rootTree = new SESENode( "root" );
52 rootSESE = new FlatSESEEnterNode( rootTree );
53 rootExit = new FlatSESEExitNode ( rootTree );
54 rootSESE.setFlatExit ( rootExit );
55 rootExit.setFlatEnter( rootSESE );
59 // run analysis on each method that is actually called
60 // reachability analysis already computed this so reuse
61 Iterator<Descriptor> methItr = ownAnalysis.descriptorsToAnalyze.iterator();
62 while( methItr.hasNext() ) {
63 Descriptor d = methItr.next();
64 FlatMethod fm = state.getMethodFlat( d );
66 // find every SESE from methods that may be called
67 // and organize them into roots and children
68 buildForestForward( fm );
73 livenessAnalysisBackward( rootSESE );
77 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
78 while( methItr.hasNext() ) {
79 Descriptor d = methItr.next();
80 FlatMethod fm = state.getMethodFlat( d );
82 // starting from roots do a forward, fixed-point
83 // variable analysis for refinement and stalls
84 variableAnalysisForward( fm );
89 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
90 while( methItr.hasNext() ) {
91 Descriptor d = methItr.next();
92 FlatMethod fm = state.getMethodFlat( d );
94 computeStallsForward( fm );
98 double timeEndAnalysis = (double) System.nanoTime();
99 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
100 String treport = String.format( "The mlp analysis took %.3f sec.", dt );
101 System.out.println( treport );
105 private void buildForestForward( FlatMethod fm ) {
107 // start from flat method top, visit every node in
108 // method exactly once, find SESEs and remember
109 // roots and child relationships
110 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
111 flatNodesToVisit.add( fm );
113 Set<FlatNode> visited = new HashSet<FlatNode>();
115 Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
116 seseStackFirst.push( rootSESE );
117 seseStacks.put( fm, seseStackFirst );
119 while( !flatNodesToVisit.isEmpty() ) {
120 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
121 FlatNode fn = fnItr.next();
123 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
124 assert seseStack != null;
126 flatNodesToVisit.remove( fn );
129 buildForest_nodeActions( fn, seseStack );
131 for( int i = 0; i < fn.numNext(); i++ ) {
132 FlatNode nn = fn.getNext( i );
134 if( !visited.contains( nn ) ) {
135 flatNodesToVisit.add( nn );
137 // clone stack and send along each analysis path
138 seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
143 if( state.MLPDEBUG ) {
148 private void buildForest_nodeActions( FlatNode fn,
149 Stack<FlatSESEEnterNode> seseStack ) {
150 switch( fn.kind() ) {
152 case FKind.FlatSESEEnterNode: {
153 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
154 assert !seseStack.empty();
155 seseStack.peek().addChild( fsen );
156 fsen.setParent( seseStack.peek() );
157 seseStack.push( fsen );
160 case FKind.FlatSESEExitNode: {
161 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
162 assert !seseStack.empty();
163 FlatSESEEnterNode fsen = seseStack.pop();
166 case FKind.FlatReturnNode: {
167 FlatReturnNode frn = (FlatReturnNode) fn;
168 if( !seseStack.empty() &&
169 !seseStack.peek().equals( rootSESE ) ) {
170 throw new Error( "Error: return statement enclosed within "+seseStack.peek() );
177 private void printSESEForest() {
178 // our forest is actually a tree now that
179 // there is an implicit root SESE
180 printSESETree( rootSESE, 0 );
181 System.out.println( "" );
184 private void printSESETree( FlatSESEEnterNode fsen, int depth ) {
185 for( int i = 0; i < depth; ++i ) {
186 System.out.print( " " );
188 System.out.println( fsen.getPrettyIdentifier() );
190 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
191 while( childItr.hasNext() ) {
192 FlatSESEEnterNode fsenChild = childItr.next();
193 printSESETree( fsenChild, depth + 1 );
198 private void livenessAnalysisBackward( FlatSESEEnterNode fsen ) {
200 // post-order traversal, so do children first
201 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
202 while( childItr.hasNext() ) {
203 FlatSESEEnterNode fsenChild = childItr.next();
204 livenessAnalysisBackward( fsenChild );
207 // start from an SESE exit, visit nodes in reverse up to
208 // SESE enter in a fixed-point scheme, where children SESEs
209 // should already be analyzed and therefore can be skipped
210 // because child SESE enter node has all necessary info
211 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
212 FlatSESEExitNode fsexn = fsen.getFlatExit();
213 flatNodesToVisit.add( fsexn );
215 while( !flatNodesToVisit.isEmpty() ) {
216 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
217 flatNodesToVisit.remove( fn );
219 Set<TempDescriptor> prev = livenessResults.get( fn );
221 // merge sets from control flow joins
222 Set<TempDescriptor> u = new HashSet<TempDescriptor>();
223 for( int i = 0; i < fn.numNext(); i++ ) {
224 FlatNode nn = fn.getNext( i );
225 Set<TempDescriptor> s = livenessResults.get( nn );
231 Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen );
233 // if a new result, schedule backward nodes for analysis
234 if( !curr.equals( prev ) ) {
236 livenessResults.put( fn, curr );
238 // don't flow backwards past current SESE enter
239 if( !fn.equals( fsen ) ) {
240 for( int i = 0; i < fn.numPrev(); i++ ) {
241 FlatNode nn = fn.getPrev( i );
242 flatNodesToVisit.add( nn );
248 Set<TempDescriptor> s = livenessResults.get( fsen );
250 fsen.addInVarSet( s );
253 if( state.MLPDEBUG ) {
254 System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
255 Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
256 while( tItr.hasNext() ) {
257 System.out.println( " "+tItr.next() );
259 System.out.println( "" );
263 private Set<TempDescriptor> liveness_nodeActions( FlatNode fn,
264 Set<TempDescriptor> liveIn,
265 FlatSESEEnterNode currentSESE ) {
266 switch( fn.kind() ) {
269 // handle effects of statement in reverse, writes then reads
270 TempDescriptor [] writeTemps = fn.writesTemps();
271 for( int i = 0; i < writeTemps.length; ++i ) {
272 liveIn.remove( writeTemps[i] );
275 TempDescriptor [] readTemps = fn.readsTemps();
276 for( int i = 0; i < readTemps.length; ++i ) {
277 liveIn.add( readTemps[i] );
287 private void variableAnalysisForward( FlatMethod fm ) {
289 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
290 flatNodesToVisit.add( fm );
292 while( !flatNodesToVisit.isEmpty() ) {
293 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
294 flatNodesToVisit.remove( fn );
296 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
297 assert seseStack != null;
299 VarSrcTokTable prev = variableResults.get( fn );
301 // merge sets from control flow joins
302 VarSrcTokTable inUnion = new VarSrcTokTable();
303 for( int i = 0; i < fn.numPrev(); i++ ) {
304 FlatNode nn = fn.getPrev( i );
305 inUnion.merge( variableResults.get( nn ) );
308 VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );
310 // if a new result, schedule forward nodes for analysis
311 if( !curr.equals( prev ) ) {
313 variableResults.put( fn, curr );
315 for( int i = 0; i < fn.numNext(); i++ ) {
316 FlatNode nn = fn.getNext( i );
317 flatNodesToVisit.add( nn );
323 private VarSrcTokTable variable_nodeActions( FlatNode fn,
324 VarSrcTokTable vstTable,
325 FlatSESEEnterNode currentSESE ) {
326 switch( fn.kind() ) {
328 case FKind.FlatSESEEnterNode: {
329 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
330 assert fsen.equals( currentSESE );
331 vstTable.age( currentSESE );
334 case FKind.FlatSESEExitNode: {
335 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
336 assert currentSESE.getChildren().contains( fsexn.getFlatEnter() );
337 vstTable = vstTable.remapChildTokens( currentSESE );
338 vstTable = vstTable.removeParentAndSiblingTokens( currentSESE );
341 case FKind.FlatOpNode: {
342 FlatOpNode fon = (FlatOpNode) fn;
344 if( fon.getOp().getOp() == Operation.ASSIGN ) {
345 TempDescriptor lhs = fon.getDest();
346 TempDescriptor rhs = fon.getLeft();
348 vstTable.remove( lhs );
350 Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
351 while( itr.hasNext() ) {
352 VariableSourceToken vst = itr.next();
354 // if this is from a child, keep the source information
355 if( currentSESE.getChildren().contains( vst.getSESE() ) ) {
356 vstTable.add( new VariableSourceToken( lhs,
363 // otherwise, it's our or an ancestor's token so we
364 // can assume we have everything we need
366 vstTable.add( new VariableSourceToken( lhs,
375 // only break if this is an ASSIGN op node,
376 // otherwise fall through to default case
381 // note that FlatOpNode's that aren't ASSIGN
382 // fall through to this default case
384 TempDescriptor [] writeTemps = fn.writesTemps();
385 if( writeTemps.length > 0 ) {
386 assert writeTemps.length == 1;
388 vstTable.remove( writeTemps[0] );
390 vstTable.add( new VariableSourceToken( writeTemps[0],
405 private void computeStallsForward( FlatMethod fm ) {
407 // start from flat method top, visit every node in
408 // method exactly once
409 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
410 flatNodesToVisit.add( fm );
412 Set<FlatNode> visited = new HashSet<FlatNode>();
414 while( !flatNodesToVisit.isEmpty() ) {
415 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
416 FlatNode fn = fnItr.next();
418 flatNodesToVisit.remove( fn );
421 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
422 assert seseStack != null;
424 // use incoming results as "dot statement" or just
425 // before the current statement
426 VarSrcTokTable dotST = new VarSrcTokTable();
427 for( int i = 0; i < fn.numPrev(); i++ ) {
428 FlatNode nn = fn.getPrev( i );
429 dotST.merge( variableResults.get( nn ) );
432 computeStalls_nodeActions( fn, dotST, seseStack.peek() );
434 for( int i = 0; i < fn.numNext(); i++ ) {
435 FlatNode nn = fn.getNext( i );
437 if( !visited.contains( nn ) ) {
438 flatNodesToVisit.add( nn );
443 if( state.MLPDEBUG ) {
444 System.out.println( fm.printMethod( codePlan ) );
448 private void computeStalls_nodeActions( FlatNode fn,
449 VarSrcTokTable vstTable,
450 FlatSESEEnterNode currentSESE ) {
453 switch( fn.kind() ) {
455 case FKind.FlatSESEEnterNode: {
456 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
459 case FKind.FlatSESEExitNode: {
460 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
464 Set<VariableSourceToken> stallSet = vstTable.getStallSet( currentSESE );
465 if( !stallSet.isEmpty() ) {
469 Iterator<VariableSourceToken> itr = stallSet.iterator();
470 while( itr.hasNext() ) {
471 VariableSourceToken vst = itr.next();
472 s += " "+vst.getVarLive();
479 codePlan.put( fn, s );