예제 #1
0
        /// <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));
        }
예제 #2
0
        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));
        }