compute when to write dynamic address of variables
[IRC.git] / Robust / src / Analysis / MLP / MLPAnalysis.java
index c143c5182ca3b5864a542060ed5cb5834104a867..7dddb90a8df507311e56d4b52270105ad816eb3a 100644 (file)
@@ -22,8 +22,11 @@ public class MLPAnalysis {
   private FlatSESEExitNode  rootExit;
 
   private Hashtable< FlatNode, Stack<FlatSESEEnterNode> > seseStacks;
-  private Hashtable< FlatNode, Set<TempDescriptor>      > livenessResults;
+  private Hashtable< FlatNode, Set<TempDescriptor>      > livenessRootView;
+  private Hashtable< FlatNode, Set<TempDescriptor>      > livenessVirtualReads;
   private Hashtable< FlatNode, VarSrcTokTable           > variableResults;
+  private Hashtable< FlatNode, Set<TempDescriptor>      > isAvailableResults;
+  private Hashtable< FlatNode, CodePlan                 > codePlans;
 
 
   public MLPAnalysis( State             state,
@@ -40,9 +43,13 @@ public class MLPAnalysis {
     this.ownAnalysis = ownAnalysis;
 
     // initialize analysis data structures
-    seseStacks      = new Hashtable< FlatNode, Stack<FlatSESEEnterNode> >();
-    livenessResults = new Hashtable< FlatNode, Set<TempDescriptor>      >();
-    variableResults = new Hashtable< FlatNode, VarSrcTokTable           >();
+    seseStacks           = new Hashtable< FlatNode, Stack<FlatSESEEnterNode> >();
+    livenessVirtualReads = new Hashtable< FlatNode, Set<TempDescriptor>      >();
+    variableResults      = new Hashtable< FlatNode, VarSrcTokTable           >();
+    isAvailableResults   = new Hashtable< FlatNode, Set<TempDescriptor>      >();
+    codePlans            = new Hashtable< FlatNode, CodePlan                 >();
+
+
 
     // build an implicit root SESE to wrap contents of main method
     rootTree = new SESENode( "root" );
@@ -51,48 +58,33 @@ public class MLPAnalysis {
     rootSESE.setFlatExit ( rootExit );
     rootExit.setFlatEnter( rootSESE );
 
+    FlatMethod fmMain = state.getMethodFlat( tu.getMain() );
+
 
     // 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 );
-
-      if( state.MLPDEBUG ) { 
-       printSESEForest();
-      }
     }
 
 
-    // 2nd pass
-    livenessAnalysisBackward( rootSESE );
+    // 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;
-      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 );
 
       // starting from roots do a forward, fixed-point
       // variable analysis for refinement and stalls
@@ -100,12 +92,41 @@ public class MLPAnalysis {
     }
 
 
+    // 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 is available for every live variable at
+      // every program point, in a forward fixed-point pass
+      isAvailableForward( 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 );
+    }
+
+
     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 );
     System.out.println( treport );
   }
 
+
   private void buildForestForward( FlatMethod fm ) {
     
     // start from flat method top, visit every node in
@@ -143,6 +164,10 @@ public class MLPAnalysis {
        }
       }
     }      
+
+    if( state.MLPDEBUG ) { 
+      printSESEForest();
+    }
   }
 
   private void buildForest_nodeActions( FlatNode fn,                                                      
@@ -153,6 +178,7 @@ public class MLPAnalysis {
       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;      
       assert !seseStack.empty();
       seseStack.peek().addChild( fsen );
+      fsen.setParent( seseStack.peek() );
       seseStack.push( fsen );
     } break;
 
@@ -194,23 +220,28 @@ public class MLPAnalysis {
   }
 
 
-  private void livenessAnalysisBackward( FlatSESEEnterNode fsen ) {
-    
-    // post-order traversal, so do children first
-    Iterator<FlatSESEEnterNode> childItr = fsen.getChildren().iterator();
-    while( childItr.hasNext() ) {
-      FlatSESEEnterNode fsenChild = childItr.next();
-      livenessAnalysisBackward( fsenChild );
-    }
+    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>();
-    FlatSESEExitNode fsexn = fsen.getFlatExit();
-    flatNodesToVisit.add( fsexn );
 
+    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 );      
@@ -227,18 +258,17 @@ public class MLPAnalysis {
         }
       }
 
-      Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen );
+      Set<TempDescriptor> curr = liveness_nodeActions( fn, u, fsen, toplevel, liveout);
 
       // if a new result, schedule backward nodes for analysis
-      if( !curr.equals( prev ) ) {
-
+      if(!curr.equals(prev)) {
        livenessResults.put( fn, curr );
 
        // don't flow backwards past current SESE enter
-       if( !fn.equals( fsen ) ) {      
+       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 );
          }
        }
       }
@@ -255,26 +285,76 @@ public class MLPAnalysis {
       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( "" );
     }
