FAUST compiler  0.9.9.6b8
compile_vect.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 
00024 #include "compile_vect.hh"
00025 #include "floats.hh"
00026 #include "ppsig.hh"
00027 
00028 extern int gVecSize;
00029 
00030 void VectorCompiler::compileMultiSignal (Tree L)
00031 {
00032     //contextor recursivness(0);
00033     L = prepare(L);     // optimize, share and annotate expression
00034 
00035     for (int i = 0; i < fClass->inputs(); i++) {
00036         fClass->addZone3(subst("$1* input$0 = &input[$0][index];", T(i), xfloat()));
00037     }
00038     for (int i = 0; i < fClass->outputs(); i++) {
00039         fClass->addZone3(subst("$1* output$0 = &output[$0][index];", T(i), xfloat()));
00040     }
00041 
00042     fClass->addSharedDecl("fullcount");
00043     fClass->addSharedDecl("input");
00044     fClass->addSharedDecl("output");
00045 
00046     for (int i = 0; isList(L); L = tl(L), i++) {
00047         Tree sig = hd(L);
00048         fClass->openLoop("count");
00049         fClass->addExecCode(subst("output$0[i] = $2$1;", T(i), CS(sig), xcast()));
00050         fClass->closeLoop(sig);
00051     }
00052 
00053     generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot));
00054     generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
00055     if (fDescription) {
00056         fDescription->ui(prepareUserInterfaceTree(fUIRoot));
00057     }
00058 }
00059 
00060 
00066 string  VectorCompiler::CS (Tree sig)
00067 {
00068     string      code;
00069     //cerr << "ENTER VectorCompiler::CS : "<< ppsig(sig) << endl;
00070     if (!getCompiledExpression(sig, code)) {
00071         code = generateCode(sig);
00072         //cerr << "CS : " << code << " for " << ppsig(sig) << endl;
00073         setCompiledExpression(sig, code);
00074     } else {
00075         // we require an already compiled expression
00076         // therefore we must update the dependencies of
00077         // the current loop
00078         int     i;
00079         Tree    x, d, r;
00080         Loop*   ls;
00081         Loop*   tl = fClass->topLoop();
00082 
00083         if (fClass->getLoopProperty(sig,ls)) {
00084             // sig has a loop property
00085             //cerr << "CASE SH : fBackwardLoopDependencies.insert : " << tl << " --depend(A)son--> " << ls << endl;
00086             tl->fBackwardLoopDependencies.insert(ls);
00087 
00088         } else if (isSigFixDelay(sig, x, d) && fClass->getLoopProperty(x,ls)) {
00089             //cerr << "CASE DL : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
00090             tl->fBackwardLoopDependencies.insert(ls);
00091 
00092         } else if (isSigFixDelay(sig, x, d) && isProj(x, &i, r) && fClass->getLoopProperty(r,ls)) {
00093             //cerr << "CASE DR : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
00094             tl->fBackwardLoopDependencies.insert(ls);
00095 
00096         } else if (isProj(sig, &i, r) && fClass->getLoopProperty(r,ls)) {
00097             //cerr << "CASE R* : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
00098             tl->fBackwardLoopDependencies.insert(ls);
00099 
00100         } else {
00101             if (isProj(sig, &i, r)) {
00102                 //cerr << "SYMBOL RECURSIF EN COURS ??? " << *r << endl;
00103             } else if (getCertifiedSigType(sig)->variability()<kSamp) {
00104                 //cerr << "SLOW EXPRESSION " << endl;
00105             } else {
00106                 //cerr << "Expression absorbée" << *sig << endl;
00107             }
00108 
00109         }
00110     }
00111     //cerr << "EXIT VectorCompiler::CS : "<< ppsig(sig) << "---code---> " << code << endl;
00112     return code;
00113 }
00114 
00115 string VectorCompiler::generateCode (Tree sig)
00116 {
00117     generateCodeRecursions(sig);
00118     return generateCodeNonRec(sig);
00119 }
00120 
00121 void VectorCompiler::generateCodeRecursions (Tree sig)
00122 {
00123     Tree    id, body;
00124     string  code;
00125     //cerr << "VectorCompiler::generateCodeRecursions( " << ppsig(sig) << " )" << endl;
00126     if (getCompiledExpression(sig, code)) {
00127         //cerr << "** ALREADY VISITED : " << code << " ===> " << ppsig(sig) << endl;
00128         return;
00129     } else if( isRec(sig, id, body) ) {
00130         //cerr << "we have a recursive expression non compiled yet : " << ppsig(sig) << endl;
00131         setCompiledExpression(sig, "[RecursionVisited]");
00132         fClass->openLoop(sig, "count");
00133         generateRec(sig, id, body);
00134         fClass->closeLoop(sig);
00135     } else {
00136         // we go down the expression
00137         vector<Tree>  subsigs;
00138         int n = getSubSignals(sig, subsigs, false);
00139         for (int i=0; i<n; i++) { generateCodeRecursions(subsigs[i]); }
00140     }
00141 }
00142 
00143 string VectorCompiler::generateCodeNonRec (Tree sig)
00144 {
00145     string  code;
00146     if (getCompiledExpression(sig, code)) {
00147         // already visited
00148         return code;
00149     } else {
00150         //cerr << "VectorCompiler::generateCodeNonRec( " << ppsig(sig) << " )" << endl;
00151         code = generateLoopCode(sig);
00152         setCompiledExpression(sig, code);
00153         return code;
00154     }
00155 }
00156 
00162 string VectorCompiler::generateLoopCode (Tree sig)
00163 {
00164     int     i;
00165     Tree    x;
00166     Loop*   l;
00167 
00168     l = fClass->topLoop();
00169     assert(l);
00170     //cerr << "VectorCompiler::OLDgenerateCode " << ppsig(sig) << endl;
00171     if (needSeparateLoop(sig)) {
00172         // we need a separate loop unless it's an old recursion
00173         if (isProj(sig, &i, x)) {
00174             // projection of a recursive group x
00175             if (l->hasRecDependencyIn(singleton(x))) {
00176                 // x is already in the loop stack
00177                 return ScalarCompiler::generateCode(sig);
00178             } else {
00179                 // x must be defined
00180                 fClass->openLoop(x, "count");
00181                 string c = ScalarCompiler::generateCode(sig);
00182                 fClass->closeLoop(sig);
00183                 return c;
00184             }
00185         } else {
00186             fClass->openLoop("count");
00187             string c = ScalarCompiler::generateCode(sig);
00188             fClass->closeLoop(sig);
00189             return c;
00190         }
00191     } else {
00192         return ScalarCompiler::generateCode(sig);
00193     }
00194 }
00195 
00196 
00203 string VectorCompiler::generateCacheCode(Tree sig, const string& exp)
00204 {
00205     string      vname, ctype;
00206     int         sharing = getSharingCount(sig);
00207     Type        t = getCertifiedSigType(sig);
00208     Occurences* o = fOccMarkup.retrieve(sig);
00209     int         d = o->getMaxDelay();
00210 
00211     if (t->variability() < kSamp) {
00212         if (d==0) {
00213             // non-sample, not delayed : same as scalar cache
00214             return ScalarCompiler::generateCacheCode(sig,exp);
00215 
00216         } else {
00217             // it is a non-sample expressions but used delayed
00218             // we need a delay line
00219             getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
00220             if ((sharing > 1) && !verySimple(sig)) {
00221                 // first cache this expression because it
00222                 // it is shared and complex
00223                 string cachedexp =  generateVariableStore(sig, exp);
00224                 generateDelayLine(ctype, vname, d, cachedexp);
00225                 setVectorNameProperty(sig, vname);
00226                 return cachedexp;
00227             } else {
00228                 // no need to cache this expression because
00229                 // it is either not shared or very simple
00230                 generateDelayLine(ctype, vname, d, exp);
00231                 setVectorNameProperty(sig, vname);
00232                 return exp;
00233             }
00234         }
00235     } else {
00236         // sample-rate signal
00237         if (d > 0) {
00238             // used delayed : we need a delay line
00239             getTypedNames(getCertifiedSigType(sig), "Yec", ctype, vname);
00240             generateDelayLine(ctype, vname, d, exp);
00241             setVectorNameProperty(sig, vname);
00242 
00243             if (verySimple(sig)) {
00244                 return exp;
00245             } else {
00246                 if (d < gMaxCopyDelay) {
00247                     return subst("$0[i]", vname);
00248                 } else {
00249                     // we use a ring buffer
00250                     string mask = T(pow2limit(d + gVecSize)-1);
00251                     return subst("$0[($0_idx+i) & $1]", vname, mask);
00252                 }
00253             }
00254         } else {
00255             // not delayed
00256             if ( sharing > 1 && ! verySimple(sig) ) {
00257                 // shared and not simple : we need a vector
00258                 // cerr << "ZEC : " << ppsig(sig) << endl;
00259                 getTypedNames(getCertifiedSigType(sig), "Zec", ctype, vname);
00260                 generateDelayLine(ctype, vname, d, exp);
00261                 setVectorNameProperty(sig, vname);
00262                 return subst("$0[i]", vname);
00263            } else {
00264                 // not shared or simple : no cache needed
00265                 return exp;
00266             }
00267         }
00268     }
00269 }
00270 
00276 bool VectorCompiler::needSeparateLoop(Tree sig)
00277 {
00278     Occurences* o = fOccMarkup.retrieve(sig);
00279     Type        t = getCertifiedSigType(sig);
00280     int         c = getSharingCount(sig);
00281     bool        b;
00282 
00283     int         i;
00284     Tree        x,y;
00285 
00286 
00287     if (o->getMaxDelay()>0) {
00288         //cerr << "DLY "; // delayed expressions require a separate loop
00289         b = true;
00290     } else if (verySimple(sig) || t->variability()<kSamp) {
00291         b = false;      // non sample computation never require a loop
00292     } else if (isSigFixDelay(sig, x, y)) {
00293         b = false;      //
00294     } else if (isProj(sig, &i ,x)) {
00295         //cerr << "REC "; // recursive expressions require a separate loop
00296         b = true;
00297     } else if (c > 1) {
00298         //cerr << "SHA(" << c << ") "; // expressions used several times required a separate loop
00299         b = true;
00300     } else {
00301         // sample expressions that are not recursive, not delayed
00302         // and not shared, doesn't require a separate loop.
00303         b = false;
00304     }
00305 /*    if (b) {
00306         cerr << "Separate Loop for " << ppsig(sig) << endl;
00307     } else {
00308         cerr << "Same Loop for " << ppsig(sig) << endl;
00309     }*/
00310     return b;
00311 }
00312 
00313 void VectorCompiler::generateDelayLine(const string& ctype, const string& vname, int mxd, const string& exp)
00314 {
00315     if (mxd == 0) {
00316         vectorLoop(ctype, vname, exp);
00317     } else {
00318         dlineLoop(ctype, vname, mxd, exp);
00319     }
00320 }
00321 
00322 string VectorCompiler::generateVariableStore(Tree sig, const string& exp)
00323 {
00324     Type        t = getCertifiedSigType(sig);
00325 
00326     if (getCertifiedSigType(sig)->variability() == kSamp) {
00327         string      vname, ctype;
00328         getTypedNames(t, "Vector", ctype, vname);
00329         vectorLoop(ctype, vname, exp);
00330         return subst("$0[i]", vname);
00331     } else {
00332         return ScalarCompiler::generateVariableStore(sig, exp);
00333     }
00334 }
00335 
00336 
00342 string VectorCompiler::generateFixDelay (Tree sig, Tree exp, Tree delay)
00343 {
00344     int     mxd, d;
00345     string  vecname;
00346 
00347     //cerr << "VectorCompiler::generateFixDelay " << ppsig(sig) << endl;
00348 
00349     CS(exp); // ensure exp is compiled to have a vector name
00350 
00351     mxd = fOccMarkup.retrieve(exp)->getMaxDelay();
00352 
00353     if (! getVectorNameProperty(exp, vecname)) {
00354         cerr << "ERROR no vector name for " << ppsig(exp) << endl;
00355         exit(1);
00356     }
00357 
00358     if (mxd == 0) {
00359         // not a real vector name but a scalar name
00360         return subst("$0[i]", vecname);
00361 
00362     } else if (mxd < gMaxCopyDelay){
00363         if (isSigInt(delay, &d)) {
00364             if (d == 0) {
00365                 return subst("$0[i]", vecname);
00366             } else {
00367                 return subst("$0[i-$1]", vecname, T(d));
00368             }
00369         } else {
00370             return subst("$0[i-$1]", vecname, CS(delay));
00371         }
00372 
00373     } else {
00374 
00375         // long delay : we use a ring buffer of size 2^x
00376         int     N   = pow2limit( mxd+gVecSize );
00377 
00378         if (isSigInt(delay, &d)) {
00379             if (d == 0) {
00380                 return subst("$0[($0_idx+i)&$1]", vecname, T(N-1));
00381             } else {
00382                 return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), T(d));
00383             }
00384         } else {
00385             return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), CS(delay));
00386         }
00387     }
00388 }
00389 
00390 
00396 string VectorCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
00397 {
00398     // it is a non-sample but used delayed
00399     // we need a delay line
00400     generateDelayLine(ctype, vname, mxd, exp);
00401     setVectorNameProperty(sig, vname);
00402     if (verySimple(sig)) {
00403         return exp;
00404     } else {
00405         return subst("$0[i]", vname);
00406     }
00407 }
00408 
00409 #if 0
00410 static int pow2limit(int x)
00411 {
00412     int n = 2;
00413     while (n < x) { n = 2*n; }
00414     return n;
00415 }
00416 #endif
00417 
00427 void  VectorCompiler::vectorLoop (const string& tname, const string& vecname, const string& cexp)
00428 {
00429     // -- declare the vector
00430     fClass->addSharedDecl(vecname);
00431 
00432     // -- variables moved as class fields...
00433     fClass->addZone1(subst("$0 \t$1[$2];", tname, vecname, T(gVecSize)));
00434 
00435     // -- compute the new samples
00436     fClass->addExecCode(subst("$0[i] = $1;", vecname, cexp));
00437 }
00438 
00439 
00449 void  VectorCompiler::dlineLoop (const string& tname, const string& dlname, int delay, const string& cexp)
00450 {
00451     if (delay < gMaxCopyDelay) {
00452 
00453         // Implementation of a copy based delayline
00454 
00455         // create names for temporary and permanent storage
00456         string  buf = subst("$0_tmp", dlname);
00457         string  pmem= subst("$0_perm", dlname);
00458 
00459         // constraints delay size to be multiple of 4
00460         delay = (delay+3)&-4;
00461 
00462         // allocate permanent storage for delayed samples
00463         string  dsize   = T(delay);
00464         fClass->addDeclCode(subst("$0 \t$1[$2];", tname, pmem, dsize));
00465 
00466         // init permanent memory
00467         fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", pmem, dsize));
00468 
00469         // compute method
00470 
00471         // -- declare a buffer and a "shifted" vector
00472         fClass->addSharedDecl(buf);
00473 
00474         // -- variables moved as class fields...
00475         fClass->addZone1(subst("$0 \t$1[$2+$3];", tname, buf, T(gVecSize), dsize));
00476 
00477         fClass->addFirstPrivateDecl(dlname);
00478         fClass->addZone2(subst("$0* \t$1 = &$2[$3];", tname, dlname, buf, dsize));
00479 
00480         // -- copy the stored samples to the delay line
00481         fClass->addPreCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[i];", buf, pmem, dsize));
00482 
00483         // -- compute the new samples
00484         fClass->addExecCode(subst("$0[i] = $1;", dlname, cexp));
00485 
00486         // -- copy back to stored samples
00487         fClass->addPostCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[count+i];", pmem, buf, dsize));
00488 
00489     } else {
00490 
00491         // Implementation of a ring-buffer delayline
00492 
00493         // the size should be large enough and aligned on a power of two
00494         delay   = pow2limit(delay + gVecSize);
00495         string  dsize   = T(delay);
00496         string  mask    = T(delay-1);
00497 
00498         // create names for temporary and permanent storage
00499         string  idx = subst("$0_idx", dlname);
00500         string  idx_save = subst("$0_idx_save", dlname);
00501 
00502         // allocate permanent storage for delayed samples
00503         fClass->addDeclCode(subst("$0 \t$1[$2];", tname, dlname, dsize));
00504         fClass->addDeclCode(subst("int \t$0;", idx));
00505         fClass->addDeclCode(subst("int \t$0;", idx_save));
00506 
00507         // init permanent memory
00508         fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", dlname, dsize));
00509         fClass->addInitCode(subst("$0 = 0;", idx));
00510         fClass->addInitCode(subst("$0 = 0;", idx_save));
00511 
00512         // -- update index
00513         fClass->addPreCode(subst("$0 = ($0+$1)&$2;", idx, idx_save, mask));
00514 
00515         // -- compute the new samples
00516         fClass->addExecCode(subst("$0[($2+i)&$3] = $1;", dlname, cexp, idx, mask));
00517 
00518         // -- save index
00519         fClass->addPostCode(subst("$0 = count;", idx_save));
00520     }
00521 }
00522