primitives passed to a child and then all available stuff copied back at one stall...
[IRC.git] / Robust / src / Analysis / MLP / MLPAnalysis.java
index 1f3611ad1ec857b83a6f4e35dcb362adc5271c91..752de79ade0509f330246c71a3634b20e7418279 100644 (file)
@@ -4,6 +4,7 @@ import Analysis.CallGraph.*;
 import Analysis.OwnershipAnalysis.*;
 import IR.*;
 import IR.Flat.*;
+import IR.Tree.*;
 import java.util.*;
 import java.io.*;
 
@@ -11,21 +12,47 @@ import java.io.*;
 public class MLPAnalysis {
 
   // data from the compiler
-  private State state;
-  private TypeUtil typeUtil;
-  private CallGraph callGraph;
+  private State             state;
+  private TypeUtil          typeUtil;
+  private CallGraph         callGraph;
   private OwnershipAnalysis ownAnalysis;
 
+  private FlatSESEEnterNode      rootSESE;  
+  private Set<FlatSESEEnterNode> allSESEs;
 
-  private Stack<FlatSESEEnterNode> seseStack;
-  private Set<FlatSESEEnterNode>   seseRoots;
+  private Hashtable< FlatNode, Stack<FlatSESEEnterNode> > seseStacks;
+  private Hashtable< FlatNode, Set<TempDescriptor>      > livenessRootView;
+  private Hashtable< FlatNode, Set<TempDescriptor>      > livenessVirtualReads;
+  private Hashtable< FlatNode, VarSrcTokTable           > variableResults;
+  private Hashtable< FlatNode, Set<TempDescriptor>      > notAvailableResults;
+  private Hashtable< FlatNode, CodePlan                 > codePlans;
 
-  private Hashtable< FlatNode, Set<VariableSourceToken> > pointResults;
+  private static int maxSESEage = -1;
 
 
-  public MLPAnalysis( State state,
-                     TypeUtil tu,
-                     CallGraph callGraph,
+  // use these methods in BuildCode to have access to analysis results
+  public FlatSESEEnterNode getRootSESE() {
+    return rootSESE;
+  }
+
+  public Set<FlatSESEEnterNode> getAllSESEs() {
+    return allSESEs;
+  }
+
+  public int getMaxSESEage() {
+    return maxSESEage;
+  }
+
+  // may be null
+  public CodePlan getCodePlan( FlatNode fn ) {
+    CodePlan cp = codePlans.get( fn );
+    return cp;
+  }
+
+
+  public MLPAnalysis( State             state,
+                     TypeUtil          tu,
+                     CallGraph         callGraph,
                      OwnershipAnalysis ownAnalysis
                      ) {
 
@@ -35,44 +62,95 @@ public class MLPAnalysis {
     this.typeUtil    = tu;
     this.callGraph   = callGraph;
     this.ownAnalysis = ownAnalysis;
+    this.maxSESEage  = state.MLP_MAXSESEAGE;
 
     // initialize analysis data structures
-    seseStack = new Stack  <FlatSESEEnterNode>();
-    seseRoots = new HashSet<FlatSESEEnterNode>();
+    allSESEs = new HashSet<FlatSESEEnterNode>();
+
+    seseStacks           = new Hashtable< FlatNode, Stack<FlatSESEEnterNode> >();
+    livenessVirtualReads = new Hashtable< FlatNode, Set<TempDescriptor>      >();
+    variableResults      = new Hashtable< FlatNode, VarSrcTokTable           >();
+    notAvailableResults  = new Hashtable< FlatNode, Set<TempDescriptor>      >();
+    codePlans            = new Hashtable< FlatNode, CodePlan                 >();
 
-    pointResults = new Hashtable< FlatNode, Set<VariableSourceToken> >();
+    FlatMethod fmMain = state.getMethodFlat( tu.getMain() );
 
+    rootSESE = (FlatSESEEnterNode) fmMain.getNext(0);    
+    rootSESE.setfmEnclosing( fmMain );
+    rootSESE.setmdEnclosing( fmMain.getMethod() );
+    rootSESE.setcdEnclosing( fmMain.getMethod().getClassDesc() );
 
+
+    // 1st pass
     // run analysis on each method that is actually called
     // reachability analysis already computed this so reuse
     Iterator<Descriptor> methItr = ownAnalysis.descriptorsToAnalyze.iterator();
     while( methItr.hasNext() ) {
-      Descriptor d = methItr.next();
-      
-      FlatMethod fm;
-      if( d instanceof MethodDescriptor ) {
-       fm = state.getMethodFlat( (MethodDescriptor) d);
-      } else {
-       assert d instanceof TaskDescriptor;
-       fm = state.getMethodFlat( (TaskDescriptor) d);
-      }
+      Descriptor d  = methItr.next();      
+      FlatMethod fm = state.getMethodFlat( d );
 
       // find every SESE from methods that may be called
       // and organize them into roots and children
       buildForestForward( fm );
     }
 
-    Iterator<FlatSESEEnterNode> seseItr = seseRoots.iterator();
-    while( seseItr.hasNext() ) {
-      FlatSESEEnterNode fsen = seseItr.next();
 
-      // do a post-order traversal of the forest so that
-      // a child is analyzed before a parent.  Start from
-      // SESE's exit and do a backward data-flow analysis
-      // for the source of variables
-      computeReadAndWriteSetBackward( fsen );
+    // 2nd pass, results are saved in FlatSESEEnterNode, so
+    // intermediate results, for safety, are discarded
+    livenessAnalysisBackward( rootSESE, true, null, fmMain.getFlatExit() );
+
+
+    // 3rd pass
+    methItr = ownAnalysis.descriptorsToAnalyze.iterator();
+    while( methItr.hasNext() ) {
+      Descriptor d  = methItr.next();      
+      FlatMethod fm = state.getMethodFlat( d );
+
+      // starting from roots do a forward, fixed-point
+      // variable analysis for refinement and stalls
+      variableAnalysisForward( fm );
+    }
+
+
+    // 4th pass, compute liveness contribution from
+    // virtual reads discovered in variable pass
+    livenessAnalysisBackward( rootSESE, true, null, fmMain.getFlatExit() );        
+
+
+    // 5th pass
+    methItr = ownAnalysis.descriptorsToAnalyze.iterator();
+    while( methItr.hasNext() ) {
+      Descriptor d  = methItr.next();      
+      FlatMethod fm = state.getMethodFlat( d );
+
+      // compute what is not available at every program
+      // point, in a forward fixed-point pass
+      notAvailableForward( fm );
+    }
+
+
+    // 5th pass
+    methItr = ownAnalysis.descriptorsToAnalyze.iterator();
+    while( methItr.hasNext() ) {
+      Descriptor d  = methItr.next();      
+      FlatMethod fm = state.getMethodFlat( d );
+
+      // compute a plan for code injections
+      computeStallsForward( fm );
+    }
+
+
+    if( state.MLPDEBUG ) {      
+      System.out.println( "" );
+      //System.out.println( "\nSESE Hierarchy\n--------------\n" ); printSESEHierarchy();
+      //System.out.println( "\nSESE Liveness\n-------------\n" ); printSESELiveness();
+      System.out.println( "\nLiveness Root View\n------------------\n"+fmMain.printMethod( livenessRootView ) );
+      System.out.println( "\nVariable Results\n----------------\n"+fmMain.printMethod( variableResults ) );
+      //System.out.println( "\nNot Available Results\n---------------------\n"+fmMain.printMethod( notAvailableResults ) );
+      System.out.println( "\nCode Plans\n----------\n"+fmMain.printMethod( codePlans ) );
     }
 
+
     double timeEndAnalysis = (double) System.nanoTime();
     double dt = (timeEndAnalysis - timeStartAnalysis)/(Math.pow( 10.0, 9.0 ) );
     String treport = String.format( "The mlp analysis took %.3f sec.", dt );
@@ -88,296 +166,741 @@ public class MLPAnalysis {
     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
     flatNodesToVisit.add( fm );
 
-    Set<FlatNode> visited = new HashSet<FlatNode>();
+    Set<FlatNode> visited = new HashSet<FlatNode>();    
+
+    Stack<FlatSESEEnterNode> seseStackFirst = new Stack<FlatSESEEnterNode>();
+    seseStacks.put( fm, seseStackFirst );
 
     while( !flatNodesToVisit.isEmpty() ) {
       Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
       FlatNode fn = fnItr.next();
 
-      System.out.println( "  considering "+fn );
-
-      // only analyze sese exit nodes when all the nodes between
-      // it and its matching enter have been analyzed
-      if( !seseStack.empty() &&
-         fn.equals( seseStack.peek().getFlatExit() ) &&
-         flatNodesToVisit.size() != 1 ) {
-       // not ready for this exit node yet, just grab another
-       fn = fnItr.next();
-      }
+      Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
+      assert seseStack != null;      
 
       flatNodesToVisit.remove( fn );
       visited.add( fn );      
 
-      System.out.println( "    visiting "+fn );
-
-      analyzeFlatNode( fn, true, null, null );
-
-      // initialize for backward computation in next step
-      pointResults.put( fn, new HashSet<VariableSourceToken>() );
+      buildForest_nodeActions( fn, seseStack, fm );
 
       for( int i = 0; i < fn.numNext(); i++ ) {
        FlatNode nn = fn.getNext( i );
 
        if( !visited.contains( nn ) ) {
          flatNodesToVisit.add( nn );
+
+         // clone stack and send along each analysis path
+         seseStacks.put( nn, (Stack<FlatSESEEnterNode>)seseStack.clone() );
        }
       }
     }      
   }
 
+  private void buildForest_nodeActions( FlatNode fn,                                                      
+                                       Stack<FlatSESEEnterNode> seseStack,
+                                       FlatMethod fm ) {
+    switch( fn.kind() ) {
+
+    case FKind.FlatSESEEnterNode: {
+      FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
+
+      allSESEs.add( fsen );
+      fsen.setfmEnclosing( fm );
+      fsen.setmdEnclosing( fm.getMethod() );
+      fsen.setcdEnclosing( fm.getMethod().getClassDesc() );
+
+      if( !seseStack.empty() ) {
+       seseStack.peek().addChild( fsen );
+       fsen.setParent( seseStack.peek() );
+      }
+
+      seseStack.push( fsen );
+    } break;
+
+    case FKind.FlatSESEExitNode: {
+      FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
+      assert !seseStack.empty();
+      FlatSESEEnterNode fsen = seseStack.pop();
+    } break;
+
+    case FKind.FlatReturnNode: {
+      FlatReturnNode frn = (FlatReturnNode) fn;
+      if( !seseStack.empty() ) {
+       throw new Error( "Error: return statement enclosed within SESE "+
+                        seseStack.peek().getPrettyIdentifier() );
+      }
+    } break;
+      
+    }
+  }
+
+  private void printSESEHierarchy() {
+    // our forest is actually a tree now that
+    // there is an implicit root SESE
+    printSESEHierarchyTree( rootSESE, 0 );
+    System.out.println( "" );
+  }
+
+  private void printSESEHierarchyTree( FlatSESEEnterNode fsen, int depth ) {
+    for( int i = 0; i < depth; ++i ) {
+      System.out.print( "  " );
+    }
+    System.out.println( "- "+fsen.getPrettyIdentifier() );
+
+    Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
+    while( childItr.hasNext() ) {
+      FlatSESEEnterNode fsenChild = childItr.next();
+      printSESEHierarchyTree( fsenChild, depth + 1 );
+    }
+  }
+
 
-  private void computeReadAndWriteSetBackward( FlatSESEEnterNode fsen ) {
+  private void livenessAnalysisBackward( FlatSESEEnterNode fsen, 
+                                         boolean toplevel, 
+                                         Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout, 
+                                         FlatExit fexit ) {
 
     // start from an SESE exit, visit nodes in reverse up to
     // SESE enter in a fixed-point scheme, where children SESEs
     // should already be analyzed and therefore can be skipped 
     // because child SESE enter node has all necessary info
     Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
-    flatNodesToVisit.add( fsen.getFlatExit() );
 
+    FlatSESEExitNode fsexn = fsen.getFlatExit();
+    if (toplevel) {
+       //handle root SESE
+       flatNodesToVisit.add( fexit );
+    } else
+       flatNodesToVisit.add( fsexn );
+    Hashtable<FlatNode, Set<TempDescriptor>> livenessResults=new Hashtable<FlatNode, Set<TempDescriptor>>();
+
+    if (toplevel==true)
+       liveout=new Hashtable<FlatSESEExitNode, Set<TempDescriptor>>();
+    
     while( !flatNodesToVisit.isEmpty() ) {
       FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
       flatNodesToVisit.remove( fn );      
-
-      Set<VariableSourceToken> prev = pointResults.get( fn );
+      
+      Set<TempDescriptor> prev = livenessResults.get( fn );
 
       // merge sets from control flow joins
-      Set<VariableSourceToken> merge = new HashSet<VariableSourceToken>();
+      Set<TempDescriptor> u = new HashSet<TempDescriptor>();
       for( int i = 0; i < fn.numNext(); i++ ) {
-       FlatNode nn = fn.getNext( i );   
-       merge = mergeVSTsets( merge, pointResults.get( nn ) );
+       FlatNode nn = fn.getNext( i );
+        Set<TempDescriptor> s = livenessResults.get( nn );
+        if( s != null ) {
+          u.addAll( s );
+        }
       }
-
-      Set<VariableSourceToken> curr = analyzeFlatNode( fn, false, merge, fsen );
+      
+      Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen, toplevel, liveout);
 
       // if a new result, schedule backward nodes for analysis
-      if( !prev.equals( curr ) ) {
-
-       System.out.println( "  "+fn+":" );
-       System.out.println( "    prev ="+prev  );
-       System.out.println( "    merge="+merge );
-       System.out.println( "    curr ="+curr  );
-       System.out.println( "" );
+      if( !curr.equals( prev ) ) {
+       livenessResults.put( fn, curr );
 
-       pointResults.put( fn, curr );
-
-       // don't flow backwards past SESE enter
-       if( !fn.equals( fsen ) ) {      
+       // don't flow backwards past current SESE enter
+       if( !fn.equals( fsen ) ) {
          for( int i = 0; i < fn.numPrev(); i++ ) {
-           FlatNode nn = fn.getPrev( i );       
-           flatNodesToVisit.add( nn );  
+           FlatNode nn = fn.getPrev( i );
+           flatNodesToVisit.add( nn );
          }
        }
       }
     }
+    
+    Set<TempDescriptor> s = livenessResults.get( fsen );
+    if( s != null ) {
+      fsen.addInVarSet( s );
+    }
+    
+    // remember liveness per node from the root view as the
+    // global liveness of variables for later passes to use
+    if( toplevel == true ) {
+      livenessRootView = livenessResults;
+    }
 
-    if( state.MLPDEBUG ) {
-      System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
-      Iterator<VariableSourceToken> tItr = pointResults.get( fsen ).iterator();
-      while( tItr.hasNext() ) {
-       System.out.println( "  "+tItr.next() );
-      }
+    // post-order traversal, so do children first
+    Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
+    while( childItr.hasNext() ) {
+      FlatSESEEnterNode fsenChild = childItr.next();
+      livenessAnalysisBackward( fsenChild, false, liveout, null );
     }
   }
 
+  private Set<TempDescriptor> liveness_nodeActions( FlatNode fn, 
+                                                    Set<TempDescriptor> liveIn,
+                                                    FlatSESEEnterNode currentSESE,
+                                                   boolean toplevel,
+                                                   Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout ) {
 
-  private Set<VariableSourceToken> analyzeFlatNode( FlatNode fn, 
-                                                   boolean buildForest,
-                                                   Set<VariableSourceToken> vstSet,
-                                                   FlatSESEEnterNode currentSESE ) {
-
-    // use node type to decide what alterations to make
-    // to the ownership graph
     switch( fn.kind() ) {
 
-    case FKind.FlatSESEEnterNode: {
-      FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
+    case FKind.FlatSESEExitNode:
+      if (toplevel==true) {
+         FlatSESEExitNode exitn=(FlatSESEExitNode) fn;
+       //update liveout set for FlatSESEExitNode
+         if (!liveout.containsKey(exitn))
+           liveout.put(exitn, new HashSet<TempDescriptor>());
+         liveout.get(exitn).addAll(liveIn);
+      }
+      // no break, sese exits should also execute default actions
+      
+    default: {
+      // handle effects of statement in reverse, writes then reads
+      TempDescriptor [] writeTemps = fn.writesTemps();
+      for( int i = 0; i < writeTemps.length; ++i ) {
+       liveIn.remove( writeTemps[i] );
+
+       if (!toplevel) {
+          FlatSESEExitNode exitnode=currentSESE.getFlatExit();
+          Set<TempDescriptor> livetemps=liveout.get(exitnode);
+          if (livetemps.contains(writeTemps[i])) {
+            //write to a live out temp...
+            //need to put in SESE liveout set
+            currentSESE.addOutVar(writeTemps[i]);
+          }
+       }
+      }
 
-      if( buildForest ) {
-       if( seseStack.empty() ) {
-         seseRoots.add( fsen );
-       } else {
-         seseStack.peek().addChild( fsen );
+      TempDescriptor [] readTemps = fn.readsTemps();
+      for( int i = 0; i < readTemps.length; ++i ) {
+       liveIn.add( readTemps[i] );
+      }
+
+      Set<TempDescriptor> virtualReadTemps = livenessVirtualReads.get( fn );
+      if( virtualReadTemps != null ) {
+       Iterator<TempDescriptor> vrItr = virtualReadTemps.iterator();
+       while( vrItr.hasNext() ) {
+          TempDescriptor vrt = vrItr.next();
+         liveIn.add( vrt );
        }
-       seseStack.push( fsen );
-       System.out.println( "  pushed "+fsen );
       }
     } break;
 
-    case FKind.FlatSESEExitNode: {
-      FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
+    } // end switch
+
+    return liveIn;
+  }
+
+  private void printSESELiveness() {
+    // our forest is actually a tree now that
+    // there is an implicit root SESE
+    printSESELivenessTree( rootSESE );
+    System.out.println( "" );
+  }
+
+  private void printSESELivenessTree( FlatSESEEnterNode fsen ) {
+
+    System.out.println( "SESE "+fsen.getPrettyIdentifier()+" has in-set:" );
+    Iterator<TempDescriptor> tItr = fsen.getInVarSet().iterator();
+    while( tItr.hasNext() ) {
+      System.out.println( "  "+tItr.next() );
+    }
+    System.out.println( "and out-set:" );
+    tItr = fsen.getOutVarSet().iterator();
+    while( tItr.hasNext() ) {
+      System.out.println( "  "+tItr.next() );
+    }
+    System.out.println( "" );
+
+
+    Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
+    while( childItr.hasNext() ) {
+      FlatSESEEnterNode fsenChild = childItr.next();
+      printSESELivenessTree( fsenChild );
+    }
+  }
+
+
+  private void variableAnalysisForward( FlatMethod fm ) {
 
-      if( buildForest ) {
-       assert !seseStack.empty();
-       FlatSESEEnterNode fsen = seseStack.pop();
-       System.out.println( "  popped "+fsen );
+    Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
+    flatNodesToVisit.add( fm );         
+
+    while( !flatNodesToVisit.isEmpty() ) {
+      FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
+      flatNodesToVisit.remove( fn );      
+
+      Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
+      assert seseStack != null;      
+
+      VarSrcTokTable prev = variableResults.get( fn );
+
+      // merge sets from control flow joins
+      VarSrcTokTable curr = new VarSrcTokTable();
+      for( int i = 0; i < fn.numPrev(); i++ ) {
+       FlatNode nn = fn.getPrev( i );          
+       VarSrcTokTable incoming = variableResults.get( nn );
+       curr.merge( incoming );
       }
-       
-      //FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
-      //assert fsen == seseStack.pop();
-      //seseStack.peek().addInVarSet ( fsen.getInVarSet()  );
-      //seseStack.peek().addOutVarSet( fsen.getOutVarSet() );
-    } break;
 
-    /*  
-    case FKind.FlatMethod: {
-      FlatMethod fm = (FlatMethod) fn;
-    } break;
-    */
-
-    case FKind.FlatOpNode: 
-    case FKind.FlatCastNode:
-    case FKind.FlatFieldNode:
-    case FKind.FlatSetFieldNode: 
-    case FKind.FlatElementNode:
-    case FKind.FlatSetElementNode: {
-      if( !buildForest ) {
-       // handle effects of statement in reverse, writes then reads
-       TempDescriptor [] writeTemps = fn.writesTemps();
-       for( int i = 0; i < writeTemps.length; ++i ) {
-         vstSet = killTemp( vstSet, writeTemps[i] );
-       }
+      if( !seseStack.empty() ) {
+       variable_nodeActions( fn, curr, seseStack.peek() );
+      }
+
+      // if a new result, schedule forward nodes for analysis
+      if( !curr.equals( prev ) ) {       
+       variableResults.put( fn, curr );
 
-       TempDescriptor [] readTemps = fn.readsTemps();
-       for( int i = 0; i < readTemps.length; ++i ) {
-         Set<VariableSourceToken> vstNew = new HashSet<VariableSourceToken>();
-         vstNew.add( new VariableSourceToken( currentSESE, 
-                                              readTemps[i],
-                                              new Integer( 0 ) ) );
-         vstSet = mergeVSTsets( vstSet, vstNew );
+       for( int i = 0; i < fn.numNext(); i++ ) {
+         FlatNode nn = fn.getNext( i );         
+         flatNodesToVisit.add( nn );    
        }
       }
+    }
+  }
+
+  private void variable_nodeActions( FlatNode fn, 
+                                    VarSrcTokTable vstTable,
+                                    FlatSESEEnterNode currentSESE ) {
+    switch( fn.kind() ) {
+
+    case FKind.FlatSESEEnterNode: {
+      FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
+      assert fsen.equals( currentSESE );
+      vstTable.age( currentSESE );
+      vstTable.assertConsistency();
     } break;
 
-    /*
-    case FKind.FlatNew: {
-      FlatNew fnn = (FlatNew) fn;
-      lhs = fnn.getDst();
-      if( !lhs.getType().isImmutable() || lhs.getType().isArray() ) {
-       //AllocationSite as = getAllocationSiteFromFlatNewPRIVATE( fnn );
+    case FKind.FlatSESEExitNode: {
+      FlatSESEExitNode  fsexn = (FlatSESEExitNode)  fn;
+      FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
+      assert currentSESE.getChildren().contains( fsen );
+      vstTable.remapChildTokens( fsen );
+
+      Set<TempDescriptor> liveIn       = currentSESE.getInVarSet();
+      Set<TempDescriptor> virLiveIn    = vstTable.removeParentAndSiblingTokens( fsen, liveIn );
+      Set<TempDescriptor> virLiveInOld = livenessVirtualReads.get( fn );
+      if( virLiveInOld != null ) {
+        virLiveIn.addAll( virLiveInOld );
       }
+      livenessVirtualReads.put( fn, virLiveIn );
+      vstTable.assertConsistency();
     } break;
-    */
 
-    /*
-    case FKind.FlatCall: {
-      FlatCall fc = (FlatCall) fn;
-      MethodDescriptor md = fc.getMethod();
-      FlatMethod flatm = state.getMethodFlat( md );
+    case FKind.FlatOpNode: {
+      FlatOpNode fon = (FlatOpNode) fn;
+
+      if( fon.getOp().getOp() == Operation.ASSIGN ) {
+       TempDescriptor lhs = fon.getDest();
+       TempDescriptor rhs = fon.getLeft();
+
+       vstTable.remove( lhs );
+
+        Set<VariableSourceToken> forAddition = new HashSet<VariableSourceToken>();
+
+       Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
+       while( itr.hasNext() ) {
+         VariableSourceToken vst = itr.next();
+
+          HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
+          ts.add( lhs );
+
+          // if this is from a child, keep the source information
+          if( currentSESE.getChildren().contains( vst.getSESE() ) ) {    
+            forAddition.add( new VariableSourceToken( ts,
+                                                      vst.getSESE(),
+                                                      vst.getAge(),
+                                                      vst.getAddrVar()
+                                                      )
+                             );
+
+          // otherwise, it's our or an ancestor's token so we
+          // can assume we have everything we need
+          } else {
+            forAddition.add( new VariableSourceToken( ts,
+                                                      currentSESE,
+                                                      new Integer( 0 ),
+                                                      lhs
+                                                      )
+                             );
+          }
+       }
 
+        vstTable.addAll( forAddition );
 
-      if( md.isStatic() ) {
+       // only break if this is an ASSIGN op node,
+       // otherwise fall through to default case
+       vstTable.assertConsistency();
+       break;
+      }
+    }
 
-      } else {
-       // if the method descriptor is virtual, then there could be a
-       // set of possible methods that will actually be invoked, so
-       // find all of them and merge all of their results together
-       TypeDescriptor typeDesc = fc.getThis().getType();
-       Set possibleCallees = callGraph.getMethods( md, typeDesc );
+    // note that FlatOpNode's that aren't ASSIGN
+    // fall through to this default case
+    default: {
+      TempDescriptor [] writeTemps = fn.writesTemps();
+      if( writeTemps.length > 0 ) {
 
-       Iterator i = possibleCallees.iterator();
-       while( i.hasNext() ) {
-         MethodDescriptor possibleMd = (MethodDescriptor) i.next();
-         FlatMethod pflatm = state.getMethodFlat( possibleMd );
 
-       }
-      }
+        // for now, when writeTemps > 1, make sure
+        // its a call node, programmer enforce only
+        // doing stuff like calling a print routine
+       //assert writeTemps.length == 1;
+        if( writeTemps.length > 1 ) {
+          assert fn.kind() == FKind.FlatCall ||
+                 fn.kind() == FKind.FlatMethod;
+          break;
+        }
 
-    } break;
-    */
 
-    case FKind.FlatReturnNode: {
-      FlatReturnNode frn = (FlatReturnNode) fn;
-      if( buildForest && !seseStack.empty() ) {
-       throw new Error( "Error: return statement enclosed within "+seseStack.peek() );
-      }
+       vstTable.remove( writeTemps[0] );
+
+        HashSet<TempDescriptor> ts = new HashSet<TempDescriptor>();
+        ts.add( writeTemps[0] );
+
+       vstTable.add( new VariableSourceToken( ts,
+                                              currentSESE,
+                                              new Integer( 0 ),
+                                              writeTemps[0]
+                                            )
+                     );
+      }      
+
+      vstTable.assertConsistency();
     } break;
 
     } // end switch
+  }
+
+
+  private void notAvailableForward( FlatMethod fm ) {
+
+    Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
+    flatNodesToVisit.add( fm );         
+
+    while( !flatNodesToVisit.isEmpty() ) {
+      FlatNode fn = (FlatNode) flatNodesToVisit.iterator().next();
+      flatNodesToVisit.remove( fn );      
+
+      Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
+      assert seseStack != null;      
+
+      Set<TempDescriptor> prev = notAvailableResults.get( fn );
+
+      Set<TempDescriptor> curr = new HashSet<TempDescriptor>();      
+      for( int i = 0; i < fn.numPrev(); i++ ) {
+       FlatNode nn = fn.getPrev( i );       
+       Set<TempDescriptor> notAvailIn = notAvailableResults.get( nn );
+        if( notAvailIn != null ) {
+          curr.addAll( notAvailIn );
+        }
+      }
+
+      if( !seseStack.empty() ) {
+       notAvailable_nodeActions( fn, curr, seseStack.peek() );     
+      }
 
+      // if a new result, schedule forward nodes for analysis
+      if( !curr.equals( prev ) ) {
+       notAvailableResults.put( fn, curr );
 
-    return vstSet;
+       for( int i = 0; i < fn.numNext(); i++ ) {
+         FlatNode nn = fn.getNext( i );         
+         flatNodesToVisit.add( nn );    
+       }
+      }
+    }
   }
 
+  private void notAvailable_nodeActions( FlatNode fn, 
+                                        Set<TempDescriptor> notAvailSet,
+                                        FlatSESEEnterNode currentSESE ) {
+
+    // any temps that are removed from the not available set
+    // at this node should be marked in this node's code plan
+    // as temps to be grabbed at runtime!
+
+    switch( fn.kind() ) {
+
+    case FKind.FlatSESEEnterNode: {
+      FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
+      assert fsen.equals( currentSESE );
+      notAvailSet.clear();
+    } break;
+
+    case FKind.FlatSESEExitNode: {
+      FlatSESEExitNode  fsexn = (FlatSESEExitNode)  fn;
+      FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
+      assert currentSESE.getChildren().contains( fsen );
+
+      Set<TempDescriptor> liveTemps = livenessRootView.get( fn );
+      assert liveTemps != null;
 
-  private Set<VariableSourceToken> killTemp( Set<VariableSourceToken> s,
-                                            TempDescriptor t ) {
-    Set<VariableSourceToken> out = new HashSet<VariableSourceToken>();
+      VarSrcTokTable vstTable = variableResults.get( fn );
+      assert vstTable != null;
 
-    Iterator<VariableSourceToken> vstitr = s.iterator();
-    while( vstitr.hasNext() ) {
-      VariableSourceToken vst = vstitr.next();    
+      Set<TempDescriptor> notAvailAtEnter = notAvailableResults.get( fsen );
+      assert notAvailAtEnter != null;
 
-      if( !vst.getVar().equals( t ) ) {
-       out.add( vst );
+      Iterator<TempDescriptor> tdItr = liveTemps.iterator();
+      while( tdItr.hasNext() ) {
+       TempDescriptor td = tdItr.next();
+
+       if( vstTable.get( fsen, td ).size() > 0 ) {
+         // there is at least one child token for this variable
+         notAvailSet.add( td );
+         continue;
+       }
+
+       if( notAvailAtEnter.contains( td ) ) {
+         // wasn't available at enter, not available now
+         notAvailSet.add( td );
+         continue;
+       }
+      }
+    } break;
+
+    case FKind.FlatOpNode: {
+      FlatOpNode fon = (FlatOpNode) fn;
+
+      if( fon.getOp().getOp() == Operation.ASSIGN ) {
+       TempDescriptor lhs = fon.getDest();
+       TempDescriptor rhs = fon.getLeft();
+
+       // copy makes lhs same availability as rhs
+       if( notAvailSet.contains( rhs ) ) {
+         notAvailSet.add( lhs );
+       } else {
+         notAvailSet.remove( lhs );
+       }
+
+       // only break if this is an ASSIGN op node,
+       // otherwise fall through to default case
+       break;
       }
     }
 
-    return out;
+    // note that FlatOpNode's that aren't ASSIGN
+    // fall through to this default case
+    default: {
+      TempDescriptor [] writeTemps = fn.writesTemps();
+      for( int i = 0; i < writeTemps.length; i++ ) {
+        TempDescriptor wTemp = writeTemps[i];
+        notAvailSet.remove( wTemp );
+      }
+      TempDescriptor [] readTemps = fn.readsTemps();
+      for( int i = 0; i < readTemps.length; i++ ) {
+        TempDescriptor rTemp = readTemps[i];
+        notAvailSet.remove( rTemp );
+
+       // if this variable has exactly one source, mark everything
+       // else from that source as available as well
+       VarSrcTokTable table = variableResults.get( fn );
+       Set<VariableSourceToken> srcs = table.get( rTemp );
+
+       if( srcs.size() == 1 ) {
+         VariableSourceToken vst = srcs.iterator().next();
+         
+         Iterator<VariableSourceToken> availItr = table.get( vst.getSESE(), 
+                                                             vst.getAge()
+                                                           ).iterator();
+         while( availItr.hasNext() ) {
+           VariableSourceToken vstAlsoAvail = availItr.next();
+           notAvailSet.removeAll( vstAlsoAvail.getRefVars() );
+         }
+       }
+      }
+    } break;
+
+    } // end switch
   }
 
 
-  private Set<VariableSourceToken> mergeVSTsets( Set<VariableSourceToken> s1,
-                                                Set<VariableSourceToken> s2 ) {
+  private void computeStallsForward( FlatMethod fm ) {
     
-    Set<VariableSourceToken> out = new HashSet<VariableSourceToken>();
+    // start from flat method top, visit every node in
+    // method exactly once
+    Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
+    flatNodesToVisit.add( fm );
 
-    Iterator<VariableSourceToken> vst1itr = s1.iterator();
-    while( vst1itr.hasNext() ) {
-      VariableSourceToken vst1 = vst1itr.next();
+    Set<FlatNode> visited = new HashSet<FlatNode>();    
 
-      int changeAge = -1;
-      
-      Iterator<VariableSourceToken> vst2itr = s2.iterator();
-      while( vst2itr.hasNext() ) {
-       VariableSourceToken vst2 = vst2itr.next();
-
-       if( vst1.getSESE().equals( vst2.getSESE() ) &&
-           vst1.getVar() .equals( vst2.getVar()  )    ) {
-         changeAge = vst1.getAge();
-         int a = vst2.getAge();
-         if( a < changeAge ) {
-           changeAge = a;
-         }
-         break;
+    while( !flatNodesToVisit.isEmpty() ) {
+      Iterator<FlatNode> fnItr = flatNodesToVisit.iterator();
+      FlatNode fn = fnItr.next();
+
+      flatNodesToVisit.remove( fn );
+      visited.add( fn );      
+
+      Stack<FlatSESEEnterNode> seseStack = seseStacks.get( fn );
+      assert seseStack != null;      
+
+      // use incoming results as "dot statement" or just
+      // before the current statement
+      VarSrcTokTable dotSTtable = new VarSrcTokTable();
+      for( int i = 0; i < fn.numPrev(); i++ ) {
+       FlatNode nn = fn.getPrev( i );
+       dotSTtable.merge( variableResults.get( nn ) );
+      }
+
+      // find dt-st notAvailableSet also
+      Set<TempDescriptor> dotSTnotAvailSet = new HashSet<TempDescriptor>();      
+      for( int i = 0; i < fn.numPrev(); i++ ) {
+       FlatNode nn = fn.getPrev( i );       
+       Set<TempDescriptor> notAvailIn = notAvailableResults.get( nn );
+        if( notAvailIn != null ) {
+         dotSTnotAvailSet.addAll( notAvailIn );
+        }
+      }
+
+      if( !seseStack.empty() ) {
+       computeStalls_nodeActions( fn, dotSTtable, dotSTnotAvailSet, seseStack.peek() );
+      }
+
+      for( int i = 0; i < fn.numNext(); i++ ) {
+       FlatNode nn = fn.getNext( i );
+
+       if( !visited.contains( nn ) ) {
+         flatNodesToVisit.add( nn );
        }
       }
+    }
+  }
+
+  private void computeStalls_nodeActions( FlatNode fn,
+                                          VarSrcTokTable vstTable,
+                                         Set<TempDescriptor> notAvailSet,
+                                          FlatSESEEnterNode currentSESE ) {
+    CodePlan plan = new CodePlan();
 
-      if( changeAge < 0 ) {
-       out.add( vst1 );
-      } else {
-       out.add( new VariableSourceToken( vst1.getSESE(),
-                                         vst1.getVar(),
-                                         new Integer( changeAge ) ) );
+
+    switch( fn.kind() ) {
+
+    case FKind.FlatSESEEnterNode: {
+      FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
+    } break;
+
+    case FKind.FlatSESEExitNode: {
+      FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
+    } break;
+
+    case FKind.FlatOpNode: {
+      FlatOpNode fon = (FlatOpNode) fn;
+
+      if( fon.getOp().getOp() == Operation.ASSIGN ) {
+       // if this is an op node, don't stall, copy
+       // source and delay until we need to use value
+
+       // only break if this is an ASSIGN op node,
+       // otherwise fall through to default case
+       break;
       }
     }
 
+    // note that FlatOpNode's that aren't ASSIGN
+    // fall through to this default case
+    default: {          
 
-    Iterator<VariableSourceToken> vst2itr = s2.iterator();
-    while( vst2itr.hasNext() ) {
-      VariableSourceToken vst2 = vst2itr.next();           
+      // decide if we must stall for variables dereferenced at this node
+      Set<VariableSourceToken> potentialStallSet = 
+       vstTable.getChildrenVSTs( currentSESE );
 
-      boolean matchSESEandVar = false;
+      // a node with no live set has nothing to stall for
+      Set<TempDescriptor> liveSet = livenessRootView.get( fn );
+      if( liveSet == null ) {
+       break;
+      }
 
-      vst1itr = s1.iterator();
-      while( vst1itr.hasNext() ) {
-       VariableSourceToken vst1 = vst1itr.next();
+      TempDescriptor[] readarray = fn.readsTemps();
+      for( int i = 0; i < readarray.length; i++ ) {
+        TempDescriptor readtmp = readarray[i];
 
-       if( vst1.getSESE().equals( vst2.getSESE() ) &&
-           vst1.getVar() .equals( vst2.getVar()  )    ) {
-         matchSESEandVar = true;
-         break;
+       // ignore temps that are definitely available 
+       // when considering to stall on it
+       if( !notAvailSet.contains( readtmp ) ) {
+         continue;
        }
-      }
 
-      if( !matchSESEandVar ) {
-       out.add( vst2 );
+       // Two cases:
+        Set<VariableSourceToken> srcs = vstTable.get( readtmp );
+       assert !srcs.isEmpty();
+
+       // 1) Multiple token/age pairs or unknown age: Stall for
+       // dynamic name only.
+       if( srcs.size() > 1 || 
+           srcs.iterator().next().getAge() == maxSESEage ) {
+
+         // identify that this is a stall, and allocate an integer
+         // pointer in the generated code that keeps a pointer to
+         // the source SESE and the address of where to get this thing
+         // --then the stall is just wait for that, and copy the
+         // one thing because we're not sure if we can copy other stuff
+
+         // NEEDS WORK!
+         
+         
+
+       // 2) Single token/age pair: Stall for token/age pair, and copy
+       // all live variables with same token/age pair at the same
+       // time.  This is the same stuff that the notavaialable analysis 
+       // marks as now available.        
+       } else {          
+         VariableSourceToken vst = srcs.iterator().next();                       
+
+         Iterator<VariableSourceToken> availItr = 
+           vstTable.get( vst.getSESE(), vst.getAge() ).iterator();
+
+         while( availItr.hasNext() ) {
+           VariableSourceToken vstAlsoAvail = availItr.next();
+
+           // only grab additional stuff that is live
+           Set<TempDescriptor> copySet = new HashSet<TempDescriptor>();
+
+           Iterator<TempDescriptor> refVarItr = vstAlsoAvail.getRefVars().iterator();
+           while( refVarItr.hasNext() ) {
+             TempDescriptor refVar = refVarItr.next();
+             if( liveSet.contains( refVar ) ) {
+               copySet.add( refVar );
+             }
+           }
+
+           if( !copySet.isEmpty() ) {
+             plan.addStall2CopySet( vstAlsoAvail, copySet );
+           }
+         }                      
+       }
+
+       // assert that everything being stalled for is in the
+       // "not available" set coming into this flat node and
+       // that every VST identified is in the possible "stall set"
+       // that represents VST's from children SESE's
+
+      }      
+    } break;
+
+    } // end switch
+
+
+    // identify sese-age pairs that are statically useful
+    // and should have an associated SESE variable in code
+    Set<VariableSourceToken> staticSet = vstTable.getStaticSet();
+    Iterator<VariableSourceToken> vstItr = staticSet.iterator();
+    while( vstItr.hasNext() ) {
+      VariableSourceToken vst = vstItr.next();
+      currentSESE.addNeededStaticName( 
+        new SESEandAgePair( vst.getSESE(), vst.getAge() ) 
+                                    );
+    }
+
+    // if any variable at this node has a static source (exactly one sese)
+    // but goes to a dynamic source at a next node, write its dynamic addr      
+    Set<VariableSourceToken> static2dynamicSet = new HashSet<VariableSourceToken>();
+    for( int i = 0; i < fn.numNext(); i++ ) {
+      FlatNode nn = fn.getNext( i );
+      VarSrcTokTable nextVstTable = variableResults.get( nn );
+      // the table can be null if it is one of the few IR nodes
+      // completely outside of the root SESE scope
+      if( nextVstTable != null ) {
+       static2dynamicSet.addAll( vstTable.getStatic2DynamicSet( nextVstTable ) );
       }
     }
-    
 
-    return out;
+    if( !static2dynamicSet.isEmpty() ) {
+      plan.setWriteToDynamicSrc( static2dynamicSet );
+    }
+
+    codePlans.put( fn, plan );
   }
 }
-
-