public void Dominates() { var cfg = new Graph(); cfg.Nodes.Add("1"); cfg.Nodes.Add("2"); cfg.Nodes.Add("3"); cfg.Nodes.Add("4"); cfg.Edges.Add("1", "2"); cfg.Edges.Add("2", "3"); cfg.Edges.Add("3", "4"); var info = new DominatorInfo(cfg.Nodes["1"]); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["1"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["2"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["4"])); Assert.False(info.Dominates(cfg.Nodes["2"], cfg.Nodes["1"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["2"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["4"])); Assert.False(info.Dominates(cfg.Nodes["3"], cfg.Nodes["1"])); Assert.False(info.Dominates(cfg.Nodes["3"], cfg.Nodes["2"])); Assert.True(info.Dominates(cfg.Nodes["3"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["3"], cfg.Nodes["4"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["1"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["2"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["4"], cfg.Nodes["4"])); }
public void LoopFrontiers() { var info = new DominatorInfo(LoopGraph.Nodes["1"]); var frontier = new HashSet <Node>(new[] { LoopGraph.Nodes["2"] }); Assert.Equal(frontier, info.GetDominanceFrontier(LoopGraph.Nodes["2"])); Assert.Equal(frontier, info.GetDominanceFrontier(LoopGraph.Nodes["3"])); }
public void LoopHeader() { var cfg = LoopGraph; var info = new DominatorInfo(cfg.Nodes["1"]); Assert.True(info.IsLoopHeader(cfg.Nodes["2"])); Assert.False(info.IsLoopHeader(cfg.Nodes["1"])); }
public void LoopDominators() { var info = new DominatorInfo(LoopGraph.Nodes["1"]); Assert.Equal(LoopGraph.Nodes["1"], info.GetImmediateDominator(LoopGraph.Nodes["1"])); Assert.Equal(LoopGraph.Nodes["1"], info.GetImmediateDominator(LoopGraph.Nodes["2"])); Assert.Equal(LoopGraph.Nodes["2"], info.GetImmediateDominator(LoopGraph.Nodes["3"])); Assert.Equal(LoopGraph.Nodes["2"], info.GetImmediateDominator(LoopGraph.Nodes["4"])); }
public void IfStatementFrontiers() { var cfg = IfStatementGraph; var info = new DominatorInfo(IfStatementGraph.Nodes["1"]); var frontier = new HashSet <Node>(new[] { IfStatementGraph.Nodes["4"] }); Assert.Equal(frontier, info.GetDominanceFrontier(IfStatementGraph.Nodes["3"])); Assert.Equal(frontier, info.GetDominanceFrontier(IfStatementGraph.Nodes["3"])); }
public void LoopDominated() { var cfg = LoopGraph; var info = new DominatorInfo(LoopGraph.Nodes["1"]); Assert.True(info.GetDominatedNodes(cfg.Nodes["1"]).SetEquals(cfg.Nodes)); Assert.True(info.GetDominatedNodes(cfg.Nodes["2"]).SetEquals(new[] { cfg.Nodes["2"], cfg.Nodes["3"], cfg.Nodes["4"] })); Assert.True(info.GetDominatedNodes(cfg.Nodes["3"]).SetEquals(new[] { cfg.Nodes["3"] })); Assert.True(info.GetDominatedNodes(cfg.Nodes["4"]).SetEquals(new[] { cfg.Nodes["4"] })); }
public void IfStatementDominated() { var cfg = IfStatementGraph; var info = new DominatorInfo(IfStatementGraph.Nodes["1"]); Assert.True(info.GetDominatedNodes(cfg.Nodes["1"]).SetEquals(cfg.Nodes)); Assert.True(info.GetDominatedNodes(cfg.Nodes["2"]).SetEquals(new[] { cfg.Nodes["2"] })); Assert.True(info.GetDominatedNodes(cfg.Nodes["3"]).SetEquals(new[] { cfg.Nodes["3"] })); Assert.True(info.GetDominatedNodes(cfg.Nodes["4"]).SetEquals(new[] { cfg.Nodes["4"] })); }
public void IfStatementDominators() { var cfg = IfStatementGraph; var info = new DominatorInfo(cfg.Nodes["1"]); Assert.Equal(cfg.Nodes["1"], info.GetImmediateDominator(cfg.Nodes["1"])); Assert.Equal(cfg.Nodes["1"], info.GetImmediateDominator(cfg.Nodes["2"])); Assert.Equal(cfg.Nodes["1"], info.GetImmediateDominator(cfg.Nodes["3"])); Assert.Equal(cfg.Nodes["1"], info.GetImmediateDominator(cfg.Nodes["4"])); }
public ILCompilationUnit(ControlFlowGraph controlFlowGraph, IFrameLayout frameLayout) { ControlFlowGraph = controlFlowGraph ?? throw new ArgumentNullException(nameof(controlFlowGraph)); FrameLayout = frameLayout; DominatorInfo = new DominatorInfo(controlFlowGraph.Entrypoint); DominatorTree = DominatorInfo.ToDominatorTree(); for (int i = 0; i < frameLayout.Parameters.Count; i++) { var parameter = new ILParameter("arg_" + i, i); Parameters.Add(parameter); _variables.Add(parameter.Name, parameter); } }
public BlockGenerator(ControlFlowGraph cfg, CilCodeGenerator generator) { _cfg = cfg ?? throw new ArgumentNullException(nameof(cfg)); _generator = generator; _dominatorInfo = new DominatorInfo(cfg.Entrypoint); _dominatorTree = _dominatorInfo.ToDominatorTree(); var components = cfg.Entrypoint.FindStronglyConnectedComponents(); _nodeToComponent = new Dictionary <Node, ISet <Node> >(); foreach (var component in components) { foreach (var node in component) { _nodeToComponent[node] = component; } } }
private void AddAbnormalEdges(ControlFlowGraph graph) { if (graph.SubGraphs.Count == 0) { return; } // Since exception handlers make it possible to transfer control to the handler block // at any time, we have these "abnormal edges" from each node in the try block // to the first node in the handler block (or filter block). // First, add the initial abnormal handler edges from every try-start to the handler-start (or filter start). // This allows us to do some more dominator-magic, where we can just infer the handler body based // on the nodes dominated by the handler node. foreach (var subGraph in graph.SubGraphs.OrderBy(x => x.Nodes.Count)) { var ehFrame = (EHFrame)subGraph.UserData[EHFrame.EHFrameProperty]; // Find the try entry node. var tryEntry = GetNode(graph, (long)ehFrame.TryStart); tryEntry.UserData[ControlFlowGraph.TryStartProperty] = ehFrame; // Find the handler entry node. var handlerEntry = GetNode(graph, (long)ehFrame.HandlerAddress); handlerEntry.UserData[ControlFlowGraph.HandlerStartProperty] = ehFrame; // Add initial abnormal edge. if (ehFrame.Type != EHType.FILTER) { // Jump straight to the handler entry. AddAbnormalEdge(graph, tryEntry, ehFrame, handlerEntry); } else { // Jump to the filter entry. var filterEntry = GetNode(graph, (long)ehFrame.FilterAddress); filterEntry.UserData[ControlFlowGraph.FilterStartProperty] = ehFrame; AddAbnormalEdge(graph, tryEntry, ehFrame, filterEntry); // Connect all terminators of the filter block to the handler entry. foreach (var terminator in FindReachableReturnNodes(filterEntry)) { AddAbnormalEdge(graph, terminator, ehFrame, handlerEntry); } } } // Obtain dominator info. var dominatorInfo = new DominatorInfo(graph.Entrypoint); // Add all handler nodes to the cluster, and add abnormal edges for each try node to the handler start node. var handlerExits = new Dictionary <EHFrame, ICollection <Node> >(); foreach (var subGraph in graph.SubGraphs.OrderBy(x => x.Nodes.Count)) { var ehFrame = (EHFrame)subGraph.UserData[EHFrame.EHFrameProperty]; var tryEntry = GetNode(graph, (long)ehFrame.TryStart); var handlerEntry = GetNode(graph, (long)ehFrame.HandlerAddress); // Determine the handler exits. var handlerBody = CollectHandlerNodes(handlerEntry, dominatorInfo.GetDominatedNodes(handlerEntry)); foreach (var handlerNode in handlerBody) { subGraph.Nodes.Add(handlerNode); } handlerExits.Add(ehFrame, new HashSet <Node>(handlerBody.Where(x => x.OutgoingEdges.Count == 0))); // Add for each node in the try block an abnormal edge. var tryBody = new HashSet <Node>(subGraph.Nodes.Except(handlerBody)); foreach (var node in tryBody.Where(n => !n.UserData.ContainsKey(ControlFlowGraph.TopMostEHProperty) && n != tryEntry)) { AddAbnormalEdge(graph, node, ehFrame, handlerEntry); } // Register EH boundaries in the sub graph. subGraph.UserData[ControlFlowGraph.TryBlockProperty] = tryBody; subGraph.UserData[ControlFlowGraph.HandlerBlockProperty] = handlerBody; if (ehFrame.Type == EHType.FILTER) { var filterEntry = GetNode(graph, (long)ehFrame.FilterAddress); subGraph.UserData[ControlFlowGraph.FilterStartProperty] = filterEntry; } } // Since a LEAVE instruction might not directly transfer control to the referenced instruction, // but rather transfer control to a finally block first, we have to add edges to these nodes // as well. foreach (var node in graph.Nodes) { if (node.SubGraphs.Count > 0) { // Check if the node ends with a LEAVE. var block = GetUserData <ILBasicBlock>(node, ILBasicBlock.BasicBlockProperty); if (block == null) { continue; } var last = block.Instructions[block.Instructions.Count - 1]; if (last.OpCode.Code == ILCode.LEAVE) { // Find the frame we're jumping out of. var ehFrame = last.ProgramState.EHStack.Peek(); // Add for each handler exit an edge to the referenced instruction. foreach (var exit in handlerExits[ehFrame]) { var edge = CreateEdge(exit, node.OutgoingEdges.First().Target, ControlFlowGraph.EndFinallyConditionLabel); exit.UserData[ControlFlowGraph.TopMostEHProperty] = ehFrame; graph.Edges.Add(edge); } } } } }
public void ComplexLoopTest() { var reader = new DotReader(new StringReader(@" strict digraph { 1 -> 2 -> 3 -> 4 -> 3 -> 5 -> 6 -> 7 }")); var cfg = reader.Read(); var info = new DominatorInfo(cfg.Nodes["1"]); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["1"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["2"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["4"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["5"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["6"])); Assert.True(info.Dominates(cfg.Nodes["1"], cfg.Nodes["7"])); Assert.False(info.Dominates(cfg.Nodes["2"], cfg.Nodes["1"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["2"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["4"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["5"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["6"])); Assert.True(info.Dominates(cfg.Nodes["2"], cfg.Nodes["7"])); Assert.False(info.Dominates(cfg.Nodes["3"], cfg.Nodes["1"])); Assert.False(info.Dominates(cfg.Nodes["3"], cfg.Nodes["2"])); Assert.True(info.Dominates(cfg.Nodes["3"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["3"], cfg.Nodes["4"])); Assert.True(info.Dominates(cfg.Nodes["3"], cfg.Nodes["5"])); Assert.True(info.Dominates(cfg.Nodes["3"], cfg.Nodes["6"])); Assert.True(info.Dominates(cfg.Nodes["3"], cfg.Nodes["7"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["1"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["2"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["3"])); Assert.True(info.Dominates(cfg.Nodes["4"], cfg.Nodes["4"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["5"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["6"])); Assert.False(info.Dominates(cfg.Nodes["4"], cfg.Nodes["7"])); Assert.False(info.Dominates(cfg.Nodes["5"], cfg.Nodes["1"])); Assert.False(info.Dominates(cfg.Nodes["5"], cfg.Nodes["2"])); Assert.False(info.Dominates(cfg.Nodes["5"], cfg.Nodes["3"])); Assert.False(info.Dominates(cfg.Nodes["5"], cfg.Nodes["4"])); Assert.True(info.Dominates(cfg.Nodes["5"], cfg.Nodes["5"])); Assert.True(info.Dominates(cfg.Nodes["5"], cfg.Nodes["6"])); Assert.True(info.Dominates(cfg.Nodes["5"], cfg.Nodes["7"])); Assert.False(info.Dominates(cfg.Nodes["6"], cfg.Nodes["1"])); Assert.False(info.Dominates(cfg.Nodes["6"], cfg.Nodes["2"])); Assert.False(info.Dominates(cfg.Nodes["6"], cfg.Nodes["3"])); Assert.False(info.Dominates(cfg.Nodes["6"], cfg.Nodes["4"])); Assert.False(info.Dominates(cfg.Nodes["6"], cfg.Nodes["5"])); Assert.True(info.Dominates(cfg.Nodes["6"], cfg.Nodes["6"])); Assert.True(info.Dominates(cfg.Nodes["6"], cfg.Nodes["7"])); Assert.False(info.Dominates(cfg.Nodes["7"], cfg.Nodes["1"])); Assert.False(info.Dominates(cfg.Nodes["7"], cfg.Nodes["2"])); Assert.False(info.Dominates(cfg.Nodes["7"], cfg.Nodes["3"])); Assert.False(info.Dominates(cfg.Nodes["7"], cfg.Nodes["4"])); Assert.False(info.Dominates(cfg.Nodes["7"], cfg.Nodes["5"])); Assert.False(info.Dominates(cfg.Nodes["7"], cfg.Nodes["6"])); Assert.True(info.Dominates(cfg.Nodes["7"], cfg.Nodes["7"])); }