blob: aca78f425a35bc3c86dc7f3561bedd9a48f1b937 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.rephraserengine.core.analysis.flow;
import java.util.HashMap;
import java.util.Map;
/**
* Method object to construct basic blocks from the nodes in a control flow graph and build a new
* flow graph from those basic blocks. Used by {@link FlowGraph#formBasicBlocks(BasicBlockBuilder)}.
* <p>
* If the underlying language contains unconditional branch instructions or instructions that may
* halt execution of the program, the default algorithm for constructing basic blocks will be
* incorrect; in such cases, subclasses must override {@link #isGoToOrStop(Object)} in order to
* properly recognize these instructions. (By definition, if control enters a basic block, it
* must exit the block without halting or branching in the middle of the block. If the language
* contains an unconditional branch, and the target of the branch has only one predecessor (the
* branch instruction), the default algorithm will try to coalesce the target instruction into the
* basic block containing the branch instruction. Therefore, subclasses must explicitly determine
* that the instruction is a branch so that its target will become the leader of a new basic block.)
* <p>
* See Aho et al., <i>Compilers: Principles, Techniques, and Tools</i> (1986), pp. 528-529 for more
* information.
*
* @author Jeff Overbey
*
* @see FlowGraph#formBasicBlocks(BasicBlockBuilder)
*
* @since 3.0
*/
public class BasicBlockBuilder<U>
{
private FlowGraph<U> cfg;
private Map<FlowGraphNode<U>, FlowGraphNode<BasicBlock<U>>> newNodes;
FlowGraph<BasicBlock<U>> buildFlowGraphFrom(FlowGraph<U> cfg)
{
this.cfg = cfg;
this.newNodes = new HashMap<FlowGraphNode<U>, FlowGraphNode<BasicBlock<U>>>();
constructNewNodes();
connectNewNodes();
return new FlowGraph<BasicBlock<U>>(newNodes.get(cfg.getEntryNode()), newNodes.get(cfg.getExitNode()));
}
private void constructNewNodes()
{
FlowGraphNode<BasicBlock<U>> currentNode = null;
for (FlowGraphNode<U> node : cfg.nodesInPreOrder())
{
if (currentNode == null
|| node.getPrecedessors().size() != 1
|| isGoToOrStop(node.getPrecedessors().get(0).getData()))
currentNode = new FlowGraphNode<BasicBlock<U>>(node.getName(), new BasicBlock<U>(node.getData()));
else
currentNode.getData().add(node.getData());
newNodes.put(node, currentNode);
if (node.getSuccessors().size() != 1)
currentNode = null;
}
}
private void connectNewNodes()
{
for (FlowGraphNode<U> node : cfg.nodesInPreOrder())
{
FlowGraphNode<BasicBlock<U>> nodeBB = newNodes.get(node);
for (FlowGraphNode<U> succ : node.getSuccessors())
{
FlowGraphNode<BasicBlock<U>> succBB = newNodes.get(succ);
if (succBB != nodeBB)
nodeBB.connectTo(succBB);
}
}
}
/**
* @return true iff the given data (instruction/statement) corresponds to either
* <ul>
* <li> a conditional or unconditional branch, or
* <li> a statement that stops execution of the program.
* </ul>
* The statement(s)/instructions(s) following this one will become leaders of new basic blocks.
*/
protected boolean isGoToOrStop(U data)
{
return false;
}
}