FAUST compiler  0.9.9.6b8
compile_scal.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003     FAUST compiler
00004     Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
00005     ---------------------------------------------------------------------
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021 
00022 /*****************************************************************************
00023     HISTORY
00024     22/01/05 : corrected bug on bool signals cached in float variables
00025 *****************************************************************************/
00026 
00027 
00028 #include "compile_scal.hh"
00029 #include "timing.hh"
00030 
00031 #include "compile.hh"
00032 #include "sigtype.hh"
00033 
00034 #include <stdio.h>
00035 #include <iostream>
00036 #include <fstream>
00037 #include <sstream>
00038 #include <vector>
00039 #include <math.h>
00040 
00041 #include "floats.hh"
00042 #include "sigprint.hh"
00043 #include "sigtyperules.hh"
00044 #include "recursivness.hh"
00045 #include "simplify.hh"
00046 #include "privatise.hh"
00047 #include "prim2.hh"
00048 #include "xtended.hh"
00049 
00050 #include "compatibility.hh"
00051 #include "ppsig.hh"
00052 #include "sigToGraph.hh"
00053 
00054 using namespace std;
00055 
00056 extern bool     gDrawSignals;
00057 extern bool     gLessTempSwitch;
00058 extern int      gMaxCopyDelay;
00059 extern string   gClassName;
00060 extern string   gMasterDocument;
00061 
00062 static Klass* signal2klass (const string& name, Tree sig)
00063 {
00064     Type t = getCertifiedSigType(sig); //, NULLENV);
00065     if (t->nature() == kInt) {
00066 
00067         ScalarCompiler C( new SigIntGenKlass(name) );
00068         C.compileSingleSignal(sig);
00069         return C.getClass();
00070 
00071     } else {
00072 
00073         ScalarCompiler C( new SigFloatGenKlass(name) );
00074         C.compileSingleSignal(sig);
00075         return C.getClass();
00076 
00077     }
00078 }
00079 
00080 
00081 /*****************************************************************************
00082                         getFreshID
00083 *****************************************************************************/
00084 
00085 map<string, int>    ScalarCompiler::fIDCounters;
00086 
00087 string ScalarCompiler::getFreshID(const string& prefix)
00088 {
00089     if (fIDCounters.find(prefix) == fIDCounters.end()) {
00090         fIDCounters[prefix]=0;
00091     }
00092     int n = fIDCounters[prefix];
00093     fIDCounters[prefix] = n+1;
00094     return subst("$0$1", prefix, T(n));
00095 }
00096 
00097 
00098 /*****************************************************************************
00099                             prepare
00100 *****************************************************************************/
00101 
00102 extern bool gDumpNorm;
00103 
00104 Tree ScalarCompiler::prepare(Tree LS)
00105 {
00106 startTiming("ScalarCompiler::prepare");
00107  startTiming("deBruijn2Sym");
00108     Tree L1 = deBruijn2Sym(LS);     // convert debruijn recursion into symbolic recursion
00109  endTiming("deBruijn2Sym");
00110     Tree L2 = simplify(L1);         // simplify by executing every computable operation
00111     Tree L3 = privatise(L2);        // Un-share tables with multiple writers
00112 
00113     // dump normal form
00114     if (gDumpNorm) {
00115         cout << ppsig(L3) << endl;
00116         exit(0);
00117     }
00118 
00119     recursivnessAnnotation(L3);     // Annotate L3 with recursivness information
00120 
00121     startTiming("typeAnnotation");
00122         typeAnnotation(L3);             // Annotate L3 with type information
00123     endTiming("typeAnnotation");
00124 
00125     sharingAnalysis(L3);            // annotate L3 with sharing count
00126     fOccMarkup.mark(L3);            // annotate L3 with occurences analysis
00127     //annotationStatistics();
00128 endTiming("ScalarCompiler::prepare");
00129 
00130     if (gDrawSignals) {
00131         ofstream dotfile(subst("$0-sig.dot", gMasterDocument).c_str());
00132         sigToGraph(L3, dotfile);
00133     }
00134     return L3;
00135 }
00136 
00137 Tree ScalarCompiler::prepare2(Tree L0)
00138 {
00139 startTiming("ScalarCompiler::prepare2");
00140     recursivnessAnnotation(L0);     // Annotate L0 with recursivness information
00141     typeAnnotation(L0);             // Annotate L0 with type information
00142     sharingAnalysis(L0);            // annotate L0 with sharing count
00143     fOccMarkup.mark(L0);            // annotate L0 with occurences analysis
00144 endTiming("ScalarCompiler::prepare2");
00145 
00146     return L0;
00147 }
00148 
00149 /*****************************************************************************
00150                             compileMultiSignal
00151 *****************************************************************************/
00152 
00153 void ScalarCompiler::compileMultiSignal (Tree L)
00154 {
00155     //contextor recursivness(0);
00156     L = prepare(L);     // optimize, share and annotate expression
00157 
00158     for (int i = 0; i < fClass->inputs(); i++) {
00159         fClass->addZone3(subst("$1* input$0 = input[$0];", T(i), xfloat()));
00160     }
00161     for (int i = 0; i < fClass->outputs(); i++) {
00162         fClass->addZone3(subst("$1* output$0 = output[$0];", T(i), xfloat()));
00163     }
00164 
00165     for (int i = 0; isList(L); L = tl(L), i++) {
00166         Tree sig = hd(L);
00167         fClass->addExecCode(subst("output$0[i] = $2$1;", T(i), CS(sig), xcast()));
00168     }
00169     generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot));
00170     generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
00171     if (fDescription) {
00172         fDescription->ui(prepareUserInterfaceTree(fUIRoot));
00173     }
00174 }
00175 
00176 
00177 /*****************************************************************************
00178                             compileSingleSignal
00179 *****************************************************************************/
00180 
00181 void ScalarCompiler::compileSingleSignal (Tree sig)
00182 {
00183     //contextor recursivness(0);
00184     sig = prepare2(sig);        // optimize and annotate expression
00185     fClass->addExecCode(subst("output[i] = $0;", CS(sig)));
00186     generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot));
00187     generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
00188     if (fDescription) {
00189         fDescription->ui(prepareUserInterfaceTree(fUIRoot));
00190     }
00191 }
00192 
00193 
00194 /*****************************************************************************
00195                              CS : compile a signal
00196 *****************************************************************************/
00197 
00204 bool ScalarCompiler::getCompiledExpression(Tree sig, string& cexp)
00205 {
00206     return fCompileProperty.get(sig, cexp);
00207 }
00208 
00215 string ScalarCompiler::setCompiledExpression(Tree sig, const string& cexp)
00216 {
00217     //cerr << "ScalarCompiler::setCompiledExpression : " << cexp << " ==> " << ppsig(sig) << endl;
00218     string old; if (fCompileProperty.get(sig, old) && (old != cexp)) {
00219         cerr << "ERROR already a compiled expression attached : " << old << " replaced by " << cexp << endl;
00220         exit(1);
00221     }
00222     fCompileProperty.set(sig, cexp);
00223     return cexp;
00224 }
00225 
00231 string  ScalarCompiler::CS (Tree sig)
00232 {
00233     //contextor   contextRecursivness;
00234     string      code;
00235 
00236     if (!getCompiledExpression(sig, code)) {
00237         // not compiled yet
00238 /*        if (getRecursivness(sig) != contextRecursivness.get()) {
00239             contextRecursivness.set(getRecursivness(sig));
00240         }*/
00241         code = generateCode(sig);
00242         setCompiledExpression(sig, code);
00243     }
00244     return code;
00245 }
00246 
00247 /*****************************************************************************
00248                         generateCode : dispatch according to signal
00249 *****************************************************************************/
00256 string  ScalarCompiler::generateCode (Tree sig)
00257 {
00258 #if 0
00259     fprintf(stderr, "CALL generateCode(");
00260         printSignal(sig, stderr);
00261     fprintf(stderr, ")\n");
00262 #endif
00263 
00264     int     i;
00265     double  r;
00266     Tree    c, sel, x, y, z, label, id, ff, largs, type, name, file;
00267 
00268     //printf("compilation of %p : ", sig); print(sig); printf("\n");
00269 
00270          if ( getUserData(sig) )                    { return generateXtended(sig); }
00271     else if ( isSigInt(sig, &i) )                   { return generateNumber(sig, T(i)); }
00272     else if ( isSigReal(sig, &r) )                  { return generateNumber(sig, T(r)); }
00273     else if ( isSigInput(sig, &i) )                 { return generateInput  (sig, T(i));            }
00274     else if ( isSigOutput(sig, &i, x) )             { return generateOutput     (sig, T(i), CS(x));}
00275 
00276     else if ( isSigFixDelay(sig, x, y) )            { return generateFixDelay   (sig, x, y);            }
00277     else if ( isSigPrefix(sig, x, y) )              { return generatePrefix     (sig, x, y);            }
00278     else if ( isSigIota(sig, x) )                   { return generateIota       (sig, x);               }
00279 
00280     else if ( isSigBinOp(sig, &i, x, y) )           { return generateBinOp  (sig, i, x, y);         }
00281     else if ( isSigFFun(sig, ff, largs) )           { return generateFFun       (sig, ff, largs);       }
00282     else if ( isSigFConst(sig, type, name, file) )  { return generateFConst(sig, tree2str(file), tree2str(name)); }
00283     else if ( isSigFVar(sig, type, name, file) )    { return generateFVar(sig, tree2str(file), tree2str(name)); }
00284 
00285     else if ( isSigTable(sig, id, x, y) )           { return generateTable  (sig, x, y);            }
00286     else if ( isSigWRTbl(sig, id, x, y, z) )        { return generateWRTbl  (sig, x, y, z);         }
00287     else if ( isSigRDTbl(sig, x, y) )               { return generateRDTbl  (sig, x, y);            }
00288 
00289     else if ( isSigSelect2(sig, sel, x, y) )        { return generateSelect2    (sig, sel, x, y);       }
00290     else if ( isSigSelect3(sig, sel, x, y, z) )     { return generateSelect3    (sig, sel, x, y, z);    }
00291 
00292     else if ( isSigGen(sig, x) )                    { return generateSigGen     (sig, x);               }
00293 
00294     else if ( isProj(sig, &i, x) )                  { return generateRecProj    (sig, x, i);    }
00295 
00296     else if ( isSigIntCast(sig, x) )                { return generateIntCast   (sig, x);                }
00297     else if ( isSigFloatCast(sig, x) )              { return generateFloatCast (sig, x);                }
00298 
00299     else if ( isSigButton(sig, label) )             { return generateButton     (sig, label);           }
00300     else if ( isSigCheckbox(sig, label) )           { return generateCheckbox   (sig, label);           }
00301     else if ( isSigVSlider(sig, label,c,x,y,z) )    { return generateVSlider    (sig, label, c,x,y,z); }
00302     else if ( isSigHSlider(sig, label,c,x,y,z) )    { return generateHSlider    (sig, label, c,x,y,z); }
00303     else if ( isSigNumEntry(sig, label,c,x,y,z) )   { return generateNumEntry   (sig, label, c,x,y,z); }
00304 
00305     else if ( isSigVBargraph(sig, label,x,y,z) )    { return generateVBargraph  (sig, label, x, y, CS(z)); }
00306     else if ( isSigHBargraph(sig, label,x,y,z) )    { return generateHBargraph  (sig, label, x, y, CS(z)); }
00307     else if ( isSigAttach(sig, x, y) )              { CS(y); return generateCacheCode(sig, CS(x)); }
00308 
00309     else {
00310         printf("Error in compiling signal, unrecognized signal : ");
00311         print(sig);
00312         printf("\n");
00313         exit(1);
00314     }
00315     return "error in generate code";
00316 }
00317 
00318 
00319 /*****************************************************************************
00320                                NUMBERS
00321 *****************************************************************************/
00322 
00323 
00324 string ScalarCompiler::generateNumber (Tree sig, const string& exp)
00325 {
00326     string      ctype, vname;
00327     Occurences* o = fOccMarkup.retrieve(sig);
00328 
00329     // check for number occuring in delays
00330     if (o->getMaxDelay()>0) {
00331         getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
00332         generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
00333     }
00334     return exp;
00335 }
00336 
00337 /*****************************************************************************
00338                                FOREIGN CONSTANTS
00339 *****************************************************************************/
00340 
00341 
00342 string ScalarCompiler::generateFConst (Tree sig, const string& file, const string& exp)
00343 {
00344     string      ctype, vname;
00345     Occurences* o = fOccMarkup.retrieve(sig);
00346 
00347     addIncludeFile(file);
00348 
00349     if (o->getMaxDelay()>0) {
00350         getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
00351         generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
00352     }
00353     return exp;
00354 }
00355 
00356 /*****************************************************************************
00357                                FOREIGN VARIABLES
00358 *****************************************************************************/
00359 
00360 
00361 string ScalarCompiler::generateFVar (Tree sig, const string& file, const string& exp)
00362 {
00363     string      ctype, vname;
00364 
00365     addIncludeFile(file);
00366     return generateCacheCode(sig, exp);
00367 }
00368 
00369 /*****************************************************************************
00370                                INPUTS - OUTPUTS
00371 *****************************************************************************/
00372 
00373 
00374 string ScalarCompiler::generateInput (Tree sig, const string& idx)
00375 {
00376     return generateCacheCode(sig, subst("$1input$0[i]", idx, icast()));
00377 }
00378 
00379 
00380 string ScalarCompiler::generateOutput (Tree sig, const string& idx, const string& arg)
00381 {
00382     string dst = subst("output$0[i]", idx);
00383     fClass->addExecCode(subst("$0 = $2$1;", dst, arg, xcast()));
00384     return dst;
00385 }
00386 
00387 
00388 /*****************************************************************************
00389                                BINARY OPERATION
00390 *****************************************************************************/
00391 
00392 string ScalarCompiler::generateBinOp(Tree sig, int opcode, Tree arg1, Tree arg2)
00393 {
00394     return generateCacheCode(sig, subst("($0 $1 $2)", CS(arg1), gBinOpTable[opcode]->fName, CS(arg2)));
00395 }
00396 
00397 
00398 /*****************************************************************************
00399                                Primitive Operations
00400 *****************************************************************************/
00401 
00402 string ScalarCompiler::generateFFun(Tree sig, Tree ff, Tree largs)
00403 {
00404     addIncludeFile(ffincfile(ff));  //printf("inc file %s\n", ffincfile(ff));
00405     addLibrary(fflibfile(ff));      //printf("lib file %s\n", fflibfile(ff));
00406 
00407     string code = ffname(ff);
00408     code += '(';
00409     string sep = "";
00410     for (int i = 0; i< ffarity(ff); i++) {
00411         code += sep;
00412         code += CS(nth(largs, i));
00413         sep = ", ";
00414     }
00415     code += ')';
00416     return generateCacheCode(sig, code);
00417 }
00418 
00419 
00420 /*****************************************************************************
00421                                CACHE CODE
00422 *****************************************************************************/
00423 
00424 void ScalarCompiler::getTypedNames(Type t, const string& prefix, string& ctype, string& vname)
00425 {
00426     if (t->nature() == kInt) {
00427         ctype = "int"; vname = subst("i$0", getFreshID(prefix));
00428     } else {
00429         ctype = ifloat(); vname = subst("f$0", getFreshID(prefix));
00430     }
00431 }
00432 
00433 string ScalarCompiler::generateCacheCode(Tree sig, const string& exp)
00434 {
00435     string      vname, ctype, code;
00436     int         sharing = getSharingCount(sig);
00437     Occurences* o = fOccMarkup.retrieve(sig);
00438 
00439     // check reentrance
00440     if (getCompiledExpression(sig, code)) {
00441         return code;
00442     }
00443 
00444     // check for expression occuring in delays
00445     if (o->getMaxDelay()>0) {
00446 
00447         getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
00448         if (sharing>1) {
00449             return generateDelayVec(sig, generateVariableStore(sig,exp), ctype, vname, o->getMaxDelay());
00450         } else {
00451             return generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
00452         }
00453 
00454     } else if (sharing == 1) {
00455 
00456         return exp;
00457 
00458     } else if (sharing > 1) {
00459 
00460         return generateVariableStore(sig, exp);
00461 
00462     } else {
00463         cerr << "Error in sharing count (" << sharing << ") for " << *sig << endl;
00464         exit(1);
00465     }
00466 
00467     return "Error in generateCacheCode";
00468 }
00469 
00470 
00471 string ScalarCompiler::generateVariableStore(Tree sig, const string& exp)
00472 {
00473     string      vname, ctype;
00474     Type        t = getCertifiedSigType(sig);
00475 
00476     switch (t->variability()) {
00477 
00478         case kKonst :
00479 
00480             getTypedNames(t, "Const", ctype, vname);
00481             fClass->addDeclCode(subst("$0 \t$1;", ctype, vname));
00482             fClass->addInitCode(subst("$0 = $1;", vname, exp));
00483             break;
00484 
00485         case kBlock :
00486 
00487             getTypedNames(t, "Slow", ctype, vname);
00488             fClass->addFirstPrivateDecl(vname);
00489             fClass->addZone2(subst("$0 \t$1 = $2;", ctype, vname, exp));
00490             break;
00491 
00492         case kSamp :
00493 
00494             getTypedNames(t, "Temp", ctype, vname);
00495             fClass->addExecCode(subst("$0 $1 = $2;", ctype, vname, exp));
00496             break;
00497     }
00498     return vname;
00499 }
00500 
00501 
00502 /*****************************************************************************
00503                                     CASTING
00504 *****************************************************************************/
00505 
00506 
00507 string ScalarCompiler::generateIntCast(Tree sig, Tree x)
00508 {
00509     return generateCacheCode(sig, subst("int($0)", CS(x)));
00510 }
00511 
00512 string ScalarCompiler::generateFloatCast (Tree sig, Tree x)
00513 {
00514     return generateCacheCode(sig, subst("$1($0)", CS(x), ifloat()));
00515 }
00516 
00517 /*****************************************************************************
00518                             user interface elements
00519 *****************************************************************************/
00520 
00521 string ScalarCompiler::generateButton(Tree sig, Tree path)
00522 {
00523     string varname = getFreshID("fbutton");
00524     fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
00525     fClass->addInitCode(subst("$0 = 0.0;", varname));
00526     addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
00527     return generateCacheCode(sig, varname);
00528 }
00529 
00530 string ScalarCompiler::generateCheckbox(Tree sig, Tree path)
00531 {
00532     string varname = getFreshID("fcheckbox");
00533     fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
00534     fClass->addInitCode(subst("$0 = 0.0;", varname));
00535     addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
00536     return generateCacheCode(sig, varname);
00537 }
00538 
00539 
00540 string ScalarCompiler::generateVSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
00541 {
00542     string varname = getFreshID("fslider");
00543     fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
00544     fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur))));
00545     addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
00546     return generateCacheCode(sig, varname);
00547 }
00548 
00549 string ScalarCompiler::generateHSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
00550 {
00551     string varname = getFreshID("fslider");
00552     fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
00553     fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur))));
00554     addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
00555     return generateCacheCode(sig, varname);
00556 }
00557 
00558 string ScalarCompiler::generateNumEntry(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
00559 {
00560     string varname = getFreshID("fentry");
00561     fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
00562     fClass->addInitCode(subst("$0 = $1;", varname, T(tree2float(cur))));
00563     addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
00564     return generateCacheCode(sig, varname);
00565 }
00566 
00567 
00568 string ScalarCompiler::generateVBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
00569 {
00570     string varname = getFreshID("fbargraph");
00571     fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
00572     addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
00573 
00574     Type t = getCertifiedSigType(sig);
00575     switch (t->variability()) {
00576 
00577         case kKonst :
00578             fClass->addInitCode(subst("$0 = $1;", varname, exp));
00579             break;
00580 
00581         case kBlock :
00582             fClass->addZone2(subst("$0 = $1;", varname, exp));
00583             break;
00584 
00585         case kSamp :
00586             fClass->addExecCode(subst("$0 = $1;", varname, exp));
00587             break;
00588     }
00589 
00590     //return varname;
00591     return generateCacheCode(sig, varname);
00592 }
00593 
00594 
00595 string ScalarCompiler::generateHBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
00596 {
00597     string varname = getFreshID("fbargraph");
00598     fClass->addDeclCode(subst("$1 \t$0;", varname, xfloat()));
00599     addUIWidget(reverse(tl(path)), uiWidget(hd(path), tree(varname), sig));
00600 
00601     Type t = getCertifiedSigType(sig);
00602     switch (t->variability()) {
00603 
00604         case kKonst :
00605             fClass->addInitCode(subst("$0 = $1;", varname, exp));
00606             break;
00607 
00608         case kBlock :
00609             fClass->addZone2(subst("$0 = $1;", varname, exp));
00610             break;
00611 
00612         case kSamp :
00613             fClass->addExecCode(subst("$0 = $1;", varname, exp));
00614             break;
00615     }
00616 
00617     //return varname;
00618     return generateCacheCode(sig, varname);
00619 }
00620 
00621 
00622 
00623 
00624 /*****************************************************************************
00625                                     TABLES
00626 *****************************************************************************/
00627 
00628 
00629 
00630 /*----------------------------------------------------------------------------
00631                         sigGen : initial table content
00632 ----------------------------------------------------------------------------*/
00633 
00634 string ScalarCompiler::generateSigGen(Tree sig, Tree content)
00635 {
00636     string klassname = getFreshID("SIG");
00637     string signame = getFreshID("sig");
00638 
00639     fClass->addSubKlass(signal2klass(klassname, content));
00640     fClass->addInitCode(subst("$0 $1;", klassname, signame));
00641     fInstanceInitProperty.set(content, pair<string,string>(klassname,signame));
00642 
00643     return signame;
00644 }
00645 
00646 string ScalarCompiler::generateStaticSigGen(Tree sig, Tree content)
00647 {
00648     string klassname = getFreshID("SIG");
00649     string signame = getFreshID("sig");
00650 
00651     fClass->addSubKlass(signal2klass(klassname, content));
00652     fClass->addStaticInitCode(subst("$0 $1;", klassname, signame));
00653     fStaticInitProperty.set(content, pair<string,string>(klassname,signame));
00654 
00655     return signame;
00656 }
00657 
00658 
00659 /*----------------------------------------------------------------------------
00660                         sigTable : table declaration
00661 ----------------------------------------------------------------------------*/
00662 
00663 string ScalarCompiler::generateTable(Tree sig, Tree tsize, Tree content)
00664 {
00665     string      generator(CS(content));
00666     Tree        g;
00667     string      cexp;
00668     string      ctype, vname;
00669     int         size;
00670 
00671     // already compiled but check if we need to add declarations
00672 
00673     assert ( isSigGen(content, g) );
00674     pair<string,string> kvnames;
00675     if ( ! fInstanceInitProperty.get(g, kvnames)) {
00676         // not declared here, we add a declaration
00677         bool b = fStaticInitProperty.get(g, kvnames);
00678         assert(b);
00679         fClass->addInitCode(subst("$0 $1;", kvnames.first, kvnames.second));
00680     }
00681 
00682     if (!isSigInt(tsize, &size)) {
00683         //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
00684         cerr << "error in ScalarCompiler::generateTable() : "
00685              << *tsize
00686              << " is not a constant integer table size expression "
00687              << endl;
00688         exit(1);
00689     }
00690     // definition du nom et du type de la table
00691     // A REVOIR !!!!!!!!!
00692     Type t = getCertifiedSigType(content);//, tEnv);
00693     if (t->nature() == kInt) {
00694         vname = getFreshID("itbl");
00695         ctype = "int";
00696     } else {
00697         vname = getFreshID("ftbl");
00698         ctype = ifloat();
00699     }
00700 
00701     // declaration de la table
00702     fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(size)));
00703 
00704     // initialisation du generateur de contenu
00705     fClass->addInitCode(subst("$0.init(samplingFreq);", generator));
00706     // remplissage de la table
00707     fClass->addInitCode(subst("$0.fill($1,$2);", generator, T(size), vname));
00708 
00709     // on retourne le nom de la table
00710     return vname;
00711 }
00712 
00713 string ScalarCompiler::generateStaticTable(Tree sig, Tree tsize, Tree content)
00714 {
00715     //string        generator(CS(content));
00716     Tree        g;
00717     string      cexp;
00718     string      ctype, vname;
00719     int         size;
00720 
00721     assert ( isSigGen(content, g) );
00722 
00723     if (!getCompiledExpression(content, cexp)) {
00724         cexp = setCompiledExpression(content, generateStaticSigGen(content, g));
00725     } else {
00726         // already compiled but check if we need to add declarations
00727         pair<string,string> kvnames;
00728         if ( ! fStaticInitProperty.get(g, kvnames)) {
00729             // not declared here, we add a declaration
00730             bool b = fInstanceInitProperty.get(g, kvnames);
00731             assert(b);
00732             fClass->addStaticInitCode(subst("$0 $1;", kvnames.first, kvnames.second));
00733         }
00734     }
00735 
00736     if (!isSigInt(tsize, &size)) {
00737         //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
00738         cerr << "error in ScalarCompiler::generateTable() : "
00739              << *tsize
00740              << " is not a constant integer table size expression "
00741              << endl;
00742         exit(1);
00743     }
00744     // definition du nom et du type de la table
00745     // A REVOIR !!!!!!!!!
00746     Type t = getCertifiedSigType(content);//, tEnv);
00747     if (t->nature() == kInt) {
00748         vname = getFreshID("itbl");
00749         ctype = "int";
00750     } else {
00751         vname = getFreshID("ftbl");
00752         ctype = ifloat();
00753     }
00754 
00755     // declaration de la table
00756     fClass->addDeclCode(subst("static $0 \t$1[$2];", ctype, vname, T(size)));
00757     fClass->addStaticFields(subst("$0 \t$1::$2[$3];", ctype, fClass->getClassName(), vname, T(size) ));
00758 
00759     // initialisation du generateur de contenu
00760     fClass->addStaticInitCode(subst("$0.init(samplingFreq);", cexp));
00761     // remplissage de la table
00762     fClass->addStaticInitCode(subst("$0.fill($1,$2);", cexp, T(size), vname));
00763 
00764     // on retourne le nom de la table
00765     return vname;
00766 }
00767 
00768 
00769 /*----------------------------------------------------------------------------
00770                         sigWRTable : table assignement
00771 ----------------------------------------------------------------------------*/
00772 
00773 string ScalarCompiler::generateWRTbl(Tree sig, Tree tbl, Tree idx, Tree data)
00774 {
00775     string tblName(CS(tbl));
00776     fClass->addExecCode(subst("$0[$1] = $2;", tblName, CS(idx), CS(data)));
00777     return tblName;
00778 }
00779 
00780 
00781 /*----------------------------------------------------------------------------
00782                         sigRDTable : table access
00783 ----------------------------------------------------------------------------*/
00784 
00785 string ScalarCompiler::generateRDTbl(Tree sig, Tree tbl, Tree idx)
00786 {
00787     // YO le 21/04/05 : La lecture des tables n'�ait pas mise dans le cache
00788     // et donc le code �ait dupliqu�(dans tester.dsp par exemple)
00789     //return subst("$0[$1]", CS(tEnv, tbl), CS(tEnv, idx));
00790 
00791     //cerr << "generateRDTable " << *sig << endl;
00792     // test the special case of a read only table that can be compiled
00793     // has a static member
00794     Tree    id, size, content;
00795     if( isSigTable(tbl, id, size, content) ) {
00796         string tblname;
00797         if (!getCompiledExpression(tbl, tblname)) {
00798             tblname = setCompiledExpression(tbl, generateStaticTable(tbl, size, content));
00799         }
00800         return generateCacheCode(sig, subst("$0[$1]", tblname, CS(idx)));
00801     } else {
00802         return generateCacheCode(sig, subst("$0[$1]", CS(tbl), CS(idx)));
00803     }
00804 }
00805 
00806 
00807 
00808 /*****************************************************************************
00809                                RECURSIONS
00810 *****************************************************************************/
00811 
00812 
00816 string ScalarCompiler::generateRecProj(Tree sig, Tree r, int i)
00817 {
00818     string  vname;
00819     Tree    var, le;
00820 
00821     if ( ! getVectorNameProperty(sig, vname)) {
00822         assert(isRec(r, var, le));
00823         generateRec(r, var, le);
00824         assert(getVectorNameProperty(sig, vname));
00825     }
00826     return "[[UNUSED EXP]]";    // make sure the resulting expression is never used in the generated code
00827 }
00828 
00829 
00833 void ScalarCompiler::generateRec(Tree sig, Tree var, Tree le)
00834 {
00835     int             N = len(le);
00836 
00837     vector<bool>    used(N);
00838     vector<int>     delay(N);
00839     vector<string>  vname(N);
00840     vector<string>  ctype(N);
00841 
00842     // prepare each element of a recursive definition
00843     for (int i=0; i<N; i++) {
00844         Tree    e = sigProj(i,sig);     // recreate each recursive definition
00845         if (fOccMarkup.retrieve(e)) {
00846             // this projection is used
00847             used[i] = true;
00848             getTypedNames(getCertifiedSigType(e), "Rec", ctype[i],  vname[i]);
00849             setVectorNameProperty(e, vname[i]);
00850             delay[i] = fOccMarkup.retrieve(e)->getMaxDelay();
00851         } else {
00852             // this projection is not used therefore
00853             // we should not generate code for it
00854             used[i] = false;
00855         }
00856     }
00857 
00858     // generate delayline for each element of a recursive definition
00859     for (int i=0; i<N; i++) {
00860         if (used[i]) {
00861             generateDelayLine(ctype[i], vname[i], delay[i], CS(nth(le,i)));
00862         }
00863     }
00864 }
00865 
00866 
00867 /*****************************************************************************
00868                                PREFIX, DELAY A PREFIX VALUE
00869 *****************************************************************************/
00870 
00871 string ScalarCompiler::generatePrefix (Tree sig, Tree x, Tree e)
00872 {
00873     Type te = getCertifiedSigType(sig);//, tEnv);
00874 
00875     string vperm = getFreshID("M");
00876     string vtemp = getFreshID("T");
00877 
00878     string type = cType(te);
00879 
00880     fClass->addDeclCode(subst("$0 \t$1;", type, vperm));
00881     fClass->addInitCode(subst("$0 = $1;", vperm, CS(x)));
00882 
00883     fClass->addExecCode(subst("$0 $1 = $2;", type, vtemp, vperm));
00884     fClass->addExecCode(subst("$0 = $1;", vperm, CS(e)));
00885     return vtemp;
00886 }
00887 
00888 
00889 /*****************************************************************************
00890                                IOTA(n)
00891 *****************************************************************************/
00892 static bool isPowerOf2(int n)
00893 {
00894     return !(n & (n - 1));
00895 }
00896 
00897 string ScalarCompiler::generateIota (Tree sig, Tree n)
00898 {
00899     int size;
00900     if (!isSigInt(n, &size)) { fprintf(stderr, "error in generateIota\n"); exit(1); }
00901 
00902     string vperm = getFreshID("iota");
00903 
00904     fClass->addDeclCode(subst("int \t$0;",  vperm));
00905     fClass->addInitCode(subst("$0 = 0;", vperm));
00906 
00907     if (isPowerOf2(size)) {
00908         fClass->addExecCode(subst("$0 = ($0+1)&$1;", vperm, T(size-1)));
00909     } else {
00910         fClass->addExecCode(subst("if (++$0 == $1) $0=0;", vperm, T(size)));
00911     }
00912     return vperm;
00913 }
00914 
00915 
00916 
00917 // a revoir en utilisant la lecture de table et en partageant la construction de la paire de valeurs
00918 
00919 
00924 string ScalarCompiler::generateSelect2  (Tree sig, Tree sel, Tree s1, Tree s2)
00925 {
00926     return generateCacheCode(sig, subst( "(($0)?$1:$2)", CS(sel), CS(s2), CS(s1) ) );
00927 }
00928 
00929 
00935 string ScalarCompiler::generateSelect3  (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3)
00936 {
00937     return generateCacheCode(sig, subst( "(($0==0)? $1 : (($0==1)?$2:$3) )", CS(sel), CS(s1), CS(s2), CS(s3) ) );
00938 }
00939 
00940 #if 0
00941 string ScalarCompiler::generateSelect3  (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3)
00942 {
00943     Type t  = getCertifiedSigType(sig);
00944     Type t1 = getCertifiedSigType(s1);
00945     Type t2 = getCertifiedSigType(s2);
00946     Type t3 = getCertifiedSigType(s3);
00947     Type w  = min(t1,min(t2,t3));
00948 
00949     string type = cType(t);
00950     string var  = getFreshID("S");
00951 
00952     switch (w->variability())
00953     {
00954         case kKonst :
00955             fClass->addDeclCode(subst("$0 \t$1[3];", type, var));
00956             break;
00957         case kBlock :
00958             //fClass->addLocalDecl(type, subst("$0[3]", var));
00959             //fClass->addLocalVecDecl(type, var, 3);
00960             fClass->addSharedDecl(var);
00961             fClass->addZone1(subst("$0 \t$1[3];", type, var));
00962             break;
00963         case kSamp :
00964             fClass->addExecCode(subst("$0 \t$1[3];", type, var));
00965             break;
00966     }
00967 
00968     switch (t1->variability())
00969     {
00970         case kKonst :
00971             fClass->addInitCode(subst("$0[0] = $1;", var, CS(s1)));
00972             break;
00973         case kBlock :
00974             fClass->addZone2b(subst("$0[0] = $1;", var, CS(s1)));
00975             break;
00976         case kSamp :
00977             fClass->addExecCode(subst("$0[0] = $1;", var, CS(s1)));
00978             break;
00979     }
00980 
00981     switch (t2->variability())
00982     {
00983         case kKonst :
00984             fClass->addInitCode(subst("$0[1] = $1;", var, CS(s2)));
00985             break;
00986         case kBlock :
00987             fClass->addZone2b(subst("$0[1] = $1;", var, CS(s2)));
00988             break;
00989         case kSamp :
00990             fClass->addExecCode(subst("$0[1] = $1;", var, CS(s2)));
00991             break;
00992     }
00993 
00994     switch (t3->variability())
00995     {
00996         case kKonst :
00997             fClass->addInitCode(subst("$0[2] = $1;", var, CS(s3)));
00998             break;
00999         case kBlock :
01000             fClass->addZone2b(subst("$0[2] = $1;", var, CS(s3)));
01001             break;
01002         case kSamp :
01003             fClass->addExecCode(subst("$0[2] = $1;", var, CS(s3)));
01004             break;
01005     }
01006 
01007     return generateCacheCode(sig, subst("$0[$1]", var, CS(sel)));
01008 }
01009 #endif
01010 
01015 string ScalarCompiler::generateXtended  (Tree sig)
01016 {
01017     xtended*        p = (xtended*) getUserData(sig);
01018     vector<string>  args;
01019     vector<Type>    types;
01020 
01021     for (int i=0; i<sig->arity(); i++) {
01022         args.push_back(CS(sig->branch(i)));
01023         types.push_back(getCertifiedSigType(sig->branch(i)));
01024     }
01025 
01026     if (p->needCache()) {
01027         return generateCacheCode(sig, p->generateCode(fClass, args, types));
01028     } else {
01029         return p->generateCode(fClass, args, types);
01030     }
01031 }
01032 
01033 
01034 
01035 //------------------------------------------------------------------------------------------------
01036 
01037 
01038 /*****************************************************************************
01039                         vector name property
01040 *****************************************************************************/
01041 
01049 void ScalarCompiler::setVectorNameProperty(Tree sig, const string& vecname)
01050 {
01051         fVectorProperty.set(sig, vecname);
01052 }
01053 
01054 
01063 bool ScalarCompiler::getVectorNameProperty(Tree sig, string& vecname)
01064 {
01065     return fVectorProperty.get(sig, vecname);
01066 }
01067 
01068 
01073 int ScalarCompiler::pow2limit(int x)
01074 {
01075     int n = 2;
01076     while (n < x) { n = 2*n; }
01077     return n;
01078 }
01079 
01080 /*****************************************************************************
01081                                N-SAMPLE FIXED DELAY : sig = exp@delay
01082 
01083     case 1-sample max delay :
01084         Y(t-0)  Y(t-1)
01085         Temp    Var                     gLessTempSwitch = false
01086         V[0]    V[1]                    gLessTempSwitch = true
01087 
01088     case max delay < gMaxCopyDelay :
01089         Y(t-0)  Y(t-1)  Y(t-2)  ...
01090         Temp    V[0]    V[1]    ...     gLessTempSwitch = false
01091         V[0]    V[1]    V[2]    ...     gLessTempSwitch = true
01092 
01093     case max delay >= gMaxCopyDelay :
01094         Y(t-0)  Y(t-1)  Y(t-2)  ...
01095         Temp    V[0]    V[1]    ...
01096         V[0]    V[1]    V[2]    ...
01097 
01098 
01099 *****************************************************************************/
01100 
01106 string ScalarCompiler::generateFixDelay (Tree sig, Tree exp, Tree delay)
01107 {
01108     int     mxd, d;
01109     string  vecname;
01110 
01111     //cerr << "ScalarCompiler::generateFixDelay sig = " << *sig << endl;
01112     //cerr << "ScalarCompiler::generateFixDelay exp = " << *exp << endl;
01113     //cerr << "ScalarCompiler::generateFixDelay del = " << *delay << endl;
01114 
01115     CS(exp); // ensure exp is compiled to have a vector name
01116 
01117     mxd = fOccMarkup.retrieve(exp)->getMaxDelay();
01118 
01119     if (! getVectorNameProperty(exp, vecname)) {
01120         cerr << "No vector name for : " << ppsig(exp) << endl;
01121         assert(0);
01122     }
01123 
01124     if (mxd == 0) {
01125         // not a real vector name but a scalar name
01126         return vecname;
01127 
01128     } else if (mxd < gMaxCopyDelay) {
01129         if (isSigInt(delay, &d)) {
01130             return subst("$0[$1]", vecname, CS(delay));
01131         } else {
01132             return generateCacheCode(sig, subst("$0[$1]", vecname, CS(delay)));
01133         }
01134 
01135     } else {
01136 
01137         // long delay : we use a ring buffer of size 2^x
01138         int     N   = pow2limit( mxd+1 );
01139         return generateCacheCode(sig, subst("$0[(IOTA-$1)&$2]", vecname, CS(delay), T(N-1)));
01140     }
01141 }
01142 
01143 
01149 string ScalarCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
01150 {
01151     string s = generateDelayVecNoTemp(sig, exp, ctype, vname, mxd);
01152     if (getCertifiedSigType(sig)->variability() < kSamp) {
01153         return exp;
01154     } else {
01155         return s;
01156     }
01157 }
01158 
01163 string ScalarCompiler::generateDelayVecNoTemp(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
01164 {
01165     assert(mxd > 0);
01166 
01167     //bool odocc = fOccMarkup.retrieve(sig)->hasOutDelayOccurences();
01168 
01169     if (mxd < gMaxCopyDelay) {
01170 
01171         // short delay : we copy
01172         fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(mxd+1)));
01173         fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(mxd+1)));
01174         fClass->addExecCode(subst("$0[0] = $1;", vname, exp));
01175 
01176         // generate post processing copy code to update delay values
01177         if (mxd == 1) {
01178             fClass->addPostCode(subst("$0[1] = $0[0];", vname));
01179         } else if (mxd == 2) {
01180             //fClass->addPostCode(subst("$0[2] = $0[1];", vname));
01181             fClass->addPostCode(subst("$0[2] = $0[1]; $0[1] = $0[0];", vname));
01182         } else {
01183             fClass->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd), vname));
01184         }
01185         setVectorNameProperty(sig, vname);
01186         return subst("$0[0]", vname);
01187 
01188     } else {
01189 
01190         // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
01191         int     N = pow2limit(mxd+1);
01192 
01193         // we need a iota index
01194         ensureIotaCode();
01195 
01196         // declare and init
01197         fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(N)));
01198         fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(N)));
01199 
01200         // execute
01201         fClass->addExecCode(subst("$0[IOTA&$1] = $2;", vname, T(N-1), exp));
01202         setVectorNameProperty(sig, vname);
01203         return subst("$0[IOTA&$1]", vname, T(N-1));
01204     }
01205 }
01206 
01211 void ScalarCompiler::generateDelayLine(const string& ctype, const string& vname, int mxd, const string& exp)
01212 {
01213     //assert(mxd > 0);
01214     if (mxd == 0) {
01215         // cerr << "MXD==0 :  " << vname << " := " << exp << endl;
01216         // no need for a real vector
01217         fClass->addExecCode(subst("$0 \t$1 = $2;", ctype, vname, exp));
01218 
01219 
01220     } else if (mxd < gMaxCopyDelay) {
01221         // cerr << "small delay : " << vname << "[" << mxd << "]" << endl;
01222 
01223         // short delay : we copy
01224         fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(mxd+1)));
01225         fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(mxd+1)));
01226         fClass->addExecCode(subst("$0[0] = $1;", vname, exp));
01227 
01228         // generate post processing copy code to update delay values
01229         if (mxd == 1) {
01230             fClass->addPostCode(subst("$0[1] = $0[0];", vname));
01231         } else if (mxd == 2) {
01232             fClass->addPostCode(subst("$0[2] = $0[1]; $0[1] = $0[0];", vname));
01233         } else {
01234             fClass->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd), vname));
01235         }
01236 
01237     } else {
01238 
01239         // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
01240         int     N = pow2limit(mxd+1);
01241 
01242         // we need a iota index
01243         ensureIotaCode();
01244 
01245         // declare and init
01246         fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(N)));
01247         fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname, T(N)));
01248 
01249         // execute
01250         fClass->addExecCode(subst("$0[IOTA&$1] = $2;", vname, T(N-1), exp));
01251     }
01252 }
01253 
01258 void ScalarCompiler::ensureIotaCode()
01259 {
01260     if (!fHasIota) {
01261         fHasIota = true;
01262         fClass->addDeclCode("int \tIOTA;");
01263         fClass->addInitCode("IOTA = 0;");
01264         fClass->addPostCode("IOTA = IOTA+1;");
01265     }
01266 }