111 lines
3.9 KiB
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;
|
|
}
|
|
}
|