ControlFlowNode[] PrepareReverseCFG(ControlFlowNode loopHead, bool treatBackEdgesAsExits) { ControlFlowNode[] cfg = context.ControlFlowGraph.cfg; ControlFlowNode[] rev = new ControlFlowNode[cfg.Length + 1]; for (int i = 0; i < cfg.Length; i++) { rev[i] = new ControlFlowNode { UserIndex = i, UserData = cfg[i].UserData }; } ControlFlowNode exitNode = new ControlFlowNode { UserIndex = -1 }; rev[cfg.Length] = exitNode; for (int i = 0; i < cfg.Length; i++) { if (!loopHead.Dominates(cfg[i])) { continue; } // Add reverse edges for all edges in cfg foreach (var succ in cfg[i].Successors) { if (loopHead.Dominates(succ) && (!treatBackEdgesAsExits || loopHead != succ)) { rev[succ.UserIndex].AddEdgeTo(rev[i]); } else { exitNode.AddEdgeTo(rev[i]); } } if (context.ControlFlowGraph.HasDirectExitOutOfContainer(cfg[i])) { exitNode.AddEdgeTo(rev[i]); } } Dominance.ComputeDominance(exitNode, context.CancellationToken); return(rev); }
/// <summary> /// Constructs a new control flow graph. /// Each node cfg[i] has a corresponding node rev[i]. /// Edges are only created for nodes dominated by loopHead, and are in reverse from their direction /// in the primary CFG. /// An artificial exit node is used for edges that leave the set of nodes dominated by loopHead, /// or that leave the block Container. /// </summary> /// <param name="loopHead">Entry point of the loop.</param> /// <param name="exitNodeArity">out: The number of different CFG nodes. /// Possible values: /// 0 = no CFG nodes used as exit nodes (although edges leaving the block container might still be exits); /// 1 = a single CFG node (not dominated by loopHead) was used as an exit node; /// 2 = more than one CFG node (not dominated by loopHead) was used as an exit node. /// </param> /// <returns></returns> ControlFlowNode[] PrepareReverseCFG(ControlFlowNode loopHead, out int exitNodeArity) { ControlFlowNode[] cfg = context.ControlFlowGraph.cfg; ControlFlowNode[] rev = new ControlFlowNode[cfg.Length + 1]; for (int i = 0; i < cfg.Length; i++) { rev[i] = new ControlFlowNode { UserIndex = i, UserData = cfg[i].UserData }; } ControlFlowNode nodeTreatedAsExitNode = null; bool multipleNodesTreatedAsExitNodes = false; ControlFlowNode exitNode = new ControlFlowNode { UserIndex = -1 }; rev[cfg.Length] = exitNode; for (int i = 0; i < cfg.Length; i++) { if (!loopHead.Dominates(cfg[i]) || isSwitch && cfg[i] != loopHead && loopContext.MatchContinue(cfg[i])) { continue; } // Add reverse edges for all edges in cfg foreach (var succ in cfg[i].Successors) { // edges to outer loops still count as exits (labelled continue not implemented) if (isSwitch && loopContext.MatchContinue(succ, 1)) { continue; } if (loopHead.Dominates(succ)) { rev[succ.UserIndex].AddEdgeTo(rev[i]); } else { if (nodeTreatedAsExitNode == null) { nodeTreatedAsExitNode = succ; } if (nodeTreatedAsExitNode != succ) { multipleNodesTreatedAsExitNodes = true; } exitNode.AddEdgeTo(rev[i]); } } if (context.ControlFlowGraph.HasDirectExitOutOfContainer(cfg[i])) { exitNode.AddEdgeTo(rev[i]); } } if (multipleNodesTreatedAsExitNodes) { exitNodeArity = 2; // more than 1 } else if (nodeTreatedAsExitNode != null) { exitNodeArity = 1; } else { exitNodeArity = 0; } Dominance.ComputeDominance(exitNode, context.CancellationToken); return(rev); }