sp-04/src/ch/usi/inf/sp/dom/DominatorAnalyzer.java

111 lines
3.9 KiB
Java

package ch.usi.inf.sp.dom;
import ch.usi.inf.sp.cfg.BasicBlock;
import ch.usi.inf.sp.cfg.ControlFlowGraph;
import ch.usi.inf.sp.graph.Edge;
import ch.usi.inf.sp.graph.Traversal;
import java.util.*;
import java.util.stream.Collectors;
public class DominatorAnalyzer {
/**
* Cooper et al.'s "Engineered Algorithm".
* <pre>
* ================================================================
* for all nodes, b // initialize the dominators array
* doms[b] ← Undefined
* doms[entryNode] ← entryNode
* Changed ← true
* while (Changed)
* Changed ← false
* for all nodes, b, in reverse postorder (except entryNode)
* newidom ← first (processed) predecessor of b // (pick one)
* for all other predecessors, p, of b
* if doms[p] != Undefined // i.e., if doms[p] already calculated
* newidom ← intersect(p, newidom)
* if doms[b] != newidom
* doms[b] ← newidom
* Changed ← true
*
* function intersect(b1, b2) returns node
* finger1 ← b1
* finger2 ← b2
* while (finger1 != finger2)
* while (finger1 < finger2)
* finger1 = doms[finger1]
* while (finger2 < finger1)
* finger2 = doms[finger2]
* return finger1
* ================================================================
* </pre>
* Figure 3 of Cooper, Harvey, Kennedy
*/
public static DominatorTree analyze(final ControlFlowGraph cfg) {
final Map<BasicBlock, BasicBlock> dominators = new HashMap<>();
final BasicBlock entryNode = cfg.getEntry();
dominators.put(entryNode, entryNode);
final List<BasicBlock> rpo = Traversal.getNodesInReversePostOrder(cfg, entryNode);
boolean changed = true;
while (changed) {
changed = false;
for (final BasicBlock bb : rpo) {
if (bb == entryNode) {
continue;
}
final List<BasicBlock> predecessors = bb.getInEdges().stream()
.map(Edge::getFrom)
.collect(Collectors.toCollection(LinkedList::new));
if (predecessors.isEmpty()) {
throw new IllegalStateException("all non-entry nodes should have one predecessor");
}
BasicBlock newDominator = predecessors.remove(0);
for (final BasicBlock pred : predecessors) {
if (dominators.containsKey(pred)) {
newDominator = intersect(pred, newDominator, dominators, Comparator.comparing(rpo::indexOf).reversed());
}
}
if (dominators.get(bb) != newDominator) {
dominators.put(bb, newDominator);
changed = true;
}
}
}
final DominatorTree tree = new DominatorTree();
tree.setRootBlock(entryNode);
for (final Map.Entry<BasicBlock, BasicBlock> entry : dominators.entrySet()) {
if (entry.getKey() != entryNode) {
tree.addDominanceEdge(entry.getValue(), entry.getKey());
}
}
return tree;
}
public static BasicBlock intersect(BasicBlock b1, BasicBlock b2, Map<BasicBlock, BasicBlock> dominators, Comparator<? super BasicBlock> postOrder) {
BasicBlock finger1 = b1;
BasicBlock finger2 = b2;
while (postOrder.compare(finger1, finger2) != 0) {
while (postOrder.compare(finger1, finger2) < 0) {
finger1 = dominators.get(finger1);
}
while (postOrder.compare(finger1, finger2) > 0) {
finger2 = dominators.get(finger2);
}
}
return finger1;
}
}