/// <summary> /// Replaces nodes with an error statement and an error edge with an empty node and a continue edge /// </summary> /// <param name="cfg"></param> /// <returns></returns> public static IControlFlowGraph NormalizeErrors(this IControlFlowGraph cfg) { var todo = new HashSet <IBasicBlock>(); // Remove the error statements and save blocks to remove edges from cfg = cfg.Modify((a, b) => { if (!a.Statements.Any()) { return; } var toCopy = a.Statements; if ((a.Statements.Last() is ErrorStatement) && a.Outgoing.Count() == 1 && a.Outgoing.Single().Type == EdgeType.RuntimeError) { toCopy = a.Statements.Take(a.Statements.Count() - 1); todo.Add(b); } foreach (var stmt in toCopy) { b.Add(stmt); } }); // Copy graph, replacing edges as necessary return(cfg.Modify((e, c) => { c(e.Start, e.End, todo.Contains(e.Start) ? EdgeType.Continue : e.Type); })); }
/// <summary> /// Merge together basic blocks on the same line connected only by a continue edge /// </summary> /// <param name="cfg"></param> /// <returns></returns> public static IControlFlowGraph MergeAdjacentBasicBlocks(this IControlFlowGraph cfg) { // This keeps looping until it finds no work to do while (true) { // Find all candidates for merging var candidates = (from vertex in cfg.Vertices where vertex.Type == BasicBlockType.Basic where vertex.Outgoing.Count() == 1 let outgoing = vertex.Outgoing.Single() where outgoing.Type == EdgeType.Continue where outgoing.End.LineNumber == vertex.LineNumber where outgoing.End.Type == BasicBlockType.Basic where outgoing.End.Incoming.Count() == 1 select(vertex, outgoing.End)); // Select a single candidate pair (A -> B), if there is no work then exit now var work = candidates.FirstOrDefault(); if (work == default) { return(cfg); } // Move all the items from the A into B, leaving A empty cfg = cfg.Modify((a, b) => { if (a.ID == work.End.ID) { work.vertex.CopyTo(b); a.CopyTo(b); } else if (a.ID != work.vertex.ID) { a.CopyTo(b); } }); // Remove all empty blocks cfg = cfg.RemoveEmptyBlocks(); } }