public static (ControlFlowGraph, string) Decompile(ControlFlowGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } foreach (var head in graph.GetDfsPostOrder()) { var(trueChild, falseChild) = graph.GetBinaryChildren(head); if (!trueChild.HasValue || !falseChild.HasValue) { continue; } int after = -1; var then = -1; // Func<string> vis = () => graph.ToVis().AddPointer("head", head).AddPointer("after", after).AddPointer("then", then).ToString(); // For VS Code debug visualisation var parents0 = graph.Parents(trueChild.Value); var parents1 = graph.Parents(falseChild.Value); if (parents0.Length == 1) { var grandChildren = graph.Children(trueChild.Value); if (grandChildren.Length == 1 && grandChildren[0] == falseChild.Value) { then = trueChild.Value; after = falseChild.Value; } } else if (parents1.Length == 1) { var grandChildren = graph.Children(falseChild.Value); if (grandChildren.Length == 1 && grandChildren[0] == trueChild.Value) { then = falseChild.Value; after = trueChild.Value; } } if (after == -1 || then == -1 || after == head) { continue; } var condition = then == falseChild.Value ? Emit.Negation(graph.Nodes[head]) : graph.Nodes[head]; var newNode = Emit.If(condition, graph.Nodes[then]); return(graph.RemoveNode(then).ReplaceNode(head, newNode), Description); } return(graph, null); }
public static (ControlFlowGraph, string) Decompile(ControlFlowGraph graph) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } foreach (var head in graph.GetDfsPostOrder()) { var(trueChild, falseChild) = graph.GetBinaryChildren(head); if (!trueChild.HasValue || !falseChild.HasValue) { continue; } var left = trueChild.Value; var right = falseChild.Value; // Func<string> vis = () => graph.ToVis().AddPointer("head", head).AddPointer("after", after).AddPointer("left", left).AddPointer("right", right).ToString(); // For VS Code debug visualisation var leftParents = graph.Parents(left); var rightParents = graph.Parents(right); var leftChildren = graph.Children(left); var rightChildren = graph.Children(right); if (leftParents.Length != 1 || rightParents.Length != 1) // Branches of an if can't be jump destinations from elsewhere { continue; } bool isRegularIfThenElse = leftChildren.Length == 1 && rightChildren.Length == 1 && leftChildren[0] == rightChildren[0]; bool isTerminalIfThenElse = leftChildren.Length == 0 && rightChildren.Length == 0; if (!isRegularIfThenElse && !isTerminalIfThenElse) { continue; } var after = isRegularIfThenElse ? leftChildren[0] : -1; if (after == head) { continue; } var newNode = Emit.IfElse( graph.Nodes[head], graph.Nodes[left], graph.Nodes[right]); var updated = graph; if (isRegularIfThenElse) { updated = updated.AddEdge(head, after, CfgEdge.True); } return(updated .RemoveNode(left) .RemoveNode(right) .ReplaceNode(head, newNode), Description); } return(graph, null); }