Exemple #1
0
    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);
        }
    }
Exemple #2
0
    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()));
    }