string VectorCompiler::generateVariableStore(Tree sig, const string& exp) { 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); } }
/** * Generate the equation of a constant table (its content is time constant). * Returns the name of the table */ string DocCompiler::generateDocConstantTbl(Tree /*tbl*/, Tree size, Tree isig) { string vname, ctype; string init = CS(isig, 0); int n; if(!isSigInt(size, &n)) { cerr << "error in DocCompiler::generateDocConstantTbl() : " << *size << " is not an integer expression and can't be used as a table size' " << endl; } // allocate a name v_i for the table getTypedNames(getCertifiedSigType(isig), "v", ctype, vname); // add a comment on tables in the notice gDocNoticeFlagMap["tablesigs"] = true; // add equation v[t] = isig(t) fLateq->addRDTblSigFormula(subst("$0[t] = $1 \\condition{when $$t \\in [0,$2]$$} ", vname, init, T(n - 1))); // note that the name of the table can never be used outside an sigDocTableAccess return vname; }
/** * Generate the equation of a write table, which content is time dependent. * It is basically a signal of vectors. */ string DocCompiler::generateDocWriteTbl(Tree /*tbl*/, Tree size, Tree isig, Tree widx, Tree wsig) { string vname, ctype; string init = CS(isig, 0); int n; if(!isSigInt(size, &n)) { cerr << "error in DocCompiler::generateDocWriteTbl() : " << *size << " is not an integer expression and can't be used as a table size' " << endl; } // allocate a name w_i for the table getTypedNames(getCertifiedSigType(isig), "w", ctype, vname); // add a comment on tables in the notice gDocNoticeFlagMap["tablesigs"] = true; // describe the table equation string ltqRWTableDef; ltqRWTableDef += subst("$0(t)[i] = \n", vname); ltqRWTableDef += "\\left\\{\\begin{array}{ll}\n"; ltqRWTableDef += subst("$0 & \\mbox{if \\,} t < 0 \\mbox{\\, and \\,} i \\in [0,$1] \\\\\n", replaceTimeBy(init, 'i'), T(n - 1)); ltqRWTableDef += subst("$0 & \\mbox{if \\,} i = $1 \\\\\n", CS(wsig, 0), CS(widx, 0)); ltqRWTableDef += subst("$0(t\\!-\\!1)[i] & \\mbox{otherwise} \\\\\n", vname); ltqRWTableDef += "\\end{array}\\right."; // add the table equation fLateq->addRWTblSigFormula(ltqRWTableDef); // w(t) = initsig(t) // note that the name of the table can never be used outside an sigDocTableAccess return vname; }
/** * Generate code for the delay mecchanism. The generated code depend of the * maximum delay attached to exp and the "less temporaries" switch */ string DocCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd) { string s = generateDelayVecNoTemp(sig, exp, ctype, vname, mxd); if (getCertifiedSigType(sig)->variability() < kSamp) { return exp; } else { return s; } }
string DocCompiler::generateCacheCode(Tree sig, const string& exp) { // cerr << "!! entering generateCacheCode with sig=\"" << ppsig(sig) << "\"" << endl; string vname, ctype, code, vectorname; int sharing = getSharingCount(sig); Occurences* o = fOccMarkup.retrieve(sig); // check reentrance if(getCompiledExpression(sig, code)) { // cerr << "!! generateCacheCode called a true getCompiledExpression" << endl; return code; } // check for expression occuring in delays if(o->getMaxDelay() > 0) { if(getVectorNameProperty(sig, vectorname)) { return exp; } getTypedNames(getCertifiedSigType(sig), "r", ctype, vname); gDocNoticeFlagMap["recursigs"] = true; // cerr << "- r : generateCacheCode : vame=\"" << vname << "\", for sig=\"" << ppsig(sig) << "\"" << endl; if(sharing > 1) { // cerr << " generateCacheCode calls generateDelayVec(generateVariableStore) on vame=\"" << vname << "\"" << endl; return generateDelayVec(sig, generateVariableStore(sig, exp), ctype, vname, o->getMaxDelay()); } else { // cerr << " generateCacheCode calls generateDelayVec(exp) on vame=\"" << vname << "\"" << endl; return generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay()); } } else if(sharing == 1 || getVectorNameProperty(sig, vectorname) || isVerySimpleFormula(sig)) { // cerr << "! generateCacheCode : sharing == 1 : return \"" << exp << "\"" << endl; return exp; } else if(sharing > 1) { // cerr << "! generateCacheCode : sharing > 1 : return \"" << exp << "\"" << endl; return generateVariableStore(sig, exp); } else { cerr << "Error in sharing count (" << sharing << ") for " << *sig << endl; exit(1); } return "Error in generateCacheCode"; }
string DocCompiler::generateFVar (Tree sig, const string& file, const string& exp) { string ctype, vname; Occurences* o = fOccMarkup.retrieve(sig); if (o->getMaxDelay()>0) { getTypedNames(getCertifiedSigType(sig), "r", ctype, vname); gGlobal->gDocNoticeFlagMap["recursigs"] = true; //cerr << "- r : generateFVar : \"" << vname << "\"" << endl; setVectorNameProperty(sig, vname); generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay()); } return generateCacheCode(sig, exp); }
string DocCompiler::generateNumber (Tree sig, const string& exp) { string ctype, vname; Occurences* o = fOccMarkup.retrieve(sig); // check for number occuring in delays if (o->getMaxDelay()>0) { getTypedNames(getCertifiedSigType(sig), "r", ctype, vname); gGlobal->gDocNoticeFlagMap["recursigs"] = true; //cerr << "- r : generateNumber : \"" << vname << "\"" << endl; generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay()); } return exp; }
/** * Compile a signal * @param sig the signal expression to compile. * @return the C code translation of sig as a string */ string VectorCompiler::CS (Tree sig) { 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; }
string DocCompiler::generateHBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp) { string varname = getFreshID("{u_g}"); Type t = getCertifiedSigType(sig); switch (t->variability()) { case kKonst : break; case kBlock : break; case kSamp : break; } return generateCacheCode(sig, varname); }
/** * Generate code for a group of mutually recursive definitions */ void DocCompiler::generateRec(Tree sig, Tree var, Tree le, int priority) { int N = len(le); vector<bool> used(N); vector<int> delay(N); vector<string> vname(N); vector<string> ctype(N); // prepare each element of a recursive definition for(int i = 0; i < N; i++) { Tree e = sigProj(i, sig); // recreate each recursive definition if(fOccMarkup.retrieve(e)) { // this projection is used used[i] = true; // cerr << "generateRec : used[" << i << "] = true" << endl; getTypedNames(getCertifiedSigType(e), "r", ctype[i], vname[i]); gDocNoticeFlagMap["recursigs"] = true; // cerr << "- r : generateRec setVectorNameProperty : \"" << vname[i] << "\"" << endl; setVectorNameProperty(e, vname[i]); delay[i] = fOccMarkup.retrieve(e)->getMaxDelay(); } else { // this projection is not used therefore // we should not generate code for it used[i] = false; // cerr << "generateRec : used[" << i << "] = false" << endl; } } // generate delayline for each element of a recursive definition for(int i = 0; i < N; i++) { if(used[i]) { generateDelayLine(ctype[i], vname[i], delay[i], CS(nth(le, i), priority)); } } }
/** * retrieve the type annotation of sig * @param sig the signal we want to know the type */ string DocCompiler::generateXtended (Tree sig, int priority) { xtended* p = (xtended*) getUserData(sig); vector<string> args; vector<Type> types; for (int i=0; i<sig->arity(); i++) { args.push_back(CS(sig->branch(i), 0)); types.push_back(getCertifiedSigType(sig->branch(i))); } if (p->needCache()) { //cerr << "!! generateXtended : <needCache> : calls generateCacheCode(sig, p->generateLateq(fLateq, args, types))" << endl; return generateCacheCode(sig, p->generateLateq(fLateq, args, types)); } else { //cerr << "!! generateXtended : <do not needCache> : calls p->generateLateq(fLateq, args, types)" << endl; return p->generateLateq(fLateq, args, types); } }
string DocCompiler::generateFConst (Tree sig, const string& file, const string& exp) { string ctype, vname; Occurences* o = fOccMarkup.retrieve(sig); if (o->getMaxDelay()>0) { getTypedNames(getCertifiedSigType(sig), "r", ctype, vname); gGlobal->gDocNoticeFlagMap["recursigs"] = true; //cerr << "- r : generateFConst : \"" << vname << "\"" << endl; generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay()); } if (exp == "fSamplingFreq") { //gGlobal->gDocNoticeFlagMap["fsamp"] = true; return "f_S"; } return "\\mathrm{"+exp+"}"; }
//------------------------------------------------------------------------------ // Create a specific property key for the sharing count of subtrees of t //------------------------------------------------------------------------------ void ScalarCompiler::sharingAnnotation(int vctxt, Tree sig) { Tree c, x, y, z; //cerr << "START sharing annotation of " << *sig << endl; int count = getSharingCount(sig); if (count > 0) { // it is not our first visit setSharingCount(sig, count+1); } else { // it is our first visit, int v = getCertifiedSigType(sig)->variability(); // check "time sharing" cases if (v < vctxt) { setSharingCount(sig, 2); // time sharing occurence : slower expression in faster context } else { setSharingCount(sig, 1); // regular occurence } if (isSigSelect3(sig,c,y,x,z)) { // make a special case for select3 implemented with real if // because the c expression will be used twice in the C++ // translation sharingAnnotation(v, c); sharingAnnotation(v, c); sharingAnnotation(v, x); sharingAnnotation(v, y); sharingAnnotation(v, z); } else { // Annotate the sub signals vector<Tree> subsig; int n = getSubSignals(sig, subsig); if (n>0 && ! isSigGen(sig)) { for (int i=0; i<n; i++) sharingAnnotation(v, subsig[i]); } } } //cerr << "END sharing annotation of " << *sig << endl; }
string DocCompiler::generateVariableStore(Tree sig, const string& exp) { string vname, ctype; Type t = getCertifiedSigType(sig); switch(t->variability()) { case kKonst: getTypedNames(t, "k", ctype, vname); ///< "k" for constants. fLateq->addConstSigFormula(subst("$0 = $1", vname, exp)); gDocNoticeFlagMap["constsigs"] = true; return vname; case kBlock: getTypedNames(t, "p", ctype, vname); ///< "p" for "parameter". fLateq->addParamSigFormula(subst("$0(t) = $1", vname, exp)); gDocNoticeFlagMap["paramsigs"] = true; setVectorNameProperty(sig, vname); return subst("$0(t)", vname); case kSamp: if(getVectorNameProperty(sig, vname)) { return subst("$0(t)", vname); } else { getTypedNames(t, "s", ctype, vname); // cerr << "- generateVariableStore : \"" << subst("$0(t) = $1", vname, exp) << "\"" << endl; fLateq->addStoreSigFormula(subst("$0(t) = $1", vname, exp)); gDocNoticeFlagMap["storedsigs"] = true; setVectorNameProperty(sig, vname); return subst("$0(t)", vname); } default: assert(0); return ""; } }
/** * Test if a signal need to be compiled in a separate loop. * @param sig the signal expression to test. * @return true if a separate loop is needed */ bool VectorCompiler::needSeparateLoop(Tree sig) { 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; }
/** * Generate cache code for a signal if needed * @param sig the signal expression. * @param exp the corresponding C code. * @return the cached C code */ string VectorCompiler::generateCacheCode(Tree sig, const string& exp) { 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 DocCompiler::generateBinOp(Tree sig, int opcode, Tree arg1, Tree arg2, int priority) { string s; int thisPriority = gBinOpLateqTable[opcode]->fPriority; /* Priority parenthesis handling. */ string lpar = ""; string rpar = ""; if((thisPriority < priority) || ((thisPriority == priority) && !associative(opcode))) { // (a+b)*c or (a/b)/c need parenthesis lpar = " \\left("; rpar = "\\right) "; } Type t1 = getCertifiedSigType(arg1); Type t2 = getCertifiedSigType(arg2); bool intOpDetected = false; if((t1->nature() == kInt) && (t2->nature() == kInt)) { intOpDetected = true; } string op; if(!intOpDetected) { op = gBinOpLateqTable[opcode]->fName; } else { switch(opcode) { case kAdd: op = "\\oplus"; gDocNoticeFlagMap["intplus"] = true; break; case kSub: op = "\\ominus"; gDocNoticeFlagMap["intminus"] = true; break; case kMul: op = "\\odot"; gDocNoticeFlagMap["intmult"] = true; break; case kDiv: op = "\\oslash"; gDocNoticeFlagMap["intdiv"] = true; gDocNoticeFlagMap["intcast"] = true; // "$normalize(int(i/j))$" in the notice. break; default: op = gBinOpLateqTable[opcode]->fName; break; } } /* LaTeX frac{}{} handling VS general case. */ if((opcode == kDiv) && (!intOpDetected)) { s = subst("$0\\frac{$1}{$2}$3", lpar, CS(arg1, 0), CS(arg2, 0), rpar); } else { s = subst("$0$1 $2 $3$4", lpar, CS(arg1, thisPriority), op, CS(arg2, thisPriority), rpar); } // if (opcode == kMul) { // gDocNoticeFlagMap["cdot"] = true; // } return generateCacheCode(sig, s); }