1c9e8eec52f465204fca70d34bcbdd49412d0cbb
[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
21   // an implicit SESE is automatically spliced into
22   // the IR graph around the C main before this analysis--it
23   // is nothing special except that we can make assumptions
24   // about it, such as the whole program ends when it ends
25   private FlatSESEEnterNode mainSESE;
26
27   // SESEs that are the root of an SESE tree belong to this
28   // set--the main SESE is always a root, statically SESEs
29   // inside methods are a root because we don't know how they
30   // will fit into the runtime tree of SESEs
31   private Set<FlatSESEEnterNode> rootSESEs;
32
33   // simply a set of every reachable SESE in the program, not
34   // including caller placeholder SESEs
35   private Set<FlatSESEEnterNode> allSESEs;
36
37
38   // A mapping of flat nodes to the stack of SESEs for that node, where
39   // an SESE is the child of the SESE directly below it on the stack.
40   // These stacks do not reflect the heirarchy over methods calls--whenever
41   // there is an empty stack it means all variables are available.
42   private Hashtable< FlatNode, Stack<FlatSESEEnterNode> > seseStacks;
43
44   private Hashtable< FlatNode, Set<TempDescriptor>      > livenessRootView;
45   private Hashtable< FlatNode, Set<TempDescriptor>      > livenessVirtualReads;
46   private Hashtable< FlatNode, VarSrcTokTable           > variableResults;
47   private Hashtable< FlatNode, Set<TempDescriptor>      > notAvailableResults;
48   private Hashtable< FlatNode, CodePlan                 > codePlans;
49
50   private Hashtable< FlatEdge, FlatWriteDynamicVarNode  > wdvNodesToSpliceIn;
51
52   public static int maxSESEage = -1;
53
54
55   // use these methods in BuildCode to have access to analysis results
56   public FlatSESEEnterNode getMainSESE() {
57     return mainSESE;
58   }
59
60   public Set<FlatSESEEnterNode> getRootSESEs() {
61     return rootSESEs;
62   }
63
64   public Set<FlatSESEEnterNode> getAllSESEs() {
65     return allSESEs;
66   }
67
68   public int getMaxSESEage() {
69     return maxSESEage;
70   }
71
72   // may be null
73   public CodePlan getCodePlan( FlatNode fn ) {
74     CodePlan cp = codePlans.get( fn );
75     return cp;
76   }
77
78
79   public MLPAnalysis( State             state,
80                       TypeUtil          tu,
81                       CallGraph         callGraph,
82                       OwnershipAnalysis ownAnalysis
83                       ) {
84
85     double timeStartAnalysis = (double) System.nanoTime();
86
87     this.state       = state;
88     this.typeUtil    = tu;
89     this.callGraph   = callGraph;
90     this.ownAnalysis = ownAnalysis;
91     this.maxSESEage  = state.MLP_MAXSESEAGE;
92
93     rootSESEs = new HashSet<FlatSESEEnterNode>();
94     allSESEs  = new HashSet<FlatSESEEnterNode>();
95
96     seseStacks           = new Hashtable< FlatNode, Stack<FlatSESEEnterNode> >();    
97     livenessRootView     = new Hashtable< FlatNode, Set<TempDescriptor>      >();
98     livenessVirtualReads = new Hashtable< FlatNode, Set<TempDescriptor>      >();
99     variableResults      = new Hashtable< FlatNode, VarSrcTokTable           >();
100     notAvailableResults  = new Hashtable< FlatNode, Set<TempDescriptor>      >();
101     codePlans            = new Hashtable< FlatNode, CodePlan                 >();
102     wdvNodesToSpliceIn   = new Hashtable< FlatEdge, FlatWriteDynamicVarNode  >();
103
104
105     FlatMethod fmMain = state.getMethodFlat( typeUtil.getMain() );
106
107     mainSESE = (FlatSESEEnterNode) fmMain.getNext(0);    
108     mainSESE.setfmEnclosing( fmMain );
109     mainSESE.setmdEnclosing( fmMain.getMethod() );
110     mainSESE.setcdEnclosing( fmMain.getMethod().getClassDesc() );
111
112
113     // 1st pass
114     // run analysis on each method that is actually called
115     // reachability analysis already computed this so reuse
116     Iterator<Descriptor> methItr = ownAnalysis.descriptorsToAnalyze.iterator();
117     while( methItr.hasNext() ) {
118       Descriptor d  = methItr.next();      
119       FlatMethod fm = state.getMethodFlat( d );
120
121       // find every SESE from methods that may be called
122       // and organize them into roots and children
123       buildForestForward( fm );
124     }
125
126
127     // 2nd pass, results are saved in FlatSESEEnterNode, so
128     // intermediate results, for safety, are discarded
129     Iterator<FlatSESEEnterNode> rootItr = rootSESEs.iterator();
130     while( rootItr.hasNext() ) {
131       FlatSESEEnterNode root = rootItr.next();
132       livenessAnalysisBackward( root, 
133                                 true, 
134                                 null );
135     }
136
137
138     // 3rd pass
139     methItr = ownAnalysis.descriptorsToAnalyze.iterator();
140     while( methItr.hasNext() ) {
141       Descriptor d  = methItr.next();      
142       FlatMethod fm = state.getMethodFlat( d );
143
144       // starting from roots do a forward, fixed-point
145       // variable analysis for refinement and stalls
146       variableAnalysisForward( fm );
147     }
148
149     // 4th pass, compute liveness contribution from
150     // virtual reads discovered in variable pass
151     rootItr = rootSESEs.iterator();
152     while( rootItr.hasNext() ) {
153       FlatSESEEnterNode root = rootItr.next();
154       livenessAnalysisBackward( root, 
155                                 true, 
156                                 null );
157     }
158
159
160     /*
161       SOMETHING IS WRONG WITH THIS, DON'T USE IT UNTIL IT CAN BE FIXED
162
163     // 5th pass
164     methItr = ownAnalysis.descriptorsToAnalyze.iterator();
165     while( methItr.hasNext() ) {
166       Descriptor d  = methItr.next();      
167       FlatMethod fm = state.getMethodFlat( d );
168
169       // prune variable results in one traversal
170       // by removing reference variables that are not live
171       pruneVariableResultsWithLiveness( fm );
172     }
173     */
174
175
176     // 6th pass
177     methItr = ownAnalysis.descriptorsToAnalyze.iterator();
178     while( methItr.hasNext() ) {
179       Descriptor d  = methItr.next();      
180       FlatMethod fm = state.getMethodFlat( d );
181
182       // compute what is not available at every program
183       // point, in a forward fixed-point pass
184       notAvailableForward( fm );
185     }
186
187
188     // 7th pass
189     methItr = ownAnalysis.descriptorsToAnalyze.iterator();
190     while( methItr.hasNext() ) {
191       Descriptor d  = methItr.next();      
192       FlatMethod fm = state.getMethodFlat( d );
193
194       // compute a plan for code injections
195       codePlansForward( fm );
196     }
197
198
199     // splice new IR nodes into graph after all
200     // analysis passes are complete
201     Iterator spliceItr = wdvNodesToSpliceIn.entrySet().iterator();
202     while( spliceItr.hasNext() ) {
203       Map.Entry               me    = (Map.Entry)               spliceItr.next();
204       FlatWriteDynamicVarNode fwdvn = (FlatWriteDynamicVarNode) me.getValue();
205       fwdvn.spliceIntoIR();
206     }
207
208
209     double timeEndAnalysis = (double) System.nanoTime();
210     double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
211     String treport = String.format( "The mlp analysis took %.3f sec.", dt );
212     System.out.println( treport );
213
214     if( state.MLPDEBUG ) {      
215       try {
216         writeReports( treport );
217       } catch( IOException e ) {}
218     }
219   }
220
221
222   private void buildForestForward( FlatMethod fm ) {
223     
224     // start from flat method top, visit every node in
225     // method exactly once, find SESEs and remember
226     // roots and child relationships
227     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
228     flatNodesToVisit.add( fm );
229
230     Set<FlatNode> visited = new HashSet<FlatNode>();    
231
232     Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
233     seseStacks.put( fm, seseStackFirst );
234
235     while( !flatNodesToVisit.isEmpty() ) {
236       Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
237       FlatNode fn = fnItr.next();
238
239       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
240       assert seseStack != null;      
241
242       flatNodesToVisit.remove( fn );
243       visited.add( fn );      
244
245       buildForest_nodeActions( fn, seseStack, fm );
246
247       for( int i = 0; i < fn.numNext(); i++ ) {
248         FlatNode nn = fn.getNext( i );
249
250         if( !visited.contains( nn ) ) {
251           flatNodesToVisit.add( nn );
252
253           // clone stack and send along each analysis path
254           seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
255         }
256       }
257     }      
258   }
259
260   private void buildForest_nodeActions( FlatNode fn,                                                       
261                                         Stack<FlatSESEEnterNode> seseStack,
262                                         FlatMethod fm ) {
263     switch( fn.kind() ) {
264
265     case FKind.FlatSESEEnterNode: {
266       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
267
268       if( !fsen.getIsCallerSESEplaceholder() ) {
269         allSESEs.add( fsen );
270       }
271
272       fsen.setfmEnclosing( fm );
273       fsen.setmdEnclosing( fm.getMethod() );
274       fsen.setcdEnclosing( fm.getMethod().getClassDesc() );
275
276       if( seseStack.empty() ) {
277         rootSESEs.add( fsen );
278         fsen.setParent( null );
279       } else {
280         seseStack.peek().addChild( fsen );
281         fsen.setParent( seseStack.peek() );
282       }
283
284       seseStack.push( fsen );
285     } break;
286
287     case FKind.FlatSESEExitNode: {
288       FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
289       assert !seseStack.empty();
290       FlatSESEEnterNode fsen = seseStack.pop();
291     } break;
292
293     case FKind.FlatReturnNode: {
294       FlatReturnNode frn = (FlatReturnNode) fn;
295       if( !seseStack.empty() &&
296           !seseStack.peek().getIsCallerSESEplaceholder() 
297         ) {
298         throw new Error( "Error: return statement enclosed within SESE "+
299                          seseStack.peek().getPrettyIdentifier() );
300       }
301     } break;
302       
303     }
304   }
305
306
307   private void livenessAnalysisBackward( FlatSESEEnterNode fsen, 
308                                          boolean toplevel, 
309                                          Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout ) {
310
311     // start from an SESE exit, visit nodes in reverse up to
312     // SESE enter in a fixed-point scheme, where children SESEs
313     // should already be analyzed and therefore can be skipped 
314     // because child SESE enter node has all necessary info
315     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
316
317     if( toplevel ) {
318       flatNodesToVisit.add( fsen.getfmEnclosing().getFlatExit() );
319     } else {
320       flatNodesToVisit.add( fsen.getFlatExit() );
321     }
322
323     Hashtable<FlatNode, Set<TempDescriptor>> livenessResults = 
324       new Hashtable< FlatNode, Set<TempDescriptor> >();
325
326     if( toplevel ) {
327       liveout = new Hashtable< FlatSESEExitNode, Set<TempDescriptor> >();
328     }
329
330     while( !flatNodesToVisit.isEmpty() ) {
331       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
332       flatNodesToVisit.remove( fn );      
333       
334       Set<TempDescriptor> prev = livenessResults.get( fn );
335
336       // merge sets from control flow joins
337       Set<TempDescriptor> u = new HashSet<TempDescriptor>();
338       for( int i = 0; i < fn.numNext(); i++ ) {
339         FlatNode nn = fn.getNext( i );
340         Set<TempDescriptor> s = livenessResults.get( nn );
341         if( s != null ) {
342           u.addAll( s );
343         }
344       }
345       
346       Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen, toplevel, liveout);
347
348       // if a new result, schedule backward nodes for analysis
349       if( !curr.equals( prev ) ) {
350         livenessResults.put( fn, curr );
351
352         // don't flow backwards past current SESE enter
353         if( !fn.equals( fsen ) ) {
354           for( int i = 0; i < fn.numPrev(); i++ ) {
355             FlatNode nn = fn.getPrev( i );
356             flatNodesToVisit.add( nn );
357           }
358         }
359       }
360     }
361     
362     Set<TempDescriptor> s = livenessResults.get( fsen );
363     if( s != null ) {
364       fsen.addInVarSet( s );
365     }
366     
367     // remember liveness per node from the root view as the
368     // global liveness of variables for later passes to use
369     if( toplevel ) {
370       livenessRootView.putAll( livenessResults );
371     }
372
373     // post-order traversal, so do children first
374     Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
375     while( childItr.hasNext() ) {
376       FlatSESEEnterNode fsenChild = childItr.next();
377       livenessAnalysisBackward( fsenChild, false, liveout );
378     }
379   }
380
381   private Set<TempDescriptor> liveness_nodeActions( FlatNode fn, 
382                                                     Set<TempDescriptor> liveIn,
383                                                     FlatSESEEnterNode currentSESE,
384                                                     boolean toplevel,
385                                                     Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout 
386                                                   ) {
387     switch( fn.kind() ) {
388       
389     case FKind.FlatSESEExitNode:
390       if( toplevel ) {
391         FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
392         if( !liveout.containsKey( fsexn ) ) {
393           liveout.put( fsexn, new HashSet<TempDescriptor>() );
394         }
395         liveout.get( fsexn ).addAll( liveIn );
396       }
397       // no break, sese exits should also execute default actions
398       
399     default: {
400       // handle effects of statement in reverse, writes then reads
401       TempDescriptor [] writeTemps = fn.writesTemps();
402       for( int i = 0; i < writeTemps.length; ++i ) {
403         liveIn.remove( writeTemps[i] );
404         
405         if( !toplevel ) {
406           FlatSESEExitNode fsexn = currentSESE.getFlatExit();
407           Set<TempDescriptor> livetemps = liveout.get( fsexn );
408           if( livetemps != null &&
409               livetemps.contains( writeTemps[i] ) ) {
410             // write to a live out temp...
411             // need to put in SESE liveout set
412             currentSESE.addOutVar( writeTemps[i] );
413           }     
414         }
415       }
416
417       TempDescriptor [] readTemps = fn.readsTemps();
418       for( int i = 0; i < readTemps.length; ++i ) {
419         liveIn.add( readTemps[i] );
420       }
421       
422       Set<TempDescriptor> virtualReadTemps = livenessVirtualReads.get( fn );
423       if( virtualReadTemps != null ) {
424         liveIn.addAll( virtualReadTemps );
425       }     
426       
427     } break;
428
429     } // end switch
430
431     return liveIn;
432   }
433
434
435   private void variableAnalysisForward( FlatMethod fm ) {
436     
437     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
438     flatNodesToVisit.add( fm );  
439
440     while( !flatNodesToVisit.isEmpty() ) {
441       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
442       flatNodesToVisit.remove( fn );      
443
444       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
445       assert seseStack != null;      
446
447       VarSrcTokTable prev = variableResults.get( fn );
448
449       // merge sets from control flow joins
450       VarSrcTokTable curr = new VarSrcTokTable();
451       for( int i = 0; i < fn.numPrev(); i++ ) {
452         FlatNode nn = fn.getPrev( i );          
453         VarSrcTokTable incoming = variableResults.get( nn );
454         curr.merge( incoming );
455       }
456
457       if( !seseStack.empty() ) {
458         variable_nodeActions( fn, curr, seseStack.peek() );
459       }
460
461       // if a new result, schedule forward nodes for analysis
462       if( !curr.equals( prev ) ) {       
463         variableResults.put( fn, curr );
464
465         for( int i = 0; i < fn.numNext(); i++ ) {
466           FlatNode nn = fn.getNext( i );         
467           flatNodesToVisit.add( nn );    
468         }
469       }
470     }
471   }
472
473   private void variable_nodeActions( FlatNode fn, 
474                                      VarSrcTokTable vstTable,
475                                      FlatSESEEnterNode currentSESE ) {
476     switch( fn.kind() ) {
477
478     case FKind.FlatSESEEnterNode: {
479       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
480       assert fsen.equals( currentSESE );
481
482       vstTable.age( currentSESE );
483       vstTable.assertConsistency();
484     } break;
485
486     case FKind.FlatSESEExitNode: {
487       FlatSESEExitNode  fsexn = (FlatSESEExitNode)  fn;
488       FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
489       assert currentSESE.getChildren().contains( fsen );
490
491       vstTable.remapChildTokens( fsen );
492       
493       // liveness virtual reads are things that might be 
494       // written by an SESE and should be added to the in-set
495       // anything virtually read by this SESE should be pruned
496       // of parent or sibling sources
497       Set<TempDescriptor> liveVars         = livenessRootView.get( fn );
498       Set<TempDescriptor> fsenVirtReads    = vstTable.calcVirtReadsAndPruneParentAndSiblingTokens( fsen, liveVars );
499       Set<TempDescriptor> fsenVirtReadsOld = livenessVirtualReads.get( fn );
500       if( fsenVirtReadsOld != null ) {
501         fsenVirtReads.addAll( fsenVirtReadsOld );
502       }
503       livenessVirtualReads.put( fn, fsenVirtReads );
504
505
506       // then all child out-set tokens are guaranteed
507       // to be filled in, so clobber those entries with
508       // the latest, clean sources
509       Iterator<TempDescriptor> outVarItr = fsen.getOutVarSet().iterator();
510       while( outVarItr.hasNext() ) {
511         TempDescriptor outVar = outVarItr.next();
512         HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
513         ts.add( outVar );
514         VariableSourceToken vst = 
515           new VariableSourceToken( ts,
516                                    fsen,
517                                    new Integer( 0 ),
518                                    outVar
519                                    );
520         vstTable.remove( outVar );
521         vstTable.add( vst );
522       }
523       vstTable.assertConsistency();
524
525     } break;
526
527     case FKind.FlatOpNode: {
528       FlatOpNode fon = (FlatOpNode) fn;
529
530       if( fon.getOp().getOp() == Operation.ASSIGN ) {
531         TempDescriptor lhs = fon.getDest();
532         TempDescriptor rhs = fon.getLeft();        
533
534         vstTable.remove( lhs );
535
536         Set<VariableSourceToken> forAddition = new HashSet<VariableSourceToken>();
537
538         Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
539         while( itr.hasNext() ) {
540           VariableSourceToken vst = itr.next();
541
542           HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
543           ts.add( lhs );
544
545           if( currentSESE.getChildren().contains( vst.getSESE() ) ) {
546             // if the source comes from a child, copy it over
547             forAddition.add( new VariableSourceToken( ts,
548                                                       vst.getSESE(),
549                                                       vst.getAge(),
550                                                       vst.getAddrVar()
551                                                       )
552                              );
553           } else {
554             // otherwise, stamp it as us as the source
555             forAddition.add( new VariableSourceToken( ts,
556                                                       currentSESE,
557                                                       new Integer( 0 ),
558                                                       lhs
559                                                       )
560                              );
561           }
562         }
563
564         vstTable.addAll( forAddition );
565
566         // only break if this is an ASSIGN op node,
567         // otherwise fall through to default case
568         vstTable.assertConsistency();
569         break;
570       }
571     }
572
573     // note that FlatOpNode's that aren't ASSIGN
574     // fall through to this default case
575     default: {
576       TempDescriptor [] writeTemps = fn.writesTemps();
577       if( writeTemps.length > 0 ) {
578
579
580         // for now, when writeTemps > 1, make sure
581         // its a call node, programmer enforce only
582         // doing stuff like calling a print routine
583         //assert writeTemps.length == 1;
584         if( writeTemps.length > 1 ) {
585           assert fn.kind() == FKind.FlatCall ||
586                  fn.kind() == FKind.FlatMethod;
587           break;
588         }
589
590         vstTable.remove( writeTemps[0] );
591
592         HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
593         ts.add( writeTemps[0] );
594
595         vstTable.add( new VariableSourceToken( ts,
596                                                currentSESE,
597                                                new Integer( 0 ),
598                                                writeTemps[0]
599                                              )
600                       );
601       }      
602
603       vstTable.assertConsistency();
604     } break;
605
606     } // end switch
607   }
608
609
610   private void pruneVariableResultsWithLiveness( FlatMethod fm ) {
611     
612     // start from flat method top, visit every node in
613     // method exactly once
614     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
615     flatNodesToVisit.add( fm );
616
617     Set<FlatNode> visited = new HashSet<FlatNode>();    
618
619     while( !flatNodesToVisit.isEmpty() ) {
620       Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
621       FlatNode fn = fnItr.next();
622
623       flatNodesToVisit.remove( fn );
624       visited.add( fn );      
625
626       Set<TempDescriptor> rootLiveSet = livenessRootView.get( fn );
627       VarSrcTokTable      vstTable    = variableResults.get( fn );
628       
629       vstTable.pruneByLiveness( rootLiveSet );
630       
631       for( int i = 0; i < fn.numNext(); i++ ) {
632         FlatNode nn = fn.getNext( i );
633
634         if( !visited.contains( nn ) ) {
635           flatNodesToVisit.add( nn );
636         }
637       }
638     }
639   }
640
641
642   private void notAvailableForward( FlatMethod fm ) {
643
644     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
645     flatNodesToVisit.add( fm );  
646
647     while( !flatNodesToVisit.isEmpty() ) {
648       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
649       flatNodesToVisit.remove( fn );      
650
651       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
652       assert seseStack != null;      
653
654       Set<TempDescriptor> prev = notAvailableResults.get( fn );
655
656       Set<TempDescriptor> curr = new HashSet<TempDescriptor>();      
657       for( int i = 0; i < fn.numPrev(); i++ ) {
658         FlatNode nn = fn.getPrev( i );       
659         Set<TempDescriptor> notAvailIn = notAvailableResults.get( nn );
660         if( notAvailIn != null ) {
661           curr.addAll( notAvailIn );
662         }
663       }
664       
665       if( !seseStack.empty() ) {
666         notAvailable_nodeActions( fn, curr, seseStack.peek() );     
667       }
668
669       // if a new result, schedule forward nodes for analysis
670       if( !curr.equals( prev ) ) {
671         notAvailableResults.put( fn, curr );
672
673         for( int i = 0; i < fn.numNext(); i++ ) {
674           FlatNode nn = fn.getNext( i );         
675           flatNodesToVisit.add( nn );    
676         }
677       }
678     }
679   }
680
681   private void notAvailable_nodeActions( FlatNode fn, 
682                                          Set<TempDescriptor> notAvailSet,
683                                          FlatSESEEnterNode currentSESE ) {
684
685     // any temps that are removed from the not available set
686     // at this node should be marked in this node's code plan
687     // as temps to be grabbed at runtime!
688
689     switch( fn.kind() ) {
690
691     case FKind.FlatSESEEnterNode: {
692       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
693       assert fsen.equals( currentSESE );
694       notAvailSet.clear();
695     } break;
696
697     case FKind.FlatSESEExitNode: {
698       FlatSESEExitNode  fsexn = (FlatSESEExitNode)  fn;
699       FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
700       assert currentSESE.getChildren().contains( fsen );
701       notAvailSet.addAll( fsen.getOutVarSet() );
702     } break;
703
704     case FKind.FlatMethod: {
705       notAvailSet.clear();
706     }
707
708     case FKind.FlatOpNode: {
709       FlatOpNode fon = (FlatOpNode) fn;
710
711       if( fon.getOp().getOp() == Operation.ASSIGN ) {
712         TempDescriptor lhs = fon.getDest();
713         TempDescriptor rhs = fon.getLeft();
714
715         // copy makes lhs same availability as rhs
716         if( notAvailSet.contains( rhs ) ) {
717           notAvailSet.add( lhs );
718         } else {
719           notAvailSet.remove( lhs );
720         }
721
722         // only break if this is an ASSIGN op node,
723         // otherwise fall through to default case
724         break;
725       }
726     }
727
728     // note that FlatOpNode's that aren't ASSIGN
729     // fall through to this default case
730     default: {
731       TempDescriptor [] writeTemps = fn.writesTemps();
732       for( int i = 0; i < writeTemps.length; i++ ) {
733         TempDescriptor wTemp = writeTemps[i];
734         notAvailSet.remove( wTemp );
735       }
736       TempDescriptor [] readTemps = fn.readsTemps();
737       for( int i = 0; i < readTemps.length; i++ ) {
738         TempDescriptor rTemp = readTemps[i];
739         notAvailSet.remove( rTemp );
740
741         // if this variable has exactly one source, potentially
742         // get other things from this source as well
743         VarSrcTokTable vstTable = variableResults.get( fn );
744
745         Integer srcType = 
746           vstTable.getRefVarSrcType( rTemp, 
747                                      currentSESE,
748                                      currentSESE.getParent() );
749
750         if( srcType.equals( VarSrcTokTable.SrcType_STATIC ) ) {
751
752           VariableSourceToken vst = vstTable.get( rTemp ).iterator().next();
753
754           Iterator<VariableSourceToken> availItr = vstTable.get( vst.getSESE(),
755                                                                  vst.getAge()
756                                                                  ).iterator();
757
758           // look through things that are also available from same source
759           while( availItr.hasNext() ) {
760             VariableSourceToken vstAlsoAvail = availItr.next();
761           
762             Iterator<TempDescriptor> refVarItr = vstAlsoAvail.getRefVars().iterator();
763             while( refVarItr.hasNext() ) {
764               TempDescriptor refVarAlso = refVarItr.next();
765
766               // if a variable is available from the same source, AND it ALSO
767               // only comes from one statically known source, mark it available
768               Integer srcTypeAlso = 
769                 vstTable.getRefVarSrcType( refVarAlso, 
770                                            currentSESE,
771                                            currentSESE.getParent() );
772               if( srcTypeAlso.equals( VarSrcTokTable.SrcType_STATIC ) ) {
773                 notAvailSet.remove( refVarAlso );
774               }
775             }
776           }
777         }
778       }
779     } break;
780
781     } // end switch
782   }
783
784
785   private void codePlansForward( FlatMethod fm ) {
786     
787     // start from flat method top, visit every node in
788     // method exactly once
789     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
790     flatNodesToVisit.add( fm );
791
792     Set<FlatNode> visited = new HashSet<FlatNode>();    
793
794     while( !flatNodesToVisit.isEmpty() ) {
795       Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
796       FlatNode fn = fnItr.next();
797
798       flatNodesToVisit.remove( fn );
799       visited.add( fn );      
800
801       Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
802       assert seseStack != null;      
803
804       // use incoming results as "dot statement" or just
805       // before the current statement
806       VarSrcTokTable dotSTtable = new VarSrcTokTable();
807       for( int i = 0; i < fn.numPrev(); i++ ) {
808         FlatNode nn = fn.getPrev( i );
809         dotSTtable.merge( variableResults.get( nn ) );
810       }
811
812       // find dt-st notAvailableSet also
813       Set<TempDescriptor> dotSTnotAvailSet = new HashSet<TempDescriptor>();      
814       for( int i = 0; i < fn.numPrev(); i++ ) {
815         FlatNode nn = fn.getPrev( i );       
816         Set<TempDescriptor> notAvailIn = notAvailableResults.get( nn );
817         if( notAvailIn != null ) {
818           dotSTnotAvailSet.addAll( notAvailIn );
819         }
820       }
821
822       Set<TempDescriptor> dotSTlive = livenessRootView.get( fn );
823
824       if( !seseStack.empty() ) {
825         codePlans_nodeActions( fn, 
826                                dotSTlive,
827                                dotSTtable,
828                                dotSTnotAvailSet,
829                                seseStack.peek()
830                                );
831       }
832
833       for( int i = 0; i < fn.numNext(); i++ ) {
834         FlatNode nn = fn.getNext( i );
835
836         if( !visited.contains( nn ) ) {
837           flatNodesToVisit.add( nn );
838         }
839       }
840     }
841   }
842
843   private void codePlans_nodeActions( FlatNode fn,
844                                       Set<TempDescriptor> liveSetIn,
845                                       VarSrcTokTable vstTableIn,
846                                       Set<TempDescriptor> notAvailSetIn,
847                                       FlatSESEEnterNode currentSESE ) {
848     
849     CodePlan plan = new CodePlan( currentSESE);
850
851     switch( fn.kind() ) {
852
853     case FKind.FlatSESEEnterNode: {
854       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
855
856       // track the source types of the in-var set so generated
857       // code at this SESE issue can compute the number of
858       // dependencies properly
859       Iterator<TempDescriptor> inVarItr = fsen.getInVarSet().iterator();
860       while( inVarItr.hasNext() ) {
861         TempDescriptor inVar = inVarItr.next();
862         Integer srcType = 
863           vstTableIn.getRefVarSrcType( inVar, 
864                                        fsen,
865                                        fsen.getParent() );
866
867         // the current SESE needs a local space to track the dynamic
868         // variable and the child needs space in its SESE record
869         if( srcType.equals( VarSrcTokTable.SrcType_DYNAMIC ) ) {
870           fsen.addDynamicInVar( inVar );
871           fsen.getParent().addDynamicVar( inVar );
872
873         } else if( srcType.equals( VarSrcTokTable.SrcType_STATIC ) ) {
874           fsen.addStaticInVar( inVar );
875           VariableSourceToken vst = vstTableIn.get( inVar ).iterator().next();
876           fsen.putStaticInVar2src( inVar, vst );
877           fsen.addStaticInVarSrc( new SESEandAgePair( vst.getSESE(), 
878                                                       vst.getAge() 
879                                                     ) 
880                                 );
881
882         } else {
883           assert srcType.equals( VarSrcTokTable.SrcType_READY );
884           fsen.addReadyInVar( inVar );
885         }       
886       }
887
888     } break;
889
890     case FKind.FlatSESEExitNode: {
891       FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
892     } break;
893
894     case FKind.FlatOpNode: {
895       FlatOpNode fon = (FlatOpNode) fn;
896
897       if( fon.getOp().getOp() == Operation.ASSIGN ) {
898         TempDescriptor lhs = fon.getDest();
899         TempDescriptor rhs = fon.getLeft();        
900
901         // if this is an op node, don't stall, copy
902         // source and delay until we need to use value
903
904         // ask whether lhs and rhs sources are dynamic, static, etc.
905         Integer lhsSrcType
906           = vstTableIn.getRefVarSrcType( lhs,
907                                          currentSESE,
908                                          currentSESE.getParent() );
909
910         Integer rhsSrcType
911           = vstTableIn.getRefVarSrcType( rhs,
912                                          currentSESE,
913                                          currentSESE.getParent() );
914
915         if( rhsSrcType.equals( VarSrcTokTable.SrcType_DYNAMIC ) ) {
916           // if rhs is dynamic going in, lhs will definitely be dynamic
917           // going out of this node, so track that here   
918           plan.addDynAssign( lhs, rhs );
919           currentSESE.addDynamicVar( lhs );
920           currentSESE.addDynamicVar( rhs );
921
922         } else if( lhsSrcType.equals( VarSrcTokTable.SrcType_DYNAMIC ) ) {
923           // otherwise, if the lhs is dynamic, but the rhs is not, we
924           // need to update the variable's dynamic source as "current SESE"
925           plan.addDynAssign( lhs );
926         }       
927
928         // only break if this is an ASSIGN op node,
929         // otherwise fall through to default case
930         break;
931       }
932     }
933
934     // note that FlatOpNode's that aren't ASSIGN
935     // fall through to this default case
936     default: {          
937
938       // a node with no live set has nothing to stall for
939       if( liveSetIn == null ) {
940         break;
941       }
942
943       TempDescriptor[] readarray = fn.readsTemps();
944       for( int i = 0; i < readarray.length; i++ ) {
945         TempDescriptor readtmp = readarray[i];
946
947         // ignore temps that are definitely available 
948         // when considering to stall on it
949         if( !notAvailSetIn.contains( readtmp ) ) {
950           continue;
951         }
952
953         // check the source type of this variable
954         Integer srcType 
955           = vstTableIn.getRefVarSrcType( readtmp,
956                                          currentSESE,
957                                          currentSESE.getParent() );
958
959         if( srcType.equals( VarSrcTokTable.SrcType_DYNAMIC ) ) {
960           // 1) It is not clear statically where this variable will
961           // come from statically, so dynamically we must keep track
962           // along various control paths, and therefore when we stall,
963           // just stall for the exact thing we need and move on
964           plan.addDynamicStall( readtmp );
965           currentSESE.addDynamicVar( readtmp );  
966
967         } else if( srcType.equals( VarSrcTokTable.SrcType_STATIC ) ) {    
968           // 2) Single token/age pair: Stall for token/age pair, and copy
969           // all live variables with same token/age pair at the same
970           // time.  This is the same stuff that the notavaialable analysis 
971           // marks as now available.      
972
973           VariableSourceToken vst = vstTableIn.get( readtmp ).iterator().next();
974
975           Iterator<VariableSourceToken> availItr = 
976             vstTableIn.get( vst.getSESE(), vst.getAge() ).iterator();
977
978           while( availItr.hasNext() ) {
979             VariableSourceToken vstAlsoAvail = availItr.next();
980
981             // only grab additional stuff that is live
982             Set<TempDescriptor> copySet = new HashSet<TempDescriptor>();
983
984             Iterator<TempDescriptor> refVarItr = vstAlsoAvail.getRefVars().iterator();
985             while( refVarItr.hasNext() ) {
986               TempDescriptor refVar = refVarItr.next();
987               if( liveSetIn.contains( refVar ) ) {
988                 copySet.add( refVar );
989               }
990             }
991
992             if( !copySet.isEmpty() ) {
993               plan.addStall2CopySet( vstAlsoAvail, copySet );
994             }
995           }                      
996
997         } else {
998           // the other case for srcs is READY, so do nothing
999         }
1000
1001         // assert that everything being stalled for is in the
1002         // "not available" set coming into this flat node and
1003         // that every VST identified is in the possible "stall set"
1004         // that represents VST's from children SESE's
1005
1006       }      
1007     } break;
1008       
1009     } // end switch
1010
1011
1012     // identify sese-age pairs that are statically useful
1013     // and should have an associated SESE variable in code
1014     // JUST GET ALL SESE/AGE NAMES FOR NOW, PRUNE LATER,
1015     // AND ALWAYS GIVE NAMES TO PARENTS
1016     Set<VariableSourceToken> staticSet = vstTableIn.get();
1017     Iterator<VariableSourceToken> vstItr = staticSet.iterator();
1018     while( vstItr.hasNext() ) {
1019       VariableSourceToken vst = vstItr.next();
1020
1021       // placeholder source tokens are useful results, but
1022       // the placeholder static name is never needed
1023       if( vst.getSESE().getIsCallerSESEplaceholder() ) {
1024         continue;
1025       }
1026
1027       FlatSESEEnterNode sese = currentSESE;
1028       while( sese != null ) {
1029         sese.addNeededStaticName( 
1030                                  new SESEandAgePair( vst.getSESE(), vst.getAge() ) 
1031                                   );
1032         sese.mustTrackAtLeastAge( vst.getAge() );
1033         
1034         sese = sese.getParent();
1035       }
1036     }
1037
1038
1039     codePlans.put( fn, plan );
1040
1041
1042     // if any variables at this-node-*dot* have a static source (exactly one vst)
1043     // but go to a dynamic source at next-node-*dot*, create a new IR graph
1044     // node on that edge to track the sources dynamically
1045     VarSrcTokTable thisVstTable = variableResults.get( fn );
1046     for( int i = 0; i < fn.numNext(); i++ ) {
1047       FlatNode            nn           = fn.getNext( i );
1048       VarSrcTokTable      nextVstTable = variableResults.get( nn );
1049       Set<TempDescriptor> nextLiveIn   = livenessRootView.get( nn );
1050
1051       // the table can be null if it is one of the few IR nodes
1052       // completely outside of the root SESE scope
1053       if( nextVstTable != null && nextLiveIn != null ) {
1054
1055         Hashtable<TempDescriptor, VariableSourceToken> static2dynamicSet = 
1056           thisVstTable.getStatic2DynamicSet( nextVstTable, 
1057                                              nextLiveIn,
1058                                              currentSESE,
1059                                              currentSESE.getParent() 
1060                                            );
1061         
1062         if( !static2dynamicSet.isEmpty() ) {
1063
1064           // either add these results to partial fixed-point result
1065           // or make a new one if we haven't made any here yet
1066           FlatEdge fe = new FlatEdge( fn, nn );
1067           FlatWriteDynamicVarNode fwdvn = wdvNodesToSpliceIn.get( fe );
1068
1069           if( fwdvn == null ) {
1070             fwdvn = new FlatWriteDynamicVarNode( fn, 
1071                                                  nn,
1072                                                  static2dynamicSet,
1073                                                  currentSESE
1074                                                  );
1075             wdvNodesToSpliceIn.put( fe, fwdvn );
1076           } else {
1077             fwdvn.addMoreVar2Src( static2dynamicSet );
1078           }
1079         }
1080       }
1081     }
1082   }
1083
1084
1085   public void writeReports( String timeReport ) throws java.io.IOException {
1086
1087     BufferedWriter bw = new BufferedWriter( new FileWriter( "mlpReport_summary.txt" ) );
1088     bw.write( "MLP Analysis Results\n\n" );
1089     bw.write( timeReport+"\n\n" );
1090     printSESEHierarchy( bw );
1091     bw.write( "\n" );
1092     printSESEInfo( bw );
1093     bw.close();
1094
1095     Iterator<Descriptor> methItr = ownAnalysis.descriptorsToAnalyze.iterator();
1096     while( methItr.hasNext() ) {
1097       MethodDescriptor md = (MethodDescriptor) methItr.next();      
1098       FlatMethod       fm = state.getMethodFlat( md );
1099       bw = new BufferedWriter( new FileWriter( "mlpReport_"+
1100                                                md.getClassMethodName()+
1101                                                md.getSafeMethodDescriptor()+
1102                                                ".txt" ) );
1103       bw.write( "MLP Results for "+md+"\n-------------------\n");
1104       bw.write( "\n\nLive-In, Root View\n------------------\n"          +fm.printMethod( livenessRootView ) );
1105       bw.write( "\n\nVariable Results-Out\n----------------\n"          +fm.printMethod( variableResults ) );
1106       bw.write( "\n\nNot Available Results-Out\n---------------------\n"+fm.printMethod( notAvailableResults ) );
1107       bw.write( "\n\nCode Plans\n----------\n"                          +fm.printMethod( codePlans ) );
1108       bw.close();
1109     }
1110   }
1111
1112   private void printSESEHierarchy( BufferedWriter bw ) throws java.io.IOException {
1113     bw.write( "SESE Hierarchy\n--------------\n" ); 
1114     Iterator<FlatSESEEnterNode> rootItr = rootSESEs.iterator();
1115     while( rootItr.hasNext() ) {
1116       FlatSESEEnterNode root = rootItr.next();
1117       if( root.getIsCallerSESEplaceholder() ) {
1118         if( !root.getChildren().isEmpty() ) {
1119           printSESEHierarchyTree( bw, root, 0 );
1120         }
1121       } else {
1122         printSESEHierarchyTree( bw, root, 0 );
1123       }
1124     }
1125   }
1126
1127   private void printSESEHierarchyTree( BufferedWriter bw,
1128                                        FlatSESEEnterNode fsen,
1129                                        int depth 
1130                                      ) throws java.io.IOException {
1131     for( int i = 0; i < depth; ++i ) {
1132       bw.write( "  " );
1133     }
1134     bw.write( "- "+fsen.getPrettyIdentifier()+"\n" );
1135
1136     Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
1137     while( childItr.hasNext() ) {
1138       FlatSESEEnterNode fsenChild = childItr.next();
1139       printSESEHierarchyTree( bw, fsenChild, depth + 1 );
1140     }
1141   }
1142
1143   
1144   private void printSESEInfo( BufferedWriter bw ) throws java.io.IOException {
1145     bw.write("\nSESE info\n-------------\n" ); 
1146     Iterator<FlatSESEEnterNode> rootItr = rootSESEs.iterator();
1147     while( rootItr.hasNext() ) {
1148       FlatSESEEnterNode root = rootItr.next();
1149       if( root.getIsCallerSESEplaceholder() ) {
1150         if( !root.getChildren().isEmpty() ) {
1151           printSESEInfoTree( bw, root );
1152         }
1153       } else {
1154         printSESEInfoTree( bw, root );
1155       }
1156     }
1157   }
1158
1159   private void printSESEInfoTree( BufferedWriter bw,
1160                                   FlatSESEEnterNode fsen 
1161                                 ) throws java.io.IOException {
1162
1163     if( !fsen.getIsCallerSESEplaceholder() ) {
1164       bw.write( "SESE "+fsen.getPrettyIdentifier()+" {\n" );
1165
1166       bw.write( "  in-set: "+fsen.getInVarSet()+"\n" );
1167       Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
1168       while( tItr.hasNext() ) {
1169         TempDescriptor inVar = tItr.next();
1170         if( fsen.getReadyInVarSet().contains( inVar ) ) {
1171           bw.write( "    (ready)  "+inVar+"\n" );
1172         }
1173         if( fsen.getStaticInVarSet().contains( inVar ) ) {
1174           bw.write( "    (static) "+inVar+"\n" );
1175         } 
1176         if( fsen.getDynamicInVarSet().contains( inVar ) ) {
1177           bw.write( "    (dynamic)"+inVar+"\n" );
1178         }
1179       }
1180       
1181       bw.write( "  out-set: "+fsen.getOutVarSet()+"\n" );
1182       bw.write( "}\n" );
1183     }
1184
1185     Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
1186     while( childItr.hasNext() ) {
1187       FlatSESEEnterNode fsenChild = childItr.next();
1188       printSESEInfoTree( bw, fsenChild );
1189     }
1190   }
1191 }