+
+    // remember liveness per node from the root view as the
+    // global liveness of variables for later passes to use
+    if( toplevel == true ) {
+      livenessRootView = livenessResults;
+    }
+
+    // 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 ) {
+                                                    FlatSESEEnterNode currentSESE,
+                                                   boolean toplevel,
+                                                   Hashtable< FlatSESEExitNode, Set<TempDescriptor> > liveout ) {
+
     switch( fn.kind() ) {
+
+    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]);
+          }
+       }
       }
 
       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 );
+       }
+      }
     } break;
 
     } // end switch
@@ -300,27 +380,22 @@ public class MLPAnalysis {
       // merge sets from control flow joins
       VarSrcTokTable inUnion = new VarSrcTokTable();
       for( int i = 0; i < fn.numPrev(); i++ ) {
-       FlatNode nn = fn.getPrev( i );
-       inUnion.merge( variableResults.get( nn ) );
+       FlatNode nn = fn.getPrev( i );          
+       VarSrcTokTable incoming = variableResults.get( nn );
+       inUnion.merge( incoming );
       }
 
-      System.out.println( fn+":"+seseStack );
-
-      VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );
+      VarSrcTokTable curr = variable_nodeActions( fn, inUnion, seseStack.peek() );     
 
       // if a new result, schedule forward nodes for analysis
-      if( !curr.equals( prev ) ) {
-       
+      if( !curr.equals( prev ) ) {       
        variableResults.put( fn, curr );
 
-       for( int i = 0; i < fn.numPrev(); i++ ) {
-         FlatNode nn = fn.getPrev( i );         
+       for( int i = 0; i < fn.numNext(); i++ ) {
+         FlatNode nn = fn.getNext( i );         
          flatNodesToVisit.add( nn );    
        }
       }
-    }    
-
-    if( state.MLPDEBUG ) { 
     }
   }
 
