/*
* Copyright (c) 2012, 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.c;
import static net.sf.orcc.OrccLaunchConstants.ENABLE_TRACES;
import static net.sf.orcc.backends.BackendsConstants.ADDITIONAL_TRANSFOS;
import static net.sf.orcc.backends.BackendsConstants.BXDF_FILE;
import static net.sf.orcc.backends.BackendsConstants.IMPORT_BXDF;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.Platform;
import net.sf.orcc.backends.AbstractBackend;
import net.sf.orcc.backends.c.transform.CBroadcastAdder;
import net.sf.orcc.backends.transform.CastAdder;
import net.sf.orcc.backends.transform.DeadVariableRemoval;
import net.sf.orcc.backends.transform.DisconnectedOutputPortRemoval;
import net.sf.orcc.backends.transform.DivisionSubstitution;
import net.sf.orcc.backends.transform.EmptyBlockRemover;
import net.sf.orcc.backends.transform.Inliner;
import net.sf.orcc.backends.transform.InlinerByAnnotation;
import net.sf.orcc.backends.transform.InstPhiTransformation;
import net.sf.orcc.backends.transform.InstTernaryAdder;
import net.sf.orcc.backends.transform.ListFlattener;
import net.sf.orcc.backends.transform.LoopUnrolling;
import net.sf.orcc.backends.transform.Multi2MonoToken;
import net.sf.orcc.backends.transform.ParameterImporter;
import net.sf.orcc.backends.transform.StoreOnceTransformation;
import net.sf.orcc.backends.util.Alignable;
import net.sf.orcc.backends.util.BroadcastMapper;
import net.sf.orcc.backends.util.Mapping;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.Instance;
import net.sf.orcc.df.Network;
import net.sf.orcc.df.transform.ArgumentEvaluator;
import net.sf.orcc.df.transform.BroadcastAdder;
import net.sf.orcc.df.transform.BroadcastRemover;
import net.sf.orcc.df.transform.FifoSizePropagator;
import net.sf.orcc.df.transform.Instantiator;
import net.sf.orcc.df.transform.NetworkFlattener;
import net.sf.orcc.df.transform.SharedVarsDetection;
import net.sf.orcc.df.transform.TypeResizer;
import net.sf.orcc.df.transform.UnitImporter;
import net.sf.orcc.df.util.DfVisitor;
import net.sf.orcc.ir.CfgNode;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.transform.BlockCombine;
import net.sf.orcc.ir.transform.ControlFlowAnalyzer;
import net.sf.orcc.ir.transform.DeadCodeElimination;
import net.sf.orcc.ir.transform.DeadGlobalElimination;
import net.sf.orcc.ir.transform.PhiRemoval;
import net.sf.orcc.ir.transform.RenameTransformation;
import net.sf.orcc.ir.transform.SSATransformation;
import net.sf.orcc.ir.transform.SSAVariableRenamer;
import net.sf.orcc.ir.transform.TacTransformation;
import net.sf.orcc.tools.classifier.Classifier;
import net.sf.orcc.tools.mapping.XmlBufferSizeConfiguration;
import net.sf.orcc.tools.merger.action.ActionMerger;
import net.sf.orcc.tools.merger.actor.ActorMerger;
import net.sf.orcc.tools.stats.StatisticsPrinter;
import net.sf.orcc.util.FilesManager;
import net.sf.orcc.util.OrccLogger;
import net.sf.orcc.util.Result;
import net.sf.orcc.util.Void;
/**
* C back-end.
*
* @author Matthieu Wipliez
* @author Herve Yviquel
* @author Antoine Lorence
*
*/
public class CBackend extends AbstractBackend {
/**
* Path to target "src" folder
*/
protected String srcPath;
private final NetworkPrinter networkPrinter;
private final CMakePrinter cmakePrinter;
private final InstancePrinter instancePrinter;
private final TracesPrinter tracesPrinter;
private final StatisticsPrinter statsPrinter;
public CBackend() {
networkPrinter = new NetworkPrinter();
cmakePrinter = new CMakePrinter();
instancePrinter = new InstancePrinter();
tracesPrinter = new TracesPrinter();
statsPrinter = new StatisticsPrinter();
}
@Override
protected void doInitializeOptions() {
// Configure paths
srcPath = outputPath + File.separator + "src";
// Load options map into code generator instances
networkPrinter.setOptions(getOptions());
instancePrinter.setOptions(getOptions());
tracesPrinter.setOptions(getOptions());
// -----------------------------------------------------
// Transformations that will be applied on the Network
// -----------------------------------------------------
if (mergeActors) {
networkTransfos.add(new FifoSizePropagator(fifoSize));
networkTransfos.add(new BroadcastAdder());
} else {
networkTransfos.add(new FifoSizePropagator(fifoSize, true));
}
networkTransfos.add(new Instantiator(true));
networkTransfos.add(new NetworkFlattener());
networkTransfos.add(new UnitImporter());
networkTransfos.add(new DisconnectedOutputPortRemoval());
if (classify) {
networkTransfos.add(new Classifier());
}
if (mergeActors) {
networkTransfos.add(new ActorMerger());
} else {
networkTransfos.add(new CBroadcastAdder());
}
if (mergeActors) {
networkTransfos.add(new BroadcastRemover());
}
networkTransfos.add(new ArgumentEvaluator());
networkTransfos.add(new TypeResizer(true, false, true, false));
networkTransfos.add(new RenameTransformation(getRenameMap()));
networkTransfos.add(new SharedVarsDetection());
// -------------------------------------------------------------------
// Transformations that will be applied on children (instances/actors)
// -------------------------------------------------------------------
if (mergeActions) {
childrenTransfos.add(new ActionMerger());
}
if (convertMulti2Mono) {
childrenTransfos.add(new Multi2MonoToken());
}
childrenTransfos.add(new DfVisitor<Void>(new InlinerByAnnotation()));
childrenTransfos.add(new DfVisitor<Void>(new LoopUnrolling()));
// If "-t" option is passed to command line, apply additional
// transformations
if (getOption(ADDITIONAL_TRANSFOS, false)) {
childrenTransfos.add(new StoreOnceTransformation());
childrenTransfos.add(new DfVisitor<Void>(new SSATransformation()));
childrenTransfos.add(new DfVisitor<Void>(new PhiRemoval()));
childrenTransfos.add(new Multi2MonoToken());
childrenTransfos.add(new DivisionSubstitution());
childrenTransfos.add(new ParameterImporter());
childrenTransfos.add(new DfVisitor<Void>(new Inliner(true, true)));
// transformations.add(new UnaryListRemoval());
// transformations.add(new GlobalArrayInitializer(true));
childrenTransfos.add(new DfVisitor<Void>(new InstTernaryAdder()));
childrenTransfos.add(new DeadGlobalElimination());
childrenTransfos.add(new DfVisitor<Void>(new DeadVariableRemoval()));
childrenTransfos.add(new DfVisitor<Void>(new DeadCodeElimination()));
childrenTransfos.add(new DfVisitor<Void>(new DeadVariableRemoval()));
childrenTransfos.add(new DfVisitor<Void>(new ListFlattener()));
childrenTransfos.add(new DfVisitor<Expression>(new TacTransformation()));
childrenTransfos.add(new DfVisitor<CfgNode>(new ControlFlowAnalyzer()));
childrenTransfos.add(new DfVisitor<Void>(new InstPhiTransformation()));
childrenTransfos.add(new DfVisitor<Void>(new EmptyBlockRemover()));
childrenTransfos.add(new DfVisitor<Void>(new BlockCombine()));
childrenTransfos.add(new DfVisitor<Expression>(new CastAdder(true, true)));
childrenTransfos.add(new DfVisitor<Void>(new SSAVariableRenamer()));
}
}
protected Map<String, String> getRenameMap() {
Map<String, String> renameMap = new HashMap<String, String>();
renameMap.put("abs", "abs_replaced");
renameMap.put("getw", "getw_replaced");
renameMap.put("exit", "exit_replaced");
renameMap.put("index", "index_replaced");
renameMap.put("log2", "log2_replaced");
renameMap.put("max", "max_replaced");
renameMap.put("min", "min_replaced");
renameMap.put("select", "select_replaced");
renameMap.put("OUT", "OUT_REPLACED");
renameMap.put("IN", "IN_REPLACED");
renameMap.put("SIZE", "SIZE_REPLACED");
return renameMap;
}
@Override
protected Result doLibrariesExtraction() {
final Result result = FilesManager.extract("/runtime/C/README.txt", outputPath);
// Copy specific windows batch file
if (Platform.OS_WIN32.equals(Platform.getOS())) {
result.merge(FilesManager.extract("/runtime/C/run_cmake_with_VS_env.bat", outputPath));
}
result.merge(FilesManager.extract("/runtime/C/libs", outputPath));
String scriptsPath = outputPath + File.separator + "scripts";
OrccLogger.traceln("Export scripts into " + scriptsPath + "... ");
result.merge(FilesManager.extract("/runtime/common/scripts", outputPath));
result.merge(FilesManager.extract("/runtime/C/scripts", outputPath));
// Fix some permissions on scripts
new File(scriptsPath + File.separator + "profilingAnalyse.py").setExecutable(true);
new File(scriptsPath + File.separator + "benchAutoMapping.py").setExecutable(true);
return result;
}
@Override
protected void beforeGeneration(Network network) {
new File(outputPath + File.separator + "build").mkdirs();
new File(outputPath + File.separator + "bin").mkdirs();
network.computeTemplateMaps();
// if required, load the buffer size from the mapping file
if (getOption(IMPORT_BXDF, false)) {
File f = new File(getOption(BXDF_FILE, ""));
new XmlBufferSizeConfiguration(true, true).load(f, network);
}
if (network.getVertex(network.getSimpleName()) != null) {
final StringBuilder warnMsg = new StringBuilder();
warnMsg.append('"').append(network.getSimpleName()).append('"');
warnMsg.append(" is the name of both the network you want to generate");
warnMsg.append(" and a vertex in this network.").append('\n');
warnMsg.append("The 2 entities will be generated");
warnMsg.append(" in the same file. Please rename one of these elements to prevent");
warnMsg.append(" unwanted overwriting.");
OrccLogger.warnln(warnMsg.toString());
}
}
@Override
protected Result doGenerateNetwork(Network network) {
networkPrinter.setNetwork(network);
return FilesManager.writeFile(networkPrinter.getNetworkFileContent(), srcPath, network.getSimpleName() + ".c");
}
@Override
protected Result doAdditionalGeneration(Network network) {
cmakePrinter.setNetwork(network);
cmakePrinter.setOptions(getOptions());
final Result result = Result.newInstance();
result.merge(FilesManager.writeFile(cmakePrinter.rootCMakeContent(), outputPath, "CMakeLists.txt"));
result.merge(FilesManager.writeFile(cmakePrinter.srcCMakeContent(), srcPath, "CMakeLists.txt"));
if (getOption(ENABLE_TRACES, true)) {
result.merge(FilesManager.writeFile(tracesPrinter.getTracesFileContent(network), srcPath, "traces.txt"));
}
result.merge(
FilesManager.writeFile(statsPrinter.getContent(network), srcPath, network.getSimpleName() + ".csv"));
if (mergeActors) {
BroadcastMapper broadcastMapper = new BroadcastMapper();
broadcastMapper.prepareBroadcastMapping(network);
}
final Mapping mapper = new Mapping(network, mapping);
result.merge(FilesManager.writeFile(mapper.getContentFile(), srcPath, network.getSimpleName() + ".xcf"));
return result;
}
@Override
protected void beforeGeneration(Instance instance) {
// update "vectorizable" information
Alignable.setAlignability(instance.getActor());
}
@Override
protected Result doGenerateInstance(Instance instance) {
instancePrinter.setInstance(instance);
return FilesManager.writeFile(instancePrinter.getFileContent(), srcPath, instance.getSimpleName() + ".c");
}
@Override
protected void beforeGeneration(Actor actor) {
// update "vectorizable" information
Alignable.setAlignability(actor);
}
@Override
protected Result doGenerateActor(Actor actor) {
instancePrinter.setActor(actor);
return FilesManager.writeFile(instancePrinter.getFileContent(), srcPath, actor.getSimpleName() + ".c");
}
}