|
FAUST compiler
0.9.9.6b8
|
Compile a list of FAUST signals into a vector C++ class. More...
#include <compile_vect.hh>


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) |
| Main code generator dispatch. | |
| virtual void | generateCodeRecursions (Tree sig) |
| virtual string | generateCodeNonRec (Tree sig) |
| virtual string | generateLoopCode (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.
: ScalarCompiler(name,super,numInputs,numOutputs) {}
| VectorCompiler::VectorCompiler | ( | Klass * | k | ) | [inline] |
Definition at line 48 of file compile_vect.hh.
: ScalarCompiler(k) {}
| 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().
{
//contextor recursivness(0);
L = prepare(L); // optimize, share and annotate expression
for (int i = 0; i < fClass->inputs(); i++) {
fClass->addZone3(subst("$1* input$0 = &input[$0][index];", T(i), xfloat()));
}
for (int i = 0; i < fClass->outputs(); i++) {
fClass->addZone3(subst("$1* output$0 = &output[$0][index];", T(i), xfloat()));
}
fClass->addSharedDecl("fullcount");
fClass->addSharedDecl("input");
fClass->addSharedDecl("output");
for (int i = 0; isList(L); L = tl(L), i++) {
Tree sig = hd(L);
fClass->openLoop("count");
fClass->addExecCode(subst("output$0[i] = $2$1;", T(i), CS(sig), xcast()));
fClass->closeLoop(sig);
}
generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot));
generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
if (fDescription) {
fDescription->ui(prepareUserInterfaceTree(fUIRoot));
}
}

| 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::fBackwardLoopDependencies, Compiler::fClass, generateCode(), getCertifiedSigType(), ScalarCompiler::getCompiledExpression(), Klass::getLoopProperty(), isProj(), isSigFixDelay(), kSamp, ScalarCompiler::setCompiledExpression(), tl(), and Klass::topLoop().
Referenced by SchedulerCompiler::compileMultiSignal(), compileMultiSignal(), and generateFixDelay().
{
string code;
//cerr << "ENTER VectorCompiler::CS : "<< ppsig(sig) << endl;
if (!getCompiledExpression(sig, code)) {
code = generateCode(sig);
//cerr << "CS : " << code << " for " << ppsig(sig) << endl;
setCompiledExpression(sig, code);
} else {
// we require an already compiled expression
// therefore we must update the dependencies of
// the current loop
int i;
Tree x, d, r;
Loop* ls;
Loop* tl = fClass->topLoop();
if (fClass->getLoopProperty(sig,ls)) {
// sig has a loop property
//cerr << "CASE SH : fBackwardLoopDependencies.insert : " << tl << " --depend(A)son--> " << ls << endl;
tl->fBackwardLoopDependencies.insert(ls);
} else if (isSigFixDelay(sig, x, d) && fClass->getLoopProperty(x,ls)) {
//cerr << "CASE DL : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
tl->fBackwardLoopDependencies.insert(ls);
} else if (isSigFixDelay(sig, x, d) && isProj(x, &i, r) && fClass->getLoopProperty(r,ls)) {
//cerr << "CASE DR : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
tl->fBackwardLoopDependencies.insert(ls);
} else if (isProj(sig, &i, r) && fClass->getLoopProperty(r,ls)) {
//cerr << "CASE R* : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
tl->fBackwardLoopDependencies.insert(ls);
} else {
if (isProj(sig, &i, r)) {
//cerr << "SYMBOL RECURSIF EN COURS ??? " << *r << endl;
} else if (getCertifiedSigType(sig)->variability()<kSamp) {
//cerr << "SLOW EXPRESSION " << endl;
} else {
//cerr << "Expression absorbée" << *sig << endl;
}
}
}
//cerr << "EXIT VectorCompiler::CS : "<< ppsig(sig) << "---code---> " << code << endl;
return code;
}


