static ControlFlowGraph ReduceContinue(ControlFlowGraph graph, CfgLoop loop, LoopPart part) { // Func<string> vis = () => graph.ToVis().AddPointer("index", index).AddPointer("part", part.Index).ToString(); // For VS Code debug visualisation // Outside entry = non-structured code, so give up // Tail = the tail of a loop always continues by default, don't need a statement - the top-level loop reduction will handle it. // Header = continuing header should be handled by simple loop rule // !Continue = if it's not a jump back to the header, it's not a continue // Break = shouldn't be both a continue and a break if (part.OutsideEntry || part.Tail || part.Header || !part.Continue || part.Break) { return(graph); } var children = graph.Children(part.Index); switch (children.Length) { case 1: { var seq = Emit.Seq(graph.Nodes[part.Index], Emit.Continue()); var tailIndex = loop.Body.First(x => x.Tail).Index; return(graph .ReplaceNode(part.Index, seq) .RemoveEdge(part.Index, loop.Header.Index) .AddEdge(part.Index, tailIndex, CfgEdge.True)); } case 2: return(ReplaceLoopBranch(graph, part.Index, loop.Header.Index, Emit.Continue())); default: throw new ControlFlowGraphException($"Continue at {part.Index} has unexpected child count ({children.Length})", graph); } }
static ControlFlowGraph ReduceBreak(ControlFlowGraph graph, CfgLoop loop, LoopPart part) { // Func<string> vis = () => graph.ToVis().AddPointer("part", part.Index).ToString(); // For VS Code debug visualisation // Break = needs to exit the loop to be a break if (!part.Break) { return(graph); } // Outside entry = non-structured code, so give up if (part.OutsideEntry) { return(graph); } var children = graph.Children(part.Index); if (children.Length != 2) { throw new ControlFlowGraphException($"Break at {part.Index} has unexpected child count ({children.Length})", graph); } bool isfirstChildInLoop = loop.Body.Any(x => x.Index == children[0]) || children[0] == loop.Header.Index; var exitTarget = isfirstChildInLoop ? children[1] : children[0]; // Add LoopSuccessor edge if this is the last link to the MainExit. var remainingLoopChildren = loop.Body .Where(x => x.Index != part.Index) .Aggregate( (IEnumerable <int>)graph.Children(loop.Header.Index), (current, x) => current.Union(graph.Children(x.Index))); if (loop.MainExit.HasValue && !remainingLoopChildren.Contains(loop.MainExit.Value)) { graph = graph.AddEdge(loop.Header.Index, loop.MainExit.Value, CfgEdge.LoopSuccessor); } if (exitTarget != loop.MainExit) { var targetChildren = graph.Children(exitTarget); if (targetChildren.Length != 1 || targetChildren[0] != loop.MainExit) { return(graph); } var condition = graph.Nodes[part.Index]; if (graph.GetEdgeLabel(part.Index, exitTarget) == CfgEdge.False) { condition = Emit.Negation(condition); } var ifNode = Emit.If(condition, Emit.Seq(graph.Nodes[exitTarget], Emit.Break())); return(graph .RemoveNode(exitTarget) .ReplaceNode(part.Index, ifNode)); } return(ReplaceLoopBranch(graph, part.Index, exitTarget, Emit.Break())); }