/*
* Copyright (c) 2012, 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 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.List;
import net.sf.orcc.OrccRuntimeException;
import net.sf.orcc.df.Action;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.Pattern;
import net.sf.orcc.df.Port;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.InstReturn;
import net.sf.orcc.ir.Instruction;
import net.sf.orcc.ir.IrFactory;
import net.sf.orcc.ir.OpBinary;
import net.sf.orcc.ir.OpUnary;
import net.sf.orcc.ir.Procedure;
import net.sf.orcc.ir.Use;
import net.sf.orcc.ir.Var;
import net.sf.orcc.ir.util.IrUtil;
import net.sf.orcc.moc.CSDFMoC;
import net.sf.orcc.moc.MoC;
import net.sf.orcc.moc.QSDFMoC;
import net.sf.orcc.tools.classifier.GuardSatChecker;
import net.sf.orcc.util.OrccLogger;
/**
* This class defines a merger for QSDF actors. In other words, a new action is
* created for each configuration of the QSDF model of computation.
*
* @author Herve Yviquel
*
*/
public class ActionMergerQSDF {
private static IrFactory factory = IrFactory.eINSTANCE;
private Actor actor;
public void merge(Actor actor) {
this.actor = actor;
MoC clasz = actor.getMoC();
if (clasz.isQuasiStatic()) {
OrccLogger.traceln("Merge actions of " + actor.getName());
QSDFMoC qsdfmoc = (QSDFMoC) clasz;
// Remove FSM
actor.setFsm(null);
// Remove all actions from action scheduler
actor.getActionsOutsideFsm().clear();
actor.getActions().clear();
GuardSatChecker checker = new GuardSatChecker(actor);
List<Action> previousActions = new ArrayList<Action>();
for (Action action : qsdfmoc.getActions()) {
MoC moc = qsdfmoc.getMoC(action);
Action currCopy = IrUtil.copy(action);
for (Action previous : previousActions) {
@SuppressWarnings("unused")
boolean checkCompatibility = false;
Pattern prevPattern = previous.getInputPattern();
Pattern currPattern = action.getInputPattern();
// FIXME: better implementation using isSuperSetOf()
for (Port port : qsdfmoc.getConfigurationPorts()) {
if (prevPattern.getNumTokens(port) == currPattern
.getNumTokens(port)) {
checkCompatibility = true;
}
}
if (checker.checkSat(action, previous)) {
Action prevCopy = IrUtil.copy(previous);
removeCompatibility(currCopy, prevCopy);
}
}
if (moc.isSDF()) {
actor.getActions().add(currCopy);
actor.getActionsOutsideFsm().add(currCopy);
} else if (moc.isCSDF()) {
CSDFMoC csdfMoc = (CSDFMoC) moc;
Action newAction = new ActionMergerCSDF().merge(
action.getName(), csdfMoc, actor);
newAction.setPeekPattern(currCopy.getPeekPattern());
newAction.setScheduler(currCopy.getScheduler());
actor.getActions().add(newAction);
actor.getActionsOutsideFsm().add(newAction);
} else {
throw new OrccRuntimeException("Uncompatible MoC");
}
previousActions.add(action);
}
}
}
private void removeCompatibility(Action initial, Action previous) {
Procedure initSched = initial.getScheduler();
Procedure prevSched = previous.getScheduler();
// Update the guard to remove the compatibility between both actions
// New guard = guard(init) and not(guard(previous))
List<Instruction> initInstrs = IrUtil.getLast(initSched.getBlocks())
.getInstructions();
List<Instruction> prevInstrs = IrUtil.getLast(prevSched.getBlocks())
.getInstructions();
InstReturn initRet = (InstReturn) initInstrs.get(initInstrs.size() - 1);
InstReturn prevRet = (InstReturn) prevInstrs
.remove(prevInstrs.size() - 1);
Expression notPrev = factory.createExprUnary(OpUnary.LOGIC_NOT,
prevRet.getValue(), factory.createTypeBool());
initRet.setValue(factory.createExprBinary(initRet.getValue(),
OpBinary.LOGIC_AND, notPrev, factory.createTypeBool()));
renameVariables(prevSched, initSched);
// Merge both schedulers
initSched.getLocals().addAll(prevSched.getLocals());
initInstrs.addAll(0, prevInstrs);
// Update pattern
Pattern initPeeked = initial.getPeekPattern();
Pattern prevPeeked = previous.getPeekPattern();
for (Port port : prevPeeked.getPorts()) {
if (initPeeked.contains(port)) {
// Update uses
for (Use prevUse : new ArrayList<Use>(prevPeeked.getVariable(
port).getUses())) {
prevUse.setVariable(initPeeked.getVariable(port));
}
} else {
// Add port and variable
initPeeked.setVariable(port, prevPeeked.getVariable(port));
initPeeked.setNumTokens(port, prevPeeked.getNumTokens(port));
}
}
}
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);
}
}
}