X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/1059e1cc0c2ecfa237406949aa26155b6a5b9154..66f23d4fabf89ad09adbd4dfc15ac6b5b2b7da83:/interpreter/preprocessor/faust-0.9.47mr3/compiler/generator/compile_scal.cpp diff --git a/interpreter/preprocessor/faust-0.9.47mr3/compiler/generator/compile_scal.cpp b/interpreter/preprocessor/faust-0.9.47mr3/compiler/generator/compile_scal.cpp new file mode 100644 index 0000000..a1dfaef --- /dev/null +++ b/interpreter/preprocessor/faust-0.9.47mr3/compiler/generator/compile_scal.cpp @@ -0,0 +1,1290 @@ +/************************************************************************ + ************************************************************************ + 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 +#include +#include +#include +#include +#include + +#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 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(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(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 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 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 used(N); + vector delay(N); + vector vname(N); + vector ctype(N); + + // prepare each element of a recursive definition + for (int i=0; igetMaxDelay(); + } 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; iaddDeclCode(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 args; + vector types; + + for (int i=0; iarity(); 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;"); + } +}