| 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 449 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().
{
if (delay < gMaxCopyDelay) {
// Implementation of a copy based delayline
// create names for temporary and permanent storage
string buf = subst("$0_tmp", dlname);
string pmem= subst("$0_perm", dlname);
// constraints delay size to be multiple of 4
delay = (delay+3)&-4;
// allocate permanent storage for delayed samples
string dsize = T(delay);
fClass->addDeclCode(subst("$0 \t$1[$2];", tname, pmem, dsize));
// init permanent memory
fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", pmem, dsize));
// compute method
// -- declare a buffer and a "shifted" vector
fClass->addSharedDecl(buf);
// -- variables moved as class fields...
fClass->addZone1(subst("$0 \t$1[$2+$3];", tname, buf, T(gVecSize), dsize));
fClass->addFirstPrivateDecl(dlname);
fClass->addZone2(subst("$0* \t$1 = &$2[$3];", tname, dlname, buf, dsize));
// -- copy the stored samples to the delay line
fClass->addPreCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[i];", buf, pmem, dsize));
// -- compute the new samples
fClass->addExecCode(subst("$0[i] = $1;", dlname, cexp));
// -- copy back to stored samples
fClass->addPostCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[count+i];", pmem, buf, dsize));
} else {
// Implementation of a ring-buffer delayline
// the size should be large enough and aligned on a power of two
delay = pow2limit(delay + gVecSize);
string dsize = T(delay);
string mask = T(delay-1);
// create names for temporary and permanent storage
string idx = subst("$0_idx", dlname);
string idx_save = subst("$0_idx_save", dlname);
// allocate permanent storage for delayed samples
fClass->addDeclCode(subst("$0 \t$1[$2];", tname, dlname, dsize));
fClass->addDeclCode(subst("int \t$0;", idx));
fClass->addDeclCode(subst("int \t$0;", idx_save));
// init permanent memory
fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", dlname, dsize));
fClass->addInitCode(subst("$0 = 0;", idx));
fClass->addInitCode(subst("$0 = 0;", idx_save));
// -- update index
fClass->addPreCode(subst("$0 = ($0+$1)&$2;", idx, idx_save, mask));
// -- compute the new samples
fClass->addExecCode(subst("$0[($2+i)&$3] = $1;", dlname, cexp, idx, mask));
// -- save index
fClass->addPostCode(subst("$0 = count;", idx_save));
}
}


| 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 203 of file compile_vect.cpp.
References ScalarCompiler::fOccMarkup, generateDelayLine(), generateVariableStore(), getCertifiedSigType(), Occurences::getMaxDelay(), ScalarCompiler::getSharingCount(), ScalarCompiler::getTypedNames(), gMaxCopyDelay, gVecSize, kSamp, ScalarCompiler::pow2limit(), OccMarkup::retrieve(), ScalarCompiler::setVectorNameProperty(), subst(), T(), and verySimple().
{
string vname, ctype;
int sharing = getSharingCount(sig);
Type t = getCertifiedSigType(sig);
Occurences* o = fOccMarkup.retrieve(sig);
int d = o->getMaxDelay();
if (t->variability() < kSamp) {
if (d==0) {
// non-sample, not delayed : same as scalar cache
return ScalarCompiler::generateCacheCode(sig,exp);
} else {
// it is a non-sample expressions but used delayed
// we need a delay line
getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
if ((sharing > 1) && !verySimple(sig)) {
// first cache this expression because it
// it is shared and complex
string cachedexp = generateVariableStore(sig, exp);
generateDelayLine(ctype, vname, d, cachedexp);
setVectorNameProperty(sig, vname);
return cachedexp;
} else {
// no need to cache this expression because
// it is either not shared or very simple
generateDelayLine(ctype, vname, d, exp);
setVectorNameProperty(sig, vname);
return exp;
}
}
} else {
// sample-rate signal
if (d > 0) {
// used delayed : we need a delay line
getTypedNames(getCertifiedSigType(sig), "Yec", ctype, vname);
generateDelayLine(ctype, vname, d, exp);
setVectorNameProperty(sig, vname);
if (verySimple(sig)) {
return exp;
} else {
if (d < gMaxCopyDelay) {
return subst("$0[i]", vname);
} else {
// we use a ring buffer
string mask = T(pow2limit(d + gVecSize)-1);
return subst("$0[($0_idx+i) & $1]", vname, mask);
}
}
} else {
// not delayed
if ( sharing > 1 && ! verySimple(sig) ) {
// shared and not simple : we need a vector
// cerr << "ZEC : " << ppsig(sig) << endl;
getTypedNames(getCertifiedSigType(sig), "Zec", ctype, vname);
generateDelayLine(ctype, vname, d, exp);
setVectorNameProperty(sig, vname);
return subst("$0[i]", vname);
} else {
// not shared or simple : no cache needed
return exp;
}
}
}
}

