/*
* Copyright (c) 2012-2013, Synflow SAS
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.graph.visit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.orcc.graph.Edge;
import net.sf.orcc.graph.Graph;
import net.sf.orcc.graph.GraphPackage;
import net.sf.orcc.graph.Vertex;
import org.eclipse.emf.ecore.EReference;
/**
* This class computes the dominance information of a graph using the algorithm
* described in "A Simple, Fast Dominance Algorithm" by Keith D. Cooper, Timothy
* J. Harvey, and Ken Kennedy.
*
* @author Matthieu Wipliez
*
*/
public class DominatorComputer {
private final EReference refEdges;
private final EReference refVertex;
private final List<Vertex> vertices;
/**
*
* @param graph
* a directed graph
* @param root
* the root vertex (entry for dominance, exit for post-dominance)
* @param isPost
* <code>true</code> if computing post-dominance information,
* <code>false</code> otherwise
*/
public DominatorComputer(Graph graph, Vertex root, boolean isPost) {
if (isPost) {
refEdges = GraphPackage.Literals.VERTEX__OUTGOING;
refVertex = GraphPackage.Literals.EDGE__TARGET;
} else {
refEdges = GraphPackage.Literals.VERTEX__INCOMING;
refVertex = GraphPackage.Literals.EDGE__SOURCE;
}
// opposite of source/target is outgoing/incoming
// opposite of incoming/outgoing is target/source
Ordering rpo = new ReversePostOrder(graph, refVertex.getEOpposite(),
refEdges.getEOpposite(), root);
this.vertices = rpo.getVertices();
}
/**
* Computes the dominance information.
*/
public Map<Vertex, Vertex> computeDominance() {
// initialize doms
// 0 is considered as "Undefined"
// so we start from 1 (hence the "n + 1" allocation)
int n = vertices.size();
int[] doms = new int[n + 1];
// n is the start node by definition of the post-order numbering
doms[n] = n;
// update dominance information
updateDom(doms, n);
// return the immediate dominator map
Map<Vertex, Vertex> map = new HashMap<Vertex, Vertex>(doms.length);
for (int i = 1; i < n; i++) {
// b is the post-order number of vertex
Vertex vertex = vertices.get(i);
int b = vertex.getNumber();
map.put(vertex, vertices.get(n - doms[b]));
}
return map;
}
/**
* Returns the list of vertices in the specified order.
*
* @return the list of vertices in the specified order
*/
public List<Vertex> getVertices() {
return vertices;
}
private int intersect(int[] doms, int b1, int b2) {
int finger1 = b1;
int finger2 = b2;
while (finger1 != finger2) {
while (finger1 < finger2) {
finger1 = doms[finger1];
}
while (finger2 < finger1) {
finger2 = doms[finger2];
}
}
return finger1;
}
private void updateDom(int[] doms, int n) {
boolean changed = true;
while (changed) {
changed = false;
// skip the first node of vertices (the start node)
for (int i = 1; i < n; i++) {
// find the first processed predecessor and set newIdom
int newIdom = 0;
Vertex processed = null;
Vertex vertex = vertices.get(i);
@SuppressWarnings("unchecked")
List<Edge> edges = (List<Edge>) vertex.eGet(refEdges);
for (Edge edge : edges) {
Vertex pred = (Vertex) edge.eGet(refVertex);
int p = pred.getNumber();
if (doms[p] != 0) {
// pred has already been processed, set newIdom
processed = pred;
newIdom = p;
break;
}
}
// for all predecessors different from processed
for (Edge edge : edges) {
Vertex pred = (Vertex) edge.eGet(refVertex);
if (pred != processed) {
int p = pred.getNumber();
if (doms[p] != 0) {
// i.e., if doms[p] already calculated
newIdom = intersect(doms, p, newIdom);
}
}
}
// b is the post-order number of vertex
int b = vertex.getNumber();
if (doms[b] != newIdom) {
doms[b] = newIdom;
changed = true;
}
}
}
}
}