sp-04/test/ch/usi/inf/sp/dom/DominatorAnalyzerTest.java

208 lines
9.7 KiB
Java

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));
}
}