@@ -331,22 +406,25 @@ public class MLPAnalysis {
 
     case FKind.FlatSESEEnterNode: {
       FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;
-      /*
-      if( seseStack.empty() ) {
-       seseRoots.add( fsen );
-      } else {
-       seseStack.peek().addChild( fsen );
-      }
-      seseStack.push( fsen );
-      */
+      assert fsen.equals( currentSESE );
+      vstTable.age( currentSESE );
+      vstTable.assertConsistency();
     } break;
 
     case FKind.FlatSESEExitNode: {
-      FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
-      /*
-      assert !seseStack.empty();
-      FlatSESEEnterNode fsen = seseStack.pop();
-      */
+      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.FlatOpNode: {
@@ -358,20 +436,41 @@ public class MLPAnalysis {
 
        vstTable.remove( lhs );
 
+        Set<VariableSourceToken> forAddition = new HashSet<VariableSourceToken>();
+
        Iterator<VariableSourceToken> itr = vstTable.get( rhs ).iterator();
        while( itr.hasNext() ) {
          VariableSourceToken vst = itr.next();
-         
-         vstTable.add( new VariableSourceToken( lhs,
-                                                vst.getSESE(),
-                                                vst.getAge(),
-                                                vst.getVarSrc()
-                                              )
-                       );
+
+          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 );
+
        // only break if this is an ASSIGN op node,
        // otherwise fall through to default case
+       vstTable.assertConsistency();
        break;
       }
     }
@@ -385,17 +484,230 @@ public class MLPAnalysis {
 
        vstTable.remove( writeTemps[0] );
 
-       vstTable.add( new VariableSourceToken( 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
 
     return vstTable;
   }
+
+
+  private void isAvailableForward( 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 = isAvailableResults.get( fn );
+
+      // merge control flow joins where something is available
+      // into this node only if it is available on every incoming
+      // node, so do intersect of all incoming nodes with live in
+      HashSet<TempDescriptor> rootLiveSet = (HashSet<TempDescriptor>) livenessRootView.get( fn );
+      Set<TempDescriptor>     inIntersect = (Set<TempDescriptor>)     rootLiveSet.clone();
+      
+      for( int i = 0; i < fn.numPrev(); i++ ) {
+       FlatNode nn = fn.getPrev( i );       
+       Set<TempDescriptor> availIn = isAvailableResults.get( nn );
+        if( availIn != null ) {
+          inIntersect.retainAll( availIn );
+        }
+      }
+
+      Set<TempDescriptor> curr = isAvailable_nodeActions( fn, inIntersect, seseStack.peek() );     
+
+      // if a new result, schedule forward nodes for analysis
+      if( !curr.equals( prev ) ) {
+       isAvailableResults.put( fn, curr );
+
+       for( int i = 0; i < fn.numNext(); i++ ) {
+         FlatNode nn = fn.getNext( i );         
+         flatNodesToVisit.add( nn );    
+       }
+      }
+    }
+  }
+
+  private Set<TempDescriptor> isAvailable_nodeActions( FlatNode fn, 
+                                                      Set<TempDescriptor> isAvailSet,
+                                                      FlatSESEEnterNode currentSESE ) {
+    // any temps that get added to the 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 );
+    } break;
+
+    case FKind.FlatSESEExitNode: {
+      FlatSESEExitNode  fsexn = (FlatSESEExitNode)  fn;
+      FlatSESEEnterNode fsen  = fsexn.getFlatEnter();
+      assert currentSESE.getChildren().contains( fsen );
+      isAvailSet.addAll( fsen.getOutVarSet() );
+    } break;
+
+    default: {
+      TempDescriptor [] readTemps = fn.readsTemps();
+      for( int i = 0; i < readTemps.length; i++ ) {
+        TempDescriptor rTemp = readTemps[i];
+        isAvailSet.add( rTemp );
+      }
+    } break;
+
+    } // end switch
+
+    return isAvailSet;
+  }
+
+
+  private void computeStallsForward( FlatMethod fm ) {
+    
+    // start from flat method top, visit every node in
+    // method exactly once
+    Set<FlatNode> flatNodesToVisit = new HashSet<FlatNode>();
+    flatNodesToVisit.add( fm );
+
+    Set<FlatNode> visited = new HashSet<FlatNode>();    
+
+    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 dotST = new VarSrcTokTable();
+      for( int i = 0; i < fn.numPrev(); i++ ) {
+       FlatNode nn = fn.getPrev( i );
+       dotST.merge( variableResults.get( nn ) );
+      }
+
+      computeStalls_nodeActions( fn, dotST, seseStack.peek() );
+
+      for( int i = 0; i < fn.numNext(); i++ ) {
+       FlatNode nn = fn.getNext( i );
+
+       if( !visited.contains( nn ) ) {
+         flatNodesToVisit.add( nn );
+       }
+      }
+    }
+
+    if( state.MLPDEBUG ) { 
+      //System.out.println( fm.printMethod( livenessRootView ) );
+      //System.out.println( fm.printMethod( variableResults ) );
+      //System.out.println( fm.printMethod( isAvailableResults ) );
+      System.out.println( fm.printMethod( codePlans ) );
+    }
+  }
+
+  private void computeStalls_nodeActions( FlatNode fn,
+                                          VarSrcTokTable vstTable,
+                                          FlatSESEEnterNode currentSESE ) {
+    String before = null;
+    String after  = null;
+
+    switch( fn.kind() ) {
+
+    case FKind.FlatSESEEnterNode: {
+      FlatSESEEnterNode fsen = (FlatSESEEnterNode) fn;      
+    } break;
+
+    case FKind.FlatSESEExitNode: {
+      FlatSESEExitNode fsexn = (FlatSESEExitNode) fn;
+    } break;
+
+    default: {          
+      // decide if we must stall for variables 
+      // dereferenced at this node
+      Set<VariableSourceToken> stallSet = vstTable.getStallSet( currentSESE );
+      TempDescriptor[] readarray = fn.readsTemps();
+      for( int i = 0; i < readarray.length; i++ ) {
+        Set<VariableSourceToken> forRemoval = new HashSet<VariableSourceToken>();
+        TempDescriptor readtmp = readarray[i];
+        Set<VariableSourceToken> readSet = vstTable.get( readtmp );
+        //containsAny
+        for( Iterator<VariableSourceToken> readit = readSet.iterator(); 
+             readit.hasNext(); ) {
+          VariableSourceToken vst = readit.next();
+          if( stallSet.contains( vst ) ) {
+            if( before == null ) {
+              before = "**STALL for:";
+            }
+            before += "("+vst+" "+readtmp+")";
+
+            // mark any other variables from the static SESE for
+            // removal, because after this stall we'll have them
+            // all for later statements
+            forRemoval.addAll( vstTable.get( vst.getSESE(), 
+                                             vst.getAge() 
+                                           ) 
+                             );
+          }
+        }
+
+        Iterator<VariableSourceToken> vstItr = forRemoval.iterator();
+        while( vstItr.hasNext() ) {
+          VariableSourceToken vst = vstItr.next();
+          vstTable.remove( vst );
+        }
+      }
+
+      // 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 );
+        assert nextVstTable != null;
+        static2dynamicSet.addAll( vstTable.getStatic2DynamicSet( nextVstTable ) );
+      }
+      Iterator<VariableSourceToken> vstItr = static2dynamicSet.iterator();
+      while( vstItr.hasNext() ) {
+        VariableSourceToken vst = vstItr.next();
+        if( after == null ) {
+          after = "** Write dynamic: ";
+        }
+        after += "("+vst+")";
+      }
+      
+    } break;
+
+    } // end switch
+    if( before == null ) {
+      before = "";
+    }
+
+    if( after == null ) {
+      after = "";
+    }
+
+    codePlans.put( fn, new CodePlan( before, after ) );
+  }
 }