| string VectorCompiler::generateCode | ( | Tree | sig | ) | [protected, virtual] |
Main code generator dispatch.
| sig | the signal expression to compile. |
Reimplemented from ScalarCompiler.
Definition at line 115 of file compile_vect.cpp.
References generateCodeNonRec(), and generateCodeRecursions().
Referenced by CS(), and generateLoopCode().
{
generateCodeRecursions(sig);
return generateCodeNonRec(sig);
}


| string VectorCompiler::generateCodeNonRec | ( | Tree | sig | ) | [protected, virtual] |
Definition at line 143 of file compile_vect.cpp.
References generateLoopCode(), ScalarCompiler::getCompiledExpression(), and ScalarCompiler::setCompiledExpression().
Referenced by generateCode().
{
string code;
if (getCompiledExpression(sig, code)) {
// already visited
return code;
} else {
//cerr << "VectorCompiler::generateCodeNonRec( " << ppsig(sig) << " )" << endl;
code = generateLoopCode(sig);
setCompiledExpression(sig, code);
return code;
}
}


| void VectorCompiler::generateCodeRecursions | ( | Tree | sig | ) | [protected, virtual] |
Definition at line 121 of file compile_vect.cpp.
References Klass::closeLoop(), Compiler::fClass, ScalarCompiler::generateRec(), ScalarCompiler::getCompiledExpression(), getSubSignals(), isRec(), Klass::openLoop(), and ScalarCompiler::setCompiledExpression().
Referenced by generateCode().
{
Tree id, body;
string code;
//cerr << "VectorCompiler::generateCodeRecursions( " << ppsig(sig) << " )" << endl;
if (getCompiledExpression(sig, code)) {
//cerr << "** ALREADY VISITED : " << code << " ===> " << ppsig(sig) << endl;
return;
} else if( isRec(sig, id, body) ) {
//cerr << "we have a recursive expression non compiled yet : " << ppsig(sig) << endl;
setCompiledExpression(sig, "[RecursionVisited]");
fClass->openLoop(sig, "count");
generateRec(sig, id, body);
fClass->closeLoop(sig);
} else {
// we go down the expression
vector<Tree> subsigs;
int n = getSubSignals(sig, subsigs, false);
for (int i=0; i<n; i++) { generateCodeRecursions(subsigs[i]); }
}
}


| 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 313 of file compile_vect.cpp.
References dlineLoop(), and vectorLoop().
Referenced by generateCacheCode(), and generateDelayVec().
{
if (mxd == 0) {
vectorLoop(ctype, vname, exp);
} else {
dlineLoop(ctype, vname, mxd, exp);
}
}


| 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 396 of file compile_vect.cpp.
References generateDelayLine(), ScalarCompiler::setVectorNameProperty(), subst(), and verySimple().
{
// it is a non-sample but used delayed
// we need a delay line
generateDelayLine(ctype, vname, mxd, exp);
setVectorNameProperty(sig, vname);
if (verySimple(sig)) {
return exp;
} else {
return subst("$0[i]", vname);
}
}

| string VectorCompiler::generateFixDelay | ( | Tree | sig, |
| Tree | exp, | ||
| Tree | delay | ||
| ) | [protected, virtual] |
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 342 of file compile_vect.cpp.
References CS(), ScalarCompiler::fOccMarkup, Occurences::getMaxDelay(), ScalarCompiler::getVectorNameProperty(), gMaxCopyDelay, gVecSize, isSigInt(), ScalarCompiler::pow2limit(), OccMarkup::retrieve(), subst(), and T().
{
int mxd, d;
string vecname;
//cerr << "VectorCompiler::generateFixDelay " << ppsig(sig) << endl;
CS(exp); // ensure exp is compiled to have a vector name
mxd = fOccMarkup.retrieve(exp)->getMaxDelay();
if (! getVectorNameProperty(exp, vecname)) {
cerr << "ERROR no vector name for " << ppsig(exp) << endl;
exit(1);
}
if (mxd == 0) {
// not a real vector name but a scalar name
return subst("$0[i]", vecname);
} else if (mxd < gMaxCopyDelay){
if (isSigInt(delay, &d)) {
if (d == 0) {
return subst("$0[i]", vecname);
} else {
return subst("$0[i-$1]", vecname, T(d));
}
} else {
return subst("$0[i-$1]", vecname, CS(delay));
}
} else {
// long delay : we use a ring buffer of size 2^x
int N = pow2limit( mxd+gVecSize );
if (isSigInt(delay, &d)) {
if (d == 0) {
return subst("$0[($0_idx+i)&$1]", vecname, T(N-1));
} else {
return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), T(d));
}
} else {
return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), CS(delay));
}
}
}

