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> > livenessVirtualReads;
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 livenessVirtualReads = 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 );
57 FlatMethod fmMain = state.getMethodFlat( tu.getMain() );
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, true, null, fmMain.getFlatExit() );
80 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
81 while( methItr.hasNext() ) {
82 Descriptor d = methItr.next();
83 FlatMethod fm = state.getMethodFlat( d );
85 // starting from roots do a forward, fixed-point
86 // variable analysis for refinement and stalls
87 variableAnalysisForward( fm );
91 // 4th pass, compute liveness contribution from
92 // virtual reads discovered in variable pass
93 livenessAnalysisBackward( rootSESE, true, null, fmMain.getFlatExit() );
97 methItr = ownAnalysis.descriptorsToAnalyze.iterator();
98 while( methItr.hasNext() ) {
99 Descriptor d = methItr.next();
100 FlatMethod fm = state.getMethodFlat( d );
102 // compute a plan for code injections
103 computeStallsForward( fm );
107 double timeEndAnalysis = (double) System.nanoTime();
108 double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
109 String treport = String.format( "The mlp analysis took %.3f sec.", dt );
110 System.out.println( treport );
114 private void buildForestForward( FlatMethod fm ) {
116 // start from flat method top, visit every node in
117 // method exactly once, find SESEs and remember
118 // roots and child relationships
119 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
120 flatNodesToVisit.add( fm );
122 Set<FlatNode> visited = new HashSet<FlatNode>();
124 Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
125 seseStackFirst.push( rootSESE );
126 seseStacks.put( fm, seseStackFirst );
128 while( !flatNodesToVisit.isEmpty() ) {
129 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
130 FlatNode fn = fnItr.next();
132 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
133 assert seseStack != null;
135 flatNodesToVisit.remove( fn );
138 buildForest_nodeActions( fn, seseStack );
140 for( int i = 0; i < fn.numNext(); i++ ) {
141 FlatNode nn = fn.getNext( i );
143 if( !visited.contains( nn ) ) {
144 flatNodesToVisit.add( nn );
146 // clone stack and send along each analysis path
147 seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
152 if( state.MLPDEBUG ) {
157 private void buildForest_nodeActions( FlatNode fn,
158 Stack<FlatSESEEnterNode> seseStack ) {
159 switch( fn.kind() ) {
161 case FKind.FlatSESEEnterNode: {
162 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
163 assert !seseStack.empty();
164 seseStack.peek().addChild( fsen );
165 fsen.setParent( seseStack.peek() );
166 seseStack.push( fsen );
169 case FKind.FlatSESEExitNode: {
170 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
171 assert !seseStack.empty();
172 FlatSESEEnterNode fsen = seseStack.pop();
175 case FKind.FlatReturnNode: {
176 FlatReturnNode frn = (FlatReturnNode) fn;
177 if( !seseStack.empty() &&
178 !seseStack.peek().equals( rootSESE ) ) {
179 throw new Error( "Error: return statement enclosed within "+seseStack.peek() );
186 private void printSESEForest() {
187 // our forest is actually a tree now that
188 // there is an implicit root SESE
189 printSESETree( rootSESE, 0 );
190 System.out.println( "" );
193 private void printSESETree( FlatSESEEnterNode fsen, int depth ) {
194 for( int i = 0; i < depth; ++i ) {
195 System.out.print( " " );
197 System.out.println( fsen.getPrettyIdentifier() );
199 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
200 while( childItr.hasNext() ) {
201 FlatSESEEnterNode fsenChild = childItr.next();
202 printSESETree( fsenChild, depth + 1 );
207 private void livenessAnalysisBackward( FlatSESEEnterNode fsen,
209 Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout,
212 // start from an SESE exit, visit nodes in reverse up to
213 // SESE enter in a fixed-point scheme, where children SESEs
214 // should already be analyzed and therefore can be skipped
215 // because child SESE enter node has all necessary info
216 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
218 FlatSESEExitNode fsexn = fsen.getFlatExit();
221 flatNodesToVisit.add( fexit );
223 flatNodesToVisit.add( fsexn );
224 Hashtable<FlatNode, Set<TempDescriptor>> livenessResults=new Hashtable<FlatNode, Set<TempDescriptor>>();
227 liveout=new Hashtable<FlatSESEExitNode, Set<TempDescriptor>>();
229 while( !flatNodesToVisit.isEmpty() ) {
230 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
231 flatNodesToVisit.remove( fn );
233 Set<TempDescriptor> prev = livenessResults.get( fn );
235 // merge sets from control flow joins
236 Set<TempDescriptor> u = new HashSet<TempDescriptor>();
237 for( int i = 0; i < fn.numNext(); i++ ) {
238 FlatNode nn = fn.getNext( i );
239 Set<TempDescriptor> s = livenessResults.get( nn );
245 Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen, toplevel, liveout);
247 // if a new result, schedule backward nodes for analysis
248 if(!curr.equals(prev)) {
249 livenessResults.put( fn, curr );
251 // don't flow backwards past current SESE enter
252 if( !fn.equals( fsen ) ) {
253 for( int i = 0; i < fn.numPrev(); i++ ) {
254 FlatNode nn = fn.getPrev( i );
255 flatNodesToVisit.add( nn );
261 Set<TempDescriptor> s = livenessResults.get( fsen );
263 fsen.addInVarSet( s );
266 if( state.MLPDEBUG ) {
267 System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
268 Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
269 while( tItr.hasNext() ) {
270 System.out.println( " "+tItr.next() );
272 System.out.println( "and out-set:" );
273 tItr = fsen.getOutVarSet().iterator();
274 while( tItr.hasNext() ) {
275 System.out.println( " "+tItr.next() );
277 System.out.println( "" );
279 // post-order traversal, so do children first
280 Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
281 while( childItr.hasNext() ) {
282 FlatSESEEnterNode fsenChild = childItr.next();
283 livenessAnalysisBackward( fsenChild, false, liveout, null);
287 private Set<TempDescriptor> liveness_nodeActions( FlatNode fn,
288 Set<TempDescriptor> liveIn,
289 FlatSESEEnterNode currentSESE,
291 Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout ) {
293 switch( fn.kind() ) {
295 case FKind.FlatSESEExitNode:
296 if (toplevel==true) {
297 FlatSESEExitNode exitn=(FlatSESEExitNode) fn;
298 //update liveout set for FlatSESEExitNode
299 if (!liveout.containsKey(exitn))
300 liveout.put(exitn, new HashSet<TempDescriptor>());
301 liveout.get(exitn).addAll(liveIn);
303 // no break, sese exits should also execute default actions
306 // handle effects of statement in reverse, writes then reads
307 TempDescriptor [] writeTemps = fn.writesTemps();
308 for( int i = 0; i < writeTemps.length; ++i ) {
309 liveIn.remove( writeTemps[i] );
312 FlatSESEExitNode exitnode=currentSESE.getFlatExit();
313 Set<TempDescriptor> livetemps=liveout.get(exitnode);
314 if (livetemps.contains(writeTemps[i])) {
315 //write to a live out temp...
316 //need to put in SESE liveout set
317 currentSESE.addOutVar(writeTemps[i]);
322 TempDescriptor [] readTemps = fn.readsTemps();
323 for( int i = 0; i < readTemps.length; ++i ) {
324 liveIn.add( readTemps[i] );
327 Set<TempDescriptor> virtualReadTemps = livenessVirtualReads.get( fn );
328 if( virtualReadTemps != null ) {
329 Iterator<TempDescriptor> vrItr = virtualReadTemps.iterator();
330 while( vrItr.hasNext() ) {
331 liveIn.add( vrItr.next() );
342 private void variableAnalysisForward( FlatMethod fm ) {
344 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
345 flatNodesToVisit.add( fm );
347 while( !flatNodesToVisit.isEmpty() ) {
348 FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
349 flatNodesToVisit.remove( fn );
351 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
352 assert seseStack != null;
354 VarSrcTokTable prev = variableResults.get( fn );
356 // merge sets from control flow joins
357 VarSrcTokTable inUnion = new VarSrcTokTable();
358 for( int i = 0; i < fn.numPrev(); i++ ) {
359 FlatNode nn = fn.getPrev( i );
361 VarSrcTokTable incoming = variableResults.get( nn );
362 if( incoming != null ) {
363 incoming.assertConsistency();
366 inUnion.merge( incoming );
369 VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );
371 // if a new result, schedule forward nodes for analysis
372 if( !curr.equals( prev ) ) {
375 curr.assertConsistency();
377 variableResults.put( fn, curr );
379 for( int i = 0; i < fn.numNext(); i++ ) {
380 FlatNode nn = fn.getNext( i );
381 flatNodesToVisit.add( nn );
387 private VarSrcTokTable variable_nodeActions( FlatNode fn,
388 VarSrcTokTable vstTable,
389 FlatSESEEnterNode currentSESE ) {
390 switch( fn.kind() ) {
392 case FKind.FlatSESEEnterNode: {
393 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
394 assert fsen.equals( currentSESE );
395 vstTable.age( currentSESE );
397 vstTable.assertConsistency();
401 case FKind.FlatSESEExitNode: {
402 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
403 FlatSESEEnterNode fsen = fsexn.getFlatEnter();
404 assert currentSESE.getChildren().contains( fsen );
405 vstTable.remapChildTokens( fsen );
407 Set<TempDescriptor> liveIn = currentSESE.getInVarSet();
408 Set<TempDescriptor> virLiveIn = vstTable.removeParentAndSiblingTokens( fsen, liveIn );
409 Set<TempDescriptor> virLiveInOld = livenessVirtualReads.get( fn );
410 if( virLiveInOld != null ) {
411 virLiveIn.addAll( virLiveInOld );
413 livenessVirtualReads.put( fn, virLiveIn );
415 vstTable.assertConsistency();
419 case FKind.FlatOpNode: {
420 FlatOpNode fon = (FlatOpNode) fn;
422 if( fon.getOp().getOp() == Operation.ASSIGN ) {
423 TempDescriptor lhs = fon.getDest();
424 TempDescriptor rhs = fon.getLeft();
426 vstTable.remove( lhs );
428 Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
429 while( itr.hasNext() ) {
430 VariableSourceToken vst = itr.next();
432 HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
435 // if this is from a child, keep the source information
436 if( currentSESE.getChildren().contains( vst.getSESE() ) ) {
437 vstTable.add( new VariableSourceToken( ts,
444 // otherwise, it's our or an ancestor's token so we
445 // can assume we have everything we need
447 vstTable.add( new VariableSourceToken( ts,
456 // only break if this is an ASSIGN op node,
457 // otherwise fall through to default case
459 vstTable.assertConsistency();
465 // note that FlatOpNode's that aren't ASSIGN
466 // fall through to this default case
468 TempDescriptor [] writeTemps = fn.writesTemps();
469 if( writeTemps.length > 0 ) {
470 assert writeTemps.length == 1;
472 vstTable.remove( writeTemps[0] );
474 HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
475 ts.add( writeTemps[0] );
477 vstTable.add( new VariableSourceToken( ts,
485 vstTable.assertConsistency();
495 private void computeStallsForward( FlatMethod fm ) {
497 // start from flat method top, visit every node in
498 // method exactly once
499 Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
500 flatNodesToVisit.add( fm );
502 Set<FlatNode> visited = new HashSet<FlatNode>();
504 while( !flatNodesToVisit.isEmpty() ) {
505 Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
506 FlatNode fn = fnItr.next();
508 flatNodesToVisit.remove( fn );
511 Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
512 assert seseStack != null;
514 // use incoming results as "dot statement" or just
515 // before the current statement
516 VarSrcTokTable dotST = new VarSrcTokTable();
517 for( int i = 0; i < fn.numPrev(); i++ ) {
518 FlatNode nn = fn.getPrev( i );
519 dotST.merge( variableResults.get( nn ) );
522 computeStalls_nodeActions( fn, dotST, seseStack.peek() );
524 for( int i = 0; i < fn.numNext(); i++ ) {
525 FlatNode nn = fn.getNext( i );
527 if( !visited.contains( nn ) ) {
528 flatNodesToVisit.add( nn );
533 if( state.MLPDEBUG ) {
534 System.out.println( fm.printMethod( codePlan ) );
538 private void computeStalls_nodeActions( FlatNode fn,
539 VarSrcTokTable vstTable,
540 FlatSESEEnterNode currentSESE ) {
543 switch( fn.kind() ) {
545 case FKind.FlatSESEEnterNode: {
546 FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
549 case FKind.FlatSESEExitNode: {
550 FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
554 Set<VariableSourceToken> stallSet = vstTable.getStallSet( currentSESE );
555 TempDescriptor[] readarray=fn.readsTemps();
556 for(int i=0;i<readarray.length;i++) {
557 TempDescriptor readtmp=readarray[i];
558 Set<VariableSourceToken> readSet = vstTable.get(readtmp);
560 for(Iterator<VariableSourceToken> readit=readSet.iterator();readit.hasNext();) {
561 VariableSourceToken vst=readit.next();
562 if (stallSet.contains(vst)) {
565 s+="("+vst+" "+readtmp+")";
576 codePlan.put( fn, s );