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 );
75 livenessAnalysisBackward( rootSESE );
79 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
80 while( methItr.hasNext() ) {
81 Descriptor d = methItr.next();
82 FlatMethod fm = state.getMethodFlat( d );
84 // starting from roots do a forward, fixed-point
85 // variable analysis for refinement and stalls
86 variableAnalysisForward( fm );
91 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
92 while( methItr.hasNext() ) {
93 Descriptor d = methItr.next();
94 FlatMethod fm = state.getMethodFlat( d );
96 computeStallsForward( fm );
100 // 5th pass, compute liveness contribution from
101 // virtual reads discovered in stall pass
102 livenessAnalysisBackward( rootSESE );
105 double timeEndAnalysis = (double) System.nanoTime();
106 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
107 String treport = String.format( "The mlp analysis took %.3f sec.", dt );
108 System.out.println( treport );
112 private void buildForestForward( FlatMethod fm ) {
114 // start from flat method top, visit every node in
115 // method exactly once, find SESEs and remember
116 // roots and child relationships
117 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
118 flatNodesToVisit.add( fm );
120 Set<FlatNode> visited = new HashSet<FlatNode>();
122 Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
123 seseStackFirst.push( rootSESE );
124 seseStacks.put( fm, seseStackFirst );
126 while( !flatNodesToVisit.isEmpty() ) {
127 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
128 FlatNode fn = fnItr.next();
130 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
131 assert seseStack != null;
133 flatNodesToVisit.remove( fn );
136 buildForest_nodeActions( fn, seseStack );
138 for( int i = 0; i < fn.numNext(); i++ ) {
139 FlatNode nn = fn.getNext( i );
141 if( !visited.contains( nn ) ) {
142 flatNodesToVisit.add( nn );
144 // clone stack and send along each analysis path
145 seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
150 if( state.MLPDEBUG ) {
155 private void buildForest_nodeActions( FlatNode fn,
156 Stack<FlatSESEEnterNode> seseStack ) {
157 switch( fn.kind() ) {
159 case FKind.FlatSESEEnterNode: {
160 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
161 assert !seseStack.empty();
162 seseStack.peek().addChild( fsen );
163 fsen.setParent( seseStack.peek() );
164 seseStack.push( fsen );
167 case FKind.FlatSESEExitNode: {
168 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
169 assert !seseStack.empty();
170 FlatSESEEnterNode fsen = seseStack.pop();
173 case FKind.FlatReturnNode: {
174 FlatReturnNode frn = (FlatReturnNode) fn;
175 if( !seseStack.empty() &&
176 !seseStack.peek().equals( rootSESE ) ) {
177 throw new Error( "Error: return statement enclosed within "+seseStack.peek() );
184 private void printSESEForest() {
185 // our forest is actually a tree now that
186 // there is an implicit root SESE
187 printSESETree( rootSESE, 0 );
188 System.out.println( "" );
191 private void printSESETree( FlatSESEEnterNode fsen, int depth ) {
192 for( int i = 0; i < depth; ++i ) {
193 System.out.print( " " );
195 System.out.println( fsen.getPrettyIdentifier() );
197 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
198 while( childItr.hasNext() ) {
199 FlatSESEEnterNode fsenChild = childItr.next();
200 printSESETree( fsenChild, depth + 1 );
205 private void livenessAnalysisBackward( FlatSESEEnterNode fsen ) {
207 // post-order traversal, so do children first
208 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
209 while( childItr.hasNext() ) {
210 FlatSESEEnterNode fsenChild = childItr.next();
211 livenessAnalysisBackward( fsenChild );
214 // start from an SESE exit, visit nodes in reverse up to
215 // SESE enter in a fixed-point scheme, where children SESEs
216 // should already be analyzed and therefore can be skipped
217 // because child SESE enter node has all necessary info
218 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
219 FlatSESEExitNode fsexn = fsen.getFlatExit();
220 flatNodesToVisit.add( fsexn );
222 while( !flatNodesToVisit.isEmpty() ) {
223 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
224 flatNodesToVisit.remove( fn );
226 Set<TempDescriptor> prev = livenessResults.get( fn );
228 // merge sets from control flow joins
229 Set<TempDescriptor> u = new HashSet<TempDescriptor>();
230 for( int i = 0; i < fn.numNext(); i++ ) {
231 FlatNode nn = fn.getNext( i );
232 Set<TempDescriptor> s = livenessResults.get( nn );
238 Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen );
240 // if a new result, schedule backward nodes for analysis
241 if( !curr.equals( prev ) ) {
243 livenessResults.put( fn, curr );
245 // don't flow backwards past current SESE enter
246 if( !fn.equals( fsen ) ) {
247 for( int i = 0; i < fn.numPrev(); i++ ) {
248 FlatNode nn = fn.getPrev( i );
249 flatNodesToVisit.add( nn );
255 Set<TempDescriptor> s = livenessResults.get( fsen );
257 fsen.addInVarSet( s );
260 if( state.MLPDEBUG ) {
261 System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
262 Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
263 while( tItr.hasNext() ) {
264 System.out.println( " "+tItr.next() );
266 System.out.println( "" );
270 private Set<TempDescriptor> liveness_nodeActions( FlatNode fn,
271 Set<TempDescriptor> liveIn,
272 FlatSESEEnterNode currentSESE ) {
273 switch( fn.kind() ) {
276 // handle effects of statement in reverse, writes then reads
277 TempDescriptor [] writeTemps = fn.writesTemps();
278 for( int i = 0; i < writeTemps.length; ++i ) {
279 liveIn.remove( writeTemps[i] );
282 TempDescriptor [] readTemps = fn.readsTemps();
283 for( int i = 0; i < readTemps.length; ++i ) {
284 liveIn.add( readTemps[i] );
287 Set<TempDescriptor> virtualReadTemps = livenessVirtualReads.get( fn );
288 if( virtualReadTemps != null ) {
289 Iterator<TempDescriptor> vrItr = virtualReadTemps.iterator();
290 while( vrItr.hasNext() ) {
291 liveIn.add( vrItr.next() );
302 private void variableAnalysisForward( FlatMethod fm ) {
304 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
305 flatNodesToVisit.add( fm );
307 while( !flatNodesToVisit.isEmpty() ) {
308 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
309 flatNodesToVisit.remove( fn );
311 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
312 assert seseStack != null;
314 VarSrcTokTable prev = variableResults.get( fn );
317 if( state.MLPDEBUG ) {
319 prev.assertConsistency();
323 // merge sets from control flow joins
324 VarSrcTokTable inUnion = new VarSrcTokTable();
325 for( int i = 0; i < fn.numPrev(); i++ ) {
326 FlatNode nn = fn.getPrev( i );
328 inUnion.merge( variableResults.get( nn ) );
331 // check merge results before sending
332 if( state.MLPDEBUG ) {
333 inUnion.assertConsistency();
336 VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );
338 // a sanity check after table operations before we proceed
339 if( state.MLPDEBUG ) {
340 curr.assertConsistency();
343 // if a new result, schedule forward nodes for analysis
344 if( !curr.equals( prev ) ) {
346 variableResults.put( fn, curr );
348 for( int i = 0; i < fn.numNext(); i++ ) {
349 FlatNode nn = fn.getNext( i );
350 flatNodesToVisit.add( nn );
356 private VarSrcTokTable variable_nodeActions( FlatNode fn,
357 VarSrcTokTable vstTable,
358 FlatSESEEnterNode currentSESE ) {
359 switch( fn.kind() ) {
361 case FKind.FlatSESEEnterNode: {
362 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
363 assert fsen.equals( currentSESE );
364 vstTable.age( currentSESE );
367 case FKind.FlatSESEExitNode: {
368 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
369 FlatSESEEnterNode fsen = fsexn.getFlatEnter();
370 assert currentSESE.getChildren().contains( fsen );
371 vstTable.remapChildTokens( fsen );
373 Set<TempDescriptor> liveIn = livenessResults.get( fn );
374 Set<TempDescriptor> virLiveIn = vstTable.removeParentAndSiblingTokens( fsen, liveIn );
375 Set<TempDescriptor> virLiveInNew = livenessVirtualReads.get( fn );
376 if( virLiveInNew == null ) {
377 virLiveInNew = new HashSet<TempDescriptor>();
379 virLiveInNew.addAll( virLiveIn );
380 livenessVirtualReads.put( fn, virLiveInNew );
383 case FKind.FlatOpNode: {
384 FlatOpNode fon = (FlatOpNode) fn;
386 if( fon.getOp().getOp() == Operation.ASSIGN ) {
387 TempDescriptor lhs = fon.getDest();
388 TempDescriptor rhs = fon.getLeft();
390 vstTable.remove( lhs );
392 Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
393 while( itr.hasNext() ) {
394 VariableSourceToken vst = itr.next();
396 // if this is from a child, keep the source information
397 if( currentSESE.getChildren().contains( vst.getSESE() ) ) {
398 vstTable.add( new VariableSourceToken( lhs,
405 // otherwise, it's our or an ancestor's token so we
406 // can assume we have everything we need
408 vstTable.add( new VariableSourceToken( lhs,
417 // only break if this is an ASSIGN op node,
418 // otherwise fall through to default case
423 // note that FlatOpNode's that aren't ASSIGN
424 // fall through to this default case
426 TempDescriptor [] writeTemps = fn.writesTemps();
427 if( writeTemps.length > 0 ) {
428 assert writeTemps.length == 1;
430 vstTable.remove( writeTemps[0] );
432 vstTable.add( new VariableSourceToken( writeTemps[0],
447 private void computeStallsForward( FlatMethod fm ) {
449 // start from flat method top, visit every node in
450 // method exactly once
451 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
452 flatNodesToVisit.add( fm );
454 Set<FlatNode> visited = new HashSet<FlatNode>();
456 while( !flatNodesToVisit.isEmpty() ) {
457 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
458 FlatNode fn = fnItr.next();
460 flatNodesToVisit.remove( fn );
463 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
464 assert seseStack != null;
466 // use incoming results as "dot statement" or just
467 // before the current statement
468 VarSrcTokTable dotST = new VarSrcTokTable();
469 for( int i = 0; i < fn.numPrev(); i++ ) {
470 FlatNode nn = fn.getPrev( i );
471 dotST.merge( variableResults.get( nn ) );
474 computeStalls_nodeActions( fn, dotST, seseStack.peek() );
476 for( int i = 0; i < fn.numNext(); i++ ) {
477 FlatNode nn = fn.getNext( i );
479 if( !visited.contains( nn ) ) {
480 flatNodesToVisit.add( nn );
485 if( state.MLPDEBUG ) {
486 System.out.println( fm.printMethod( codePlan ) );
490 private void computeStalls_nodeActions( FlatNode fn,
491 VarSrcTokTable vstTable,
492 FlatSESEEnterNode currentSESE ) {
495 switch( fn.kind() ) {
497 case FKind.FlatSESEEnterNode: {
498 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
501 case FKind.FlatSESEExitNode: {
502 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
506 Set<VariableSourceToken> stallSet = vstTable.getStallSet( currentSESE );
509 Set<TempDescriptor> liveIn = livenessResults.get( fn );
511 if( liveIn != null ) {
512 stallSet.retainAll( liveIn );
514 // there is nothing live, clear all
519 if( !stallSet.isEmpty() ) {
521 Iterator<VariableSourceToken> itr = stallSet.iterator();
522 while( itr.hasNext() ) {
523 VariableSourceToken vst = itr.next();
524 s += " "+vst.getVarLive();
531 codePlan.put( fn, s );