/*
* 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.tools.merger.action;
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.DfFactory;
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.Instruction;
import net.sf.orcc.ir.IrFactory;
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.MoC;
import net.sf.orcc.tools.merger.pattern.PatternExecution;
import net.sf.orcc.tools.merger.pattern.PatternLoop;
import net.sf.orcc.tools.merger.pattern.PatternLoopRecognizer;
import net.sf.orcc.tools.merger.pattern.PatternSequential;
import net.sf.orcc.tools.merger.pattern.PatternSimple;
import net.sf.orcc.tools.merger.pattern.PatternVisitor;
import net.sf.orcc.util.OrccLogger;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
/**
* This class defines a merger for CSDF actors. In other words, a new action is
* created from the detected pattern of a CSDF model of computation.
*
* @author Matthieu Wipliez
* @author Jerome Gorin
* @author Herve Yviquel
*
*/
public class ActionMergerCSDF {
/**
* This class contains code to transform a pattern to IR code.
*/
private class BodyBuilder implements PatternVisitor {
private List<Block> blocks;
private int depth;
private List<Var> indexes;
private Procedure procedure;
public BodyBuilder(Procedure procedure) {
this.procedure = procedure;
this.blocks = procedure.getBlocks();
this.indexes = new ArrayList<Var>();
}
private EList<Instruction> updateCounter(Pattern pattern) {
EList<Instruction> instrs = new BasicEList<Instruction>();
for (Port port : pattern.getPorts()) {
int numTokens = pattern.getNumTokens(port);
Var varCount = portToVarCountMap.get(port);
InstAssign assign = irFactory.createInstAssign(varCount,
irFactory.createExprBinary(
irFactory.createExprVar(varCount),
OpBinary.PLUS,
irFactory.createExprInt(numTokens),
irFactory.createTypeInt(32)));
instrs.add(assign);
}
return instrs;
}
@Override
public void visit(PatternLoop pattern) {
depth++;
if (indexes.size() < depth) {
Var varDef = irFactory.createVar(0, irFactory.createTypeBool(),
"loop", true, depth - 1);
procedure.getLocals().add(varDef);
indexes.add(varDef);
}
Var loopVar = indexes.get(depth - 1);
// Initialize loop counter
BlockBasic block = IrUtil.getLast(blocks);
InstAssign assign = irFactory.createInstAssign(loopVar,
irFactory.createExprInt(0));
block.add(assign);
// Create while
List<Block> oldBlocks = blocks;
BlockWhile blockWhile = irFactory.createBlockWhile();
blockWhile.setJoinBlock(irFactory.createBlockBasic());
blocks = blockWhile.getBlocks();
oldBlocks.add(blockWhile);
// Create the loop condition
Expression condition = irFactory.createExprBinary(
irFactory.createExprVar(loopVar), OpBinary.LT,
irFactory.createExprInt(pattern.getNumIterations()),
irFactory.createTypeBool());
blockWhile.setCondition(condition);
// Accept sub pattern
pattern.getPattern().accept(this);
// Increment the loop counter
block = IrUtil.getLast(blocks);
assign = irFactory.createInstAssign(loopVar, irFactory
.createExprBinary(irFactory.createExprVar(loopVar),
OpBinary.PLUS, irFactory.createExprInt(1),
irFactory.createTypeInt(32)));
block.add(assign);
// Restore stuff
this.blocks = oldBlocks;
depth--;
}
@Override
public void visit(PatternSequential pattern) {
for (PatternExecution subPattern : pattern) {
subPattern.accept(this);
}
}
@Override
public void visit(PatternSimple pattern) {
// Copy the body of the action
Action action = pattern.getAction();
Procedure bodyCopy = IrUtil.copy(action.getBody());
renameVariables(bodyCopy, procedure);
// Move variables and blocks in the body of the new action
procedure.getLocals().addAll(bodyCopy.getLocals());
blocks.addAll(bodyCopy.getBlocks());
// Update variable counter index
BlockBasic block = IrUtil.getLast(blocks);
block.getInstructions().addAll(
updateCounter(action.getInputPattern()));
block.getInstructions().addAll(
updateCounter(action.getOutputPattern()));
}
}
private class UpdatePortAccesses extends AbstractIrVisitor<Void> {
@Override
public Void caseInstLoad(InstLoad load) {
Use use = load.getSource();
Var var = use.getVariable();
if (var.eContainer() instanceof Pattern) {
Pattern oldPattern = (Pattern) var.eContainer();
Port port = oldPattern.getPort(var);
use.setVariable(inputPattern.getVariable(port));
updateIndex(portToVarCountMap.get(port), load.getIndexes());
}
return null;
}
@Override
public Void caseInstStore(InstStore store) {
Def def = store.getTarget();
Var var = def.getVariable();
if (var.eContainer() instanceof Pattern) {
Pattern oldPattern = (Pattern) var.eContainer();
Port port = oldPattern.getPort(var);
def.setVariable(outputPattern.getVariable(port));
updateIndex(portToVarCountMap.get(port), store.getIndexes());
}
return null;
}
private void updateIndex(Var varCount, List<Expression> indexes) {
ExprBinary expr = IrFactory.eINSTANCE.createExprBinary(
IrFactory.eINSTANCE.createExprVar(varCount), OpBinary.PLUS,
indexes.get(0), IrFactory.eINSTANCE.createTypeInt(32));
indexes.add(expr);
}
}
private Actor actor;
private CSDFMoC clasz;
private final DfFactory dfFactory = DfFactory.eINSTANCE;
private Pattern inputPattern;
private final IrFactory irFactory = IrFactory.eINSTANCE;
private String name;
private Pattern outputPattern;
private Map<Port, Var> portToVarCountMap;
/**
* Creates the body of the static action.
*
* @return the body of the static action
*/
private Procedure createBody() {
Procedure procedure = irFactory.createProcedure(name, 0,
irFactory.createTypeVoid());
// Initialize input and output port variables and their counters
initializePorts(procedure, inputPattern);
initializePorts(procedure, outputPattern);
// Finds a pattern in the actions
PatternLoopRecognizer r = new PatternLoopRecognizer();
PatternExecution pattern = r.getPattern(clasz.getInvocations());
// Build the new body
pattern.accept(new BodyBuilder(procedure));
// Update port accesses
new UpdatePortAccesses().doSwitch(procedure);
return procedure;
}
/**
* Creates the scheduler of the static action.
*
* @return a scheduling procedure
*/
private Procedure createScheduler() {
Procedure procedure = irFactory.createProcedure(
"isSchedulable_" + name, 0, irFactory.createTypeBool());
BlockBasic block = irFactory.createBlockBasic();
InstReturn returnInstr = irFactory.createInstReturn(irFactory
.createExprBool(true));
block.add(returnInstr);
procedure.getBlocks().add(block);
return procedure;
}
/**
* Add port variables to the pattern. Create a counter for each port and
* initialize it to 0.
*
* @param procedure
* body of the target action
* @param pattern
* input or output pattern
*/
private void initializePorts(Procedure procedure, Pattern pattern) {
BlockBasic block = procedure.getLast();
for (Port port : pattern.getPorts()) {
// Port variable
Type type = irFactory.createTypeList(pattern.getNumTokens(port),
port.getType());
Var var = irFactory.createVar(type, port.getName(), true, 0);
pattern.setVariable(port, var);
// Counter variable
Var varCount = procedure.newTempLocalVariable(
irFactory.createTypeInt(32), port.getName() + "_count");
InstAssign assign = irFactory.createInstAssign(varCount,
irFactory.createExprInt(0));
block.add(assign);
portToVarCountMap.put(port, varCount);
}
}
public void merge(Actor actor) {
MoC clasz = actor.getMoC();
if (clasz.isCSDF()) {
OrccLogger.traceln("Merge actions of " + actor.getName());
Action action = merge("xxx", (CSDFMoC) clasz, actor);
// Remove FSM
actor.setFsm(null);
// Remove all actions from action scheduler
actor.getActionsOutsideFsm().clear();
actor.getActions().clear();
// Add the static action
actor.getActions().add(action);
actor.getActionsOutsideFsm().add(action);
}
}
public Action merge(String name, CSDFMoC moc, Actor actor) {
this.clasz = moc;
this.name = name;
this.inputPattern = IrUtil.copy(clasz.getInputPattern());
this.outputPattern = IrUtil.copy(clasz.getOutputPattern());
this.portToVarCountMap = new HashMap<Port, Var>();
this.actor = actor;
Procedure scheduler = createScheduler();
Procedure body = createBody();
Pattern peeked = dfFactory.createPattern();
return dfFactory.createAction(name, inputPattern, outputPattern,
peeked, scheduler, body);
}
private void renameVariables(Procedure oldProc, Procedure newProc) {
for (Var var : oldProc.getLocals()) {
String varName = var.getName();
for (int i = 0; newProc.getLocal(varName) != null
|| actor.getStateVar(varName) != null
|| (oldProc.getLocal(varName) != null && oldProc
.getLocal(varName) != var); i++) {
varName = var.getName() + i;
}
var.setName(varName);
}
}
}