/*
* Copyright (c) 2013, University of Rennes 1 / IRISA
* 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 University of Rennes 1 / IRISA 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.backends.transform;
import java.util.List;
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.ExprBool;
import net.sf.orcc.ir.ExprFloat;
import net.sf.orcc.ir.ExprInt;
import net.sf.orcc.ir.ExprList;
import net.sf.orcc.ir.ExprString;
import net.sf.orcc.ir.ExprUnary;
import net.sf.orcc.ir.ExprVar;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.InstAssign;
import net.sf.orcc.ir.Instruction;
import net.sf.orcc.ir.IrFactory;
import net.sf.orcc.ir.OpBinary;
import net.sf.orcc.ir.Var;
import net.sf.orcc.ir.util.AbstractIrVisitor;
import net.sf.orcc.ir.util.IrUtil;
import net.sf.orcc.util.util.EcoreHelper;
import org.eclipse.emf.ecore.util.EcoreUtil;
/**
*
*
* @author Herve Yviquel
*
*/
public class ShortCircuitTransformation extends AbstractIrVisitor<Expression> {
private static IrFactory factory = IrFactory.eINSTANCE;
public ShortCircuitTransformation() {
super(true);
}
@Override
public Expression caseExprBinary(ExprBinary expr) {
// visit both branches
expr.setE1(doSwitch(expr.getE1()));
expr.setE2(doSwitch(expr.getE2()));
if (isEvaluableShortly(expr.getOp())) {
Var newVar = procedure.newTempLocalVariable(
IrUtil.copy(expr.getType()), "sc_expr");
ExprVar newExpr = factory.createExprVar(newVar);
// Binary expression is split into several BlockIf blocks
BlockIf newIf = factory.createBlockIf();
BlockBasic join = factory.createBlockBasic();
newIf.setJoinBlock(join);
Instruction containingInst = EcoreHelper.getContainerOfType(expr,
Instruction.class);
Block containingBlock = EcoreHelper.getContainerOfType(expr,
Block.class);
// In all cases, the transformation block is added before the expression location
IrUtil.addBlockBeforeExpr(expr, newIf);
newIf.setCondition(expr.getE1());
BlockBasic blockTrue = factory.createBlockBasic();
InstAssign assignTrue = factory.createInstAssign();
assignTrue.setTarget(factory.createDef(newVar));
blockTrue.add(assignTrue);
newIf.getThenBlocks().add(blockTrue);
BlockBasic blockFalse = factory.createBlockBasic();
InstAssign assignFalse = factory.createInstAssign();
assignFalse.setTarget(factory.createDef(newVar));
blockFalse.add(assignFalse);
newIf.getElseBlocks().add(blockFalse);
if (expr.getOp() == OpBinary.LOGIC_AND) {
assignTrue.setValue(expr.getE2());
assignFalse.setValue(factory.createExprBool(false));
} else if (expr.getOp() == OpBinary.LOGIC_OR) {
assignTrue.setValue(factory.createExprBool(true));
assignFalse.setValue(expr.getE2());
}
// If the expression is contained in the condition of a BlockWhile,
// the transformation block is also put at the end of this BlockWhile
if (containingInst == null && containingBlock.isBlockWhile()) {
List<Block> whileBlocks = ((BlockWhile) containingBlock)
.getBlocks();
whileBlocks.add(IrUtil.copy(newIf));
}
EcoreUtil.replace(expr, newExpr);
IrUtil.delete(expr);
return newExpr;
}
return expr;
}
@Override
public Expression caseExprBool(ExprBool expr) {
return expr;
}
@Override
public Expression caseExprFloat(ExprFloat expr) {
return expr;
}
@Override
public Expression caseExprInt(ExprInt expr) {
return expr;
}
@Override
public Expression caseExprList(ExprList expr) {
return expr;
}
@Override
public Expression caseExprString(ExprString expr) {
return expr;
}
@Override
public Expression caseExprUnary(ExprUnary expr) {
expr.setExpr(doSwitch(expr.getExpr()));
return expr;
}
@Override
public Expression caseExprVar(ExprVar expr) {
return expr;
}
private boolean isEvaluableShortly(OpBinary op) {
return op == OpBinary.LOGIC_AND || op == OpBinary.LOGIC_OR;
}
}