add frame for another pass to compute whether variables are available, then use to...
[IRC.git] / Robust / src / Analysis / MLP / MLPAnalysis.java
1 package Analysis.MLP;
2
3 import Analysis.CallGraph.*;
4 import Analysis.OwnershipAnalysis.*;
5 import IR.*;
6 import IR.Flat.*;
7 import IR.Tree.*;
8 import java.util.*;
9 import java.io.*;
10
11
12 public class MLPAnalysis {
13
14   // data from the compiler
15   private State state;
16   private TypeUtil typeUtil;
17   private CallGraph callGraph;
18   private OwnershipAnalysis ownAnalysis;
19
20   private SESENode          rootTree;
21   private FlatSESEEnterNode rootSESE;
22   private FlatSESEExitNode  rootExit;
23
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;
30
31
32   public MLPAnalysis( State             state,
33                       TypeUtil          tu,
34                       CallGraph         callGraph,
35                       OwnershipAnalysis ownAnalysis
36                       ) {
37
38     double timeStartAnalysis = (double) System.nanoTime();
39
40     this.state       = state;
41     this.typeUtil    = tu;
42     this.callGraph   = callGraph;
43     this.ownAnalysis = ownAnalysis;
44
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                 >();
51
52
53
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 );
60
61     FlatMethod fmMain = state.getMethodFlat( tu.getMain() );
62
63
64     // 1st pass
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 );
71
72       // find every SESE from methods that may be called
73       // and organize them into roots and children
74       buildForestForward( fm );
75     }
76
77
78     // 2nd pass, results are saved in FlatSESEEnterNode, so
79     // intermediate results, for safety, are discarded
80     livenessAnalysisBackward( rootSESE, true, null, fmMain.getFlatExit() );
81
82
83     // 3rd pass
84     methItr = ownAnalysis.descriptorsToAnalyze.iterator();
85     while( methItr.hasNext() ) {
86       Descriptor d  = methItr.next();      
87       FlatMethod fm = state.getMethodFlat( d );
88
89       // starting from roots do a forward, fixed-point
90       // variable analysis for refinement and stalls
91       variableAnalysisForward( fm );
92     }
93
94
95     // 4th pass, compute liveness contribution from
96     // virtual reads discovered in variable pass
97     livenessAnalysisBackward( rootSESE, true, null, fmMain.getFlatExit() );        
98
99
100     // 5th pass
101     methItr = ownAnalysis.descriptorsToAnalyze.iterator();
102     while( methItr.hasNext() ) {
103       Descriptor d  = methItr.next();      
104       FlatMethod fm = state.getMethodFlat( d );
105
106       // compute is available for every live variable at
107       // every program point, in a forward fixed-point pass
108       isAvailableForward( fm );
109     }
110
111
112     // 5th pass
113     methItr = ownAnalysis.descriptorsToAnalyze.iterator();
114     while( methItr.hasNext() ) {
115       Descriptor d  = methItr.next();      
116       FlatMethod fm = state.getMethodFlat( d );
117
118       // compute a plan for code injections
119       computeStallsForward( fm );
120     }
121
122
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 );
127   }
128
129
130   private void buildForestForward( FlatMethod fm ) {
131     
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 );
137
138     Set<FlatNode> visited = new HashSet<FlatNode>();    
139
140     Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
141     seseStackFirst.push( rootSESE );
142     seseStacks.put( fm, seseStackFirst );
143
144     while( !flatNodesToVisit.isEmpty() ) {
145       Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
146       FlatNode fn = fnItr.next();
147
148       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
149       assert seseStack != null;      
150
151       flatNodesToVisit.remove( fn );
152       visited.add( fn );      
153
154       buildForest_nodeActions( fn, seseStack );
155
156       for( int i = 0; i < fn.numNext(); i++ ) {
157         FlatNode nn = fn.getNext( i );
158
159         if( !visited.contains( nn ) ) {
160           flatNodesToVisit.add( nn );
161
162           // clone stack and send along each analysis path
163           seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
164         }
165       }
166     }      
167
168     if( state.MLPDEBUG ) { 
169       printSESEForest();
170     }
171   }
172
173   private void buildForest_nodeActions( FlatNode fn,                                                       
174                                         Stack<FlatSESEEnterNode> seseStack ) {
175     switch( fn.kind() ) {
176
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 );
183     } break;
184
185     case FKind.FlatSESEExitNode: {
186       FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
187       assert !seseStack.empty();
188       FlatSESEEnterNode fsen = seseStack.pop();
189     } break;
190
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() );
196       }
197     } break;
198       
199     }
200   }
201
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( "" );
207   }
208
209   private void printSESETree( FlatSESEEnterNode fsen, int depth ) {
210     for( int i = 0; i < depth; ++i ) {
211       System.out.print( "  " );
212     }
213     System.out.println( fsen.getPrettyIdentifier() );
214
215     Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
216     while( childItr.hasNext() ) {
217       FlatSESEEnterNode fsenChild = childItr.next();
218       printSESETree( fsenChild, depth + 1 );
219     }
220   }
221
222
223     private void livenessAnalysisBackward( FlatSESEEnterNode fsen, 
224                                            boolean toplevel, 
225                                            Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout, 
226                                            FlatExit fexit ) {
227
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>();
233
234     FlatSESEExitNode fsexn = fsen.getFlatExit();
235     if (toplevel) {
236         //handle root SESE
237         flatNodesToVisit.add( fexit );
238     } else
239         flatNodesToVisit.add( fsexn );
240     Hashtable<FlatNode, Set<TempDescriptor>> livenessResults=new Hashtable<FlatNode, Set<TempDescriptor>>();
241
242     if (toplevel==true)
243         liveout=new Hashtable<FlatSESEExitNode, Set<TempDescriptor>>();
244     
245     while( !flatNodesToVisit.isEmpty() ) {
246       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
247       flatNodesToVisit.remove( fn );      
248       
249       Set<TempDescriptor> prev = livenessResults.get( fn );
250
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 );
256         if( s != null ) {
257           u.addAll( s );
258         }
259       }
260
261       Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen, toplevel, liveout);
262
263       // if a new result, schedule backward nodes for analysis
264       if(!curr.equals(prev)) {
265         livenessResults.put( fn, curr );
266
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 );
272           }
273         }
274       }
275     }
276     
277     Set<TempDescriptor> s = livenessResults.get( fsen );
278     if( s != null ) {
279       fsen.addInVarSet( s );
280     }
281     
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() );
287       }
288       System.out.println( "and out-set:" );
289       tItr = fsen.getOutVarSet().iterator();
290       while( tItr.hasNext() ) {
291         System.out.println( "  "+tItr.next() );
292       }
293       System.out.println( "" );
294     }
295
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;
300     }
301
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);
307     }
308   }
309
310   private Set<TempDescriptor> liveness_nodeActions( FlatNode fn, 
311                                                     Set<TempDescriptor> liveIn,
312                                                     FlatSESEEnterNode currentSESE,
313                                                     boolean toplevel,
314                                                     Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout ) {
315
316     switch( fn.kind() ) {
317
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);
325       }
326       // no break, sese exits should also execute default actions
327       
328     default: {
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] );
333
334         if (!toplevel) {
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]);
341           }
342         }
343       }
344
345       TempDescriptor [] readTemps = fn.readsTemps();
346       for( int i = 0; i < readTemps.length; ++i ) {
347         liveIn.add( readTemps[i] );
348       }
349
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() );
355         }
356       }
357     } break;
358
359     } // end switch
360
361     return liveIn;
362   }
363
364
365   private void variableAnalysisForward( FlatMethod fm ) {
366
367     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
368     flatNodesToVisit.add( fm );  
369
370     while( !flatNodesToVisit.isEmpty() ) {
371       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
372       flatNodesToVisit.remove( fn );      
373
374       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
375       assert seseStack != null;      
376
377       VarSrcTokTable prev = variableResults.get( fn );
378
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 );  
383         
384         VarSrcTokTable incoming = variableResults.get( nn );
385         if( incoming != null ) {
386           incoming.assertConsistency();
387         }
388
389         inUnion.merge( incoming );
390       }
391
392       VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );     
393
394       // if a new result, schedule forward nodes for analysis
395       if( !curr.equals( prev ) ) {
396         
397
398         curr.assertConsistency();
399
400         variableResults.put( fn, curr );
401
402         for( int i = 0; i < fn.numNext(); i++ ) {
403           FlatNode nn = fn.getNext( i );         
404           flatNodesToVisit.add( nn );    
405         }
406       }
407     }
408   }
409
410   private VarSrcTokTable variable_nodeActions( FlatNode fn, 
411                                                VarSrcTokTable vstTable,
412                                                FlatSESEEnterNode currentSESE ) {
413     switch( fn.kind() ) {
414
415     case FKind.FlatSESEEnterNode: {
416       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
417       assert fsen.equals( currentSESE );
418       vstTable.age( currentSESE );
419       vstTable.assertConsistency();
420     } break;
421
422     case FKind.FlatSESEExitNode: {
423       FlatSESEExitNode  fsexn = (FlatSESEExitNode)  fn;
424       FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
425       assert currentSESE.getChildren().contains( fsen );
426       vstTable.remapChildTokens( fsen );
427
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 );
433       }
434       livenessVirtualReads.put( fn, virLiveIn );
435       vstTable.assertConsistency();
436     } break;
437
438     case FKind.FlatOpNode: {
439       FlatOpNode fon = (FlatOpNode) fn;
440
441       if( fon.getOp().getOp() == Operation.ASSIGN ) {
442         TempDescriptor lhs = fon.getDest();
443         TempDescriptor rhs = fon.getLeft();
444
445         vstTable.remove( lhs );
446
447         Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
448         while( itr.hasNext() ) {
449           VariableSourceToken vst = itr.next();
450
451           HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
452           ts.add( lhs );
453
454           // if this is from a child, keep the source information
455           if( currentSESE.getChildren().contains( vst.getSESE() ) ) {     
456             vstTable.add( new VariableSourceToken( ts,
457                                                    vst.getSESE(),
458                                                    vst.getAge(),
459                                                    vst.getAddrVar()
460                                                    )
461                           );
462
463           // otherwise, it's our or an ancestor's token so we
464           // can assume we have everything we need
465           } else {
466             vstTable.add( new VariableSourceToken( ts,
467                                                    currentSESE,
468                                                    new Integer( 0 ),
469                                                    lhs
470                                                    )
471                           );
472           }
473         }
474
475         // only break if this is an ASSIGN op node,
476         // otherwise fall through to default case
477         vstTable.assertConsistency();
478         break;
479       }
480     }
481
482     // note that FlatOpNode's that aren't ASSIGN
483     // fall through to this default case
484     default: {
485       TempDescriptor [] writeTemps = fn.writesTemps();
486       if( writeTemps.length > 0 ) {
487         assert writeTemps.length == 1;
488
489         vstTable.remove( writeTemps[0] );
490
491         HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
492         ts.add( writeTemps[0] );
493
494         vstTable.add( new VariableSourceToken( ts,
495                                                currentSESE,
496                                                new Integer( 0 ),
497                                                writeTemps[0]
498                                              )
499                       );
500       }      
501
502       vstTable.assertConsistency();
503     } break;
504
505     } // end switch
506
507     return vstTable;
508   }
509
510
511   private void isAvailableForward( FlatMethod fm ) {
512
513     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
514     flatNodesToVisit.add( fm );  
515
516     while( !flatNodesToVisit.isEmpty() ) {
517       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
518       flatNodesToVisit.remove( fn );      
519
520       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
521       assert seseStack != null;      
522
523       Set<TempDescriptor> prev = isAvailableResults.get( fn );
524
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();
530       
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 );
535       }
536
537       Set<TempDescriptor> curr = isAvailable_nodeActions( fn, inIntersect, seseStack.peek() );     
538
539       // if a new result, schedule forward nodes for analysis
540       if( !curr.equals( prev ) ) {
541         isAvailableResults.put( fn, curr );
542
543         for( int i = 0; i < fn.numNext(); i++ ) {
544           FlatNode nn = fn.getNext( i );         
545           flatNodesToVisit.add( nn );    
546         }
547       }
548     }
549   }
550
551   private Set<TempDescriptor> isAvailable_nodeActions( FlatNode fn, 
552                                                        Set<TempDescriptor> isAvailSet,
553                                                        FlatSESEEnterNode currentSESE ) {
554     switch( fn.kind() ) {
555
556     case FKind.FlatSESEEnterNode: {
557       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
558       assert fsen.equals( currentSESE );
559     } break;
560
561     case FKind.FlatSESEExitNode: {
562       FlatSESEExitNode  fsexn = (FlatSESEExitNode)  fn;
563       FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
564       assert currentSESE.getChildren().contains( fsen );
565     } break;
566
567     default: {
568       TempDescriptor [] writeTemps = fn.writesTemps();
569     } break;
570
571     } // end switch
572
573     return isAvailSet;
574   }
575
576
577   private void computeStallsForward( FlatMethod fm ) {
578     
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 );
583
584     Set<FlatNode> visited = new HashSet<FlatNode>();    
585
586     while( !flatNodesToVisit.isEmpty() ) {
587       Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
588       FlatNode fn = fnItr.next();
589
590       flatNodesToVisit.remove( fn );
591       visited.add( fn );      
592
593       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
594       assert seseStack != null;      
595
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 ) );
602       }
603
604       computeStalls_nodeActions( fn, dotST, seseStack.peek() );
605
606       for( int i = 0; i < fn.numNext(); i++ ) {
607         FlatNode nn = fn.getNext( i );
608
609         if( !visited.contains( nn ) ) {
610           flatNodesToVisit.add( nn );
611         }
612       }
613     }      
614
615     if( state.MLPDEBUG ) { 
616       System.out.println( fm.printMethod( codePlans ) );
617     }
618   }
619
620   private void computeStalls_nodeActions( FlatNode fn,
621                                           VarSrcTokTable vstTable,
622                                           FlatSESEEnterNode currentSESE ) {
623     String before = null;
624     String after  = null;
625
626     switch( fn.kind() ) {
627
628     case FKind.FlatSESEEnterNode: {
629       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;      
630     } break;
631
632     case FKind.FlatSESEExitNode: {
633       FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
634     } break;
635
636     default: {          
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 );
642         //containsAny
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:";
649             }
650             before += "("+vst+" "+readtmp+")";
651           }
652         }         
653       }
654     } break;
655
656     } // end switch
657     if( before == null ) {
658       before = "";
659     }
660
661     if( after == null ) {
662       after = "";
663     }
664
665     codePlans.put( fn, new CodePlan( before, after ) );
666   }
667 }