--- /dev/null
+/************************************************************************
+ ************************************************************************
+ FAUST compiler
+ Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ************************************************************************
+ ************************************************************************/
+
+/*****************************************************************************
+ HISTORY
+ 22/01/05 : corrected bug on bool signals cached in float variables
+*****************************************************************************/
+
+
+#include "compile_scal.hh"
+#include "timing.hh"
+
+#include "compile.hh"
+#include "sigtype.hh"
+
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <vector>
+#include <math.h>
+
+#include "floats.hh"
+#include "sigprint.hh"
+#include "sigtyperules.hh"
+#include "recursivness.hh"
+#include "simplify.hh"
+#include "privatise.hh"
+#include "prim2.hh"
+#include "xtended.hh"
+
+#include "compatibility.hh"
+#include "ppsig.hh"
+#include "sigToGraph.hh"
+
+using namespace std;
+
+extern bool gDrawSignals;
+extern bool gLessTempSwitch;
+extern int gMaxCopyDelay;
+extern string gClassName;
+extern string gMasterDocument;
+
+static Klass* signal2klass (const string& name, Tree sig)
+{
+ Type t = getCertifiedSigType(sig); //, NULLENV);
+ if (t->nature() == kInt) {
+
+ ScalarCompiler C( new SigIntGenKlass(name) );
+ C.compileSingleSignal(sig);
+ return C.getClass();
+
+ } else {
+
+ ScalarCompiler C( new SigFloatGenKlass(name) );
+ C.compileSingleSignal(sig);
+ return C.getClass();
+
+ }
+}
+
+
+/*****************************************************************************
+ getFreshID
+*****************************************************************************/
+
+map<string, int> ScalarCompiler::fIDCounters;
+
+string ScalarCompiler::getFreshID(const string& prefix)
+{
+ if (fIDCounters.find(prefix) == fIDCounters.end()) {
+ fIDCounters[prefix]=0;
+ }
+ int n = fIDCounters[prefix];
+ fIDCounters[prefix] = n+1;
+ return subst("$0$1", prefix, T(n));
+}
+
+
+/*****************************************************************************
+ prepare
+*****************************************************************************/
+
+extern bool gDumpNorm;
+
+Tree ScalarCompiler::prepare(Tree LS)
+{
+startTiming("ScalarCompiler::prepare");
+ startTiming("deBruijn2Sym");
+ Tree L1 = deBruijn2Sym(LS); // convert debruijn recursion into symbolic recursion
+ endTiming("deBruijn2Sym");
+ Tree L2 = simplify(L1); // simplify by executing every computable operation
+ Tree L3 = privatise(L2); // Un-share tables with multiple writers
+
+ // dump normal form
+ if (gDumpNorm) {
+ cout << ppsig(L3) << endl;
+ exit(0);
+ }
+
+ recursivnessAnnotation(L3); // Annotate L3 with recursivness information
+
+ startTiming("typeAnnotation");
+ typeAnnotation(L3); // Annotate L3 with type information
+ endTiming("typeAnnotation");
+
+ sharingAnalysis(L3); // annotate L3 with sharing count
+ fOccMarkup.mark(L3); // annotate L3 with occurences analysis
+ //annotationStatistics();
+endTiming("ScalarCompiler::prepare");
+
+ fRates = new RateInferrer(L3);
+ if (gDrawSignals) {
+ ofstream dotfile(subst("$0-sig.dot", gMasterDocument).c_str());
+ sigToGraph(L3, dotfile, fRates);
+ }
+ return L3;
+}
+
+Tree ScalarCompiler::prepare2(Tree L0)
+{
+startTiming("ScalarCompiler::prepare2");
+ recursivnessAnnotation(L0); // Annotate L0 with recursivness information
+ typeAnnotation(L0); // Annotate L0 with type information
+ sharingAnalysis(L0); // annotate L0 with sharing count
+ fOccMarkup.mark(L0); // annotate L0 with occurences analysis
+endTiming("ScalarCompiler::prepare2");
+
+ return L0;
+}
+
+/*****************************************************************************
+ compileMultiSignal
+*****************************************************************************/
+
+void ScalarCompiler::compileMultiSignal (Tree L)
+{
+ //contextor recursivness(0);
+ L = prepare(L); // optimize, share and annotate expression
+
+ for (int i = 0; i < fClass->inputs(); i++) {
+ fClass->addZone3(subst("$1* input$0 = input[$0];", T(i), xfloat()));
+ }
+ for (int i = 0; i < fClass->outputs(); i++) {
+ fClass->addZone3(subst("$1* output$0 = output[$0];", T(i), xfloat()));
+ }
+
+ for (int i = 0; isList(L); L = tl(L), i++) {
+ Tree sig = hd(L);
+ fClass->addExecCode(subst("output$0[i] = $2$1;", T(i), CS(sig), xcast()));
+ }
+ generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot));
+ generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
+ if (fDescription) {
+ fDescription->ui(prepareUserInterfaceTree(fUIRoot));
+ }
+}
+
+
+/*****************************************************************************
+ compileSingleSignal
+*****************************************************************************/
+
+void ScalarCompiler::compileSingleSignal (Tree sig)
+{
+ //contextor recursivness(0);
+ sig = prepare2(sig); // optimize and annotate expression
+ fClass->addExecCode(subst("output[i] = $0;", CS(sig)));
+ generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot));
+ generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
+ if (fDescription) {
+ fDescription->ui(prepareUserInterfaceTree(fUIRoot));
+ }
+}
+
+
+/*****************************************************************************
+ CS : compile a signal
+*****************************************************************************/
+
+/**
+ * Test if a signal is already compiled
+ * @param sig the signal expression to compile.
+ * @param name the string representing the compiled expression.
+ * @return true is already compiled
+ */
+bool ScalarCompiler::getCompiledExpression(Tree sig, string& cexp)
+{
+ return fCompileProperty.get(sig, cexp);
+}
+
+/**
+ * Set the string of a compiled expression is already compiled
+ * @param sig the signal expression to compile.
+ * @param cexp the string representing the compiled expression.
+ * @return the cexp (for commodity)
+ */
+string ScalarCompiler::setCompiledExpression(Tree sig, const string& cexp)
+{
+ //cerr << "ScalarCompiler::setCompiledExpression : " << cexp << " ==> " << ppsig(sig) << endl;
+ string old; if (fCompileProperty.get(sig, old) && (old != cexp)) {
+ cerr << "ERROR already a compiled expression attached : " << old << " replaced by " << cexp << endl;
+ exit(1);
+ }
+ fCompileProperty.set(sig, cexp);
+ return cexp;
+}
+
+/**
+ * Compile a signal
+ * @param sig the signal expression to compile.
+ * @return the C code translation of sig as a string
+ */
+string ScalarCompiler::CS (Tree sig)
+{
+ //contextor contextRecursivness;
+ string code;
+
+ if (!getCompiledExpression(sig, code)) {
+ // not compiled yet
+/* if (getRecursivness(sig) != contextRecursivness.get()) {
+ contextRecursivness.set(getRecursivness(sig));
+ }*/
+ code = generateCode(sig);
+ setCompiledExpression(sig, code);
+ }
+ return code;
+}
+
+/*****************************************************************************
+ generateCode : dispatch according to signal
+*****************************************************************************/
+/**
+ * Main code generator dispatch.
+ * @param sig the signal expression to compile.
+ * @return the C code translation of sig
+ */
+
+string ScalarCompiler::generateCode (Tree sig)
+{
+#if 0
+ fprintf(stderr, "CALL generateCode(");
+ printSignal(sig, stderr);
+ fprintf(stderr, ")\n");
+#endif
+
+ int i;
+ double r;
+ Tree c, sel, x, y, z, label, id, ff, largs, type, name, file;
+
+ //printf("compilation of %p : ", sig); print(sig); printf("\n");
+
+ if ( getUserData(sig) ) { return generateXtended(sig); }
+ else if ( isSigInt(sig, &i) ) { return generateNumber(sig, T(i)); }
+ else if ( isSigReal(sig, &r) ) { return generateNumber(sig, T(r)); }
+ else if ( isSigInput(sig, &i) ) { return generateInput (sig, T(i)); }
+ else if ( isSigOutput(sig, &i, x) ) { return generateOutput (sig, T(i), CS(x));}
+
+ else if ( isSigFixDelay(sig, x, y) ) { return generateFixDelay (sig, x, y); }
+ else if ( isSigPrefix(sig, x, y) ) { return generatePrefix (sig, x, y); }
+ else if ( isSigIota(sig, x) ) { return generateIota (sig, x); }
+
+ else if ( isSigBinOp(sig, &i, x, y) ) { return generateBinOp (sig, i, x, y); }
+ else if ( isSigFFun(sig, ff, largs) ) { return generateFFun (sig, ff, largs); }
+ else if ( isSigFConst(sig, type, name, file) ) { return generateFConst(sig, tree2str(file), tree2str(name)); }
+ else if ( isSigFVar(sig, type, name, file) ) { return generateFVar(sig, tree2str(file), tree2str(name)); }
+
+ else if ( isSigTable(sig, id, x, y) ) { return generateTable (sig, x, y); }
+ else if ( isSigWRTbl(sig, id, x, y, z) ) { return generateWRTbl (sig, x, y, z); }
+ else if ( isSigRDTbl(sig, x, y) ) { return generateRDTbl (sig, x, y); }
+
+ else if ( isSigSelect2(sig, sel, x, y) ) { return generateSelect2 (sig, sel, x, y); }
+ else if ( isSigSelect3(sig, sel, x, y, z) ) { return generateSelect3 (sig, sel, x, y, z); }
+
+ else if ( isSigGen(sig, x) ) { return generateSigGen (sig, x); }
+
+ else if ( isProj(sig, &i, x) ) { return generateRecProj (sig, x, i); }
+
+ else if ( isSigIntCast(sig, x) ) { return generateIntCast (sig, x); }
+ else if ( isSigFloatCast(sig, x) ) { return generateFloatCast (sig, x); }
+
+ else if ( isSigButton(sig, label) ) { return generateButton (sig, label); }
+ else if ( isSigCheckbox(sig, label) ) { return generateCheckbox (sig, label); }
+ else if ( isSigVSlider(sig, label,c,x,y,z) ) { return generateVSlider (sig, label, c,x,y,z); }
+ else if ( isSigHSlider(sig, label,c,x,y,z) ) { return generateHSlider (sig, label, c,x,y,z); }
+ else if ( isSigNumEntry(sig, label,c,x,y,z) ) { return generateNumEntry (sig, label, c,x,y,z); }
+
+ else if ( isSigVBargraph(sig, label,x,y,z) ) { return generateVBargraph (sig, label, x, y, CS(z)); }
+ else if ( isSigHBargraph(sig, label,x,y,z) ) { return generateHBargraph (sig, label, x, y, CS(z)); }
+ else if ( isSigAttach(sig, x, y) ) { CS(y); return generateCacheCode(sig, CS(x)); }
+
+ else if ( isSigUpSample(sig, x, y) ) { return generateUpSample(sig, x, y); }
+ else if ( isSigDownSample(sig, x, y) ) { return generateDownSample(sig, x, y); }
+
+
+ else {
+ printf("Error in compiling signal, unrecognized signal : ");
+ print(sig);
+ printf("\n");
+ exit(1);
+ }
+ return "error in generate code";
+}
+
+
+/*****************************************************************************
+ NUMBERS
+*****************************************************************************/
+
+
+string ScalarCompiler::generateNumber (Tree sig, const string& exp)
+{
+ string ctype, vname;
+ Occurences* o = fOccMarkup.retrieve(sig);
+
+ // check for number occuring in delays
+ if (o->getMaxDelay()>0) {
+ getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
+ generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
+ }
+ return exp;
+}
+
+/*****************************************************************************
+ FOREIGN CONSTANTS
+*****************************************************************************/
+
+
+string ScalarCompiler::generateFConst (Tree sig, const string& file, const string& exp)
+{
+ string ctype, vname;
+ Occurences* o = fOccMarkup.retrieve(sig);
+
+ addIncludeFile(file);
+
+ if (o->getMaxDelay()>0) {
+ getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
+ generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
+ }
+ return exp;
+}
+
+/*****************************************************************************
+ FOREIGN VARIABLES
+*****************************************************************************/
+
+
+string ScalarCompiler::generateFVar (Tree sig, const string& file, const string& exp)
+{
+ string ctype, vname;
+
+ addIncludeFile(file);
+ return generateCacheCode(sig, exp);
+}
+
+/*****************************************************************************
+ INPUTS - OUTPUTS
+*****************************************************************************/
+
+
+string ScalarCompiler::generateInput (Tree sig, const string& idx)
+{
+ return generateCacheCode(sig, subst("$1input$0[i]", idx, icast()));
+}
+
+
+string ScalarCompiler::generateOutput (Tree sig, const string& idx, const string& arg)
+{
+ string dst = subst("output$0[i]", idx);
+ fClass->addExecCode(subst("$0 = $2$1;", dst, arg, xcast()));
+ return dst;
+}
+
+
+/*****************************************************************************
+ BINARY OPERATION
+*****************************************************************************/
+
+string ScalarCompiler::generateBinOp(Tree sig, int opcode, Tree arg1, Tree arg2)
+{
+ return generateCacheCode(sig, subst("($0 $1 $2)", CS(arg1), gBinOpTable[opcode]->fName, CS(arg2)));
+}
+
+
+/*****************************************************************************
+ Primitive Operations
+*****************************************************************************/
+
+string ScalarCompiler::generateFFun(Tree sig, Tree ff, Tree largs)
+{
+ addIncludeFile(ffincfile(ff)); //printf("inc file %s\n", ffincfile(ff));
+ addLibrary(fflibfile(ff)); //printf("lib file %s\n", fflibfile(ff));
+
+ string code = ffname(ff);
+ code += '(';
+ string sep = "";
+ for (int i = 0; i< ffarity(ff); i++) {
+ code += sep;
+ code += CS(nth(largs, i));
+ sep = ", ";
+ }
+ code += ')';
+ return generateCacheCode(sig, code);
+}
+
+
+/*****************************************************************************
+ CACHE CODE
+*****************************************************************************/
+
+void ScalarCompiler::getTypedNames(Type t, const string& prefix, string& ctype, string& vname)
+{
+ if (t->nature() == kInt) {
+ ctype = "int"; vname = subst("i$0", getFreshID(prefix));
+ } else {
+ ctype = ifloat(); vname = subst("f$0", getFreshID(prefix));
+ }
+}
+
+string ScalarCompiler::generateCacheCode(Tree sig, const string& exp)
+{
+ string vname, ctype, code;
+ int sharing = getSharingCount(sig);
+ Occurences* o = fOccMarkup.retrieve(sig);
+
+ // check reentrance
+ if (getCompiledExpression(sig, code)) {
+ return code;
+ }
+
+ // check for expression occuring in delays
+ if (o->getMaxDelay()>0) {
+
+ getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
+ if (sharing>1) {
+ return generateDelayVec(sig, generateVariableStore(sig,exp), ctype, vname, o->getMaxDelay());
+ } else {
+ return generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
+ }
+
+ } else if (sharing == 1) {
+
+ return exp;
+
+ } else if (sharing > 1) {
+
+ return generateVariableStore(sig, exp);
+
+ } else {
+ cerr << "Error in sharing count (" << sharing << ") for " << *sig << endl;
+ exit(1);
+ }
+
+ return "Error in generateCacheCode";
+}
+
+
+string ScalarCompiler::generateVariableStore(Tree sig, const string& exp)
+{
+ string vname, ctype;
+ Type t = getCertifiedSigType(sig);
+
+ switch (t->variability()) {
+
+ case kKonst :
+
+ getTypedNames(t, "Const", ctype, vname);
+ fClass->addDeclCode(subst("$0 \t$1;", ctype, vname));
+ fClass->addInitCode(subst("$0 = $1;", vname, exp));
+ break;
+
+ case kBlock :
+
+ getTypedNames(t, "Slow", ctype, vname);
+ fClass->addFirstPrivateDecl(vname);
+ fClass->addZone2(subst("$0 \t$1 = $2;", ctype, vname, exp));
+ break;
+
+ case kSamp :
+
+ getTypedNames(t, "Temp", ctype, vname);
+ fClass->addExecCode(subst("$0 $1 = $2;", ctype, vname, exp));
+ break;
+ }
+ return vname;
+}
+
+
+/*****************************************************************************
+ CASTING
+*****************************************************************************/
+
+
+string ScalarCompiler::generateIntCast(Tree sig, Tree x)
+{
+ return generateCacheCode(sig, subst("int($0)", CS(x)));
+}
+
+string ScalarCompiler::generateFloatCast (Tree sig, Tree x)
+{
+ return generateCacheCode(sig, subst("$1($0)", CS(x), ifloat()));
+}
+
+/*****************************************************************************
+ user interface elements
+*****************************************************************************/
+
+string ScalarCompiler::generateButton(Tree sig, Tree path)
+{
+ string varname = getFreshID("fbutton");
+ fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
+ fClass->addInitCode(subst("$0 = 0.0;", varname));
+ addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
+ return generateCacheCode(sig, varname);
+}
+
+string ScalarCompiler::generateCheckbox(Tree sig, Tree path)
+{
+ string varname = getFreshID("fcheckbox");
+ fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
+ fClass->addInitCode(subst("$0 = 0.0;", varname));
+ addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
+ return generateCacheCode(sig, varname);
+}
+
+
+string ScalarCompiler::generateVSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
+{
+ string varname = getFreshID("fslider");
+ fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
+ fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur))));
+ addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
+ return generateCacheCode(sig, varname);
+}
+
+string ScalarCompiler::generateHSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
+{
+ string varname = getFreshID("fslider");
+ fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
+ fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur))));
+ addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
+ return generateCacheCode(sig, varname);
+}
+
+string ScalarCompiler::generateNumEntry(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
+{
+ string varname = getFreshID("fentry");
+ fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
+ fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur))));
+ addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
+ return generateCacheCode(sig, varname);
+}
+
+
+string ScalarCompiler::generateVBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
+{
+ string varname = getFreshID("fbargraph");
+ fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
+ addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
+
+ Type t = getCertifiedSigType(sig);
+ switch (t->variability()) {
+
+ case kKonst :
+ fClass->addInitCode(subst("$0 = $1;", varname, exp));
+ break;
+
+ case kBlock :
+ fClass->addZone2(subst("$0 = $1;", varname, exp));
+ break;
+
+ case kSamp :
+ fClass->addExecCode(subst("$0 = $1;", varname, exp));
+ break;
+ }
+
+ //return varname;
+ return generateCacheCode(sig, varname);
+}
+
+
+string ScalarCompiler::generateHBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
+{
+ string varname = getFreshID("fbargraph");
+ fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
+ addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
+
+ Type t = getCertifiedSigType(sig);
+ switch (t->variability()) {
+
+ case kKonst :
+ fClass->addInitCode(subst("$0 = $1;", varname, exp));
+ break;
+
+ case kBlock :
+ fClass->addZone2(subst("$0 = $1;", varname, exp));
+ break;
+
+ case kSamp :
+ fClass->addExecCode(subst("$0 = $1;", varname, exp));
+ break;
+ }
+
+ //return varname;
+ return generateCacheCode(sig, varname);
+}
+
+
+
+
+/*****************************************************************************
+ TABLES
+*****************************************************************************/
+
+
+
+/*----------------------------------------------------------------------------
+ sigGen : initial table content
+----------------------------------------------------------------------------*/
+
+string ScalarCompiler::generateSigGen(Tree sig, Tree content)
+{
+ string klassname = getFreshID("SIG");
+ string signame = getFreshID("sig");
+
+ fClass->addSubKlass(signal2klass(klassname, content));
+ fClass->addInitCode(subst("$0 $1;", klassname, signame));
+ fInstanceInitProperty.set(content, pair<string,string>(klassname,signame));
+
+ return signame;
+}
+
+string ScalarCompiler::generateStaticSigGen(Tree sig, Tree content)
+{
+ string klassname = getFreshID("SIG");
+ string signame = getFreshID("sig");
+
+ fClass->addSubKlass(signal2klass(klassname, content));
+ fClass->addStaticInitCode(subst("$0 $1;", klassname, signame));
+ fStaticInitProperty.set(content, pair<string,string>(klassname,signame));
+
+ return signame;
+}
+
+
+/*----------------------------------------------------------------------------
+ sigTable : table declaration
+----------------------------------------------------------------------------*/
+
+string ScalarCompiler::generateTable(Tree sig, Tree tsize, Tree content)
+{
+ string generator(CS(content));
+ Tree g;
+ string cexp;
+ string ctype, vname;
+ int size;
+
+ // already compiled but check if we need to add declarations
+
+ assert ( isSigGen(content, g) );
+ pair<string,string> kvnames;
+ if ( ! fInstanceInitProperty.get(g, kvnames)) {
+ // not declared here, we add a declaration
+ bool b = fStaticInitProperty.get(g, kvnames);
+ assert(b);
+ fClass->addInitCode(subst("$0 $1;", kvnames.first, kvnames.second));
+ }
+
+ if (!isSigInt(tsize, &size)) {
+ //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
+ cerr << "error in ScalarCompiler::generateTable() : "
+ << *tsize
+ << " is not a constant integer table size expression "
+ << endl;
+ exit(1);
+ }
+ // definition du nom et du type de la table
+ // A REVOIR !!!!!!!!!
+ Type t = getCertifiedSigType(content);//, tEnv);
+ if (t->nature() == kInt) {
+ vname = getFreshID("itbl");
+ ctype = "int";
+ } else {
+ vname = getFreshID("ftbl");
+ ctype = ifloat();
+ }
+
+ // declaration de la table
+ fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(size)));
+
+ // initialisation du generateur de contenu
+ fClass->addInitCode(subst("$0.init(samplingFreq);", generator));
+ // remplissage de la table
+ fClass->addInitCode(subst("$0.fill($1,$2);", generator, T(size), vname));
+
+ // on retourne le nom de la table
+ return vname;
+}
+
+string ScalarCompiler::generateStaticTable(Tree sig, Tree tsize, Tree content)
+{
+ //string generator(CS(content));
+ Tree g;
+ string cexp;
+ string ctype, vname;
+ int size;
+
+ assert ( isSigGen(content, g) );
+
+ if (!getCompiledExpression(content, cexp)) {
+ cexp = setCompiledExpression(content, generateStaticSigGen(content, g));
+ } else {
+ // already compiled but check if we need to add declarations
+ pair<string,string> kvnames;
+ if ( ! fStaticInitProperty.get(g, kvnames)) {
+ // not declared here, we add a declaration
+ bool b = fInstanceInitProperty.get(g, kvnames);
+ assert(b);
+ fClass->addStaticInitCode(subst("$0 $1;", kvnames.first, kvnames.second));
+ }
+ }
+
+ if (!isSigInt(tsize, &size)) {
+ //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
+ cerr << "error in ScalarCompiler::generateTable() : "
+ << *tsize
+ << " is not a constant integer table size expression "
+ << endl;
+ exit(1);
+ }
+ // definition du nom et du type de la table
+ // A REVOIR !!!!!!!!!
+ Type t = getCertifiedSigType(content);//, tEnv);
+ if (t->nature() == kInt) {
+ vname = getFreshID("itbl");
+ ctype = "int";
+ } else {
+ vname = getFreshID("ftbl");
+ ctype = ifloat();
+ }
+
+ // declaration de la table
+ fClass->addDeclCode(subst("static $0 \t$1[$2];", ctype, vname, T(size)));
+ fClass->addStaticFields(subst("$0 \t$1::$2[$3];", ctype, fClass->getClassName(), vname, T(size) ));
+
+ // initialisation du generateur de contenu
+ fClass->addStaticInitCode(subst("$0.init(samplingFreq);", cexp));
+ // remplissage de la table
+ fClass->addStaticInitCode(subst("$0.fill($1,$2);", cexp, T(size), vname));
+
+ // on retourne le nom de la table
+ return vname;
+}
+
+
+/*----------------------------------------------------------------------------
+ sigWRTable : table assignement
+----------------------------------------------------------------------------*/
+
+string ScalarCompiler::generateWRTbl(Tree sig, Tree tbl, Tree idx, Tree data)
+{
+ string tblName(CS(tbl));
+ fClass->addExecCode(subst("$0[$1] = $2;", tblName, CS(idx), CS(data)));
+ return tblName;
+}
+
+
+/*----------------------------------------------------------------------------
+ sigRDTable : table access
+----------------------------------------------------------------------------*/
+
+string ScalarCompiler::generateRDTbl(Tree sig, Tree tbl, Tree idx)
+{
+ // YO le 21/04/05 : La lecture des tables n'�ait pas mise dans le cache
+ // et donc le code �ait dupliqu�(dans tester.dsp par exemple)
+ //return subst("$0[$1]", CS(tEnv, tbl), CS(tEnv, idx));
+
+ //cerr << "generateRDTable " << *sig << endl;
+ // test the special case of a read only table that can be compiled
+ // has a static member
+ Tree id, size, content;
+ if( isSigTable(tbl, id, size, content) ) {
+ string tblname;
+ if (!getCompiledExpression(tbl, tblname)) {
+ tblname = setCompiledExpression(tbl, generateStaticTable(tbl, size, content));
+ }
+ return generateCacheCode(sig, subst("$0[$1]", tblname, CS(idx)));
+ } else {
+ return generateCacheCode(sig, subst("$0[$1]", CS(tbl), CS(idx)));
+ }
+}
+
+
+
+/*****************************************************************************
+ RECURSIONS
+*****************************************************************************/
+
+
+/**
+ * Generate code for a projection of a group of mutually recursive definitions
+ */
+string ScalarCompiler::generateRecProj(Tree sig, Tree r, int i)
+{
+ string vname;
+ Tree var, le;
+
+ if ( ! getVectorNameProperty(sig, vname)) {
+ assert(isRec(r, var, le));
+ generateRec(r, var, le);
+ assert(getVectorNameProperty(sig, vname));
+ }
+ return "[[UNUSED EXP]]"; // make sure the resulting expression is never used in the generated code
+}
+
+
+/**
+ * Generate code for a group of mutually recursive definitions
+ */
+void ScalarCompiler::generateRec(Tree sig, Tree var, Tree le)
+{
+ int N = len(le);
+
+ vector<bool> used(N);
+ vector<int> delay(N);
+ vector<string> vname(N);
+ vector<string> ctype(N);
+
+ // prepare each element of a recursive definition
+ for (int i=0; i<N; i++) {
+ Tree e = sigProj(i,sig); // recreate each recursive definition
+ if (fOccMarkup.retrieve(e)) {
+ // this projection is used
+ used[i] = true;
+ getTypedNames(getCertifiedSigType(e), "Rec", ctype[i], vname[i]);
+ setVectorNameProperty(e, vname[i]);
+ delay[i] = fOccMarkup.retrieve(e)->getMaxDelay();
+ } else {
+ // this projection is not used therefore
+ // we should not generate code for it
+ used[i] = false;
+ }
+ }
+
+ // generate delayline for each element of a recursive definition
+ for (int i=0; i<N; i++) {
+ if (used[i]) {
+ generateDelayLine(ctype[i], vname[i], delay[i], CS(nth(le,i)));
+ }
+ }
+}
+
+
+/*****************************************************************************
+ PREFIX, DELAY A PREFIX VALUE
+*****************************************************************************/
+
+string ScalarCompiler::generatePrefix (Tree sig, Tree x, Tree e)
+{
+ Type te = getCertifiedSigType(sig);//, tEnv);
+
+ string vperm = getFreshID("M");
+ string vtemp = getFreshID("T");
+
+ string type = cType(te);
+
+ fClass->addDeclCode(subst("$0 \t$1;", type, vperm));
+ fClass->addInitCode(subst("$0 = $1;", vperm, CS(x)));
+
+ fClass->addExecCode(subst("$0 $1 = $2;", type, vtemp, vperm));
+ fClass->addExecCode(subst("$0 = $1;", vperm, CS(e)));
+ return vtemp;
+}
+
+
+/*****************************************************************************
+ IOTA(n)
+*****************************************************************************/
+static bool isPowerOf2(int n)
+{
+ return !(n & (n - 1));
+}
+
+string ScalarCompiler::generateIota (Tree sig, Tree n)
+{
+ int size;
+ if (!isSigInt(n, &size)) { fprintf(stderr, "error in generateIota\n"); exit(1); }
+
+ string vperm = getFreshID("iota");
+
+ fClass->addDeclCode(subst("int \t$0;", vperm));
+ fClass->addInitCode(subst("$0 = 0;", vperm));
+
+ if (isPowerOf2(size)) {
+ fClass->addExecCode(subst("$0 = ($0+1)&$1;", vperm, T(size-1)));
+ } else {
+ fClass->addExecCode(subst("if (++$0 == $1) $0=0;", vperm, T(size)));
+ }
+ return vperm;
+}
+
+
+
+// a revoir en utilisant la lecture de table et en partageant la construction de la paire de valeurs
+
+
+/**
+ * Generate a select2 code
+ */
+
+string ScalarCompiler::generateSelect2 (Tree sig, Tree sel, Tree s1, Tree s2)
+{
+ return generateCacheCode(sig, subst( "(($0)?$1:$2)", CS(sel), CS(s2), CS(s1) ) );
+}
+
+
+/**
+ * Generate a select3 code (using if-then-else)
+ * ((int n = sel==0)? s0 : ((sel==1)? s1 : s2))
+ * int nn; ((nn=sel) ? ((nn==1)? s1 : s2) : s0);
+ */
+string ScalarCompiler::generateSelect3 (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3)
+{
+ return generateCacheCode(sig, subst( "(($0==0)? $1 : (($0==1)?$2:$3) )", CS(sel), CS(s1), CS(s2), CS(s3) ) );
+}
+
+#if 0
+string ScalarCompiler::generateSelect3 (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3)
+{
+ Type t = getCertifiedSigType(sig);
+ Type t1 = getCertifiedSigType(s1);
+ Type t2 = getCertifiedSigType(s2);
+ Type t3 = getCertifiedSigType(s3);
+ Type w = min(t1,min(t2,t3));
+
+ string type = cType(t);
+ string var = getFreshID("S");
+
+ switch (w->variability())
+ {
+ case kKonst :
+ fClass->addDeclCode(subst("$0 \t$1[3];", type, var));
+ break;
+ case kBlock :
+ //fClass->addLocalDecl(type, subst("$0[3]", var));
+ //fClass->addLocalVecDecl(type, var, 3);
+ fClass->addSharedDecl(var);
+ fClass->addZone1(subst("$0 \t$1[3];", type, var));
+ break;
+ case kSamp :
+ fClass->addExecCode(subst("$0 \t$1[3];", type, var));
+ break;
+ }
+
+ switch (t1->variability())
+ {
+ case kKonst :
+ fClass->addInitCode(subst("$0[0] = $1;", var, CS(s1)));
+ break;
+ case kBlock :
+ fClass->addZone2b(subst("$0[0] = $1;", var, CS(s1)));
+ break;
+ case kSamp :
+ fClass->addExecCode(subst("$0[0] = $1;", var, CS(s1)));
+ break;
+ }
+
+ switch (t2->variability())
+ {
+ case kKonst :
+ fClass->addInitCode(subst("$0[1] = $1;", var, CS(s2)));
+ break;
+ case kBlock :
+ fClass->addZone2b(subst("$0[1] = $1;", var, CS(s2)));
+ break;
+ case kSamp :
+ fClass->addExecCode(subst("$0[1] = $1;", var, CS(s2)));
+ break;
+ }
+
+ switch (t3->variability())
+ {
+ case kKonst :
+ fClass->addInitCode(subst("$0[2] = $1;", var, CS(s3)));
+ break;
+ case kBlock :
+ fClass->addZone2b(subst("$0[2] = $1;", var, CS(s3)));
+ break;
+ case kSamp :
+ fClass->addExecCode(subst("$0[2] = $1;", var, CS(s3)));
+ break;
+ }
+
+ return generateCacheCode(sig, subst("$0[$1]", var, CS(sel)));
+}
+#endif
+
+/**
+ * retrieve the type annotation of sig
+ * @param sig the signal we want to know the type
+ */
+string ScalarCompiler::generateXtended (Tree sig)
+{
+ xtended* p = (xtended*) getUserData(sig);
+ vector<string> args;
+ vector<Type> types;
+
+ for (int i=0; i<sig->arity(); i++) {
+ args.push_back(CS(sig->branch(i)));
+ types.push_back(getCertifiedSigType(sig->branch(i)));
+ }
+
+ if (p->needCache()) {
+ return generateCacheCode(sig, p->generateCode(fClass, args, types));
+ } else {
+ return p->generateCode(fClass, args, types);
+ }
+}
+
+
+
+//------------------------------------------------------------------------------------------------
+
+
+/*****************************************************************************
+ vector name property
+*****************************************************************************/
+
+/**
+ * Set the vector name property of a signal, the name of the vector used to
+ * store the previous values of the signal to implement a delay.
+ * @param sig the signal expression.
+ * @param vecname the string representing the vector name.
+ * @return true is already compiled
+ */
+void ScalarCompiler::setVectorNameProperty(Tree sig, const string& vecname)
+{
+ fVectorProperty.set(sig, vecname);
+}
+
+
+/**
+ * Get the vector name property of a signal, the name of the vector used to
+ * store the previous values of the signal to implement a delay.
+ * @param sig the signal expression.
+ * @param vecname the string where to store the vector name.
+ * @return true if the signal has this property, false otherwise
+ */
+
+bool ScalarCompiler::getVectorNameProperty(Tree sig, string& vecname)
+{
+ return fVectorProperty.get(sig, vecname);
+}
+
+
+/**
+ * Compute the minimal power of 2 greater than x
+ */
+
+int ScalarCompiler::pow2limit(int x)
+{
+ int n = 2;
+ while (n < x) { n = 2*n; }
+ return n;
+}
+
+/*****************************************************************************
+ N-SAMPLE FIXED DELAY : sig = exp@delay
+
+ case 1-sample max delay :
+ Y(t-0) Y(t-1)
+ Temp Var gLessTempSwitch = false
+ V[0] V[1] gLessTempSwitch = true
+
+ case max delay < gMaxCopyDelay :
+ Y(t-0) Y(t-1) Y(t-2) ...
+ Temp V[0] V[1] ... gLessTempSwitch = false
+ V[0] V[1] V[2] ... gLessTempSwitch = true
+
+ case max delay >= gMaxCopyDelay :
+ Y(t-0) Y(t-1) Y(t-2) ...
+ Temp V[0] V[1] ...
+ V[0] V[1] V[2] ...
+
+
+*****************************************************************************/
+
+/**
+ * Generate code for accessing a delayed signal. The generated code depend of
+ * the maximum delay attached to exp and the gLessTempSwitch.
+ */
+
+string ScalarCompiler::generateFixDelay (Tree sig, Tree exp, Tree delay)
+{
+ int mxd, d;
+ string vecname;
+
+ //cerr << "ScalarCompiler::generateFixDelay sig = " << *sig << endl;
+ //cerr << "ScalarCompiler::generateFixDelay exp = " << *exp << endl;
+ //cerr << "ScalarCompiler::generateFixDelay del = " << *delay << endl;
+
+ CS(exp); // ensure exp is compiled to have a vector name
+
+ mxd = fOccMarkup.retrieve(exp)->getMaxDelay();
+
+ if (! getVectorNameProperty(exp, vecname)) {
+ cerr << "No vector name for : " << ppsig(exp) << endl;
+ assert(0);
+ }
+
+ if (mxd == 0) {
+ // not a real vector name but a scalar name
+ return vecname;
+
+ } else if (mxd < gMaxCopyDelay) {
+ if (isSigInt(delay, &d)) {
+ return subst("$0[$1]", vecname, CS(delay));
+ } else {
+ return generateCacheCode(sig, subst("$0[$1]", vecname, CS(delay)));
+ }
+
+ } else {
+
+ // long delay : we use a ring buffer of size 2^x
+ int N = pow2limit( mxd+1 );
+ return generateCacheCode(sig, subst("$0[(IOTA-$1)&$2]", vecname, CS(delay), T(N-1)));
+ }
+}
+
+
+/**
+ * Generate code for the delay mecchanism. The generated code depend of the
+ * maximum delay attached to exp and the "less temporaries" switch
+ */
+
+string ScalarCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
+{
+ string s = generateDelayVecNoTemp(sig, exp, ctype, vname, mxd);
+ if (getCertifiedSigType(sig)->variability() < kSamp) {
+ return exp;
+ } else {
+ return s;
+ }
+}
+
+/**
+ * Generate code for the delay mecchanism without using temporary variables
+ */
+
+string ScalarCompiler::generateDelayVecNoTemp(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
+{
+ assert(mxd > 0);
+
+ //bool odocc = fOccMarkup.retrieve(sig)->hasOutDelayOccurences();
+
+ if (mxd < gMaxCopyDelay) {
+
+ // short delay : we copy
+ fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(mxd+1)));
+ fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(mxd+1)));
+ fClass->addExecCode(subst("$0[0] = $1;", vname, exp));
+
+ // generate post processing copy code to update delay values
+ if (mxd == 1) {
+ fClass->addPostCode(subst("$0[1] = $0[0];", vname));
+ } else if (mxd == 2) {
+ //fClass->addPostCode(subst("$0[2] = $0[1];", vname));
+ fClass->addPostCode(subst("$0[2] = $0[1]; $0[1] = $0[0];", vname));
+ } else {
+ fClass->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd), vname));
+ }
+ setVectorNameProperty(sig, vname);
+ return subst("$0[0]", vname);
+
+ } else {
+
+ // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
+ int N = pow2limit(mxd+1);
+
+ // we need a iota index
+ ensureIotaCode();
+
+ // declare and init
+ fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(N)));
+ fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(N)));
+
+ // execute
+ fClass->addExecCode(subst("$0[IOTA&$1] = $2;", vname, T(N-1), exp));
+ setVectorNameProperty(sig, vname);
+ return subst("$0[IOTA&$1]", vname, T(N-1));
+ }
+}
+
+/**
+ * Generate code for the delay mecchanism without using temporary variables
+ */
+
+void ScalarCompiler::generateDelayLine(const string& ctype, const string& vname, int mxd, const string& exp)
+{
+ //assert(mxd > 0);
+ if (mxd == 0) {
+ // cerr << "MXD==0 : " << vname << " := " << exp << endl;
+ // no need for a real vector
+ fClass->addExecCode(subst("$0 \t$1 = $2;", ctype, vname, exp));
+
+
+ } else if (mxd < gMaxCopyDelay) {
+ // cerr << "small delay : " << vname << "[" << mxd << "]" << endl;
+
+ // short delay : we copy
+ fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(mxd+1)));
+ fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(mxd+1)));
+ fClass->addExecCode(subst("$0[0] = $1;", vname, exp));
+
+ // generate post processing copy code to update delay values
+ if (mxd == 1) {
+ fClass->addPostCode(subst("$0[1] = $0[0];", vname));
+ } else if (mxd == 2) {
+ fClass->addPostCode(subst("$0[2] = $0[1]; $0[1] = $0[0];", vname));
+ } else {
+ fClass->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd), vname));
+ }
+
+ } else {
+
+ // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
+ int N = pow2limit(mxd+1);
+
+ // we need a iota index
+ ensureIotaCode();
+
+ // declare and init
+ fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(N)));
+ fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(N)));
+
+ // execute
+ fClass->addExecCode(subst("$0[IOTA&$1] = $2;", vname, T(N-1), exp));
+ }
+}
+
+/**
+ * Generate up sampling code
+ */
+
+string ScalarCompiler::generateUpSample(Tree sig, Tree w, Tree x)
+{
+ return CS(x);
+}
+
+/**
+ * Generate down sampling code
+ */
+
+string ScalarCompiler::generateDownSample(Tree sig, Tree w, Tree x)
+{
+ return CS(x);
+}
+
+
+/**
+ * Generate code for a unique IOTA variable increased at each sample
+ * and used to index ring buffers.
+ */
+void ScalarCompiler::ensureIotaCode()
+{
+ if (!fHasIota) {
+ fHasIota = true;
+ fClass->addDeclCode("int \tIOTA;");
+ fClass->addInitCode("IOTA = 0;");
+ fClass->addPostCode("IOTA = IOTA+1;");
+ }
+}