| string VectorCompiler::generateLoopCode | ( | Tree | sig | ) | [protected, virtual] |
Compile a signal.
| sig | the signal expression to compile. |
Definition at line 162 of file compile_vect.cpp.
References Klass::closeLoop(), Compiler::fClass, generateCode(), Loop::hasRecDependencyIn(), isProj(), needSeparateLoop(), Klass::openLoop(), singleton(), and Klass::topLoop().
Referenced by generateCodeNonRec().
{
int i;
Tree x;
Loop* l;
l = fClass->topLoop();
assert(l);
//cerr << "VectorCompiler::OLDgenerateCode " << ppsig(sig) << endl;
if (needSeparateLoop(sig)) {
// we need a separate loop unless it's an old recursion
if (isProj(sig, &i, x)) {
// projection of a recursive group x
if (l->hasRecDependencyIn(singleton(x))) {
// x is already in the loop stack
return ScalarCompiler::generateCode(sig);
} else {
// x must be defined
fClass->openLoop(x, "count");
string c = ScalarCompiler::generateCode(sig);
fClass->closeLoop(sig);
return c;
}
} else {
fClass->openLoop("count");
string c = ScalarCompiler::generateCode(sig);
fClass->closeLoop(sig);
return c;
}
} else {
return ScalarCompiler::generateCode(sig);
}
}


| string VectorCompiler::generateVariableStore | ( | Tree | sig, |
| const string & | exp | ||
| ) | [protected, virtual] |
Reimplemented from ScalarCompiler.
Definition at line 322 of file compile_vect.cpp.
References getCertifiedSigType(), ScalarCompiler::getTypedNames(), kSamp, subst(), and vectorLoop().
Referenced by generateCacheCode().
{
Type t = getCertifiedSigType(sig);
if (getCertifiedSigType(sig)->variability() == kSamp) {
string vname, ctype;
getTypedNames(t, "Vector", ctype, vname);
vectorLoop(ctype, vname, exp);
return subst("$0[i]", vname);
} else {
return ScalarCompiler::generateVariableStore(sig, exp);
}
}


| 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 276 of file compile_vect.cpp.
References ScalarCompiler::fOccMarkup, getCertifiedSigType(), Occurences::getMaxDelay(), ScalarCompiler::getSharingCount(), isProj(), isSigFixDelay(), kSamp, OccMarkup::retrieve(), and verySimple().
Referenced by generateLoopCode().
{
Occurences* o = fOccMarkup.retrieve(sig);
Type t = getCertifiedSigType(sig);
int c = getSharingCount(sig);
bool b;
int i;
Tree x,y;
if (o->getMaxDelay()>0) {
//cerr << "DLY "; // delayed expressions require a separate loop
b = true;
} else if (verySimple(sig) || t->variability()<kSamp) {
b = false; // non sample computation never require a loop
} else if (isSigFixDelay(sig, x, y)) {
b = false; //
} else if (isProj(sig, &i ,x)) {
//cerr << "REC "; // recursive expressions require a separate loop
b = true;
} else if (c > 1) {
//cerr << "SHA(" << c << ") "; // expressions used several times required a separate loop
b = true;
} else {
// sample expressions that are not recursive, not delayed
// and not shared, doesn't require a separate loop.
b = false;
}
/* if (b) {
cerr << "Separate Loop for " << ppsig(sig) << endl;
} else {
cerr << "Same Loop for " << ppsig(sig) << endl;
}*/
return b;
}


| 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 427 of file compile_vect.cpp.
References Klass::addExecCode(), Klass::addSharedDecl(), Klass::addZone1(), Compiler::fClass, gVecSize, subst(), and T().
Referenced by generateDelayLine(), and generateVariableStore().
{
// -- declare the vector
fClass->addSharedDecl(vecname);
// -- variables moved as class fields...
fClass->addZone1(subst("$0 \t$1[$2];", tname, vecname, T(gVecSize)));
// -- compute the new samples
fClass->addExecCode(subst("$0[i] = $1;", vecname, cexp));
}


1.8.0