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.Network; import net.sf.orcc.df.Port; import net.sf.orcc.df.Connection; import net.sf.orcc.df.FSM; import net.sf.orcc.df.Pattern; import net.sf.orcc.graph.Vertex; import net.sf.orcc.ir.Block; import net.sf.orcc.ir.BlockBasic; import net.sf.orcc.ir.BlockWhile; import net.sf.orcc.ir.Expression; import net.sf.orcc.ir.InstAssign; import net.sf.orcc.ir.InstLoad; import net.sf.orcc.ir.InstStore; import net.sf.orcc.ir.Instruction; import net.sf.orcc.ir.OpBinary; import net.sf.orcc.ir.Procedure; import net.sf.orcc.ir.Type; import net.sf.orcc.ir.Var; import net.sf.orcc.ir.Param; import net.sf.orcc.ir.util.AbstractIrVisitor; import net.sf.orcc.ir.util.IrUtil; import net.sf.orcc.util.OrccLogger; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.EcoreUtil.Copier; /** * This class merges actors based on a merging specification in * an XML file. The class is analogous to ActorMergerSDF. * * @author Jani Boutellier * @author Ghislain Roquier * */ public class ActorMergerQS extends ActorMergerBase { private Network network; private List<Schedule> scheduleList; private List<Action> guardList; public class ActionUpdater extends AbstractIrVisitor<Void> { private Pattern oldInputPattern; private Pattern oldOutputPattern; /** * Create a new visitor able to update the FIFO accesses. * * @param action * the action containing the old patterns */ public ActionUpdater(Action action) { this.oldInputPattern = action.getInputPattern(); this.oldOutputPattern = action.getOutputPattern(); } @Override public Void caseInstLoad(InstLoad load) { Port port = oldInputPattern.getPort(load.getSource().getVariable()); if (port != null) { List<Expression> indexes = load.getIndexes(); String portName = port.getAttribute("shortName").getStringValue(); Expression e1 = irFactory.createExprVar(irFactory.createVar(irFactory.createTypeInt(32), "offset_" + portName, false, 0)); Expression e2 = IrUtil.copy(indexes.get(0)); Expression bop = irFactory.createExprBinary(e1, OpBinary.PLUS, e2, e1.getType()); if (!buffersMap.containsKey(port)) { indexes.set(0, bop); } else if (port.hasAttribute("externalized")) { int size = buffersMap.get(port).getType().getDimensions().get(0); indexes.set(0, irFactory.createExprBinary(bop, OpBinary.MOD, irFactory.createExprInt(size), e1.getType())); } else { indexes.set(0, bop); } } return null; } @Override public Void caseInstStore(InstStore store) { Port port = oldOutputPattern.getPort(store.getTarget().getVariable()); if (port != null) { List<Expression> indexes = store.getIndexes(); String portName = port.getAttribute("shortName").getStringValue(); Expression e1 = irFactory.createExprVar(irFactory.createVar(irFactory.createTypeInt(32), "offset_" + portName, false, 0)); Expression e2 = IrUtil.copy(indexes.get(0)); Expression bop = irFactory.createExprBinary(e1, OpBinary.PLUS, e2, e1.getType()); if (!buffersMap.containsKey(port)) { indexes.set(0, bop); } else if (port.hasAttribute("externalized")) { int size = buffersMap.get(port).getType().getDimensions().get(0); indexes.set(0, irFactory.createExprBinary(bop, OpBinary.MOD, irFactory.createExprInt(size), e1.getType())); } else { indexes.set(0, bop); } } return null; } @Override public Void caseProcedure(Procedure procedure) { super.caseProcedure(procedure); return null; } } private class ActionProcedureMap { private class ActionProcedurePair { Procedure procedure; Action action; ActionProcedurePair(Action action, Procedure procedure) { this.action = action; this.procedure = procedure; } Action getAction() { return action; } Procedure getProcedure() { return procedure; } } private List<ActionProcedurePair> list; /** * Keep track of actions that have been transformed to procedures. * */ public ActionProcedureMap() { this.list = new ArrayList<ActionProcedurePair>(); } public void add(Action action, Procedure procedure) { list.add(new ActionProcedurePair(action, procedure)); } public Procedure getProcedure(Action action) { for (ActionProcedurePair pair : list) { if (pair.getAction().equals(action)) { return pair.getProcedure(); } } return null; } } ActionProcedureMap correspondences; public ActorMergerQS(Network network, Copier copier, String definitionFile, List<Schedule> scheduleList, List<Action> guardList) { this.network = network; this.copier = copier; this.correspondences = new ActionProcedureMap(); this.scheduleList = scheduleList; this.guardList = guardList; } public Actor createMergedActor(Actor actor, FSM fsm) { superActor = actor; buffersMap = new HashMap<Port, Var>(); superActor.setName(network.getName()); superActor.setFsm(fsm); copyPorts(network); copyVariables(network); copyProcedures(network); copyActions(network); createSuperactions(); modifyMemAccesses(network); return superActor; } private void copyPorts(Network network) { // Create input/output ports for (Port port : network.getInputs()) { superActor.getInputs().add((Port)copier.copy(port)); } for (Port port : network.getOutputs()) { superActor.getOutputs().add((Port)copier.copy(port)); } } private void copyAction(String actorName, Action action) { Procedure actionCopy = IrUtil.copy(action.getBody()); actionCopy.setName(new String(actorName + "_" + action.getName() + "_p")); BlockBasic last = actionCopy.getLast(); if(!last.getInstructions().get(last.getInstructions().size() - 1).isInstReturn()) { last.add(irFactory.createInstReturn()); } createParameters(actionCopy, action); correspondences.add(action, actionCopy); superActor.getProcs().add(actionCopy); } private void copyActions(Network network) { for (Vertex vertex : network.getChildren()) { Actor actor = vertex.getAdapter(Actor.class); for (Action action : actor.getActions()) { copyAction(actor.getName(), action); } for (Action action : actor.getInitializes()) { copyAction(actor.getName(), action); } } } private void modifyMemAccesses(Network network) { for (Vertex vertex : network.getChildren()) { Actor actor = vertex.getAdapter(Actor.class); for (Action action : actor.getActions()) { new ActionUpdater(action).doSwitch(correspondences.getProcedure(action)); } } } private void createParameters(Procedure procedure, Action action) { Pattern inputPattern = action.getInputPattern(); for(Port port : inputPattern.getPorts()) { createParameterPair(procedure, inputPattern.getVariable(port)); } Pattern outputPattern = action.getOutputPattern(); for(Port port : outputPattern.getPorts()) { createParameterPair(procedure, outputPattern.getVariable(port)); } } private void createParameterPair(Procedure procedure, Var var) { Param param = irFactory.createParam(var); param.setByRef(true); procedure.getParameters().add(param); param = irFactory.createParam(irFactory.createVar( irFactory.createTypeInt(32), "offset_" + var.getName(), true, 0)); param.setByRef(false); procedure.getParameters().add(param); } private void createSuperactions() { for(Action action : superActor.getActions()) { elaborateSuperaction(action); } } /** * Creates the body of the static action. * * @return the body of the static action */ private void elaborateSuperaction(Action superaction) { boolean useFullFifos = true; if (superActor.hasAttribute("RegisterFeedback")) { useFullFifos = false; } String actionName = superaction.getName(); BufferSizer bufferSizer = new BufferSizer(network); Schedule schedule = getSchedule(scheduleList, network.getName(), actionName); ScheduleAnalyzer analyzer = new ScheduleAnalyzer(network, copier); analyzer.analyze(superActor, schedule); analyzer.markInternalFifos(superActor, useFullFifos); Pattern inputPattern = computeScheduleInputPattern(network, schedule.getIterands()); Pattern outputPattern = computeScheduleOutputPattern(network, schedule.getIterands()); superaction.setInputPattern(inputPattern); superaction.setOutputPattern(outputPattern); superaction.setBody(irFactory.createProcedure(actionName, 0, irFactory.createTypeVoid())); createBuffers(superaction.getBody(), bufferSizer.getMaxTokens(schedule), false); if (!useFullFifos) { createFeedbackBuffers(bufferSizer.getMaxTokens(schedule)); } createPortVarCounters(superaction.getBody(), inputPattern, outputPattern); createInputBufferCopies(superaction.getBody(), inputPattern); createStaticSchedule(superaction.getBody(), schedule); createOutputBufferCopies(superaction.getBody(), outputPattern); superaction.getBody().getLast().add(irFactory.createInstReturn()); Action guard = getGuard(guardList, network.getName(), actionName); superaction.setPeekPattern(guard.getPeekPattern()); superaction.setScheduler(guard.getBody()); } private Schedule getSchedule(List<Schedule> scheduleList, String actorName, String actionName) { for(Schedule schedule : scheduleList) { if (actorName.equals(schedule.getOwner()) && actionName.equals(schedule.getName())) { return schedule; } } OrccLogger.severeln("ActorMergerQS::getSchedule() could not find a schedule for " + actorName + " " + actionName); return null; } private Action getGuard(List<Action> guardList, String actorName, String actionName) { for(Action guard : guardList) { if (actorName.equals(guard.getAttribute("actorName").getStringValue()) && actionName.equals(guard.getAttribute("actionName").getStringValue())) { return guard; } } return null; } private void addToPattern(Pattern pattern, Port port, int count) { if (!pattern.contains(port)) { pattern.getPorts().add(port); } Port superactionPort = pattern.getPorts().get( MergerUtil.findPort(pattern.getPorts(), port.getName())); pattern.setNumTokens(superactionPort, pattern.getNumTokens(superactionPort) + count); } /* * Each superaction instance has an input and output pattern * that is visible to the actors neighboring its superactor. * The pattern need to be determined from the invocations. */ public Pattern computeScheduleInputPattern(Network subNetwork, List<Iterand> invocations) { Pattern inputPattern = dfFactory.createPattern(); for (Iterand iterand : invocations) { Pattern iterandPattern = iterand.getAction().getInputPattern(); for (Port port : iterandPattern.getPorts()) { if (MergerUtil.findPort(subNetwork.getInputs(), port.getName()) >= 0) { addToPattern(inputPattern, port, iterandPattern.getNumTokens(port)); } else { int superActorPortIndex = MergerUtil.findPort(superActor.getInputs(), port.getName()); if (superActorPortIndex >= 0) { Port superActorPort = superActor.getInputs().get(superActorPortIndex); if (superActorPort.hasAttribute("externalized")) { addToPattern(inputPattern, port, iterandPattern.getNumTokens(port)); } } } } } return createInputPattern(inputPattern); } public Pattern computeScheduleOutputPattern(Network subNetwork, List<Iterand> invocations) { Pattern outputPattern = dfFactory.createPattern(); for (Iterand iterand : invocations) { Pattern iterandPattern = iterand.getAction().getOutputPattern(); for (Port port : iterandPattern.getPorts()) { if (MergerUtil.findPort(subNetwork.getOutputs(), port.getName()) >= 0) { addToPattern(outputPattern, port, iterandPattern.getNumTokens(port)); } else { int superActorPortIndex = MergerUtil.findPort(superActor.getOutputs(), port.getName()); if (superActorPortIndex >= 0) { Port superActorPort = superActor.getOutputs().get(superActorPortIndex); if (superActorPort.hasAttribute("externalized")) { addToPattern(outputPattern, port, iterandPattern.getNumTokens(port)); } } } } } return createOutputPattern(outputPattern); } private void createFeedbackBuffers(Map<Connection, Integer> maxTokens) { // Create buffers and counters for feedback connections for (Connection conn : maxTokens.keySet()) { if (conn.getSourcePort().hasAttribute("externalized")) { Var buffer = null; if (!conn.hasAttribute("bufferCreated")) { // create actor-level buffer Integer size = conn.getSize(); if (size.intValue() > 0) { String name = "buffer_" + conn.getSourcePort().getName() + "_" + conn.getTargetPort().getName(); Type eltType = conn.getSourcePort().getType(); Type type = irFactory.createTypeList(size, eltType); buffer = irFactory.createVar(0, type, name, true); superActor.addStateVar(buffer); // create read and write counters buffer.addAttribute("_w"); buffer.addAttribute("_r"); buffersMap.put(conn.getSourcePort(), buffer); buffersMap.put(conn.getTargetPort(), buffer); } conn.addAttribute("bufferCreated"); } else { buffer = buffersMap.get(conn.getSourcePort()); } buffer.setAttribute("_w", new Integer(0)); buffer.setAttribute("_r", new Integer(0)); } } } private void createPortVarCounters(Procedure body, Pattern inputPattern, Pattern outputPattern) { // Create counters for inputs for (Port port : inputPattern.getPorts()) { Var buffer = irFactory.createVar(0, irFactory.createTypeList( inputPattern.getNumTokens(port), port.getType()), port.getName() + "_tmp", true); buffer.addAttribute("_w"); buffer.addAttribute("_r"); buffer.setAttribute("_w", new Integer(0)); buffer.setAttribute("_r", new Integer(0)); body.addLocal(buffer); } // Create counters for outputs for (Port port : outputPattern.getPorts()) { Var buffer = irFactory.createVar(0, irFactory.createTypeList( outputPattern.getNumTokens(port), port.getType()), port.getName() + "_tmp", true); buffer.addAttribute("_w"); buffer.addAttribute("_r"); buffer.setAttribute("_w", new Integer(0)); buffer.setAttribute("_r", new Integer(0)); body.addLocal(buffer); } } private InstLoad createInputCopyLoopLoad(Var loopVar, Var tmpToken, Var source) { List<Expression> loadIndex = new ArrayList<Expression>(1); loadIndex.add(irFactory.createExprBinary( irFactory.createExprVar(loopVar), OpBinary.PLUS, irFactory.createExprInt(0), irFactory.createTypeInt(32))); InstLoad load = irFactory.createInstLoad(0, tmpToken, source, loadIndex); return load; } private InstStore createInputCopyLoopStore(Var loopVar, Var tmpToken, Var target) { List<Expression> storeIndex = new ArrayList<Expression>(1); storeIndex.add(irFactory.createExprVar(loopVar)); InstStore store = irFactory.createInstStore(0, target, storeIndex, irFactory.createExprVar(tmpToken)); return store; } private Instruction createOutputCopyLoopLoad(Var loopVar, Var tmpToken, Var target) { List<Expression> storeIndex = new ArrayList<Expression>(1); storeIndex.add(irFactory.createExprVar(loopVar)); InstLoad load = irFactory.createInstLoad(0, tmpToken, target, storeIndex); return load; } private Instruction createOutputCopyLoopStore(Var loopVar, Var tmpToken, Var source) { List<Expression> loadIndex = new ArrayList<Expression>(1); loadIndex.add(irFactory.createExprBinary( irFactory.createExprVar(loopVar), OpBinary.PLUS, irFactory.createExprInt(0), irFactory.createTypeInt(32))); InstStore store = irFactory.createInstStore(0, source, loadIndex, irFactory.createExprVar(tmpToken)); return store; } private void createCopyLoop(Procedure body, int rate, Var loopVar, Instruction load, Instruction store) { BlockBasic block = irFactory.createBlockBasic(); body.getLast().add(irFactory.createInstAssign(loopVar, irFactory.createExprInt(0))); block.add(load); block.add(store); InstAssign assign = irFactory.createInstAssign(loopVar, irFactory.createExprInt(0)); assign = irFactory.createInstAssign(loopVar, irFactory .createExprBinary(irFactory.createExprVar(loopVar), OpBinary.PLUS, irFactory.createExprInt(1), loopVar.getType())); block.add(assign); Expression condition = irFactory .createExprBinary(irFactory.createExprVar(loopVar), OpBinary.LT, irFactory.createExprInt(rate), irFactory.createTypeBool()); List<Block> blocks = new ArrayList<Block>(1); blocks.add(block); BlockWhile copyLoop = irFactory.createBlockWhile(); copyLoop.setJoinBlock(irFactory.createBlockBasic()); copyLoop.setCondition(condition); copyLoop.getBlocks().addAll(blocks); body.getBlocks().add(copyLoop); } private void createInputBufferCopies(Procedure body, Pattern inputPattern) { for (Port port : inputPattern.getPorts()) { Var loopVar = body.newTempLocalVariable( irFactory.createTypeInt(32), port.getName() + "_copyIdx"); Var tmpToken = body.newTempLocalVariable( EcoreUtil.copy(port.getType()), port.getName() + "_token"); createCopyLoop(body, inputPattern.getNumTokens(port), loopVar, createInputCopyLoopLoad(loopVar, tmpToken, inputPattern.getVariable(port)), createInputCopyLoopStore( loopVar, tmpToken, findVariable(body.getLocals(), port.getName() + "_tmp"))); } } private void createOutputBufferCopies(Procedure body, Pattern outputPattern) { for (Port port : outputPattern.getPorts()) { Var loopVar = body.newTempLocalVariable( irFactory.createTypeInt(32), port.getName() + "_copyIdx"); Var tmpToken = body.newTempLocalVariable( EcoreUtil.copy(port.getType()), port.getName() + "_token"); createCopyLoop(body, outputPattern.getNumTokens(port), loopVar, createOutputCopyLoopLoad(loopVar, tmpToken, findVariable(body.getLocals(), port.getName() + "_tmp")), createOutputCopyLoopStore(loopVar, tmpToken, outputPattern.getVariable(port))); } } private Pattern createInputPattern(Pattern actionInputPattern) { Pattern inputPattern = dfFactory.createPattern(); for (Port port : superActor.getInputs()) { port.setNumTokensConsumed(createPortPattern(inputPattern, actionInputPattern, port, "_r")); } return inputPattern; } private Pattern createOutputPattern(Pattern actionOutputPattern) { Pattern outputPattern = dfFactory.createPattern(); for (Port port : superActor.getOutputs()) { port.setNumTokensProduced(createPortPattern(outputPattern, actionOutputPattern, port, "_w")); } return outputPattern; } private int createPortPattern(Pattern targetPattern, Pattern sourcePattern, Port port, String attrName) { int portIndex = MergerUtil.findPort(sourcePattern.getPorts(), port.getName()); if (portIndex >= 0) { Port sourcePort = sourcePattern.getPorts().get(portIndex); sourcePort.setAttribute(attrName, new Integer(0)); int prd = sourcePattern.getNumTokens(sourcePort); targetPattern.setNumTokens(port, prd); targetPattern.setVariable(port, irFactory.createVar(0, irFactory.createTypeList(prd, EcoreUtil.copy(port.getType())), port.getName(), true)); return prd; } else { return 0; } } /** * Create the procedural code of a static schedule. * * @param procedure * the associated procedure * @param schedule * the current schedule */ private void createStaticSchedule(Procedure procedure, Schedule schedule) { for (Iterand iterand : schedule.getIterands()) { List<Expression> procParams = new ArrayList<Expression>(); processInputs(iterand.getAction(), procParams, procedure.getLocals()); processOutputs(iterand.getAction(), procParams, procedure.getLocals()); Instruction instruction = irFactory.createInstCall( null, correspondences.getProcedure(iterand.getAction()), procParams); procedure.getLast().add(instruction); } } private void processInputs(Action action, List<Expression> procParams, List<Var> locals) { for(Port port : action.getInputPattern().getPorts()) { processPort(procParams, port, "_r", action.getInputPattern().getNumTokens(port), locals); } } private void processOutputs(Action action, List<Expression> procParams, List<Var> locals) { for(Port source : action.getOutputPattern().getPorts()) { processPort(procParams, source, "_w", action.getOutputPattern().getNumTokens(source), locals); } } private Var findVariable(List<Var> varlist, String name) { for (Var var : varlist) { if (var.getName().equals(name)) { return var; } } OrccLogger.warnln("ActorMergerQS::findVariable() could not find " + name); return null; } private void processPort(List<Expression> procParams, Port port, String idxName, int tokenRate, List<Var> locals) { if (buffersMap.containsKey(port)) { Var memVar = buffersMap.get(port); procParams.add(irFactory.createExprVar(memVar)); int val = ((Integer)memVar.getValueAsObject(idxName)).intValue(); procParams.add(irFactory.createExprInt(val)); memVar.setAttribute(idxName, new Integer((val + tokenRate))); } else { Var buffer = findVariable(locals, port.getName() + "_tmp"); if (buffer != null) { procParams.add(irFactory.createExprVar(buffer)); int val = ((Integer)buffer.getValueAsObject(idxName)).intValue(); procParams.add(irFactory.createExprInt(val)); buffer.setAttribute(idxName, new Integer((val + tokenRate))); } } } }