/*
* Copyright (c) 2009, IETR/INSA of Rennes
* 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.ir.util;
import java.util.List;
import net.sf.orcc.ir.Arg;
import net.sf.orcc.ir.ArgByVal;
import net.sf.orcc.ir.Block;
import net.sf.orcc.ir.BlockBasic;
import net.sf.orcc.ir.BlockIf;
import net.sf.orcc.ir.BlockWhile;
import net.sf.orcc.ir.ExprBinary;
import net.sf.orcc.ir.ExprUnary;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.InstAssign;
import net.sf.orcc.ir.InstCall;
import net.sf.orcc.ir.InstLoad;
import net.sf.orcc.ir.InstPhi;
import net.sf.orcc.ir.InstReturn;
import net.sf.orcc.ir.InstStore;
import net.sf.orcc.ir.Instruction;
import net.sf.orcc.ir.Procedure;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
/**
* This abstract class implements a no-op visitor on IR procedures, blocks,
* instructions, and (if visitFull is <code>true</code>) expressions. This class
* should be extended by classes that implement intra-procedural IR visitors and
* transformations.
*
* @author Matthieu Wipliez
* @since 1.2
*/
public abstract class AbstractIrVisitor<T> extends IrSwitch<T> {
protected int indexInst;
protected int indexBlock;
/**
* current procedure being visited
*/
protected Procedure procedure;
private final boolean visitFull;
/**
* Creates a new abstract IR visitor that visits all blocks and instructions.
*/
public AbstractIrVisitor() {
visitFull = false;
}
/**
* Creates a new abstract actor visitor that visits all blocks and
* instructions, and may also visit all the expressions if
* <code>visitFull</code> is <code>true</code>.
*
* @param visitFull
* when <code>true</code>, visits all the expressions
*/
public AbstractIrVisitor(boolean visitFull) {
this.visitFull = visitFull;
}
@Override
public T caseArgByVal(ArgByVal arg) {
doSwitch(arg.getValue());
return null;
}
@Override
public T caseBlockBasic(BlockBasic block) {
return visitInstructions(block.getInstructions());
}
@Override
public T caseBlockIf(BlockIf blockIf) {
if (visitFull) {
doSwitch(blockIf.getCondition());
}
doSwitch(blockIf.getThenBlocks());
doSwitch(blockIf.getElseBlocks());
doSwitch(blockIf.getJoinBlock());
return null;
}
@Override
public T caseBlockWhile(BlockWhile blockWhile) {
if (visitFull) {
doSwitch(blockWhile.getCondition());
}
doSwitch(blockWhile.getBlocks());
doSwitch(blockWhile.getJoinBlock());
return null;
}
@Override
public T caseExprBinary(ExprBinary expr) {
doSwitch(expr.getE1());
doSwitch(expr.getE2());
return null;
}
@Override
public T caseExprUnary(ExprUnary expr) {
doSwitch(expr.getExpr());
return null;
}
@Override
public T caseInstAssign(InstAssign assign) {
if (visitFull) {
doSwitch(assign.getValue());
}
return null;
}
@Override
public T caseInstCall(InstCall call) {
if (visitFull) {
for (Arg arg : call.getArguments()) {
doSwitch(arg);
}
}
return null;
}
@Override
public T caseInstLoad(InstLoad load) {
if (visitFull) {
for (Expression expr : load.getIndexes()) {
doSwitch(expr);
}
}
return null;
}
@Override
public T caseInstPhi(InstPhi phi) {
if (visitFull) {
for (Expression expr : phi.getValues()) {
doSwitch(expr);
}
}
return null;
}
@Override
public T caseInstReturn(InstReturn returnInstr) {
if (visitFull) {
Expression expr = returnInstr.getValue();
if (expr != null) {
doSwitch(expr);
}
}
return null;
}
@Override
public T caseInstStore(InstStore store) {
if (visitFull) {
for (Expression expr : store.getIndexes()) {
doSwitch(expr);
}
doSwitch(store.getValue());
}
return null;
}
@Override
public T caseProcedure(Procedure procedure) {
this.procedure = procedure;
return doSwitch(procedure.getBlocks());
}
@Override
public final T doSwitch(EObject eObject) {
if (eObject == null) {
return null;
}
return doSwitch(eObject.eClass(), eObject);
}
/**
* Visits each block of the given block list.
*
* @param blocks
* a list of blocks that belong to a procedure
*/
public T doSwitch(List<Block> blocks) {
return visitBlocks(blocks);
}
@Override
public boolean isSwitchFor(EPackage ePackage) {
// just so we can use it in DfVisitor
return super.isSwitchFor(ePackage);
}
/**
* Visits each block of the given block list.
*
* @param blocks
* a list of blocks that belong to a procedure
*/
public T visitBlocks(List<Block> blocks) {
int oldIndexBlock = indexBlock;
T result = null;
for (indexBlock = 0; indexBlock < blocks.size() && result == null; indexBlock++) {
Block block = blocks.get(indexBlock);
result = doSwitch(block);
}
indexBlock = oldIndexBlock;
return result;
}
/**
* Visits each block of the given block list in the reverse order.
*
* @param blocks
* a list of blocks that belong to a procedure
*/
public T visitBlocksReverse(List<Block> blocks) {
int oldIndexBlock = indexBlock;
T result = null;
for (indexBlock = blocks.size() - 1; indexBlock >= 0 && result == null; indexBlock--) {
Block block = blocks.get(indexBlock);
result = doSwitch(block);
}
indexBlock = oldIndexBlock;
return result;
}
/**
* Visits the given list of instructions.
*
* @param instructions
* a list of instructions
* @return a result
*/
public T visitInstructions(List<Instruction> instructions) {
int oldIndexInst = indexInst;
T result = null;
for (indexInst = 0; indexInst < instructions.size() && result == null; indexInst++) {
Instruction inst = instructions.get(indexInst);
result = doSwitch(inst);
}
// restore old index
indexInst = oldIndexInst;
return result;
}
/**
* Visits the given list of instructions in the reverse order.
*
* @param instructions
* a list of instructions
* @return a result
*/
public T visitInstructionsReverse(List<Instruction> instructions) {
int oldIndexInst = indexInst;
T result = null;
for (indexInst = instructions.size() - 1; indexInst >= 0
&& result == null; indexInst--) {
Instruction inst = instructions.get(indexInst);
result = doSwitch(inst);
}
// restore old index
indexInst = oldIndexInst;
return result;
}
}