package ch.usi.inf.sp.dom; import ch.usi.inf.sp.cfg.BasicBlock; import ch.usi.inf.sp.cfg.ControlFlowGraph; import org.junit.jupiter.api.Test; import java.util.Arrays; import static ch.usi.inf.sp.dom.DominatorTreeAssertions.*; import static org.junit.jupiter.api.Assertions.*; class DominatorAnalyzerTest { @Test void analyzeEntryExit() { ControlFlowGraph cfg = new ControlFlowGraph(); cfg.addFallthroughEdge(cfg.getEntry(), cfg.getExit()); System.out.println(cfg); DominatorTree t = DominatorAnalyzer.analyze(cfg); System.out.println(t); assertAllNodesMapToTheirBlocks(t); assertNodesHaveCorrectNumberOfParents(t); assertChildrenPointToParent(t); assertPathToRoot(t, Arrays.asList(cfg.getExit(), cfg.getEntry())); assertSame(cfg.getEntry(), t.getRoot().getBlock(), "Root must hold entry block"); assertEquals(1, t.getRoot().getOutEdges().size(), "Root must have one out edge"); assertTrue(t.getRoot().getOutEdges().stream().map(e->e.getTo()).anyMatch(d -> d==t.getNodeForBlock(cfg.getExit())), "Root must have child holding exit block"); } @Test void analyzeEntryNodeExit() { ControlFlowGraph cfg = new ControlFlowGraph(); BasicBlock b0 = new BasicBlock(0); cfg.addNode(b0); cfg.addFallthroughEdge(cfg.getEntry(), b0); cfg.addFallthroughEdge(b0, cfg.getExit()); System.out.println(cfg); DominatorTree t = DominatorAnalyzer.analyze(cfg); System.out.println(t); assertAllNodesMapToTheirBlocks(t); assertNodesHaveCorrectNumberOfParents(t); assertChildrenPointToParent(t); assertSame(cfg.getEntry(), t.getRoot().getBlock(), "Root must hold entry block"); assertEquals(1, t.getRoot().getOutEdges().size(), "Root must have one out edge"); assertSame(b0, t.getRoot().getOutEdges().get(0).getTo().getBlock(), "Root must have child holding b0 block"); assertEquals(1, t.getRoot().getOutEdges().get(0).getTo().getOutEdges().size(), "Root must have child that has one out edge"); assertSame(cfg.getExit(), t.getRoot().getOutEdges().get(0).getTo().getOutEdges().get(0).getTo().getBlock(), "Root must have child that has child holding exit block"); } @Test void analyzeIfThen() { ControlFlowGraph cfg = new ControlFlowGraph(); BasicBlock bIf = new BasicBlock(0); cfg.addNode(bIf); BasicBlock bThen = new BasicBlock(1); cfg.addNode(bThen); cfg.addFallthroughEdge(cfg.getEntry(), bIf); cfg.addFallthroughEdge(bIf, cfg.getExit()); cfg.addBranchTakenEdge(bIf, bThen); cfg.addFallthroughEdge(bThen, cfg.getExit()); System.out.println(cfg); DominatorTree t = DominatorAnalyzer.analyze(cfg); System.out.println(t); assertAllNodesMapToTheirBlocks(t); assertNodesHaveCorrectNumberOfParents(t); assertChildrenPointToParent(t); assertSame(cfg.getEntry(), t.getRoot().getBlock(), "Root must hold entry block"); assertEquals(1, t.getRoot().getOutEdges().size(), "Root must have one out edge"); assertSame(bIf, t.getRoot().getOutEdges().get(0).getTo().getBlock(), "Root must have child holding bIf block"); assertEquals(2, t.getRoot().getOutEdges().get(0).getTo().getOutEdges().size(), "Root must have child that has two out edges"); assertTrue(t.getRoot().getOutEdges().get(0).getTo().getOutEdges().stream().map(e->e.getTo()).anyMatch(d->d.getBlock()==bThen), "Root must have child that has child holding bThen block"); assertTrue(t.getRoot().getOutEdges().get(0).getTo().getOutEdges().stream().map(e->e.getTo()).anyMatch(d->d.getBlock()==cfg.getExit()), "Root must have child that has child holding exit block"); assertEquals(0, t.getNodeForBlock(bThen).getOutEdges().size()); } @Test void analyzeIfThenElse() { ControlFlowGraph cfg = new ControlFlowGraph(); BasicBlock bIf = new BasicBlock(0); cfg.addNode(bIf); BasicBlock bThen = new BasicBlock(1); cfg.addNode(bThen); BasicBlock bElse = new BasicBlock(2); cfg.addNode(bElse); cfg.addFallthroughEdge(cfg.getEntry(), bIf); cfg.addBranchTakenEdge(bIf, bElse); cfg.addFallthroughEdge(bIf, bThen); cfg.addFallthroughEdge(bElse, cfg.getExit()); cfg.addFallthroughEdge(bThen, cfg.getExit()); System.out.println(cfg); DominatorTree t = DominatorAnalyzer.analyze(cfg); System.out.println(t); assertAllNodesMapToTheirBlocks(t); assertNodesHaveCorrectNumberOfParents(t); assertChildrenPointToParent(t); assertSame(cfg.getEntry(), t.getRoot().getBlock(), "Root must hold entry block"); assertEquals(1, t.getRoot().getOutEdges().size(), "Root must have one out edge"); assertSame(bIf, t.getRoot().getOutEdges().get(0).getTo().getBlock(), "Root must have child holding bIf block"); assertEquals(3, t.getNodeForBlock(bIf).getOutEdges().size(), "bIf must have three out edges"); assertTrue(t.getNodeForBlock(bIf).getOutEdges().stream().map(e->e.getTo()).anyMatch(d->d.getBlock()==bThen), "bIf must have child holding bThen block"); assertTrue(t.getNodeForBlock(bIf).getOutEdges().stream().map(e->e.getTo()).anyMatch(d->d.getBlock()==bElse), "bIf must have child holding bElse block"); assertTrue(t.getNodeForBlock(bIf).getOutEdges().stream().map(e->e.getTo()).anyMatch(d->d.getBlock()==cfg.getExit()), "bIf must have child holding exit block"); assertEquals(0, t.getNodeForBlock(bThen).getOutEdges().size()); assertEquals(0, t.getNodeForBlock(bElse).getOutEdges().size()); } @Test void analyzeLoop() { ControlFlowGraph cfg = new ControlFlowGraph(); BasicBlock bHeader = new BasicBlock(0); cfg.addNode(bHeader); BasicBlock bBody = new BasicBlock(1); cfg.addNode(bBody); cfg.addFallthroughEdge(cfg.getEntry(), bHeader); cfg.addBranchTakenEdge(bHeader, bBody); cfg.addFallthroughEdge(bHeader, cfg.getExit()); cfg.addFallthroughEdge(bBody, bHeader); System.out.println(cfg); DominatorTree t = DominatorAnalyzer.analyze(cfg); System.out.println(t); assertAllNodesMapToTheirBlocks(t); assertNodesHaveCorrectNumberOfParents(t); assertChildrenPointToParent(t); assertSame(cfg.getEntry(), t.getRoot().getBlock(), "Root must hold entry block"); assertEquals(1, t.getRoot().getOutEdges().size(), "Root must have one out edge"); assertSame(bHeader, t.getRoot().getOutEdges().get(0).getTo().getBlock(), "Root must have child holding bHeader block"); assertEquals(2, t.getNodeForBlock(bHeader).getOutEdges().size(), "bHeader must have two out edges"); assertTrue(t.getNodeForBlock(bHeader).getOutEdges().stream().map(e->e.getTo()).anyMatch(d->d.getBlock()==bBody), "bHeader must have child holding bBody block"); assertTrue(t.getNodeForBlock(bHeader).getOutEdges().stream().map(e->e.getTo()).anyMatch(d->d.getBlock()==cfg.getExit()), "bHeader must have child holding exit block"); assertEquals(0, t.getNodeForBlock(bBody).getOutEdges().size(), "bBody must have zero out edges"); } @Test void analyzeCooperFigure2() { // This is an irreducible graph // (and it doesn't have an exit edge, so we "abuse" the CFG a bit, which is fine) ControlFlowGraph g = new ControlFlowGraph(); BasicBlock b5 = g.getEntry(); BasicBlock b4 = new BasicBlock(4); g.addNode(b4); BasicBlock b3 = new BasicBlock(3); g.addNode(b3); BasicBlock b2 = new BasicBlock(2); g.addNode(b2); BasicBlock b1 = g.getExit(); g.addFallthroughEdge(b5, b3); g.addFallthroughEdge(b5, b4); g.addFallthroughEdge(b3, b2); g.addFallthroughEdge(b4, b1); g.addFallthroughEdge(b2, b1); g.addFallthroughEdge(b1, b2); System.out.println(g); DominatorTree t = DominatorAnalyzer.analyze(g); System.out.println(t); assertAllNodesMapToTheirBlocks(t); assertNodesHaveCorrectNumberOfParents(t); assertChildrenPointToParent(t); assertPathToRoot(t, Arrays.asList(b4, b5)); assertPathToRoot(t, Arrays.asList(b3, b5)); assertPathToRoot(t, Arrays.asList(b2, b5)); assertPathToRoot(t, Arrays.asList(b1, b5)); } @Test void analyzeCooperFigure4() { // This is an irreducible graph // (and it doesn't have an exit edge, so we "abuse" the CFG a bit, which is fine) ControlFlowGraph g = new ControlFlowGraph(); BasicBlock b6 = g.getEntry(); BasicBlock b5 = new BasicBlock(5); g.addNode(b5); BasicBlock b4 = new BasicBlock(4); g.addNode(b4); BasicBlock b3 = new BasicBlock(3); g.addNode(b3); BasicBlock b2 = new BasicBlock(2); g.addNode(b2); BasicBlock b1 = g.getExit(); g.addFallthroughEdge(b6, b4); g.addFallthroughEdge(b6, b5); g.addFallthroughEdge(b4, b3); g.addFallthroughEdge(b4, b2); g.addFallthroughEdge(b3, b2); g.addFallthroughEdge(b2, b1); g.addFallthroughEdge(b2, b3); g.addFallthroughEdge(b1, b2); g.addFallthroughEdge(b5, b1); System.out.println(g); DominatorTree t = DominatorAnalyzer.analyze(g); System.out.println(t); assertAllNodesMapToTheirBlocks(t); assertNodesHaveCorrectNumberOfParents(t); assertChildrenPointToParent(t); assertPathToRoot(t, Arrays.asList(b5, b6)); assertPathToRoot(t, Arrays.asList(b4, b6)); assertPathToRoot(t, Arrays.asList(b3, b6)); assertPathToRoot(t, Arrays.asList(b2, b6)); assertPathToRoot(t, Arrays.asList(b1, b6)); } }