/* * Copyright (c) 2010, 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.backends.transform; import java.util.ArrayList; import java.util.List; import net.sf.orcc.df.Action; import net.sf.orcc.df.Actor; import net.sf.orcc.df.util.DfVisitor; import net.sf.orcc.ir.Block; import net.sf.orcc.ir.BlockBasic; import net.sf.orcc.ir.BlockIf; import net.sf.orcc.ir.ExprBinary; import net.sf.orcc.ir.Expression; import net.sf.orcc.ir.InstAssign; import net.sf.orcc.ir.InstCall; import net.sf.orcc.ir.InstReturn; import net.sf.orcc.ir.IrFactory; import net.sf.orcc.ir.OpBinary; import net.sf.orcc.ir.Procedure; import net.sf.orcc.ir.Var; import net.sf.orcc.ir.util.AbstractIrVisitor; import net.sf.orcc.ir.util.IrUtil; import net.sf.orcc.ir.util.ValueUtil; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.util.EcoreUtil; /** * This class defines a visitor that transforms a division and a modulo into an * equivalent hardware compilable function specified in xilinx division model * * @author Khaled Jerbi * @author Herve Yviquel * @author Endri Bezati * */ public class DivisionSubstitution extends DfVisitor<Void> { private IrFactory factory = IrFactory.eINSTANCE; private Procedure divProc; private class Substitutor extends AbstractIrVisitor<Object> { public Substitutor() { super(true); } @Override public Object caseExprBinary(ExprBinary expr) { super.caseExprBinary(expr); boolean toShift = false; // int pow = 0; if (expr.getOp() == OpBinary.DIV) { // check the second operand if pow2 toshift =1 else 0 /* * if (expr.getE2().isExprInt()) { ExprInt scndOperand = * (ExprInt) expr.getE2(); int x = scndOperand.getIntValue(); * pow = closestPow_2(x); if (pow == x){ toShift =true; }else{ * toShift = false; } } */ if (ValueUtil.isPowerOfTwo(expr.getE2())) { toShift = true; } else { toShift = false; } if (toShift == false) { if (divProc == null) { divProc = createDivProc(); } // what ever the expression type of division operands they // are // put in local variables VarNum and varDenum the result of // callInst is put in result Var varNum = procedure.newTempLocalVariable( factory.createTypeInt(16), "num"); Var varDenum = procedure.newTempLocalVariable( factory.createTypeInt(16), "den"); Var varResult = procedure.newTempLocalVariable( factory.createTypeInt(16), "result"); InstAssign assign0 = factory.createInstAssign(varNum, expr.getE1()); InstAssign assign1 = factory.createInstAssign(varDenum, expr.getE2()); List<Expression> parameters = new ArrayList<Expression>(); parameters.add(factory.createExprVar(varNum)); parameters.add(factory.createExprVar(varDenum)); InstCall call = factory.createInstCall(varResult, divProc, parameters); IrUtil.addInstBeforeExpr(expr, assign0); IrUtil.addInstBeforeExpr(expr, assign1); IrUtil.addInstBeforeExpr(expr, call); EcoreUtil.replace(expr, factory.createExprVar(varResult)); } } else if (expr.getOp() == OpBinary.MOD) { // Replace the modulo by the naive operation of // mod(num, den) = num - den*(num/den) if (ValueUtil.isPowerOfTwo(expr.getE2())) { toShift = true; } else { toShift = false; } if (toShift == false) { if (divProc == null) { divProc = createDivProc(); } Var varNum = procedure.newTempLocalVariable( factory.createTypeInt(16), "num_mod"); Var varDenum = procedure.newTempLocalVariable( factory.createTypeInt(16), "den_mod"); Var varDivResult = procedure.newTempLocalVariable( factory.createTypeInt(16), "divResult_mod"); InstAssign assign0 = factory.createInstAssign(varNum, expr.getE1()); InstAssign assign1 = factory.createInstAssign(varDenum, expr.getE2()); List<Expression> parameters = new ArrayList<Expression>(); parameters.add(factory.createExprVar(varNum)); parameters.add(factory.createExprVar(varDenum)); InstCall call = factory.createInstCall(varDivResult, divProc, parameters); Var varResult = procedure.newTempLocalVariable( factory.createTypeInt(16), "result_mod"); ExprBinary exprDenumMultDiv = factory.createExprBinary( factory.createExprVar(varDenum), OpBinary.TIMES, factory.createExprVar(varDivResult), factory.createTypeInt(16)); InstAssign assign2 = factory.createInstAssign(varResult, factory.createExprBinary( factory.createExprVar(varNum), OpBinary.MINUS, exprDenumMultDiv, factory.createTypeInt(16))); IrUtil.addInstBeforeExpr(expr, assign0); IrUtil.addInstBeforeExpr(expr, assign1); IrUtil.addInstBeforeExpr(expr, call); IrUtil.addInstBeforeExpr(expr, assign2); EcoreUtil.replace(expr, factory.createExprVar(varResult)); } } toShift = false; return null; } /** * This method creates the alternative division function using the num * and the denom * * @param varNum * numerator * @param varDenum * denumerator * @return division function */ private Procedure createDivProc() { Procedure divProc = factory.createProcedure("DIV_II", 0, factory.createTypeInt()); // Create parameters Var varNum = factory.createVarInt("num", true, 0); varNum.setType(factory.createTypeInt(16)); Var varDenum = factory.createVarInt("den", true, 0); varDenum.setType(factory.createTypeInt(16)); divProc.getParameters().add(factory.createParam(varNum)); divProc.getParameters().add(factory.createParam(varDenum)); // Create needed local variables Var result = divProc.newTempLocalVariable( factory.createTypeInt(16), "result"); Var i = divProc.newTempLocalVariable(factory.createTypeInt(), "i"); Var flipResult = divProc.newTempLocalVariable( factory.createTypeInt(), "flipResult"); Var denom = divProc.newTempLocalVariable(factory.createTypeInt(), "denom"); Var numer = divProc.newTempLocalVariable(factory.createTypeInt(), "numer"); Var mask = divProc.newTempLocalVariable(factory.createTypeInt(), "mask"); Var remainder = divProc.newTempLocalVariable( factory.createTypeInt(16), "remainder"); // Create procedural code EList<Block> blocks = divProc.getBlocks(); blocks.add(createInitBlock(result, flipResult, denom, numer, mask, remainder)); blocks.add(createBlockIf(varNum, flipResult)); blocks.add(createBlockIf(varDenum, flipResult)); blocks.add(createAssignmentBlock(varDenum, remainder, varNum, denom, mask, i)); for (int k = 0; k < 16; k++) { createRepeatBlock(blocks, k, numer, remainder, denom, result, mask, varDenum); } blocks.add(createResultBlockIf(flipResult, result)); // Create return instruction BlockBasic blockReturn = factory.createBlockBasic(); InstReturn instReturn = factory.createInstReturn(factory .createExprVar(result)); blockReturn.add(instReturn); divProc.setReturnType(factory.createTypeInt(16)); divProc.getBlocks().add(blockReturn); return divProc; } private BlockBasic createAssignmentBlock(Var varDenum, Var remainder, Var varNum, Var denom, Var mask, Var i) { BlockBasic block = factory.createBlockBasic(); Expression blk11And = factory.createExprBinary( factory.createExprVar(varDenum), OpBinary.BITAND, factory.createExprInt(0x0000FFFF), factory.createTypeInt()); block.add(factory.createInstAssign(remainder, varNum)); block.add(factory.createInstAssign(denom, blk11And)); block.add(factory.createInstAssign(mask, 0x8000)); block.add(factory.createInstAssign(i, 0)); return block; } /** * this method creates an initializing instructions for result and * flipResult variables to zero * * @param result * to be initialized to zero * @param flipResult * to be initialized to zero * @return a basic block with initialization assigns */ private BlockBasic createInitBlock(Var result, Var flipResult, Var denom, Var numer, Var mask, Var remainder) { BlockBasic initBlock = factory.createBlockBasic(); initBlock.add(factory.createInstAssign(result, 0)); initBlock.add(factory.createInstAssign(flipResult, 0)); initBlock.add(factory.createInstAssign(denom, 0)); initBlock.add(factory.createInstAssign(numer, 0)); initBlock.add(factory.createInstAssign(mask, 0)); initBlock.add(factory.createInstAssign(remainder, 0)); return initBlock; } /** * creates the following if block: if (var < 0) var = -var; flip ^= 1; * * @param var * (see definition) * @param flip * (see definition) * @return if block */ private BlockIf createBlockIf(Var var, Var flip) { BlockIf blockIf = factory.createBlockIf(); BlockBasic blockIf_1 = factory.createBlockBasic(); Expression conditionIf_1 = factory.createExprBinary( factory.createExprVar(var), OpBinary.LT, factory.createExprInt(0), factory.createTypeBool()); blockIf.setCondition(conditionIf_1); BlockBasic join = factory.createBlockBasic(); blockIf.setJoinBlock(join); Expression oppNomerator = factory.createExprBinary( factory.createExprInt(0), OpBinary.MINUS, factory.createExprVar(var), factory.createTypeInt()); InstAssign assign10 = factory.createInstAssign(var, oppNomerator); blockIf_1.add(assign10); Expression xorFlip = factory.createExprBinary( factory.createExprVar(flip), OpBinary.BITXOR, factory.createExprInt(1), factory.createTypeInt()); InstAssign assign11 = factory.createInstAssign(flip, xorFlip); blockIf_1.add(assign11); blockIf.getThenBlocks().add(blockIf_1); BlockBasic blockIf_2 = factory.createBlockBasic(); InstAssign assign20 = factory.createInstAssign(var, var); blockIf_2.add(assign20); InstAssign assign21 = factory.createInstAssign(flip, flip); blockIf_2.add(assign21); blockIf.getElseBlocks().add(blockIf_2); return blockIf; } /** * creates the required if block specified in the xilinx division model * * @param numer * @param denom * @param result * @param mask * @param remainder * @param varDenum * @param i * @return if block */ private BlockIf createBlockIfRepeatBlock(Var numer, Var denom, Var result, Var mask, Var remainder, Var varDenum, int k) { BlockIf blockIf = factory.createBlockIf(); Expression condition = factory.createExprBinary( factory.createExprVar(numer), OpBinary.GE, factory.createExprVar(denom), factory.createTypeBool()); blockIf.setCondition(condition); BlockBasic join = factory.createBlockBasic(); blockIf.setJoinBlock(join); BlockBasic basic = factory.createBlockBasic(); Expression orExpr = factory.createExprBinary( factory.createExprVar(result), OpBinary.BITOR, factory.createExprVar(mask), factory.createTypeInt()); InstAssign assignBlk_0 = factory.createInstAssign(result, orExpr); basic.add(assignBlk_0); Expression minusExpr = factory.createExprBinary( factory.createExprInt(15), OpBinary.MINUS, factory.createExprInt(k), factory.createTypeInt()); Expression lShiftExpr = factory.createExprBinary( factory.createExprVar(varDenum), OpBinary.SHIFT_LEFT, minusExpr, factory.createTypeInt()); Expression RemainderMinus = factory.createExprBinary( factory.createExprVar(remainder), OpBinary.MINUS, lShiftExpr, factory.createTypeInt()); InstAssign assignBlk_1 = factory.createInstAssign(remainder, RemainderMinus); basic.add(assignBlk_1); blockIf.getThenBlocks().add(basic); return blockIf; } /** * returns the required while block Specified in the xilinx division * model * * @param i * @param numer * @param remainder * @param denom * @param result * @param mask * @param varDenum * @return */ private void createRepeatBlock(EList<Block> blocks, int k, Var numer, Var remainder, Var denom, Var result, Var mask, Var varDenum) { BlockBasic basic0 = factory.createBlockBasic(); BlockBasic basic1 = factory.createBlockBasic(); Expression andExpr = factory.createExprBinary( factory.createExprVar(remainder), OpBinary.BITAND, factory.createExprInt(0x0000FFFF), factory.createTypeInt()); Expression minusExpr = factory.createExprBinary( factory.createExprInt(15), OpBinary.MINUS, factory.createExprInt(k), factory.createTypeInt()); Expression shiftExpr = factory.createExprBinary(andExpr, OpBinary.SHIFT_RIGHT, minusExpr, factory.createTypeInt()); InstAssign assignBlk_0 = factory.createInstAssign(numer, shiftExpr); basic0.add(assignBlk_0); blocks.add(basic0); BlockIf nodeIf = createBlockIfRepeatBlock(numer, denom, result, mask, remainder, varDenum, k); blocks.add(nodeIf); Expression maskShift = factory.createExprBinary( factory.createExprVar(mask), OpBinary.SHIFT_RIGHT, factory.createExprInt(1), factory.createTypeInt()); Expression assignBlk_1Value = factory.createExprBinary(maskShift, OpBinary.BITAND, factory.createExprInt(0x7FFFFFFF), factory.createTypeInt()); InstAssign assignBlk_10 = factory.createInstAssign(mask, assignBlk_1Value); basic1.add(assignBlk_10); blocks.add(basic1); } /** * returns an if block if (flipResult != 0) { result = -result; } * * @param flipResult * (see definition) * @param result * (see definition) * @return If block (see definition) */ private BlockIf createResultBlockIf(Var flipResult, Var result) { BlockIf blockIf = factory.createBlockIf(); BlockBasic blockIf_1 = factory.createBlockBasic(); Expression conditionIf = factory.createExprBinary( factory.createExprVar(flipResult), OpBinary.NE, factory.createExprInt(0), factory.createTypeBool()); blockIf.setCondition(conditionIf); BlockBasic join = factory.createBlockBasic(); blockIf.setJoinBlock(join); Expression oppflip = factory.createExprBinary( factory.createExprInt(0), OpBinary.MINUS, factory.createExprVar(result), factory.createTypeInt()); InstAssign assign10 = factory.createInstAssign(result, oppflip); blockIf_1.add(assign10); blockIf.getThenBlocks().add(blockIf_1); return blockIf; } } @Override public Void caseActor(Actor actor) { this.actor = actor; divProc = null; checkDiv(); if (divProc != null) { actor.getProcs().add(0, divProc); } return null; } public void checkDiv() { List<Action> actions = new ArrayList<Action>(actor.getActions()); for (Action verifAction : actions) { Substitutor substitutor = new Substitutor(); substitutor.doSwitch(verifAction.getBody()); substitutor.doSwitch(verifAction.getScheduler()); } for (Procedure proc : actor.getProcs()) { Substitutor substitutor = new Substitutor(); substitutor.doSwitch(proc); } } }