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, Set<TempDescriptor> > livenessVirtualReads;
27 private Hashtable< FlatNode, VarSrcTokTable > variableResults;
28 private Hashtable< FlatNode, String > codePlan;
31 public MLPAnalysis( State state,
34 OwnershipAnalysis ownAnalysis
37 double timeStartAnalysis = (double) System.nanoTime();
41 this.callGraph = callGraph;
42 this.ownAnalysis = ownAnalysis;
44 // initialize analysis data structures
45 seseStacks = new Hashtable< FlatNode, Stack<FlatSESEEnterNode> >();
46 livenessResults = new Hashtable< FlatNode, Set<TempDescriptor> >();
47 livenessVirtualReads = new Hashtable< FlatNode, Set<TempDescriptor> >();
48 variableResults = new Hashtable< FlatNode, VarSrcTokTable >();
49 codePlan = new Hashtable< FlatNode, String >();
52 // build an implicit root SESE to wrap contents of main method
53 rootTree = new SESENode( "root" );
54 rootSESE = new FlatSESEEnterNode( rootTree );
55 rootExit = new FlatSESEExitNode ( rootTree );
56 rootSESE.setFlatExit ( rootExit );
57 rootExit.setFlatEnter( rootSESE );
61 // run analysis on each method that is actually called
62 // reachability analysis already computed this so reuse
63 Iterator<Descriptor> methItr = ownAnalysis.descriptorsToAnalyze.iterator();
64 while( methItr.hasNext() ) {
65 Descriptor d = methItr.next();
66 FlatMethod fm = state.getMethodFlat( d );
68 // find every SESE from methods that may be called
69 // and organize them into roots and children
70 buildForestForward( fm );
74 // 2nd pass, results are saved in FlatSESEEnterNode, so
75 // intermediate results, for safety, are discarded
76 livenessAnalysisBackward( rootSESE );
77 livenessResults = null;
81 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
82 while( methItr.hasNext() ) {
83 Descriptor d = methItr.next();
84 FlatMethod fm = state.getMethodFlat( d );
86 // starting from roots do a forward, fixed-point
87 // variable analysis for refinement and stalls
88 variableAnalysisForward( fm );
92 // 4th pass, compute liveness contribution from
93 // virtual reads discovered in variable pass
94 livenessResults = new Hashtable< FlatNode, Set<TempDescriptor> >();
95 livenessAnalysisBackward( rootSESE );
96 livenessResults = null;
100 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
101 while( methItr.hasNext() ) {
102 Descriptor d = methItr.next();
103 FlatMethod fm = state.getMethodFlat( d );
105 // compute a plan for code injections
106 computeStallsForward( fm );
110 double timeEndAnalysis = (double) System.nanoTime();
111 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
112 String treport = String.format( "The mlp analysis took %.3f sec.", dt );
113 System.out.println( treport );
117 private void buildForestForward( FlatMethod fm ) {
119 // start from flat method top, visit every node in
120 // method exactly once, find SESEs and remember
121 // roots and child relationships
122 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
123 flatNodesToVisit.add( fm );
125 Set<FlatNode> visited = new HashSet<FlatNode>();
127 Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
128 seseStackFirst.push( rootSESE );
129 seseStacks.put( fm, seseStackFirst );
131 while( !flatNodesToVisit.isEmpty() ) {
132 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
133 FlatNode fn = fnItr.next();
135 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
136 assert seseStack != null;
138 flatNodesToVisit.remove( fn );
141 buildForest_nodeActions( fn, seseStack );
143 for( int i = 0; i < fn.numNext(); i++ ) {
144 FlatNode nn = fn.getNext( i );
146 if( !visited.contains( nn ) ) {
147 flatNodesToVisit.add( nn );
149 // clone stack and send along each analysis path
150 seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
155 if( state.MLPDEBUG ) {
160 private void buildForest_nodeActions( FlatNode fn,
161 Stack<FlatSESEEnterNode> seseStack ) {
162 switch( fn.kind() ) {
164 case FKind.FlatSESEEnterNode: {
165 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
166 assert !seseStack.empty();
167 seseStack.peek().addChild( fsen );
168 fsen.setParent( seseStack.peek() );
169 seseStack.push( fsen );
172 case FKind.FlatSESEExitNode: {
173 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
174 assert !seseStack.empty();
175 FlatSESEEnterNode fsen = seseStack.pop();
178 case FKind.FlatReturnNode: {
179 FlatReturnNode frn = (FlatReturnNode) fn;
180 if( !seseStack.empty() &&
181 !seseStack.peek().equals( rootSESE ) ) {
182 throw new Error( "Error: return statement enclosed within "+seseStack.peek() );
189 private void printSESEForest() {
190 // our forest is actually a tree now that
191 // there is an implicit root SESE
192 printSESETree( rootSESE, 0 );
193 System.out.println( "" );
196 private void printSESETree( FlatSESEEnterNode fsen, int depth ) {
197 for( int i = 0; i < depth; ++i ) {
198 System.out.print( " " );
200 System.out.println( fsen.getPrettyIdentifier() );
202 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
203 while( childItr.hasNext() ) {
204 FlatSESEEnterNode fsenChild = childItr.next();
205 printSESETree( fsenChild, depth + 1 );
210 private void livenessAnalysisBackward( FlatSESEEnterNode fsen ) {
212 // post-order traversal, so do children first
213 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
214 while( childItr.hasNext() ) {
215 FlatSESEEnterNode fsenChild = childItr.next();
216 livenessAnalysisBackward( fsenChild );
219 // start from an SESE exit, visit nodes in reverse up to
220 // SESE enter in a fixed-point scheme, where children SESEs
221 // should already be analyzed and therefore can be skipped
222 // because child SESE enter node has all necessary info
223 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
224 FlatSESEExitNode fsexn = fsen.getFlatExit();
225 flatNodesToVisit.add( fsexn );
227 while( !flatNodesToVisit.isEmpty() ) {
228 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
229 flatNodesToVisit.remove( fn );
231 Set<TempDescriptor> prev = livenessResults.get( fn );
233 // merge sets from control flow joins
234 Set<TempDescriptor> u = new HashSet<TempDescriptor>();
235 for( int i = 0; i < fn.numNext(); i++ ) {
236 FlatNode nn = fn.getNext( i );
237 Set<TempDescriptor> s = livenessResults.get( nn );
243 Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen );
245 // if a new result, schedule backward nodes for analysis
246 if( !curr.equals( prev ) ) {
248 livenessResults.put( fn, curr );
250 // don't flow backwards past current SESE enter
251 if( !fn.equals( fsen ) ) {
252 for( int i = 0; i < fn.numPrev(); i++ ) {
253 FlatNode nn = fn.getPrev( i );
254 flatNodesToVisit.add( nn );
260 Set<TempDescriptor> s = livenessResults.get( fsen );
262 fsen.addInVarSet( s );
265 if( state.MLPDEBUG ) {
266 System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
267 Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
268 while( tItr.hasNext() ) {
269 System.out.println( " "+tItr.next() );
271 System.out.println( "and out-set:" );
272 tItr = fsen.getOutVarSet().iterator();
273 while( tItr.hasNext() ) {
274 System.out.println( " "+tItr.next() );
276 System.out.println( "" );
280 private Set<TempDescriptor> liveness_nodeActions( FlatNode fn,
281 Set<TempDescriptor> liveIn,
282 FlatSESEEnterNode currentSESE ) {
283 switch( fn.kind() ) {
286 VarSrcTokTable table = variableResults.get( fn );
288 // handle effects of statement in reverse, writes then reads
289 TempDescriptor [] writeTemps = fn.writesTemps();
290 for( int i = 0; i < writeTemps.length; ++i ) {
291 liveIn.remove( writeTemps[i] );
293 if( table != null ) {
294 Iterator<VariableSourceToken> vstItr = table.get( writeTemps[i] ).iterator();
295 while( vstItr.hasNext() ) {
296 VariableSourceToken vst = vstItr.next();
298 if( !vst.getSESE().equals( currentSESE ) ) {
299 currentSESE.addOutVar( writeTemps[i] );
306 TempDescriptor [] readTemps = fn.readsTemps();
307 for( int i = 0; i < readTemps.length; ++i ) {
308 liveIn.add( readTemps[i] );
311 Set<TempDescriptor> virtualReadTemps = livenessVirtualReads.get( fn );
312 if( virtualReadTemps != null ) {
313 Iterator<TempDescriptor> vrItr = virtualReadTemps.iterator();
314 while( vrItr.hasNext() ) {
315 liveIn.add( vrItr.next() );
326 private void variableAnalysisForward( FlatMethod fm ) {
328 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
329 flatNodesToVisit.add( fm );
331 while( !flatNodesToVisit.isEmpty() ) {
332 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
333 flatNodesToVisit.remove( fn );
335 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
336 assert seseStack != null;
338 VarSrcTokTable prev = variableResults.get( fn );
341 if( state.MLPDEBUG ) {
343 prev.assertConsistency();
347 // merge sets from control flow joins
348 VarSrcTokTable inUnion = new VarSrcTokTable();
349 for( int i = 0; i < fn.numPrev(); i++ ) {
350 FlatNode nn = fn.getPrev( i );
352 inUnion.merge( variableResults.get( nn ) );
355 // check merge results before sending
356 if( state.MLPDEBUG ) {
357 inUnion.assertConsistency();
360 VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );
362 // a sanity check after table operations before we proceed
363 if( state.MLPDEBUG ) {
364 curr.assertConsistency();
367 // if a new result, schedule forward nodes for analysis
368 if( !curr.equals( prev ) ) {
370 variableResults.put( fn, curr );
372 for( int i = 0; i < fn.numNext(); i++ ) {
373 FlatNode nn = fn.getNext( i );
374 flatNodesToVisit.add( nn );
380 private VarSrcTokTable variable_nodeActions( FlatNode fn,
381 VarSrcTokTable vstTable,
382 FlatSESEEnterNode currentSESE ) {
383 switch( fn.kind() ) {
385 case FKind.FlatSESEEnterNode: {
386 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
387 assert fsen.equals( currentSESE );
388 vstTable.age( currentSESE );
391 case FKind.FlatSESEExitNode: {
392 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
393 FlatSESEEnterNode fsen = fsexn.getFlatEnter();
394 assert currentSESE.getChildren().contains( fsen );
395 vstTable.remapChildTokens( fsen );
397 Set<TempDescriptor> liveIn = currentSESE.getInVarSet();
398 Set<TempDescriptor> virLiveIn = vstTable.removeParentAndSiblingTokens( fsen, liveIn );
399 Set<TempDescriptor> virLiveInOld = livenessVirtualReads.get( fn );
400 if( virLiveInOld != null ) {
401 virLiveIn.addAll( virLiveInOld );
403 livenessVirtualReads.put( fn, virLiveIn );
406 case FKind.FlatOpNode: {
407 FlatOpNode fon = (FlatOpNode) fn;
409 if( fon.getOp().getOp() == Operation.ASSIGN ) {
410 TempDescriptor lhs = fon.getDest();
411 TempDescriptor rhs = fon.getLeft();
413 vstTable.remove( lhs );
415 Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
416 while( itr.hasNext() ) {
417 VariableSourceToken vst = itr.next();
419 // if this is from a child, keep the source information
420 if( currentSESE.getChildren().contains( vst.getSESE() ) ) {
421 vstTable.add( new VariableSourceToken( lhs,
428 // otherwise, it's our or an ancestor's token so we
429 // can assume we have everything we need
431 vstTable.add( new VariableSourceToken( lhs,
440 // only break if this is an ASSIGN op node,
441 // otherwise fall through to default case
446 // note that FlatOpNode's that aren't ASSIGN
447 // fall through to this default case
449 TempDescriptor [] writeTemps = fn.writesTemps();
450 if( writeTemps.length > 0 ) {
451 assert writeTemps.length == 1;
453 vstTable.remove( writeTemps[0] );
455 vstTable.add( new VariableSourceToken( writeTemps[0],
470 private void computeStallsForward( FlatMethod fm ) {
472 // start from flat method top, visit every node in
473 // method exactly once
474 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
475 flatNodesToVisit.add( fm );
477 Set<FlatNode> visited = new HashSet<FlatNode>();
479 while( !flatNodesToVisit.isEmpty() ) {
480 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
481 FlatNode fn = fnItr.next();
483 flatNodesToVisit.remove( fn );
486 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
487 assert seseStack != null;
489 // use incoming results as "dot statement" or just
490 // before the current statement
491 VarSrcTokTable dotST = new VarSrcTokTable();
492 for( int i = 0; i < fn.numPrev(); i++ ) {
493 FlatNode nn = fn.getPrev( i );
494 dotST.merge( variableResults.get( nn ) );
497 computeStalls_nodeActions( fn, dotST, seseStack.peek() );
499 for( int i = 0; i < fn.numNext(); i++ ) {
500 FlatNode nn = fn.getNext( i );
502 if( !visited.contains( nn ) ) {
503 flatNodesToVisit.add( nn );
508 if( state.MLPDEBUG ) {
509 System.out.println( fm.printMethod( codePlan ) );
513 private void computeStalls_nodeActions( FlatNode fn,
514 VarSrcTokTable vstTable,
515 FlatSESEEnterNode currentSESE ) {
518 switch( fn.kind() ) {
520 case FKind.FlatSESEEnterNode: {
521 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
524 case FKind.FlatSESEExitNode: {
525 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
529 Set<VariableSourceToken> stallSet = vstTable.getStallSet( currentSESE );
530 Set<TempDescriptor> liveIn = currentSESE.getInVarSet();
532 if( liveIn != null ) {
533 stallSet.retainAll( liveIn );
535 // there is nothing live, clear all
539 if( !stallSet.isEmpty() ) {
541 Iterator<VariableSourceToken> itr = stallSet.iterator();
542 while( itr.hasNext() ) {
543 VariableSourceToken vst = itr.next();
544 s += " "+vst.getVarLive()+",";
551 codePlan.put( fn, s );