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> > livenessRootView;
26 private Hashtable< FlatNode, Set<TempDescriptor> > livenessVirtualReads;
27 private Hashtable< FlatNode, VarSrcTokTable > variableResults;
28 private Hashtable< FlatNode, Set<TempDescriptor> > isAvailableResults;
29 private Hashtable< FlatNode, CodePlan > codePlans;
32 public MLPAnalysis( State state,
35 OwnershipAnalysis ownAnalysis
38 double timeStartAnalysis = (double) System.nanoTime();
42 this.callGraph = callGraph;
43 this.ownAnalysis = ownAnalysis;
45 // initialize analysis data structures
46 seseStacks = new Hashtable< FlatNode, Stack<FlatSESEEnterNode> >();
47 livenessVirtualReads = new Hashtable< FlatNode, Set<TempDescriptor> >();
48 variableResults = new Hashtable< FlatNode, VarSrcTokTable >();
49 isAvailableResults = new Hashtable< FlatNode, Set<TempDescriptor> >();
50 codePlans = new Hashtable< FlatNode, CodePlan >();
54 // build an implicit root SESE to wrap contents of main method
55 rootTree = new SESENode( "root" );
56 rootSESE = new FlatSESEEnterNode( rootTree );
57 rootExit = new FlatSESEExitNode ( rootTree );
58 rootSESE.setFlatExit ( rootExit );
59 rootExit.setFlatEnter( rootSESE );
61 FlatMethod fmMain = state.getMethodFlat( tu.getMain() );
65 // run analysis on each method that is actually called
66 // reachability analysis already computed this so reuse
67 Iterator<Descriptor> methItr = ownAnalysis.descriptorsToAnalyze.iterator();
68 while( methItr.hasNext() ) {
69 Descriptor d = methItr.next();
70 FlatMethod fm = state.getMethodFlat( d );
72 // find every SESE from methods that may be called
73 // and organize them into roots and children
74 buildForestForward( fm );
78 // 2nd pass, results are saved in FlatSESEEnterNode, so
79 // intermediate results, for safety, are discarded
80 livenessAnalysisBackward( rootSESE, true, null, fmMain.getFlatExit() );
84 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
85 while( methItr.hasNext() ) {
86 Descriptor d = methItr.next();
87 FlatMethod fm = state.getMethodFlat( d );
89 // starting from roots do a forward, fixed-point
90 // variable analysis for refinement and stalls
91 variableAnalysisForward( fm );
95 // 4th pass, compute liveness contribution from
96 // virtual reads discovered in variable pass
97 livenessAnalysisBackward( rootSESE, true, null, fmMain.getFlatExit() );
101 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
102 while( methItr.hasNext() ) {
103 Descriptor d = methItr.next();
104 FlatMethod fm = state.getMethodFlat( d );
106 // compute is available for every live variable at
107 // every program point, in a forward fixed-point pass
108 isAvailableForward( fm );
113 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
114 while( methItr.hasNext() ) {
115 Descriptor d = methItr.next();
116 FlatMethod fm = state.getMethodFlat( d );
118 // compute a plan for code injections
119 computeStallsForward( fm );
123 double timeEndAnalysis = (double) System.nanoTime();
124 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
125 String treport = String.format( "The mlp analysis took %.3f sec.", dt );
126 System.out.println( treport );
130 private void buildForestForward( FlatMethod fm ) {
132 // start from flat method top, visit every node in
133 // method exactly once, find SESEs and remember
134 // roots and child relationships
135 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
136 flatNodesToVisit.add( fm );
138 Set<FlatNode> visited = new HashSet<FlatNode>();
140 Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
141 seseStackFirst.push( rootSESE );
142 seseStacks.put( fm, seseStackFirst );
144 while( !flatNodesToVisit.isEmpty() ) {
145 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
146 FlatNode fn = fnItr.next();
148 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
149 assert seseStack != null;
151 flatNodesToVisit.remove( fn );
154 buildForest_nodeActions( fn, seseStack );
156 for( int i = 0; i < fn.numNext(); i++ ) {
157 FlatNode nn = fn.getNext( i );
159 if( !visited.contains( nn ) ) {
160 flatNodesToVisit.add( nn );
162 // clone stack and send along each analysis path
163 seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
168 if( state.MLPDEBUG ) {
173 private void buildForest_nodeActions( FlatNode fn,
174 Stack<FlatSESEEnterNode> seseStack ) {
175 switch( fn.kind() ) {
177 case FKind.FlatSESEEnterNode: {
178 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
179 assert !seseStack.empty();
180 seseStack.peek().addChild( fsen );
181 fsen.setParent( seseStack.peek() );
182 seseStack.push( fsen );
185 case FKind.FlatSESEExitNode: {
186 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
187 assert !seseStack.empty();
188 FlatSESEEnterNode fsen = seseStack.pop();
191 case FKind.FlatReturnNode: {
192 FlatReturnNode frn = (FlatReturnNode) fn;
193 if( !seseStack.empty() &&
194 !seseStack.peek().equals( rootSESE ) ) {
195 throw new Error( "Error: return statement enclosed within "+seseStack.peek() );
202 private void printSESEForest() {
203 // our forest is actually a tree now that
204 // there is an implicit root SESE
205 printSESETree( rootSESE, 0 );
206 System.out.println( "" );
209 private void printSESETree( FlatSESEEnterNode fsen, int depth ) {
210 for( int i = 0; i < depth; ++i ) {
211 System.out.print( " " );
213 System.out.println( fsen.getPrettyIdentifier() );
215 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
216 while( childItr.hasNext() ) {
217 FlatSESEEnterNode fsenChild = childItr.next();
218 printSESETree( fsenChild, depth + 1 );
223 private void livenessAnalysisBackward( FlatSESEEnterNode fsen,
225 Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout,
228 // start from an SESE exit, visit nodes in reverse up to
229 // SESE enter in a fixed-point scheme, where children SESEs
230 // should already be analyzed and therefore can be skipped
231 // because child SESE enter node has all necessary info
232 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
234 FlatSESEExitNode fsexn = fsen.getFlatExit();
237 flatNodesToVisit.add( fexit );
239 flatNodesToVisit.add( fsexn );
240 Hashtable<FlatNode, Set<TempDescriptor>> livenessResults=new Hashtable<FlatNode, Set<TempDescriptor>>();
243 liveout=new Hashtable<FlatSESEExitNode, Set<TempDescriptor>>();
245 while( !flatNodesToVisit.isEmpty() ) {
246 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
247 flatNodesToVisit.remove( fn );
249 Set<TempDescriptor> prev = livenessResults.get( fn );
251 // merge sets from control flow joins
252 Set<TempDescriptor> u = new HashSet<TempDescriptor>();
253 for( int i = 0; i < fn.numNext(); i++ ) {
254 FlatNode nn = fn.getNext( i );
255 Set<TempDescriptor> s = livenessResults.get( nn );
261 Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen, toplevel, liveout);
263 // if a new result, schedule backward nodes for analysis
264 if(!curr.equals(prev)) {
265 livenessResults.put( fn, curr );
267 // don't flow backwards past current SESE enter
268 if( !fn.equals( fsen ) ) {
269 for( int i = 0; i < fn.numPrev(); i++ ) {
270 FlatNode nn = fn.getPrev( i );
271 flatNodesToVisit.add( nn );
277 Set<TempDescriptor> s = livenessResults.get( fsen );
279 fsen.addInVarSet( s );
282 if( state.MLPDEBUG ) {
283 System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
284 Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
285 while( tItr.hasNext() ) {
286 System.out.println( " "+tItr.next() );
288 System.out.println( "and out-set:" );
289 tItr = fsen.getOutVarSet().iterator();
290 while( tItr.hasNext() ) {
291 System.out.println( " "+tItr.next() );
293 System.out.println( "" );
296 // remember liveness per node from the root view as the
297 // global liveness of variables for later passes to use
298 if( toplevel == true ) {
299 livenessRootView = livenessResults;
302 // post-order traversal, so do children first
303 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
304 while( childItr.hasNext() ) {
305 FlatSESEEnterNode fsenChild = childItr.next();
306 livenessAnalysisBackward( fsenChild, false, liveout, null);
310 private Set<TempDescriptor> liveness_nodeActions( FlatNode fn,
311 Set<TempDescriptor> liveIn,
312 FlatSESEEnterNode currentSESE,
314 Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout ) {
316 switch( fn.kind() ) {
318 case FKind.FlatSESEExitNode:
319 if (toplevel==true) {
320 FlatSESEExitNode exitn=(FlatSESEExitNode) fn;
321 //update liveout set for FlatSESEExitNode
322 if (!liveout.containsKey(exitn))
323 liveout.put(exitn, new HashSet<TempDescriptor>());
324 liveout.get(exitn).addAll(liveIn);
326 // no break, sese exits should also execute default actions
329 // handle effects of statement in reverse, writes then reads
330 TempDescriptor [] writeTemps = fn.writesTemps();
331 for( int i = 0; i < writeTemps.length; ++i ) {
332 liveIn.remove( writeTemps[i] );
335 FlatSESEExitNode exitnode=currentSESE.getFlatExit();
336 Set<TempDescriptor> livetemps=liveout.get(exitnode);
337 if (livetemps.contains(writeTemps[i])) {
338 //write to a live out temp...
339 //need to put in SESE liveout set
340 currentSESE.addOutVar(writeTemps[i]);
345 TempDescriptor [] readTemps = fn.readsTemps();
346 for( int i = 0; i < readTemps.length; ++i ) {
347 liveIn.add( readTemps[i] );
350 Set<TempDescriptor> virtualReadTemps = livenessVirtualReads.get( fn );
351 if( virtualReadTemps != null ) {
352 Iterator<TempDescriptor> vrItr = virtualReadTemps.iterator();
353 while( vrItr.hasNext() ) {
354 liveIn.add( vrItr.next() );
365 private void variableAnalysisForward( FlatMethod fm ) {
367 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
368 flatNodesToVisit.add( fm );
370 while( !flatNodesToVisit.isEmpty() ) {
371 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
372 flatNodesToVisit.remove( fn );
374 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
375 assert seseStack != null;
377 VarSrcTokTable prev = variableResults.get( fn );
379 // merge sets from control flow joins
380 VarSrcTokTable inUnion = new VarSrcTokTable();
381 for( int i = 0; i < fn.numPrev(); i++ ) {
382 FlatNode nn = fn.getPrev( i );
384 VarSrcTokTable incoming = variableResults.get( nn );
385 if( incoming != null ) {
386 incoming.assertConsistency();
389 inUnion.merge( incoming );
392 VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );
394 // if a new result, schedule forward nodes for analysis
395 if( !curr.equals( prev ) ) {
398 curr.assertConsistency();
400 variableResults.put( fn, curr );
402 for( int i = 0; i < fn.numNext(); i++ ) {
403 FlatNode nn = fn.getNext( i );
404 flatNodesToVisit.add( nn );
410 private VarSrcTokTable variable_nodeActions( FlatNode fn,
411 VarSrcTokTable vstTable,
412 FlatSESEEnterNode currentSESE ) {
413 switch( fn.kind() ) {
415 case FKind.FlatSESEEnterNode: {
416 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
417 assert fsen.equals( currentSESE );
418 vstTable.age( currentSESE );
419 vstTable.assertConsistency();
422 case FKind.FlatSESEExitNode: {
423 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
424 FlatSESEEnterNode fsen = fsexn.getFlatEnter();
425 assert currentSESE.getChildren().contains( fsen );
426 vstTable.remapChildTokens( fsen );
428 Set<TempDescriptor> liveIn = currentSESE.getInVarSet();
429 Set<TempDescriptor> virLiveIn = vstTable.removeParentAndSiblingTokens( fsen, liveIn );
430 Set<TempDescriptor> virLiveInOld = livenessVirtualReads.get( fn );
431 if( virLiveInOld != null ) {
432 virLiveIn.addAll( virLiveInOld );
434 livenessVirtualReads.put( fn, virLiveIn );
435 vstTable.assertConsistency();
438 case FKind.FlatOpNode: {
439 FlatOpNode fon = (FlatOpNode) fn;
441 if( fon.getOp().getOp() == Operation.ASSIGN ) {
442 TempDescriptor lhs = fon.getDest();
443 TempDescriptor rhs = fon.getLeft();
445 vstTable.remove( lhs );
447 Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
448 while( itr.hasNext() ) {
449 VariableSourceToken vst = itr.next();
451 HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
454 // if this is from a child, keep the source information
455 if( currentSESE.getChildren().contains( vst.getSESE() ) ) {
456 vstTable.add( new VariableSourceToken( ts,
463 // otherwise, it's our or an ancestor's token so we
464 // can assume we have everything we need
466 vstTable.add( new VariableSourceToken( ts,
475 // only break if this is an ASSIGN op node,
476 // otherwise fall through to default case
477 vstTable.assertConsistency();
482 // note that FlatOpNode's that aren't ASSIGN
483 // fall through to this default case
485 TempDescriptor [] writeTemps = fn.writesTemps();
486 if( writeTemps.length > 0 ) {
487 assert writeTemps.length == 1;
489 vstTable.remove( writeTemps[0] );
491 HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
492 ts.add( writeTemps[0] );
494 vstTable.add( new VariableSourceToken( ts,
502 vstTable.assertConsistency();
511 private void isAvailableForward( FlatMethod fm ) {
513 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
514 flatNodesToVisit.add( fm );
516 while( !flatNodesToVisit.isEmpty() ) {
517 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
518 flatNodesToVisit.remove( fn );
520 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
521 assert seseStack != null;
523 Set<TempDescriptor> prev = isAvailableResults.get( fn );
525 // merge control flow joins where something is available
526 // into this node only if it is available on every incoming
527 // node, so do intersect of all incoming nodes with live in
528 HashSet<TempDescriptor> rootLiveSet = (HashSet<TempDescriptor>) livenessRootView.get( fn );
529 Set<TempDescriptor> inIntersect = (Set<TempDescriptor>) rootLiveSet.clone();
531 for( int i = 0; i < fn.numPrev(); i++ ) {
532 FlatNode nn = fn.getPrev( i );
533 Set<TempDescriptor> availIn = isAvailableResults.get( nn );
534 inIntersect.retainAll( availIn );
537 Set<TempDescriptor> curr = isAvailable_nodeActions( fn, inIntersect, seseStack.peek() );
539 // if a new result, schedule forward nodes for analysis
540 if( !curr.equals( prev ) ) {
541 isAvailableResults.put( fn, curr );
543 for( int i = 0; i < fn.numNext(); i++ ) {
544 FlatNode nn = fn.getNext( i );
545 flatNodesToVisit.add( nn );
551 private Set<TempDescriptor> isAvailable_nodeActions( FlatNode fn,
552 Set<TempDescriptor> isAvailSet,
553 FlatSESEEnterNode currentSESE ) {
554 switch( fn.kind() ) {
556 case FKind.FlatSESEEnterNode: {
557 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
558 assert fsen.equals( currentSESE );
561 case FKind.FlatSESEExitNode: {
562 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
563 FlatSESEEnterNode fsen = fsexn.getFlatEnter();
564 assert currentSESE.getChildren().contains( fsen );
568 TempDescriptor [] writeTemps = fn.writesTemps();
577 private void computeStallsForward( FlatMethod fm ) {
579 // start from flat method top, visit every node in
580 // method exactly once
581 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
582 flatNodesToVisit.add( fm );
584 Set<FlatNode> visited = new HashSet<FlatNode>();
586 while( !flatNodesToVisit.isEmpty() ) {
587 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
588 FlatNode fn = fnItr.next();
590 flatNodesToVisit.remove( fn );
593 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
594 assert seseStack != null;
596 // use incoming results as "dot statement" or just
597 // before the current statement
598 VarSrcTokTable dotST = new VarSrcTokTable();
599 for( int i = 0; i < fn.numPrev(); i++ ) {
600 FlatNode nn = fn.getPrev( i );
601 dotST.merge( variableResults.get( nn ) );
604 computeStalls_nodeActions( fn, dotST, seseStack.peek() );
606 for( int i = 0; i < fn.numNext(); i++ ) {
607 FlatNode nn = fn.getNext( i );
609 if( !visited.contains( nn ) ) {
610 flatNodesToVisit.add( nn );
615 if( state.MLPDEBUG ) {
616 System.out.println( fm.printMethod( codePlans ) );
620 private void computeStalls_nodeActions( FlatNode fn,
621 VarSrcTokTable vstTable,
622 FlatSESEEnterNode currentSESE ) {
623 String before = null;
626 switch( fn.kind() ) {
628 case FKind.FlatSESEEnterNode: {
629 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
632 case FKind.FlatSESEExitNode: {
633 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
637 Set<VariableSourceToken> stallSet = vstTable.getStallSet( currentSESE );
638 TempDescriptor[] readarray = fn.readsTemps();
639 for( int i = 0; i < readarray.length; i++ ) {
640 TempDescriptor readtmp = readarray[i];
641 Set<VariableSourceToken> readSet = vstTable.get( readtmp );
643 for( Iterator<VariableSourceToken> readit = readSet.iterator();
644 readit.hasNext(); ) {
645 VariableSourceToken vst = readit.next();
646 if( stallSet.contains( vst ) ) {
647 if( before == null ) {
648 before = "**STALL for:";
650 before += "("+vst+" "+readtmp+")";
657 if( before == null ) {
661 if( after == null ) {
665 codePlans.put( fn, new CodePlan( before, after ) );