FAUST compiler  0.9.9.6b8
Public Member Functions | Protected Member Functions
VectorCompiler Class Reference

Compile a list of FAUST signals into a vector C++ class. More...

#include <compile_vect.hh>

Inheritance diagram for VectorCompiler:
Inheritance graph
[legend]
Collaboration diagram for VectorCompiler:
Collaboration graph
[legend]

List of all members.

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.

Detailed Description

Compile a list of FAUST signals into a vector C++ class.

Definition at line 39 of file compile_vect.hh.


Constructor & Destructor Documentation

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)
        {}

Definition at line 48 of file compile_vect.hh.

                              : ScalarCompiler(k)
    {}

Member Function Documentation

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));
    }
}

Here is the call graph for this function:

string VectorCompiler::CS ( Tree  sig) [protected, virtual]

Compile a signal.

Parameters:
sigthe signal expression to compile.
Returns:
the C code translation of sig as a string

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void VectorCompiler::dlineLoop ( const string &  tname,
const string &  dlname,
int  delay,
const string &  cexp 
) [protected, virtual]

Generate the code for a (short) delay line.

Parameters:
kthe c++ class where the delay line will be placed.
lthe loop where the code will be placed.
tnamethe name of the C++ type (float or int)
dlnamethe name of the delay line (vector) to be used.
delaythe maximum delay
cexpthe 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));
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

string VectorCompiler::generateCacheCode ( Tree  sig,
const string &  exp 
) [protected, virtual]

Generate cache code for a signal if needed.

Parameters:
sigthe signal expression.
expthe corresponding C code.
Returns:
the cached 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;
            }
        }
    }
}

Here is the call graph for this function:

string VectorCompiler::generateCode ( Tree  sig) [protected, virtual]

Main code generator dispatch.

Parameters:
sigthe signal expression to compile.
Returns:
the C code translation of sig

Reimplemented from ScalarCompiler.

Definition at line 115 of file compile_vect.cpp.

References generateCodeNonRec(), and generateCodeRecursions().

Referenced by CS(), and generateLoopCode().

Here is the call graph for this function:

Here is the caller graph for this function:

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;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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]); }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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);
    }
}

Here is the call graph for this function:

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));
        }
    }
}

Here is the call graph for this function:

string VectorCompiler::generateLoopCode ( Tree  sig) [protected, virtual]

Compile a signal.

Parameters:
sigthe signal expression to compile.
Returns:
the C code translation of sig as a string

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);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool VectorCompiler::needSeparateLoop ( Tree  sig) [protected]

Test if a signal need to be compiled in a separate loop.

Parameters:
sigthe signal expression to test.
Returns:
true if a separate loop is needed

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void VectorCompiler::vectorLoop ( const string &  tname,
const string &  vecname,
const string &  cexp 
) [protected, virtual]

Generate the code for a (short) delay line.

Parameters:
kthe c++ class where the delay line will be placed.
lthe loop where the code will be placed.
tnamethe name of the C++ type (float or int)
dlnamethe name of the delay line (vector) to be used.
delaythe maximum delay
cexpthe 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));
}

Here is the call graph for this function:

Here is the caller graph for this function:


The documentation for this class was generated from the following files: