|
FAUST compiler
0.9.9.6b8
|
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
1.8.0