/// <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)); }
/// <summary> /// Replace expressions which result in a constant with the result /// </summary> /// <param name="cfg"></param> /// <param name="ssa"></param> /// <returns></returns> [NotNull] public static IControlFlowGraph FoldConstants([NotNull] this IControlFlowGraph cfg, ISingleStaticAssignmentTable ssa) { // Keep finding and replacing constants until nothing is found cfg = cfg.Fixpoint(c => { // Find variables which are assigned a value which is not tainted by external reads var constants = c.FindConstants(ssa); // Replace reads of a constant variable with the expression assigned to that variable c = c.VisitBlocks(() => new ReplaceConstantSubexpressions(constants)); return(c); }); // Replace constant subexpressions with their value cfg = cfg.VisitBlocks(() => new ConstantFoldingVisitor(true)); return(cfg); }