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