public static (ControlFlowGraph, string) Decompile(ControlFlowGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } foreach (var index in graph.GetDfsPostOrder()) { var children = graph.Children(index); if (children.Length != 1 || children[0] == index) { continue; } // If the node is the target of a back-edge then leave it alone: it's probably an empty loop-header node if (graph.GetBackEdges().Any(x => x.end == index)) { continue; } int child = children[0]; // Func<string> vis = () => graph.ToVis().AddPointer("index", index).AddPointer("child", child).ToString(); // For VS Code debug visualisation var childsParents = graph.Parents(child); var grandChildren = graph.Children(child); if (childsParents.Length != 1 || grandChildren.Length > 1) { continue; // Is a jump target from somewhere else as well - can't combine } if (grandChildren.Length == 1 && (grandChildren[0] == index || grandChildren[0] == child)) { continue; // Loops around, not a sequence } var node = graph.Nodes[index]; var childNode = graph.Nodes[child]; var updated = graph .RemoveNode(child) .ReplaceNode(index, Emit.Seq(node, childNode)); foreach (var grandChild in grandChildren) { updated = updated.AddEdge(index, grandChild, graph.GetEdgeLabel(child, grandChild)); } return(updated, $"Reduce sequence (node {index}, child {child})"); } return(graph, null); }
public static (ControlFlowGraph, string) Decompile(ControlFlowGraph graph /*, RecordFunc recordFunc = null*/) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } var regions = graph.GetAllSeseRegions(); // Do smallest regions first, as they may be nested in a larger one foreach (var(region, regionEntry, regionExit) in regions.OrderBy(x => x.nodes.Count)) { if (regionEntry == graph.EntryIndex) { continue; // Don't try and reduce the 'sequence' of start node -> actual entry point nodes when there's only one entry } /* Func<string> vis = () => // For VS Code debug visualisation * { * var d = graph.ToVis(); * foreach(var n in d.Nodes) * if (region.Contains(int.Parse(n.Id, CultureInfo.InvariantCulture))) * n.Color = "#4040b0"; * return d.ToString(); * }; */ bool containsOther = regions.Any(x => x.nodes != region && !x.nodes.Except(region).Any()); if (containsOther) { continue; } // If either end is a loop header then leave it alone and let the loop rule handle it. if (graph.GetBackEdges().Any(x => x.end == regionEntry || x.end == regionExit)) { continue; } var cut = graph.Cut(region, regionEntry, regionExit); if (cut.Cut.IsCyclic()) // Loop reduction comes later { continue; } return(cut.Merge(ReduceSese(cut.Cut)), Description); } return(graph, null); }
public static (ControlFlowGraph, string) Decompile(ControlFlowGraph graph) { var(reachability, reachableCount) = graph.Reverse().GetReachability(graph.ExitIndex); if (reachableCount == graph.ActiveNodeCount) { return(graph, null); } var acyclic = graph.RemoveBackEdges(); var distances = acyclic.GetLongestPaths(acyclic.EntryIndex); int longestDistance = 0; int winner = -1; for (int i = 0; i < graph.NodeCount; i++) { if (graph.Nodes[i] == null || reachability[i]) // Only consider nodes that can't reach the exit { continue; } if (distances[i] <= longestDistance) { continue; } longestDistance = distances[i]; winner = i; } if (winner == -1) { return(graph, null); } foreach (var backEdge in graph.GetBackEdges().Where(x => x.start == winner)) { return(graph.AddEdge(backEdge.end, graph.ExitIndex, CfgEdge.LoopSuccessor), Description); } return(graph.AddEdge(winner, graph.ExitIndex, CfgEdge.DisjointGraphFixup), Description); }
internal static string GetGraphInformation(ControlFlowGraph cfg) { var str = new StringBuilder(); str.AppendLine("Доминаторы:"); var domTree = new DominatorTree().GetDominators(cfg); foreach (var pair in domTree) { foreach (var x in pair.Value) { str.AppendLine($"{cfg.VertexOf(x)} dom {cfg.VertexOf(pair.Key)}"); } str.AppendLine("----------------"); } str.AppendLine("\r\nКлассификация ребер:"); foreach (var pair in cfg.ClassifiedEdges) { str.AppendLine($"{ pair }"); } str.AppendLine("\r\nОбходы графа:"); str.AppendLine($"Прямой: { string.Join(" -> ", cfg.PreOrderNumeration) }"); str.AppendLine($"Обратный: { string.Join(" -> ", cfg.PostOrderNumeration) }"); str.AppendLine($"\r\nГлубинное остовное дерево:"); foreach (var x in cfg.DepthFirstSpanningTree) { str.AppendLine($"({x.from} - > {x.to})"); } var backEdges = cfg.GetBackEdges(); if (backEdges.Count > 0) { str.AppendLine("\r\nОбратные ребра:"); foreach (var x in backEdges) { str.AppendLine($"({cfg.VertexOf(x.Item1)}, {cfg.VertexOf(x.Item2)})"); } } else { str.AppendLine("\r\nОбратных ребер нет"); } var answ = cfg.IsReducibleGraph() ? "Граф приводим" : "Граф неприводим"; str.AppendLine($"\r\n{answ}"); if (cfg.IsReducibleGraph()) { var natLoops = NaturalLoop.GetAllNaturalLoops(cfg); if (natLoops.Count > 0) { str.AppendLine($"\r\nЕстественные циклы:"); foreach (var x in natLoops) { if (x.Count == 0) { continue; } for (var i = 0; i < x.Count; i++) { str.AppendLine($"Номер блока: {i}"); foreach (var xfrom in x[i].GetInstructions()) { str.AppendLine(xfrom.ToString()); } } str.AppendLine(); str.AppendLine("-------------"); } } else { str.AppendLine($"\r\nЕстественных циклов нет"); } } else { str.AppendLine($"\r\nНевозможно определить естественные циклы, т.к. граф неприводим"); } return(str.ToString()); }