Compile a list of FAUST signals into a vector C++ class. More...
#include <compile_vect.hh>
Inherits ScalarCompiler.
Inherited by SchedulerCompiler.
Public Member Functions | |
VectorCompiler (const string &name, const string &super, int numInputs, int numOutputs) | |
VectorCompiler (Klass *k) | |
virtual void | compileMultiSignal (Tree L) |
Protected Member Functions | |
virtual string | CS (Tree sig) |
Compile a signal. | |
virtual string | generateCode (Tree sig) |
Compile a signal. | |
virtual string | generateCacheCode (Tree sig, const string &exp) |
Generate cache code for a signal if needed. | |
virtual void | generateDelayLine (const string &ctype, const string &vname, int mxd, const string &exp) |
Generate code for the delay mecchanism without using temporary variables. | |
virtual string | generateVariableStore (Tree sig, const string &exp) |
virtual string | generateFixDelay (Tree sig, Tree exp, Tree delay) |
Generate code for accessing a delayed signal. | |
virtual string | generateDelayVec (Tree sig, const string &exp, const string &ctype, const string &vname, int mxd) |
Generate code for the delay mecchanism. | |
virtual void | vectorLoop (const string &tname, const string &dlname, const string &cexp) |
Generate the code for a (short) delay line. | |
virtual void | dlineLoop (const string &tname, const string &dlname, int delay, const string &cexp) |
Generate the code for a (short) delay line. | |
bool | needSeparateLoop (Tree sig) |
Test if a signal need to be compiled in a separate loop. |
Compile a list of FAUST signals into a vector C++ class.
Definition at line 39 of file compile_vect.hh.
VectorCompiler::VectorCompiler | ( | const string & | name, | |
const string & | super, | |||
int | numInputs, | |||
int | numOutputs | |||
) | [inline] |
Definition at line 44 of file compile_vect.hh.
00045 : ScalarCompiler(name,super,numInputs,numOutputs) 00046 {}
VectorCompiler::VectorCompiler | ( | Klass * | k | ) | [inline] |
Definition at line 48 of file compile_vect.hh.
00048 : ScalarCompiler(k) 00049 {}
void VectorCompiler::compileMultiSignal | ( | Tree | L | ) | [virtual] |
Reimplemented from ScalarCompiler.
Reimplemented in SchedulerCompiler.
Definition at line 30 of file compile_vect.cpp.
References Klass::addExecCode(), Klass::addSharedDecl(), Klass::addZone3(), Klass::closeLoop(), CS(), Compiler::fClass, Compiler::fDescription, Compiler::fUIRoot, Compiler::generateMacroInterfaceTree(), Compiler::generateUserInterfaceTree(), hd(), Klass::inputs(), isList(), Klass::openLoop(), Klass::outputs(), ScalarCompiler::prepare(), Compiler::prepareUserInterfaceTree(), subst(), T(), tl(), Description::ui(), xcast(), and xfloat().
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(); 00051 } 00052 00053 generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot)); 00054 generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot)); 00055 if (fDescription) { 00056 fDescription->ui(prepareUserInterfaceTree(fUIRoot)); 00057 } 00058 }
string VectorCompiler::CS | ( | Tree | sig | ) | [protected, virtual] |
Compile a signal.
sig | the signal expression to compile. |
Reimplemented from ScalarCompiler.
Definition at line 66 of file compile_vect.cpp.
References Loop::addRecDependency(), Loop::fBackwardLoopDependencies, Compiler::fClass, Loop::findRecDefinition(), generateCode(), ScalarCompiler::getCompiledExpression(), Klass::getLoopProperty(), isProj(), isSigFixDelay(), ScalarCompiler::setCompiledExpression(), tl(), and Klass::topLoop().
Referenced by compileMultiSignal(), SchedulerCompiler::compileMultiSignal(), and generateFixDelay().
00067 { 00068 int i; 00069 Tree x; 00070 string code; 00071 //cerr << "ENTER CS : "<< ppsig(sig) << endl; 00072 if (!getCompiledExpression(sig, code)) { 00073 code = generateCode(sig); 00074 //cerr << "CS : " << code << " for " << ppsig(sig) << endl; 00075 setCompiledExpression(sig, code); 00076 } else { 00077 // check for recursive dependencies 00078 Loop* ls; 00079 Loop* tl = fClass->topLoop(); 00080 if (isProj(sig, &i, x) && tl->findRecDefinition(x)) { 00081 tl->addRecDependency(x); 00082 //cerr << "in CS : add rec dependency : " << tl << " --symbol--> " << x << endl; 00083 } else if (fClass->getLoopProperty(sig,ls)) { 00084 //cerr << "in CS : fBackwardLoopDependencies.insert : " << tl << " --depend(A)son--> " << ls << endl; 00085 tl->fBackwardLoopDependencies.insert(ls); 00086 } else { 00087 Tree x,d; 00088 if (isSigFixDelay(sig, x, d)) { 00089 if (fClass->getLoopProperty(x,ls)) { 00090 //cerr << "in CS : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl; 00091 tl->fBackwardLoopDependencies.insert(ls); 00092 } else { 00093 //cerr << "IMPOSSIBLE (dans l'etat des connaissances)" << endl; 00094 //exit(1); 00095 } 00096 } else { 00097 //cerr << "in CS : no loop property for : " << ppsig(sig) << endl; 00098 } 00099 } 00100 } 00101 //cerr << "EXIT CS : "<< ppsig(sig) << "---code---> " << code << endl; 00102 return code; 00103 }
void VectorCompiler::dlineLoop | ( | const string & | tname, | |
const string & | dlname, | |||
int | delay, | |||
const string & | cexp | |||
) | [protected, virtual] |
Generate the code for a (short) delay line.
k | the c++ class where the delay line will be placed. | |
l | the loop where the code will be placed. | |
tname | the name of the C++ type (float or int) | |
dlname | the name of the delay line (vector) to be used. | |
delay | the maximum delay | |
cexp | the content of the signal as a C++ expression |
Reimplemented in SchedulerCompiler.
Definition at line 392 of file compile_vect.cpp.
References Klass::addDeclCode(), Klass::addExecCode(), Klass::addFirstPrivateDecl(), Klass::addInitCode(), Klass::addPostCode(), Klass::addPreCode(), Klass::addSharedDecl(), Klass::addZone1(), Klass::addZone2(), Compiler::fClass, gMaxCopyDelay, gVecSize, ScalarCompiler::pow2limit(), subst(), and T().
Referenced by generateDelayLine().
00393 { 00394 if (delay < gMaxCopyDelay) { 00395 00396 // Implementation of a copy based delayline 00397 00398 // create names for temporary and permanent storage 00399 string buf = subst("$0_tmp", dlname); 00400 string pmem= subst("$0_perm", dlname); 00401 00402 // constraints delay size to be multiple of 4 00403 delay = (delay+3)&-4; 00404 00405 // allocate permanent storage for delayed samples 00406 string dsize = T(delay); 00407 fClass->addDeclCode(subst("$0 \t$1[$2];", tname, pmem, dsize)); 00408 00409 // init permanent memory 00410 fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", pmem, dsize)); 00411 00412 // compute method 00413 00414 // -- declare a buffer and a "shifted" vector 00415 fClass->addSharedDecl(buf); 00416 00417 // -- variables moved as class fields... 00418 fClass->addZone1(subst("$0 \t$1[$2+$3];", tname, buf, T(gVecSize), dsize)); 00419 00420 fClass->addFirstPrivateDecl(dlname); 00421 fClass->addZone2(subst("$0* \t$1 = &$2[$3];", tname, dlname, buf, dsize)); 00422 00423 // -- copy the stored samples to the delay line 00424 fClass->addPreCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[i];", buf, pmem, dsize)); 00425 00426 // -- compute the new samples 00427 fClass->addExecCode(subst("$0[i] = $1;", dlname, cexp)); 00428 00429 // -- copy back to stored samples 00430 fClass->addPostCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[count+i];", pmem, buf, dsize)); 00431 00432 } else { 00433 00434 // Implementation of a ring-buffer delayline 00435 00436 // the size should be large enough and aligned on a power of two 00437 delay = pow2limit(delay + gVecSize); 00438 string dsize = T(delay); 00439 string mask = T(delay-1); 00440 00441 // create names for temporary and permanent storage 00442 string idx = subst("$0_idx", dlname); 00443 string idx_save = subst("$0_idx_save", dlname); 00444 00445 // allocate permanent storage for delayed samples 00446 fClass->addDeclCode(subst("$0 \t$1[$2];", tname, dlname, dsize)); 00447 fClass->addDeclCode(subst("int \t$0;", idx)); 00448 fClass->addDeclCode(subst("int \t$0;", idx_save)); 00449 00450 // init permanent memory 00451 fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", dlname, dsize)); 00452 fClass->addInitCode(subst("$0 = 0;", idx)); 00453 fClass->addInitCode(subst("$0 = 0;", idx_save)); 00454 00455 // -- update index 00456 fClass->addPreCode(subst("$0 = ($0+$1)&$2;", idx, idx_save, mask)); 00457 00458 // -- compute the new samples 00459 fClass->addExecCode(subst("$0[($2+i)&$3] = $1;", dlname, cexp, idx, mask)); 00460 00461 // -- save index 00462 fClass->addPostCode(subst("$0 = count;", idx_save)); 00463 } 00464 }
string VectorCompiler::generateCacheCode | ( | Tree | sig, | |
const string & | exp | |||
) | [protected, virtual] |
Generate cache code for a signal if needed.
sig | the signal expression. | |
exp | the corresponding C code. |
Reimplemented from ScalarCompiler.
Definition at line 152 of file compile_vect.cpp.
References ScalarCompiler::fOccMarkup, generateDelayLine(), generateVariableStore(), Occurences::getMaxDelay(), ScalarCompiler::getSharingCount(), getSigType(), ScalarCompiler::getTypedNames(), kSamp, OccMarkup::retrieve(), ScalarCompiler::setVectorNameProperty(), subst(), and verySimple().
00153 { 00154 string vname, ctype; 00155 int sharing = getSharingCount(sig); 00156 Type t = getSigType(sig); 00157 Occurences* o = fOccMarkup.retrieve(sig); 00158 int d = o->getMaxDelay(); 00159 00160 if (t->variability() < kSamp) { 00161 if (d==0) { 00162 // non-sample, not delayed : same as scalar cache 00163 return ScalarCompiler::generateCacheCode(sig,exp); 00164 00165 } else { 00166 // it is a non-sample expressions but used delayed 00167 // we need a delay line 00168 getTypedNames(getSigType(sig), "Vec", ctype, vname); 00169 if ((sharing > 1) && !verySimple(sig)) { 00170 // first cache this expression because it 00171 // it is shared and complex 00172 string cachedexp = generateVariableStore(sig, exp); 00173 generateDelayLine(ctype, vname, d, cachedexp); 00174 setVectorNameProperty(sig, vname); 00175 return cachedexp; 00176 } else { 00177 // no need to cache this expression because 00178 // it is either not shared or very simple 00179 generateDelayLine(ctype, vname, d, exp); 00180 setVectorNameProperty(sig, vname); 00181 return exp; 00182 } 00183 } 00184 } else { 00185 // sample-rate signal 00186 if (d > 0) { 00187 // used delayed : we need a delay line 00188 getTypedNames(getSigType(sig), "Yec", ctype, vname); 00189 generateDelayLine(ctype, vname, d, exp); 00190 setVectorNameProperty(sig, vname); 00191 00192 if (verySimple(sig)) { 00193 return exp; 00194 } else { 00195 return subst("$0[i]", vname); 00196 } 00197 } else { 00198 // not delayed 00199 if ( sharing > 1 && ! verySimple(sig) ) { 00200 // shared and not simple : we need a vector 00201 // cerr << "ZEC : " << ppsig(sig) << endl; 00202 getTypedNames(getSigType(sig), "Zec", ctype, vname); 00203 generateDelayLine(ctype, vname, d, exp); 00204 setVectorNameProperty(sig, vname); 00205 return subst("$0[i]", vname); 00206 } else { 00207 // not shared or simple : no cache needed 00208 return exp; 00209 } 00210 } 00211 } 00212 }
string VectorCompiler::generateCode | ( | Tree | sig | ) | [protected, virtual] |
Compile a signal.
sig | the signal expression to compile. |
Reimplemented from ScalarCompiler.
Definition at line 110 of file compile_vect.cpp.
References Loop::addRecDependency(), Klass::closeLoop(), Compiler::fClass, Loop::findRecDefinition(), isProj(), needSeparateLoop(), Klass::openLoop(), and Klass::topLoop().
Referenced by CS().
00111 { 00112 int i; 00113 Tree x; 00114 Loop* l; 00115 00116 l = fClass->topLoop(); 00117 assert(l); 00118 00119 if (needSeparateLoop(sig)) { 00120 // we need a separate loop unless it's an old recursion 00121 if (isProj(sig, &i, x)) { 00122 // projection of a recursive group x 00123 if (l->findRecDefinition(x)) { 00124 // x is already in the loop stack 00125 l->addRecDependency(x); 00126 return ScalarCompiler::generateCode(sig); 00127 } else { 00128 // x must be defined 00129 fClass->openLoop(x, "count"); 00130 string c = ScalarCompiler::generateCode(sig); 00131 fClass->closeLoop(sig); 00132 return c; 00133 } 00134 } else { 00135 fClass->openLoop("count"); 00136 string c = ScalarCompiler::generateCode(sig); 00137 fClass->closeLoop(sig); 00138 return c; 00139 } 00140 } else { 00141 return ScalarCompiler::generateCode(sig); 00142 } 00143 }
void VectorCompiler::generateDelayLine | ( | const string & | ctype, | |
const string & | vname, | |||
int | mxd, | |||
const string & | exp | |||
) | [protected, virtual] |
Generate code for the delay mecchanism without using temporary variables.
Reimplemented from ScalarCompiler.
Definition at line 256 of file compile_vect.cpp.
References dlineLoop(), and vectorLoop().
Referenced by generateCacheCode(), and generateDelayVec().
00257 { 00258 if (mxd == 0) { 00259 vectorLoop(ctype, vname, exp); 00260 } else { 00261 dlineLoop(ctype, vname, mxd, exp); 00262 } 00263 }
string VectorCompiler::generateDelayVec | ( | Tree | sig, | |
const string & | exp, | |||
const string & | ctype, | |||
const string & | vname, | |||
int | mxd | |||
) | [protected, virtual] |
Generate code for the delay mecchanism.
The generated code depend of the maximum delay attached to exp and the "less temporaries" switch
Reimplemented from ScalarCompiler.
Definition at line 339 of file compile_vect.cpp.
References generateDelayLine(), ScalarCompiler::setVectorNameProperty(), subst(), and verySimple().
00340 { 00341 // it is a non-sample but used delayed 00342 // we need a delay line 00343 generateDelayLine(ctype, vname, mxd, exp); 00344 setVectorNameProperty(sig, vname); 00345 if (verySimple(sig)) { 00346 return exp; 00347 } else { 00348 return subst("$0[i]", vname); 00349 } 00350 }
Generate code for accessing a delayed signal.
The generated code depend of the maximum delay attached to exp and the gLessTempSwitch.
Reimplemented from ScalarCompiler.
Definition at line 285 of file compile_vect.cpp.
References CS(), ScalarCompiler::fOccMarkup, Occurences::getMaxDelay(), ScalarCompiler::getVectorNameProperty(), gMaxCopyDelay, gVecSize, isSigInt(), ScalarCompiler::pow2limit(), OccMarkup::retrieve(), subst(), and T().
00286 { 00287 int mxd, d; 00288 string vecname; 00289 00290 //cerr << "VectorCompiler::generateFixDelay " << ppsig(sig) << endl; 00291 00292 CS(exp); // ensure exp is compiled to have a vector name 00293 00294 mxd = fOccMarkup.retrieve(exp)->getMaxDelay(); 00295 00296 if (! getVectorNameProperty(exp, vecname)) { 00297 cerr << "no vector name for " << ppsig(exp) << endl; 00298 exit(1); 00299 } 00300 00301 if (mxd == 0) { 00302 // not a real vector name but a scalar name 00303 return subst("$0[i]", vecname); 00304 00305 } else if (mxd < gMaxCopyDelay){ 00306 if (isSigInt(delay, &d)) { 00307 if (d == 0) { 00308 return subst("$0[i]", vecname); 00309 } else { 00310 return subst("$0[i-$1]", vecname, T(d)); 00311 } 00312 } else { 00313 return subst("$0[i-$1]", vecname, CS(delay)); 00314 } 00315 00316 } else { 00317 00318 // long delay : we use a ring buffer of size 2^x 00319 int N = pow2limit( mxd+gVecSize ); 00320 00321 if (isSigInt(delay, &d)) { 00322 if (d == 0) { 00323 return subst("$0[($0_idx+i)&$1]", vecname, T(N-1)); 00324 } else { 00325 return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), T(d)); 00326 } 00327 } else { 00328 return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), CS(delay)); 00329 } 00330 } 00331 }
string VectorCompiler::generateVariableStore | ( | Tree | sig, | |
const string & | exp | |||
) | [protected, virtual] |
Reimplemented from ScalarCompiler.
Definition at line 265 of file compile_vect.cpp.
References getSigType(), ScalarCompiler::getTypedNames(), kSamp, subst(), and vectorLoop().
Referenced by generateCacheCode().
00266 { 00267 Type t = getSigType(sig); 00268 00269 if (getSigType(sig)->variability() == kSamp) { 00270 string vname, ctype; 00271 getTypedNames(t, "Vector", ctype, vname); 00272 vectorLoop(ctype, vname, exp); 00273 return subst("$0[i]", vname); 00274 } else { 00275 return ScalarCompiler::generateVariableStore(sig, exp); 00276 } 00277 }
bool VectorCompiler::needSeparateLoop | ( | Tree | sig | ) | [protected] |
Test if a signal need to be compiled in a separate loop.
sig | the signal expression to test. |
Definition at line 219 of file compile_vect.cpp.
References ScalarCompiler::fOccMarkup, Occurences::getMaxDelay(), ScalarCompiler::getSharingCount(), getSigType(), isProj(), isSigFixDelay(), kSamp, OccMarkup::retrieve(), and verySimple().
Referenced by generateCode().
00220 { 00221 Occurences* o = fOccMarkup.retrieve(sig); 00222 Type t = getSigType(sig); 00223 int c = getSharingCount(sig); 00224 bool b; 00225 00226 int i; 00227 Tree x,y; 00228 00229 00230 if (o->getMaxDelay()>0) { 00231 //cerr << "DLY "; // delayed expressions require a separate loop 00232 b = true; 00233 } else if (verySimple(sig) || t->variability()<kSamp) { 00234 b = false; // non sample computation never require a loop 00235 } else if (isSigFixDelay(sig, x, y)) { 00236 b = false; // 00237 } else if (isProj(sig, &i ,x)) { 00238 //cerr << "REC "; // recursive expressions require a separate loop 00239 b = true; 00240 } else if (c > 1) { 00241 //cerr << "SHA(" << c << ") "; // expressions used several times required a separate loop 00242 b = true; 00243 } else { 00244 // sample expressions that are not recursive, not delayed 00245 // and not shared, doesn't require a separate loop. 00246 b = false; 00247 } 00248 /* if (b) { 00249 cerr << "Separate Loop for " << ppsig(sig) << endl; 00250 } else { 00251 cerr << "Same Loop for " << ppsig(sig) << endl; 00252 }*/ 00253 return b; 00254 }
void VectorCompiler::vectorLoop | ( | const string & | tname, | |
const string & | vecname, | |||
const string & | cexp | |||
) | [protected, virtual] |
Generate the code for a (short) delay line.
k | the c++ class where the delay line will be placed. | |
l | the loop where the code will be placed. | |
tname | the name of the C++ type (float or int) | |
dlname | the name of the delay line (vector) to be used. | |
delay | the maximum delay | |
cexp | the content of the signal as a C++ expression |
Reimplemented in SchedulerCompiler.
Definition at line 370 of file compile_vect.cpp.
References Klass::addExecCode(), Klass::addSharedDecl(), Klass::addZone1(), Compiler::fClass, gVecSize, subst(), and T().
Referenced by generateDelayLine(), and generateVariableStore().
00371 { 00372 // -- declare the vector 00373 fClass->addSharedDecl(vecname); 00374 00375 // -- variables moved as class fields... 00376 fClass->addZone1(subst("$0 \t$1[$2];", tname, vecname, T(gVecSize))); 00377 00378 // -- compute the new samples 00379 fClass->addExecCode(subst("$0[i] = $1;", vecname, cexp)); 00380 }