/* * Copyright (c) 2010, EPFL * 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 EPFL 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.tools.merger.actor; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import net.sf.orcc.df.Action; import net.sf.orcc.df.Actor; import net.sf.orcc.df.Connection; import net.sf.orcc.df.Network; import net.sf.orcc.df.Pattern; import net.sf.orcc.df.Port; import net.sf.orcc.ir.Block; import net.sf.orcc.ir.BlockBasic; import net.sf.orcc.ir.BlockWhile; import net.sf.orcc.ir.Def; import net.sf.orcc.ir.ExprBinary; import net.sf.orcc.ir.Expression; import net.sf.orcc.ir.InstAssign; import net.sf.orcc.ir.InstLoad; import net.sf.orcc.ir.InstReturn; import net.sf.orcc.ir.InstStore; import net.sf.orcc.ir.OpBinary; import net.sf.orcc.ir.Procedure; import net.sf.orcc.ir.Type; import net.sf.orcc.ir.Use; import net.sf.orcc.ir.Var; import net.sf.orcc.ir.util.AbstractIrVisitor; import net.sf.orcc.ir.util.IrUtil; import net.sf.orcc.moc.CSDFMoC; import net.sf.orcc.moc.MocFactory; import net.sf.orcc.moc.SDFMoC; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.EcoreUtil.Copier; /** * This class defines the transformation from a network of SDF actors into a * single cluster actor. * * @author Ghislain Roquier * @author Herve Yviquel * */ public class ActorMergerSDF extends ActorMergerBase { SASLoopScheduler scheduler; private int depth; private Map<Port, Port> portsMap = new HashMap<Port, Port>(); protected Pattern inputPattern; protected Pattern outputPattern; /** * This class defines a transformation to update the FIFO accesses. * * @author Ghislain Roquier * */ public class ActionUpdater extends AbstractIrVisitor<Void> { private Procedure body; private Map<Var, Integer> loads; private Pattern oldInputPattern; private Pattern oldOutputPattern; private Map<Var, Integer> stores; /** * Create a new visitor able to update the FIFO accesses. * * @param action * the action containing the old patterns * @param body * the procedure to update */ public ActionUpdater(Action action, Procedure body) { this.body = body; this.oldInputPattern = action.getInputPattern(); this.oldOutputPattern = action.getOutputPattern(); } @Override public Void caseInstLoad(InstLoad load) { Use use = load.getSource(); Var var = use.getVariable(); Port port = oldInputPattern.getPort(var); if (port != null) { if (buffersMap.containsKey(port)) { var = buffersMap.get(port); } else { var = inputPattern.getVariable(portsMap.get(port)); } int cns = oldInputPattern.getNumTokens(port); loads.put(var, cns); use.setVariable(var); List<Expression> indexes = load.getIndexes(); Expression e1 = irFactory.createExprVar(body.getLocal(var .getName() + "_r")); Expression e2 = IrUtil.copy(indexes.get(0)); Expression bop = irFactory.createExprBinary(e1, OpBinary.PLUS, e2, e1.getType()); indexes.set(0, bop); } return null; } @Override public Void caseInstReturn(InstReturn inst) { IrUtil.delete(inst); indexInst--; return null; } @Override public Void caseInstStore(InstStore store) { Def def = store.getTarget(); Var var = def.getVariable(); Port port = oldOutputPattern.getPort(var); if (port != null) { if (buffersMap.containsKey(port)) { var = buffersMap.get(port); } else { var = outputPattern.getVariable(portsMap.get(port)); } int prd = oldOutputPattern.getNumTokens(port); stores.put(var, prd); def.setVariable(var); Expression e1 = irFactory.createExprVar(body.getLocal(var .getName() + "_w")); Expression e2 = IrUtil.copy(store.getIndexes().get(0)); Expression bop = irFactory.createExprBinary(e1, OpBinary.PLUS, e2, e1.getType()); store.getIndexes().set(0, bop); } port = oldInputPattern.getPort(var); if (port != null) { if (buffersMap.containsKey(port)) { var = buffersMap.get(port); } else { var = inputPattern.getPortToVarMap() .get(portsMap.get(port)); } int cns = oldInputPattern.getNumTokens(port); stores.put(var, cns); def.setVariable(var); Expression e1 = irFactory.createExprVar(body.getLocal(var .getName() + "_r")); Expression e2 = IrUtil.copy(store.getIndexes().get(0)); Expression bop = irFactory.createExprBinary(e1, OpBinary.PLUS, e2, e1.getType()); store.getIndexes().set(0, bop); } return null; } @Override public Void caseProcedure(Procedure procedure) { loads = new HashMap<Var, Integer>(); stores = new HashMap<Var, Integer>(); super.caseProcedure(procedure); // Update indexes for (Map.Entry<Var, Integer> entry : loads.entrySet()) { Var var = entry.getKey(); int cns = entry.getValue(); Var readVar = body.getLocal(var.getName() + "_r"); ExprBinary incr = irFactory.createExprBinary( irFactory.createExprVar(readVar), OpBinary.PLUS, irFactory.createExprInt(cns), readVar.getType()); InstAssign assign = irFactory.createInstAssign(readVar, incr); procedure.getLast().add(assign); } for (Map.Entry<Var, Integer> entry : stores.entrySet()) { Var var = entry.getKey(); int prd = entry.getValue(); Var readVar = body.getLocal(var.getName() + "_w"); ExprBinary incr = irFactory.createExprBinary( irFactory.createExprVar(readVar), OpBinary.PLUS, irFactory.createExprInt(prd), readVar.getType()); InstAssign assign = irFactory.createInstAssign(readVar, incr); procedure.getLast().add(assign); } return null; } } /** * Creates a new merger for connected SDF actor. * * @param scheduler * the pre-initialized single appearance schedule * @param copier * the associated copier */ public ActorMergerSDF(SASLoopScheduler scheduler, Copier copier) { this.scheduler = scheduler; this.copier = copier; } @Override public Actor caseNetwork(Network network) { superActor = dfFactory.createActor(); buffersMap = new HashMap<Port, Var>(); portsMap = new HashMap<Port, Port>(); superActor.setName(network.getName()); SDFMoC sdfMoC = MocFactory.eINSTANCE.createSDFMoC(); superActor.setMoC(sdfMoC); // Create input/output ports for (Port port : network.getInputs()) { Port portCopy = (Port) copier.copy(port); Connection connection = (Connection) port.getOutgoing().get(0); Actor tgt = connection.getTarget().getAdapter(Actor.class); CSDFMoC moc = (CSDFMoC) tgt.getMoC(); int cns = scheduler.getRepetitions(tgt) * moc.getNumTokensConsumed(connection.getTargetPort()); sdfMoC.getInputPattern().setNumTokens(portCopy, cns); superActor.getInputs().add(portCopy); portsMap.put(connection.getTargetPort(), portCopy); } for (Port port : network.getOutputs()) { Port portCopy = (Port) copier.copy(port); Connection connection = (Connection) port.getIncoming().get(0); Actor src = connection.getSource().getAdapter(Actor.class); CSDFMoC moc = (CSDFMoC) src.getMoC(); int prd = scheduler.getRepetitions(src) * moc.getNumTokensProduced(connection.getSourcePort()); sdfMoC.getOutputPattern().setNumTokens(portCopy, prd); superActor.getOutputs().add(portCopy); portsMap.put(connection.getSourcePort(), portCopy); } copyVariables(network); copyProcedures(network); // Create the merged action inputPattern = dfFactory.createPattern(); for (Port port : superActor.getInputs()) { int numTokens = sdfMoC.getNumTokensConsumed(port); Type type = irFactory.createTypeList(numTokens, EcoreUtil.copy(port.getType())); Var var = irFactory.createVar(0, type, port.getName(), true); inputPattern.setNumTokens(port, numTokens); inputPattern.setVariable(port, var); } outputPattern = dfFactory.createPattern(); for (Port port : superActor.getOutputs()) { int numTokens = sdfMoC.getNumTokensProduced(port); Type type = irFactory.createTypeList(numTokens, EcoreUtil.copy(port.getType())); Var var = irFactory.createVar(0, type, port.getName(), true); outputPattern.setNumTokens(port, numTokens); outputPattern.setVariable(port, var); } Pattern peekPattern = dfFactory.createPattern(); Procedure isSchedulable = irFactory.createProcedure( "isSchedulable_mergedAction", 0, irFactory.createTypeBool()); isSchedulable.getLast().add( irFactory.createInstReturn(irFactory.createExprBool(true))); Procedure body = irFactory.createProcedure("mergedAction", 0, irFactory.createTypeVoid()); createCounters(body); createBuffers(body, scheduler.getMaxTokens(), true); createLoopCounters(body, scheduler.getDepth()); createStaticSchedule(body, (Schedule) scheduler.getSchedule(), body.getBlocks()); body.getLast().add(irFactory.createInstReturn()); Action action = dfFactory.createAction("mergedAction", inputPattern, outputPattern, peekPattern, isSchedulable, body); superActor.getActions().add(action); superActor.getActionsOutsideFsm().add(action); return superActor; } private void createLoopCounters(Procedure body, int scheduleDepth) { // Add loop counter(s) int i = 0; do { // one loop var is required even if the schedule as a depth of 0 body.newTempLocalVariable(irFactory.createTypeInt(32), "idx_" + i); i++; } while (i < scheduleDepth); } private void createCounters(Procedure body) { BlockBasic block = body.getLast(); // Create counters for inputs for (Port port : superActor.getInputs()) { Var readIdx = body.newTempLocalVariable( irFactory.createTypeInt(32), port.getName() + "_r"); block.add(irFactory.createInstAssign(readIdx, irFactory.createExprInt(0))); } // Create counters for outputs for (Port port : superActor.getOutputs()) { Var writeIdx = body.newTempLocalVariable( irFactory.createTypeInt(32), port.getName() + "_w"); block.add(irFactory.createInstAssign(writeIdx, irFactory.createExprInt(0))); } } /** * Create the procedural code of a static schedule. * * @param procedure * the associated procedure * @param schedule * the current schedule * @param blocks * the current list of blocks */ private void createStaticSchedule(Procedure procedure, Schedule schedule, List<Block> blocks) { for (Iterand iterand : schedule.getIterands()) { if (iterand.isAction()) { Action action = IrUtil.copy(iterand.getAction()); // Copy local variable for (Var var : new ArrayList<Var>(action.getBody().getLocals())) { procedure.addLocal(var); } new ActionUpdater(action, procedure).doSwitch(action.getBody()); blocks.addAll(action.getBody().getBlocks()); } else { Schedule sched = iterand.getSchedule(); Var loopVar = procedure.getLocal("idx_" + depth); // init counter BlockBasic block = IrUtil.getLast(blocks); block.add(irFactory.createInstAssign(loopVar, irFactory.createExprInt(0))); // while loop Expression condition = irFactory.createExprBinary( irFactory.createExprVar(loopVar), OpBinary.LT, irFactory.createExprInt(sched.getIterationCount()), irFactory.createTypeBool()); BlockWhile blockWhile = irFactory.createBlockWhile(); blockWhile.setJoinBlock(irFactory.createBlockBasic()); blockWhile.setCondition(condition); blocks.add(blockWhile); depth++; // recursion createStaticSchedule(procedure, sched, blockWhile.getBlocks()); depth--; // Increment current while loop variable Expression expr = irFactory .createExprBinary(irFactory.createExprVar(loopVar), OpBinary.PLUS, irFactory.createExprInt(1), irFactory.createTypeInt(32)); InstAssign assign = irFactory.createInstAssign(loopVar, expr); IrUtil.getLast(blockWhile.getBlocks()).add(assign); } } } }