/*
* 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.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import net.sf.orcc.backends.util.BackendUtil;
import net.sf.orcc.df.Action;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.DfFactory;
import net.sf.orcc.df.FSM;
import net.sf.orcc.df.Pattern;
import net.sf.orcc.df.Port;
import net.sf.orcc.df.State;
import net.sf.orcc.df.Tag;
import net.sf.orcc.df.Transition;
import net.sf.orcc.df.util.DfVisitor;
import net.sf.orcc.ir.BlockBasic;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.InstLoad;
import net.sf.orcc.ir.InstReturn;
import net.sf.orcc.ir.InstStore;
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.Var;
import net.sf.orcc.ir.util.AbstractIrVisitor;
import net.sf.orcc.util.util.EcoreHelper;
import org.eclipse.emf.common.util.EList;
/**
* This class defines a visitor that transforms multi-token to mono-token data
* transfer
*
* @author Khaled Jerbi
*
*/
public class Multi2MonoToken extends DfVisitor<Void> {
/**
* This class defines a visitor that substitutes the peek from the port to
* the new buffer and changes the index from (index) to
* (index+writeIndex&maskValue)
*
* @author Khaled Jerbi
*
*/
private class ModifyActionScheduler extends AbstractIrVisitor<Object> {
private Var buffer;
private int bufferSize;
private Port currentPort;
private Var writeIndex;
public ModifyActionScheduler(Var buffer, Var writeIndex,
Port currentPort, int bufferSize) {
this.buffer = buffer;
this.writeIndex = writeIndex;
this.currentPort = currentPort;
this.bufferSize = bufferSize;
}
@Override
public Object caseInstLoad(InstLoad load) {
Var varSource = load.getSource().getVariable();
Pattern pattern = EcoreHelper.getContainerOfType(varSource,
Pattern.class);
if (pattern != null) {
Port testPort = pattern.getPort(varSource);
if (currentPort.equals(testPort)) {
// change tab Name
load.getSource().setVariable(buffer);
// change index --> writeIndex+index
Expression maskValue = irFactory
.createExprInt(bufferSize - 1);
// FIXME: rewrite this part if necessary
Expression index = null;
if (writeIndex.isGlobal()) {
int blockIndex = load.getBlock().indexOf(load);
Procedure procedure = EcoreHelper.getContainerOfType(
load, Procedure.class);
Var localWritendex = procedure.newTempLocalVariable(
irFactory.createTypeInt(32), "writeIndex");
localWritendex.setIndex(1);
InstLoad instLoad = irFactory.createInstLoad(
localWritendex, writeIndex);
load.getBlock().add(blockIndex, instLoad);
index = irFactory.createExprVar(localWritendex);
} else {
index = irFactory.createExprVar(writeIndex);
}
if (!load.getIndexes().isEmpty()) {
Expression expression1 = load.getIndexes().get(0);
Expression sum = irFactory.createExprBinary(
expression1, OpBinary.PLUS, index,
irFactory.createTypeInt(32));
Expression mask = irFactory.createExprBinary(sum,
OpBinary.BITAND, maskValue,
irFactory.createTypeInt(32));
load.getIndexes().add(mask);
} else {
Expression mask2 = irFactory.createExprBinary(index,
OpBinary.BITAND, maskValue,
irFactory.createTypeInt(32));
load.getIndexes().add(mask2);
}
}
}
return null;
}
}
/**
* This class defines a visitor that substitutes process variable names with
* those of the newly defined actions for InstStore
*
* @author Khaled Jerbi
*
*/
private class ModifyProcessActionStore extends AbstractIrVisitor<Object> {
private int bufferSize;
private Var tab;
private Var writeIndex;
public ModifyProcessActionStore(Var tab, Var writeIndex, int bufferSize) {
this.tab = tab;
this.writeIndex = writeIndex;
this.bufferSize = bufferSize;
}
@Override
public Object caseInstLoad(InstLoad load) {
Var varSource = load.getSource().getVariable();
Pattern pattern = EcoreHelper.getContainerOfType(varSource,
Pattern.class);
if (pattern != null) {
Port testPort = pattern.getPort(varSource);
if (port.equals(testPort)) {
// change tab Name
load.getSource().setVariable(tab);
Expression indexInit = load.getIndexes().get(0);
Expression indexFinal = irFactory.createExprBinary(
indexInit, OpBinary.PLUS,
irFactory.createExprVar(writeIndex),
irFactory.createTypeInt(32));
Expression exprMask = irFactory
.createExprInt(bufferSize - 1);
Expression maskValue = irFactory.createExprBinary(
indexFinal, OpBinary.BITAND, exprMask,
irFactory.createTypeInt(32));
load.getIndexes().add(maskValue);
}
}
return null;
}
@Override
public Object caseInstStore(InstStore store) {
Var varSource = store.getTarget().getVariable();
Pattern pattern = EcoreHelper.getContainerOfType(varSource,
Pattern.class);
if (pattern != null) {
Port testPort = pattern.getPort(varSource);
if (port.equals(testPort)) {
// change tab Name
store.getTarget().setVariable(tab);
Expression indexInit = store.getIndexes().get(0);
Expression indexFinal = irFactory.createExprBinary(
indexInit, OpBinary.PLUS,
irFactory.createExprVar(writeIndex),
irFactory.createTypeInt(32));
Expression exprMask = irFactory
.createExprInt(bufferSize - 1);
Expression maskValue = irFactory.createExprBinary(
indexFinal, OpBinary.BITAND, exprMask,
irFactory.createTypeInt(32));
store.getIndexes().add(maskValue);
}
}
return null;
}
}
/**
* This class defines a visitor that substitutes process variable names with
* those of the newly defined actions for write
*
* @author Khaled JERBI
*
*/
private class ModifyProcessActionWrite extends AbstractIrVisitor<Object> {
private Var tab;
public ModifyProcessActionWrite(Var tab) {
this.tab = tab;
}
@Override
public Object caseInstLoad(InstLoad load) {
Var varSource = load.getSource().getVariable();
Pattern pattern = EcoreHelper.getContainerOfType(varSource,
Pattern.class);
if (pattern != null) {
Port testPort = pattern.getPort(varSource);
if (port.equals(testPort)) {
// change tab Name
load.getSource().setVariable(tab);
}
}
return null;
}
@Override
public Object caseInstStore(InstStore store) {
Var varTarget = store.getTarget().getVariable();
Pattern pattern = EcoreHelper.getContainerOfType(varTarget,
Pattern.class);
if (pattern != null) {
Port testPort = pattern.getPort(varTarget);
if (port.equals(testPort)) {
// change tab Name
store.getTarget().setVariable(tab);
}
}
return null;
}
}
private static DfFactory dfFactory = DfFactory.eINSTANCE;
private static IrFactory irFactory = IrFactory.eINSTANCE;
private List<Action> AddedUntaggedActions;
private List<Integer> bufferSizes;
// private int bufferSize;
private Action done;
private Type entryType;
private FSM fsm;
private List<Var> inputBuffers;
private int inputIndex;
private List<Port> inputPorts;
private Set<Action> noRepeatActions;
private int numTokens;
private int outputIndex;
private Port port;
private List<Var> readIndexes;
private boolean repeatInput;
private Var result;
private List<Transition> transitionsList;
private List<Action> visitedActions;
private List<String> visitedActionsNames;
private int visitedRenameIndex;
private Action write;
private List<Var> writeIndexes;
/**
* returns the position of an action name in an actions names list
*
* @param list
* list of actions names
* @param seek
* action researched action
* @return position of the seek action in the list
*/
private int actionNamePosition(List<String> list, String seekAction) {
int position = 0;
for (String action : list) {
if (action.equals(seekAction)) {
break;
} else {
position++;
}
}
return position;
}
/**
* returns the position of an action name in an actions names list
*
* @param list
* list of actions names
* @param seek
* action researched action
* @return position of the seek action in the list
*/
private int actionPosition(List<Action> list, String seekAction) {
int position = 0;
for (Action action : list) {
if (action.getName().equals(seekAction)) {
break;
} else {
position++;
}
}
return position;
}
/**
* transforms the transformed action to a transition action
*
* @param action
* modified action
* @param buffer
* current store buffer
* @param writeIndex
* write index of the buffer
* @param readIndex
* read index of the buffer
*/
private void actionToTransition(Port port, Action action, Var buffer,
Var writeIndex, Var readIndex, int bufferSize) {
ModifyActionScheduler modifyActionScheduler = new ModifyActionScheduler(
buffer, writeIndex, port, bufferSize);
modifyActionScheduler.doSwitch(action.getScheduler());
modifyActionSchedulability(action, writeIndex, readIndex, OpBinary.GE,
irFactory.createExprInt(numTokens), port);
}
@Override
public Void caseActor(Actor actor) {
this.actor = actor;
inputIndex = 0;
outputIndex = 0;
visitedRenameIndex = 0;
repeatInput = false;
// bufferSize = 0;
AddedUntaggedActions = new ArrayList<Action>();
inputBuffers = new ArrayList<Var>();
inputPorts = new ArrayList<Port>();
noRepeatActions = new HashSet<Action>();
readIndexes = new ArrayList<Var>();
writeIndexes = new ArrayList<Var>();
bufferSizes = new ArrayList<Integer>();
visitedActions = new ArrayList<Action>();
visitedActionsNames = new ArrayList<String>();
transitionsList = new ArrayList<Transition>();
modifyRepeatActionsInFSM();
modifyUntaggedActions();
return null;
}
/**
* This method creates an action with the given name.
*
* @param name
* name of the action
* @return a new action created with the given name
*/
private Action createAction(Expression condition, String name) {
Tag tag = dfFactory.createTag(name);
// Scheduler building
Procedure scheduler = irFactory.createProcedure(
"isSchedulable_" + name, 0, irFactory.createTypeBool());
BlockBasic blockScheduler = irFactory.createBlockBasic();
Var result = scheduler.newTempLocalVariable(irFactory.createTypeBool(),
"actionResult");
result.setIndex(1);
blockScheduler.add(irFactory.createInstAssign(result, condition));
blockScheduler.add(irFactory.createInstReturn(irFactory
.createExprVar(result)));
scheduler.getBlocks().add(blockScheduler);
// Body building ;-)
Procedure body = irFactory.createProcedure(name, 0,
irFactory.createTypeVoid());
BlockBasic blockBody = irFactory.createBlockBasic();
blockBody.add(irFactory.createInstReturn());
body.getBlocks().add(blockBody);
Action action = dfFactory.createAction(tag, dfFactory.createPattern(),
dfFactory.createPattern(), dfFactory.createPattern(),
scheduler, body);
actor.getActions().add(action);
return action;
}
/**
* This method creates the required InstStore, done, untagged and process
* actions
*
* @param action
* the action getting transformed
*/
private void createActionsSet(Action action, State sourceState,
State targetState) {
scanInputs(action);
scanOutputs(action, sourceState, targetState);
}
/**
* This method creates a global variable counter for store with the given
* name.
*
* @param name
* name of the counter
* @return new counter with the given name
*/
private Var createCounter(String name) {
Var newCounter = irFactory.createVar(0, irFactory.createTypeInt(32),
name, true, irFactory.createExprInt(0));
Expression expression = irFactory.createExprInt(0);
newCounter.setInitialValue(expression);
if (!actor.getStateVars().contains(newCounter.getName())) {
actor.getStateVars().add(newCounter);
}
return newCounter;
}
/**
* This method creates the done action that is schedulable when required
* number of tokens is read (written)
*
* @param actionName
* name of the action
* @param counter
* global variable counter used for reading (writing) tokens
* @param numTokens
* repeat value
* @return new done action
*/
private Action createDoneAction(String name, Var counter, int numTokens) {
Tag tag = dfFactory.createTag(name);
// Body building
Procedure body = irFactory.createProcedure(name, 0,
irFactory.createTypeVoid());
BlockBasic blockBody = irFactory.createBlockBasic();
blockBody.add(irFactory.createInstStore(counter, 0));
blockBody.add(irFactory.createInstReturn());
body.getBlocks().add(blockBody);
// Scheduler building
Procedure scheduler = irFactory.createProcedure(
"isSchedulable_" + name, 0, irFactory.createTypeBool());
Var temp = scheduler.newTempLocalVariable(irFactory.createTypeBool(),
"temp");
temp.setIndex(1);
scheduler.getLocals().add(temp);
result = irFactory.createVar(0, irFactory.createTypeBool(), "res",
true, 0);
scheduler.getLocals().add(result);
Var localCounter = irFactory.createVar(0, counter.getType(),
"localCounter", true, 1);
scheduler.getLocals().add(localCounter);
BlockBasic blockScheduler = irFactory.createBlockBasic();
blockScheduler.add(0, irFactory.createInstLoad(localCounter, counter));
Expression guardValue = irFactory.createExprInt(numTokens);
Expression counterExpression = irFactory.createExprVar(localCounter);
Expression expression = irFactory.createExprBinary(counterExpression,
OpBinary.EQ, guardValue, irFactory.createTypeBool());
blockScheduler.add(irFactory.createInstAssign(temp, expression));
blockScheduler.add(irFactory.createInstAssign(result,
irFactory.createExprVar(temp)));
blockScheduler.add(irFactory.createInstReturn(irFactory
.createExprVar(result)));
scheduler.getBlocks().add(blockScheduler);
Action action = dfFactory.createAction(tag, dfFactory.createPattern(),
dfFactory.createPattern(), dfFactory.createPattern(),
scheduler, body);
this.actor.getActions().add(action);
return action;
}
/**
* This method creates a global variable counter for data storing (writing)
*
* @param name
* name of the list
* @param numTokens
* size of the list
* @param entryType
* type of the list
* @return a global variable list
*/
private Var createTab(String name, Type entryType, int size) {
Type type = irFactory.createTypeList(size, entryType);
Var newList = irFactory.createVar(0, type, name, true);
if (!actor.getStateVars().contains(newList.getName())) {
actor.getStateVars().add(newList);
}
return newList;
}
/**
* creates an untagged action to store tokens
*
* @param storeCounter
* global variable counter
* @param storeList
* global variable list to store
* @param priority
* whether to put the untagged action as high priority or not
* @return new untagged action
*/
private Action createUntaggedAction(Var readIndex, Var writeIndex,
Var storeList, Port port, boolean priority, int bufferSize) {
Expression expression = irFactory.createExprBool(true);
Action newUntaggedAction = createAction(expression,
"untagged_" + port.getName());
Var localINPUT = irFactory.createVar(0,
irFactory.createTypeList(1, port.getType()), port.getName(),
true, 0);
defineUntaggedBody(readIndex, storeList, newUntaggedAction.getBody(),
localINPUT, port, bufferSize);
modifyActionSchedulability(newUntaggedAction, writeIndex, readIndex,
OpBinary.LT, irFactory.createExprInt(bufferSize), port);
Pattern pattern = newUntaggedAction.getInputPattern();
pattern.setNumTokens(port, 1);
pattern.setVariable(port, localINPUT);
if (priority) {
actor.getActionsOutsideFsm().add(0, newUntaggedAction);
} else {
actor.getActionsOutsideFsm().add(newUntaggedAction);
}
AddedUntaggedActions.add(newUntaggedAction);
return newUntaggedAction;
}
/**
* This method creates the new write action
*
* @param actionName
* action name
* @param writeCounter
* global variable write counter
* @param writeList
* global variable write list
* @return new write action
*/
private Action createWriteAction(String actionName, Var writeCounter,
Var writeList) {
String name = actionName + port.getName() + "_NewWrite";
Tag tag = dfFactory.createTag(name);
Procedure scheduler = irFactory.createProcedure(
"isSchedulable_" + name, 0, irFactory.createTypeBool());
BlockBasic blockScheduler = irFactory.createBlockBasic();
Var result = scheduler.newTempLocalVariable(irFactory.createTypeBool(),
"actionResult");
result.setIndex(1);
Var wCounter = scheduler.newTempLocalVariable(
irFactory.createTypeInt(32), "writeCounter");
wCounter.setIndex(1);
Expression guardValue = irFactory.createExprInt(numTokens);
Expression counterExpression = irFactory.createExprVar(wCounter);
Expression expression = irFactory.createExprBinary(counterExpression,
OpBinary.LT, guardValue, irFactory.createTypeBool());
scheduler.getFirst().add(0,
irFactory.createInstLoad(wCounter, writeCounter));
blockScheduler.add(irFactory.createInstAssign(result, expression));
blockScheduler.add(irFactory.createInstReturn(irFactory
.createExprVar(result)));
scheduler.getBlocks().add(blockScheduler);
// Body building ;-)
Procedure body = irFactory.createProcedure(name, 0,
irFactory.createTypeVoid());
BlockBasic blockBody = irFactory.createBlockBasic();
blockBody.add(irFactory.createInstReturn());
body.getBlocks().add(blockBody);
Action newWriteAction = dfFactory.createAction(tag,
dfFactory.createPattern(), dfFactory.createPattern(),
dfFactory.createPattern(), scheduler, body);
actor.getActions().add(newWriteAction);
Var OUTPUT = irFactory.createVar(0,
irFactory.createTypeList(1, port.getType()), port.getName()
+ "_OUTPUT", true, 0);
defineWriteBody(writeCounter, writeList, newWriteAction.getBody(),
OUTPUT);
// add output pattern
Pattern pattern = newWriteAction.getOutputPattern();
pattern.setVariable(port, OUTPUT);
pattern.setNumTokens(port, 1);
return newWriteAction;
}
/**
* This method creates the instructions for the body of the new untagged
* action
*
* @param port
* repeat port
* @param readCounter
* global variable counter
* @param storeList
* global store list
* @param body
* new untagged action body
*/
private void defineUntaggedBody(Var readCounter, Var storeList,
Procedure body, Var localINPUT, Port port, int bufferSize) {
BlockBasic bodyBlock = body.getFirst();
EList<Var> locals = body.getLocals();
Var input = irFactory.createVar(0, port.getType(), port.getName()
+ "_Input", true, 1);
locals.add(input);
List<Expression> load2Index = new ArrayList<Expression>(1);
load2Index.add(irFactory.createExprInt(0));
bodyBlock.add(irFactory.createInstLoad(input, localINPUT, load2Index));
Var counter = irFactory.createVar(0, readCounter.getType(),
port.getName() + "_Local_counter", true, 1);
locals.add(counter);
bodyBlock.add(irFactory.createInstLoad(counter, readCounter));
Var mask = irFactory.createVar(0, irFactory.createTypeInt(32), "mask",
true, 1);
locals.add(mask);
Expression maskValue = irFactory.createExprBinary(
irFactory.createExprVar(counter), OpBinary.BITAND,
irFactory.createExprInt(bufferSize - 1),
irFactory.createTypeInt(32));
bodyBlock.add(irFactory.createInstAssign(mask, maskValue));
bodyBlock.add(irFactory.createInstStore(storeList, mask, input));
Expression indexInc = irFactory.createExprBinary(
irFactory.createExprVar(counter), OpBinary.PLUS,
irFactory.createExprInt(1), readCounter.getType());
bodyBlock.add(irFactory.createInstStore(readCounter, indexInc));
}
/**
* This method defines the instructions of the new write action body
*
* @param writeCounter
* global variable counter
* @param writeList
* global variable list for write
* @param body
* body of the new write action
*/
private void defineWriteBody(Var writeCounter, Var writeList,
Procedure body, Var OUTPUT) {
BlockBasic bodyNode = body.getFirst();
EList<Var> locals = body.getLocals();
Var counter1 = irFactory.createVar(0, writeCounter.getType(),
port.getName() + "_Local_writeCounter", true, outputIndex);
locals.add(counter1);
bodyNode.add(irFactory.createInstLoad(counter1, writeCounter));
Var output = irFactory.createVar(0, port.getType(), port.getName()
+ "_LocalOutput", true, outputIndex);
locals.add(output);
List<Expression> load2Index = new ArrayList<Expression>(1);
load2Index.add(irFactory.createExprVar(counter1));
bodyNode.add(irFactory.createInstLoad(output, writeList, load2Index));
Expression assign2Value = irFactory.createExprBinary(
irFactory.createExprVar(counter1), OpBinary.PLUS,
irFactory.createExprInt(1), irFactory.createTypeInt(32));
// locals.put(OUTPUT.getName(), OUTPUT);
bodyNode.add(irFactory.createInstStore(OUTPUT, 0, output));
bodyNode.add(irFactory.createInstStore(writeCounter, assign2Value));
}
/**
* this method changes the schedulability of the action accordingly to
* tokens disponibility in the buffer
*
* @param writeIndex
* write index of the buffer
* @param readIndex
* read index of the buffer
*/
private void modifyActionSchedulability(Action action, Var writeIndex,
Var readIndex, OpBinary op, Expression reference, Port port) {
int index = 0;
Procedure scheduler = action.getScheduler();
BlockBasic bodyBlock = scheduler.getLast();
EList<Var> locals = scheduler.getLocals();
Var localRead = irFactory.createVar(0, irFactory.createTypeInt(32),
"readIndex_" + port.getName() + "_" + inputIndex, true,
inputIndex);
locals.add(localRead);
bodyBlock.add(index, irFactory.createInstLoad(localRead, readIndex));
index++;
Var localWrite = irFactory.createVar(0, irFactory.createTypeInt(32),
"writeIndex_" + port.getName() + "_" + inputIndex, true,
inputIndex);
locals.add(localWrite);
bodyBlock.add(index, irFactory.createInstLoad(localWrite, writeIndex));
index++;
Var diff = irFactory.createVar(0, irFactory.createTypeInt(32), "diff"
+ port.getName() + "_" + inputIndex, true, inputIndex);
locals.add(diff);
Expression value = irFactory.createExprBinary(
irFactory.createExprVar(localRead), OpBinary.MINUS,
irFactory.createExprVar(localWrite),
irFactory.createTypeInt(32));
bodyBlock.add(index, irFactory.createInstAssign(diff, value));
index++;
Var conditionVar = irFactory.createVar(0, irFactory.createTypeBool(),
"condition_" + port.getName(), true, inputIndex);
locals.add(conditionVar);
Expression value2 = irFactory.createExprBinary(
irFactory.createExprVar(diff), op, reference,
irFactory.createTypeBool());
bodyBlock.add(index, irFactory.createInstAssign(conditionVar, value2));
index++;
Var myResult = irFactory.createVar(0, irFactory.createTypeBool(),
"myResult_" + port.getName(), true, inputIndex);
locals.add(myResult);
int returnIndex = bodyBlock.getInstructions().size() - 1;
InstReturn actionReturn = (InstReturn) bodyBlock.getInstructions().get(
returnIndex);
// VarLocal currentResult
Expression e = irFactory.createExprBinary(actionReturn.getValue(),
OpBinary.LOGIC_AND, irFactory.createExprVar(conditionVar),
irFactory.createTypeBool());
bodyBlock.add(returnIndex, irFactory.createInstAssign(myResult, e));
actionReturn.setValue(irFactory.createExprVar(myResult));
}
/**
* This method changes the schedulability of the done action
*
* @param counter
* Global Var counter
*/
private void modifyDoneAction(Var counter, int portIndex, String portName) {
BlockBasic basicBlock = done.getBody().getFirst();
basicBlock.add(irFactory.createInstStore(counter, 0));
basicBlock = done.getScheduler().getFirst();
EList<Var> schedulerLocals = done.getScheduler().getLocals();
Var localCounter = irFactory.createVar(0, counter.getType(),
"localCounterModif" + portName, true, portIndex);
schedulerLocals.add(localCounter);
basicBlock.add(1, irFactory.createInstLoad(localCounter, counter));
Var temp = irFactory.createVar(0, irFactory.createTypeBool(), "temp"
+ portName, true, portIndex);
schedulerLocals.add(temp);
Expression guardValue = irFactory.createExprInt(numTokens);
Expression counterExpression = irFactory.createExprVar(localCounter);
Expression schedulerValue = irFactory.createExprBinary(
counterExpression, OpBinary.EQ, guardValue,
irFactory.createTypeBool());
int index = basicBlock.getInstructions().size() - 1;
basicBlock.add(index, irFactory.createInstAssign(temp, schedulerValue));
index++;
Expression buffrerExpression = irFactory.createExprVar(result);
Expression resultExpression = irFactory.createExprVar(temp);
Expression expression = irFactory.createExprBinary(buffrerExpression,
OpBinary.LOGIC_AND, resultExpression,
irFactory.createTypeBool());
basicBlock.add(index, irFactory.createInstAssign(result, expression));
}
/**
* this method transforms tagged actions in the FSM
*
* @param actor
* the actor containing the FSM to modify
*/
private void modifyRepeatActionsInFSM() {
fsm = actor.getFsm();
if (fsm == null) {
State initState = dfFactory.createState("init");
// no FSM: simply visit all the actions
setFsm(initState);
List<Action> actions = new ArrayList<Action>(actor.getActions());
for (Action action : actions) {
visitTransition(initState, initState, action);
}
if (!transitionsList.isEmpty()) {
for (Transition t : transitionsList) {
fsm.add(t);
}
}
} else {
// with an FSM: visits all transitions
for (Transition transition : fsm.getTransitions()) {
State source = transition.getSource();
State target = transition.getTarget();
Action action = transition.getAction();
visitTransition(source, target, action);
}
if (!transitionsList.isEmpty()) {
for (Transition t : transitionsList) {
fsm.add(t);
}
}
}
}
/**
* this method transforms untagged actions containing repeats
*
* @param actor
* the actor containing the untagged actions to modify
*/
private void modifyUntaggedActions() {
if (actor.getFsm() != null) {
List<Action> actions = new ArrayList<Action>(
actor.getActionsOutsideFsm());
for (Action action : actions) {
// modify only untagged actions existing before transformation
if (!AddedUntaggedActions.contains(action)) {
scanUntaggedInputs(action);
// scanUntaggedOutputs(action);
}
}
}
}
/**
* This method return the closest power of 2 of the maximum repeat value of
* a port
*
* @param action
* action containing the port
* @param port
* repeat port
* @return optimal buffer size
*/
private int OptimalBufferSize(Port port) {
int size = 0;
int optimalSize = 0;
List<Action> actions = new ArrayList<Action>(actor.getActions());
for (Action action : actions) {
for (Entry<Port, Integer> entry : action.getInputPattern()
.getNumTokensMap().entrySet()) {
if (entry.getKey() == port) {
if (entry.getValue() > size) {
size = entry.getValue();
}
}
}
}
optimalSize = BackendUtil.closestPow_2(size);
return optimalSize;
}
/**
* returns the position of a port in a port list
*
* @param list
* list of ports
* @param seekPort
* researched port
* @return position of a port in a list
*/
private int portPosition(List<Port> list, Port seekPort) {
int position = 0;
for (Port inputPort : list) {
if (inputPort == seekPort) {
break;
} else {
position++;
}
}
return position;
}
/**
* Creates the new required actions for every input of the action.
*
* @param action
* action to transform
* @param sourceName
* name of the source state of the action in the FSM
* @param targetName
* name of the target state of the action in the FSM
*/
private void scanInputs(Action action) {
for (Entry<Port, Integer> entry : action.getInputPattern()
.getNumTokensMap().entrySet()) {
Var untagBuffer = irFactory.createVar(0, entryType, "buffer", true);
Var untagReadIndex = irFactory.createVar(0,
irFactory.createTypeInt(32), "UntagReadIndex", true,
irFactory.createExprInt(0));
Var untagWriteIndex = irFactory.createVar(0,
irFactory.createTypeInt(32), "UntagWriteIndex", true,
irFactory.createExprInt(0));
numTokens = entry.getValue();
inputIndex = inputIndex + 100;
port = entry.getKey();
int bufferSize = OptimalBufferSize(port);
entryType = port.getType();
if (inputPorts.contains(port)) {
int position = portPosition(inputPorts, port);
untagBuffer = inputBuffers.get(position);
untagReadIndex = readIndexes.get(position);
untagWriteIndex = writeIndexes.get(position);
bufferSize = bufferSizes.get(position);
} else {
inputPorts.add(port);
bufferSizes.add(bufferSize);
untagBuffer = createTab(port.getName() + "_buffer", entryType,
bufferSize);
inputBuffers.add(untagBuffer);
untagReadIndex = createCounter("readIndex_" + port.getName());
readIndexes.add(untagReadIndex);
untagWriteIndex = createCounter("writeIndex_" + port.getName());
writeIndexes.add(untagWriteIndex);
createUntaggedAction(untagReadIndex, untagWriteIndex,
untagBuffer, port, true, bufferSize);
}
Procedure body = action.getBody();
Var index = body.newTempLocalVariable(irFactory.createTypeInt(32),
"writeIndex");
index.setIndex(1);
body.getFirst().add(0,
irFactory.createInstLoad(index, untagWriteIndex));
ModifyProcessActionStore modifyProcessAction = new ModifyProcessActionStore(
untagBuffer, index, bufferSize);
modifyProcessAction.doSwitch(action.getBody());
actionToTransition(port, action, untagBuffer, untagWriteIndex,
untagReadIndex, bufferSize);
Expression value = irFactory.createExprBinary(
irFactory.createExprVar(index), OpBinary.PLUS,
irFactory.createExprInt(numTokens),
irFactory.createTypeInt(32));
body.getLast().add(
irFactory.createInstStore(untagWriteIndex, value));
}
action.getInputPattern().clear();
}
/**
* Creates the new required actions for every output of the action
*
* @param action
* action to transform
* @param sourceName
* name of the source state of the action in the actor fsm
* @param targetName
* name of the target state of the action in the actor fsm
*/
private void scanOutputs(Action action, State sourceState, State targetState) {
for (Entry<Port, Integer> verifEntry : action.getOutputPattern()
.getNumTokensMap().entrySet()) {
int verifNumTokens = verifEntry.getValue();
if (verifNumTokens > 1) {
String writeName = "newStateWrite" + action.getName();
State writeState = dfFactory.createState(writeName);
fsm.add(writeState);
fsm.replaceTarget(sourceState, action, writeState);
for (Entry<Port, Integer> entry : action.getOutputPattern()
.getNumTokensMap().entrySet()) {
numTokens = entry.getValue();
outputIndex = outputIndex + 100;
port = entry.getKey();
entryType = port.getType();
String counterName = action.getName() + "NewWriteCounter"
+ outputIndex;
Var counter = createCounter(counterName);
String listName = action.getName() + "NewWriteList"
+ outputIndex;
Var tab = createTab(listName, entryType, numTokens);
write = createWriteAction(action.getName(), counter, tab);
write.getOutputPattern().setNumTokens(port, 1);
ModifyProcessActionWrite modifyProcessActionWrite = new ModifyProcessActionWrite(
tab);
modifyProcessActionWrite.doSwitch(action.getBody());
Transition transitionWrite = dfFactory.createTransition(
writeState, write, writeState);
transitionsList.add(transitionWrite);
// create a new write done action once
if (outputIndex == 100) {
done = createDoneAction(action.getName()
+ "newWriteDone", counter, numTokens);
Transition transitionDone = dfFactory.createTransition(
writeState, done, targetState);
transitionsList.add(transitionDone);
} else {
modifyDoneAction(counter, outputIndex, port.getName());
}
}
// remove outputPattern from transition action
action.getOutputPattern().clear();
break;
}
}
outputIndex = 0;
}
/**
* Visits the inputs of an untagged action to check repeats
*
* @param action
* action containing the inputs to check
*/
private void scanUntaggedInputs(Action action) {
for (Entry<Port, Integer> verifEntry : action.getInputPattern()
.getNumTokensMap().entrySet()) {
int verifNumTokens = verifEntry.getValue();
Port verifPort = verifEntry.getKey();
Type entryType = verifPort.getType();
int bufferSize = OptimalBufferSize(verifPort);
if (inputPorts.contains(verifPort)) {
int position = portPosition(inputPorts, verifPort);
Var buffer = inputBuffers.get(position);
Var writeIndex = writeIndexes.get(position);
Var readIndex = readIndexes.get(position);
bufferSize = bufferSizes.get(position);
ModifyActionScheduler modifyActionScheduler = new ModifyActionScheduler(
buffer, writeIndex, verifPort, bufferSize);
modifyActionScheduler.doSwitch(action.getBody());
modifyActionScheduler.doSwitch(action.getScheduler());
modifyActionSchedulability(action, writeIndex, readIndex,
OpBinary.GE, irFactory.createExprInt(verifNumTokens),
verifPort);
updateUntagIndex(action, writeIndex, verifNumTokens);
action.getInputPattern().remove(verifPort);
} else {
if (verifNumTokens > 1) {
Var untagBuffer = irFactory.createVar(0, entryType,
"buffer", true);
Var untagReadIndex = irFactory.createVar(0,
irFactory.createTypeInt(32), "UntagReadIndex",
true, irFactory.createExprInt(0));
Var untagWriteIndex = irFactory.createVar(0,
irFactory.createTypeInt(32), "UntagWriteIndex",
true, irFactory.createExprInt(0));
inputPorts.add(verifPort);
untagBuffer = createTab(verifPort.getName() + "_buffer",
entryType, bufferSize);
inputBuffers.add(untagBuffer);
untagReadIndex = createCounter("readIndex_"
+ verifPort.getName());
readIndexes.add(untagReadIndex);
untagWriteIndex = createCounter("writeIndex_"
+ verifPort.getName());
writeIndexes.add(untagWriteIndex);
bufferSizes.add(bufferSize);
createUntaggedAction(untagReadIndex, untagWriteIndex,
untagBuffer, verifPort, false, bufferSize);
ModifyActionScheduler modifyActionScheduler = new ModifyActionScheduler(
untagBuffer, untagWriteIndex, verifPort, bufferSize);
modifyActionScheduler.doSwitch(action.getBody());
modifyActionScheduler.doSwitch(action.getScheduler());
modifyActionSchedulability(action, untagWriteIndex,
untagReadIndex, OpBinary.GE,
irFactory.createExprInt(verifNumTokens), verifPort);
updateUntagIndex(action, untagWriteIndex, verifNumTokens);
action.getInputPattern().remove(verifPort);
}
}
}
AddedUntaggedActions.add(action);
}
/**
* Visits the outputs of an untagged action to check repeats (FIXME: not
* used because it deals with a very rare case of untagged actions having
* multi-token on their inputs and outputs)
*
* @param action
* action containing the outputs to check
*/
@SuppressWarnings("unused")
private void scanUntaggedOutputs(Action action) {
for (Entry<Port, Integer> verifEntry : action.getOutputPattern()
.getNumTokensMap().entrySet()) {
int verifNumTokens = verifEntry.getValue();
if (verifNumTokens > 1) {
for (Entry<Port, Integer> entry : action.getOutputPattern()
.getNumTokensMap().entrySet()) {
numTokens = entry.getValue();
Port verifPort = entry.getKey();
String name = "TokensToSend" + verifPort.getName();
Var tokensToSend = createCounter(name);
Expression condition = irFactory.createExprBinary(
irFactory.createExprVar(tokensToSend), OpBinary.GT,
irFactory.createExprInt(0),
irFactory.createTypeBool());
String actionName = "untaggedWrite_" + verifPort.getName();
Action untaggedWrite = createAction(condition, actionName);
Pattern pattern = untaggedWrite.getOutputPattern();
pattern.setNumTokens(verifPort, 1);
Var OUTPUT = irFactory.createVar(0, verifPort.getType(),
verifPort.getName() + "OUTPUT", true, 0);
pattern.setVariable(verifPort, OUTPUT);
// add instruction: tokensToSend = tokensToSend - 1 ;
Var numTokenToSend = irFactory.createVar(0,
irFactory.createTypeInt(32), "numTokensToSend",
true, 0);
BlockBasic untaggedBlkNode = untaggedWrite.getBody()
.getLast();
untaggedBlkNode.add(irFactory.createInstLoad(
numTokenToSend, tokensToSend));
Expression value = irFactory.createExprBinary(
irFactory.createExprVar(numTokenToSend),
OpBinary.MINUS, irFactory.createExprInt(1),
irFactory.createTypeInt(32));
untaggedBlkNode.add(irFactory.createInstStore(tokensToSend,
value));
// add untagged action in high priority
actor.getActionsOutsideFsm().add(0, untaggedWrite);
// add write condition to untagged action
BlockBasic blkNode = action.getBody().getLast();
blkNode.add(irFactory.createInstStore(tokensToSend,
numTokens));
}
}
}
AddedUntaggedActions.add(action);
}
/**
* Adds an FSM to an actor if it has not already
*
* @param initialState
* initial state of the new FSM
*/
private void setFsm(State initialState) {
fsm = dfFactory.createFSM();
fsm.add(initialState);
fsm.setInitialState(initialState);
for (Action action : actor.getActionsOutsideFsm()) {
fsm.addTransition(initialState, action, initialState);
}
actor.getActionsOutsideFsm().clear();
actor.setFsm(fsm);
}
/**
* if an already transformed action is reused in an another FSM transition,
* this method uses the transformed action to connect it to the current FSM
* transition
*
* @param action
* @param source
* @param target
*/
private void updateFSM(Action action, Action oldAction, State source,
State target) {
List<Action> actions = actor.getActions();
for (Entry<Port, Integer> verifEntry : action.getInputPattern()
.getNumTokensMap().entrySet()) {
int verifNumTokens = verifEntry.getValue();
if (verifNumTokens > 1) {
repeatInput = true;
Transition transition = dfFactory.createTransition(source,
oldAction, target);
transitionsList.add(transition);
visitedRenameIndex++;
break;
}
inputIndex = 0;
}
for (Entry<Port, Integer> verifEntry : action.getOutputPattern()
.getNumTokensMap().entrySet()) {
int verifNumTokens = verifEntry.getValue();
if (verifNumTokens > 1) {
String updateWriteName = "newStateWrite" + action.getName()
+ visitedRenameIndex;
State writeState = dfFactory.createState(updateWriteName);
fsm.add(writeState);
// create new process action if not created while treating
// inputs
fsm.replaceTarget(source, oldAction, writeState);
oldAction.getOutputPattern().clear();
visitedRenameIndex++;
for (Entry<Port, Integer> entry : action.getOutputPattern()
.getNumTokensMap().entrySet()) {
outputIndex = outputIndex + 100;
port = entry.getKey();
String writeName = action.getName() + port.getName()
+ "_NewWrite";
int writeIndex = actionPosition(actions, writeName);
Action write = actions.get(writeIndex);
Transition writeTransition = dfFactory.createTransition(
writeState, write, writeState);
transitionsList.add(writeTransition);
// create a new write done action once
if (outputIndex == 100) {
String doneName = action.getName() + "newWriteDone";
int doneIndex = actionPosition(actions, doneName);
Action done = actions.get(doneIndex);
Transition doneTransition = dfFactory.createTransition(
writeState, done, target);
transitionsList.add(doneTransition);
}
}
break;
}
outputIndex = 0;
}
// repeatInput = false;
}
/**
* Updates the write index of the buffer after reading tokens
*
* @param action
* untagged action to change
* @param writeIndex
* index to update
* @param numTokens
* number of tokens read from the buffer
*/
private void updateUntagIndex(Action action, Var writeIndex, int numTokens) {
BlockBasic basicBlock = action.getBody().getLast();
Var localWriteIndex = action.getBody().newTempLocalVariable(
irFactory.createTypeInt(32), "localWriteIndex");
basicBlock.add(irFactory.createInstLoad(localWriteIndex, writeIndex));
Expression value = irFactory
.createExprBinary(irFactory.createExprVar(localWriteIndex),
OpBinary.PLUS, irFactory.createExprInt(numTokens),
irFactory.createTypeInt(32));
basicBlock.add(irFactory.createInstStore(writeIndex, value));
}
/**
* Checks if the action has already been transformed. in that case the
* non-transformed action is reconsidered
*
* @param action
* action to be checked
*/
private void verifVisitedActions(Action action, State source, State target) {
String actionName = action.getName();
if (visitedActionsNames.contains(actionName)) {
// if action is visited then it is replaced by not transformed
// action
visitedRenameIndex++;
int visitedIndex = actionNamePosition(visitedActionsNames,
actionName);
Action updateAction = visitedActions.get(visitedIndex);
updateFSM(updateAction, action, source, target);
} else {
visitedActionsNames.add(actionName);
visitedActions.add(action);
createActionsSet(action, source, target);
}
}
/**
* Visits a transition characterized by its source name, target name and
* action
*
* @param sourceName
* source state
* @param targetName
* target state
* @param action
* action of the transition
*/
private void visitTransition(State sourceState, State targetState,
Action action) {
// verify if the action is already transformed ==> update FSM
verifVisitedActions(action, sourceState, targetState);
if (!repeatInput) {
noRepeatActions.add(action);
}
repeatInput = false;
}
}