/// <summary> /// Replace a copy along a chain of variables (e.g. `b = a; c = b`) with a direct copy (e.g. `b = a; c = a`) /// </summary> /// <param name="cfg"></param> /// <param name="ssa"></param> /// <returns></returns> public static IControlFlowGraph FoldUnnecessaryCopies(this IControlFlowGraph cfg, ISingleStaticAssignmentTable ssa) { IControlFlowGraph InnerFold(IControlFlowGraph cfgi) { // Copy across vertices, modifying them in the process return(cfgi.Modify((a, b) => { // generate data flow graph for this block var dfg = (IDataFlowGraph) new DataFlowGraph.DataFlowGraph(a, ssa); // Count how many times each variable in the whole program is read var readsInProgram = cfgi.FindReadCounts().ToDictionary(x => x.Item1, x => x.Item2); // Find variables which are written in this block (we're in SSA, so everything is written exactly once) var writesInBlock = a.FindWrites(ssa).ToHashSet(); // Find variables which are written in this block and read (just once) in this block var copiesInBlock = ( from x in a.FindReadCounts() where writesInBlock.Contains(x.Item1) where x.Item2 == readsInProgram[x.Item1] where x.Item2 == 1 where !x.Item1.IsExternal select x.Item1 ).ToArray(); // Select a single var to optimise var work = ( from op in dfg.Outputs let ass = op.ToStatement() as Assignment where ass != null where copiesInBlock.Contains(ass.Left) where ass.Right is Variable select(ass, op) ).FirstOrDefault(); // Early out if there is nothing to optimise if (work == default) { a.CopyTo(b); return; } // Select the variable to replace and the expression to replace it with var varToReplace = work.ass.Left; var expToSubstitute = work.ass.Right; var modified = new SubstituteVariable(varToReplace, expToSubstitute).Visit(a); foreach (var item in modified.Statements) { b.Add(item); } })); } // Keep applying folding until no more folds are done return(cfg.Fixpoint(InnerFold)); }
public static Program FoldSingleUseVariables(this Program prog) { // Find all variables associated with a count of how many times they are read var readsInProgram = new FindReadVariables(); readsInProgram.Visit(prog); // Find all variables associated with a count of how many times they are assigned var writesInProgram = new FindAssignedVariables(); writesInProgram.Visit(prog); var lines = new List <Line>(); foreach (var item in prog.Lines) { lines.Add(item.Fixpoint(20, line => { // Find all reads in this line var readsInLine = new FindReadVariables(); readsInLine.Visit(line); // Find all writes in this line var writesInLine = new FindAssignedVariables(); writesInLine.Visit(line); // Find variables that can be folded away var toReplace = (from v in readsInLine.Counts where !v.Key.IsExternal where v.Value == 1 // Filter to things only read once in this line where readsInProgram.Counts[v.Key] == 1 // Filter to things only read once in the entire program where writesInProgram.Counts[v.Key] == 1 // Filter to things on written once in the entire program where writesInLine.Counts[v.Key] == 1 // Filter to things written once in this line select v.Key).FirstOrDefault(); // If nothing was found to fold we can break out of the loop if (toReplace == null) { return(line); } // Find the value that was assigned to this var expr = writesInLine.Expressions[toReplace].Single(); // Substitute it into the line var result = new SubstituteVariable(toReplace, expr).Visit(line); return(result); })); } return(new Program(lines)); }