1 /************************************************************************
2 ************************************************************************
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
22 /*****************************************************************************
24 22/01/05 : corrected bug on bool signals cached in float variables
25 *****************************************************************************/
28 #include "compile_scal.hh"
42 #include "sigprint.hh"
43 #include "sigtyperules.hh"
44 #include "recursivness.hh"
45 #include "simplify.hh"
46 #include "privatise.hh"
50 #include "compatibility.hh"
52 #include "sigToGraph.hh"
56 extern bool gDrawSignals
;
57 extern bool gLessTempSwitch
;
58 extern int gMaxCopyDelay
;
59 extern string gClassName
;
60 extern string gMasterDocument
;
62 static Klass
* signal2klass (const string
& name
, Tree sig
)
64 Type t
= getCertifiedSigType(sig
); //, NULLENV);
65 if (t
->nature() == kInt
) {
67 ScalarCompiler
C( new SigIntGenKlass(name
) );
68 C
.compileSingleSignal(sig
);
73 ScalarCompiler
C( new SigFloatGenKlass(name
) );
74 C
.compileSingleSignal(sig
);
81 /*****************************************************************************
83 *****************************************************************************/
85 map
<string
, int> ScalarCompiler::fIDCounters
;
87 string
ScalarCompiler::getFreshID(const string
& prefix
)
89 if (fIDCounters
.find(prefix
) == fIDCounters
.end()) {
90 fIDCounters
[prefix
]=0;
92 int n
= fIDCounters
[prefix
];
93 fIDCounters
[prefix
] = n
+1;
94 return subst("$0$1", prefix
, T(n
));
98 /*****************************************************************************
100 *****************************************************************************/
102 extern bool gDumpNorm
;
104 Tree
ScalarCompiler::prepare(Tree LS
)
106 startTiming("ScalarCompiler::prepare");
107 startTiming("deBruijn2Sym");
108 Tree L1
= deBruijn2Sym(LS
); // convert debruijn recursion into symbolic recursion
109 endTiming("deBruijn2Sym");
110 Tree L2
= simplify(L1
); // simplify by executing every computable operation
111 Tree L3
= privatise(L2
); // Un-share tables with multiple writers
115 cout
<< ppsig(L3
) << endl
;
119 recursivnessAnnotation(L3
); // Annotate L3 with recursivness information
121 startTiming("typeAnnotation");
122 typeAnnotation(L3
); // Annotate L3 with type information
123 endTiming("typeAnnotation");
125 sharingAnalysis(L3
); // annotate L3 with sharing count
126 fOccMarkup
.mark(L3
); // annotate L3 with occurences analysis
127 //annotationStatistics();
128 endTiming("ScalarCompiler::prepare");
130 fRates
= new RateInferrer(L3
);
132 ofstream
dotfile(subst("$0-sig.dot", gMasterDocument
).c_str());
133 sigToGraph(L3
, dotfile
, fRates
);
138 Tree
ScalarCompiler::prepare2(Tree L0
)
140 startTiming("ScalarCompiler::prepare2");
141 recursivnessAnnotation(L0
); // Annotate L0 with recursivness information
142 typeAnnotation(L0
); // Annotate L0 with type information
143 sharingAnalysis(L0
); // annotate L0 with sharing count
144 fOccMarkup
.mark(L0
); // annotate L0 with occurences analysis
145 endTiming("ScalarCompiler::prepare2");
150 /*****************************************************************************
152 *****************************************************************************/
154 void ScalarCompiler::compileMultiSignal (Tree L
)
156 //contextor recursivness(0);
157 L
= prepare(L
); // optimize, share and annotate expression
159 for (int i
= 0; i
< fClass
->inputs(); i
++) {
160 fClass
->addZone3(subst("$1* input$0 = input[$0];", T(i
), xfloat()));
162 for (int i
= 0; i
< fClass
->outputs(); i
++) {
163 fClass
->addZone3(subst("$1* output$0 = output[$0];", T(i
), xfloat()));
166 for (int i
= 0; isList(L
); L
= tl(L
), i
++) {
168 fClass
->addExecCode(subst("output$0[i] = $2$1;", T(i
), CS(sig
), xcast()));
170 generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot
));
171 generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot
));
173 fDescription
->ui(prepareUserInterfaceTree(fUIRoot
));
178 /*****************************************************************************
180 *****************************************************************************/
182 void ScalarCompiler::compileSingleSignal (Tree sig
)
184 //contextor recursivness(0);
185 sig
= prepare2(sig
); // optimize and annotate expression
186 fClass
->addExecCode(subst("output[i] = $0;", CS(sig
)));
187 generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot
));
188 generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot
));
190 fDescription
->ui(prepareUserInterfaceTree(fUIRoot
));
195 /*****************************************************************************
196 CS : compile a signal
197 *****************************************************************************/
200 * Test if a signal is already compiled
201 * @param sig the signal expression to compile.
202 * @param name the string representing the compiled expression.
203 * @return true is already compiled
205 bool ScalarCompiler::getCompiledExpression(Tree sig
, string
& cexp
)
207 return fCompileProperty
.get(sig
, cexp
);
211 * Set the string of a compiled expression is already compiled
212 * @param sig the signal expression to compile.
213 * @param cexp the string representing the compiled expression.
214 * @return the cexp (for commodity)
216 string
ScalarCompiler::setCompiledExpression(Tree sig
, const string
& cexp
)
218 //cerr << "ScalarCompiler::setCompiledExpression : " << cexp << " ==> " << ppsig(sig) << endl;
219 string old
; if (fCompileProperty
.get(sig
, old
) && (old
!= cexp
)) {
220 cerr
<< "ERROR already a compiled expression attached : " << old
<< " replaced by " << cexp
<< endl
;
223 fCompileProperty
.set(sig
, cexp
);
229 * @param sig the signal expression to compile.
230 * @return the C code translation of sig as a string
232 string
ScalarCompiler::CS (Tree sig
)
234 //contextor contextRecursivness;
237 if (!getCompiledExpression(sig
, code
)) {
239 /* if (getRecursivness(sig) != contextRecursivness.get()) {
240 contextRecursivness.set(getRecursivness(sig));
242 code
= generateCode(sig
);
243 setCompiledExpression(sig
, code
);
248 /*****************************************************************************
249 generateCode : dispatch according to signal
250 *****************************************************************************/
252 * Main code generator dispatch.
253 * @param sig the signal expression to compile.
254 * @return the C code translation of sig
257 string
ScalarCompiler::generateCode (Tree sig
)
260 fprintf(stderr
, "CALL generateCode(");
261 printSignal(sig
, stderr
);
262 fprintf(stderr
, ")\n");
267 Tree c
, sel
, x
, y
, z
, label
, id
, ff
, largs
, type
, name
, file
;
269 //printf("compilation of %p : ", sig); print(sig); printf("\n");
271 if ( getUserData(sig
) ) { return generateXtended(sig
); }
272 else if ( isSigInt(sig
, &i
) ) { return generateNumber(sig
, T(i
)); }
273 else if ( isSigReal(sig
, &r
) ) { return generateNumber(sig
, T(r
)); }
274 else if ( isSigInput(sig
, &i
) ) { return generateInput (sig
, T(i
)); }
275 else if ( isSigOutput(sig
, &i
, x
) ) { return generateOutput (sig
, T(i
), CS(x
));}
277 else if ( isSigFixDelay(sig
, x
, y
) ) { return generateFixDelay (sig
, x
, y
); }
278 else if ( isSigPrefix(sig
, x
, y
) ) { return generatePrefix (sig
, x
, y
); }
279 else if ( isSigIota(sig
, x
) ) { return generateIota (sig
, x
); }
281 else if ( isSigBinOp(sig
, &i
, x
, y
) ) { return generateBinOp (sig
, i
, x
, y
); }
282 else if ( isSigFFun(sig
, ff
, largs
) ) { return generateFFun (sig
, ff
, largs
); }
283 else if ( isSigFConst(sig
, type
, name
, file
) ) { return generateFConst(sig
, tree2str(file
), tree2str(name
)); }
284 else if ( isSigFVar(sig
, type
, name
, file
) ) { return generateFVar(sig
, tree2str(file
), tree2str(name
)); }
286 else if ( isSigTable(sig
, id
, x
, y
) ) { return generateTable (sig
, x
, y
); }
287 else if ( isSigWRTbl(sig
, id
, x
, y
, z
) ) { return generateWRTbl (sig
, x
, y
, z
); }
288 else if ( isSigRDTbl(sig
, x
, y
) ) { return generateRDTbl (sig
, x
, y
); }
290 else if ( isSigSelect2(sig
, sel
, x
, y
) ) { return generateSelect2 (sig
, sel
, x
, y
); }
291 else if ( isSigSelect3(sig
, sel
, x
, y
, z
) ) { return generateSelect3 (sig
, sel
, x
, y
, z
); }
293 else if ( isSigGen(sig
, x
) ) { return generateSigGen (sig
, x
); }
295 else if ( isProj(sig
, &i
, x
) ) { return generateRecProj (sig
, x
, i
); }
297 else if ( isSigIntCast(sig
, x
) ) { return generateIntCast (sig
, x
); }
298 else if ( isSigFloatCast(sig
, x
) ) { return generateFloatCast (sig
, x
); }
300 else if ( isSigButton(sig
, label
) ) { return generateButton (sig
, label
); }
301 else if ( isSigCheckbox(sig
, label
) ) { return generateCheckbox (sig
, label
); }
302 else if ( isSigVSlider(sig
, label
,c
,x
,y
,z
) ) { return generateVSlider (sig
, label
, c
,x
,y
,z
); }
303 else if ( isSigHSlider(sig
, label
,c
,x
,y
,z
) ) { return generateHSlider (sig
, label
, c
,x
,y
,z
); }
304 else if ( isSigNumEntry(sig
, label
,c
,x
,y
,z
) ) { return generateNumEntry (sig
, label
, c
,x
,y
,z
); }
306 else if ( isSigVBargraph(sig
, label
,x
,y
,z
) ) { return generateVBargraph (sig
, label
, x
, y
, CS(z
)); }
307 else if ( isSigHBargraph(sig
, label
,x
,y
,z
) ) { return generateHBargraph (sig
, label
, x
, y
, CS(z
)); }
308 else if ( isSigAttach(sig
, x
, y
) ) { CS(y
); return generateCacheCode(sig
, CS(x
)); }
310 else if ( isSigUpSample(sig
, x
, y
) ) { return generateUpSample(sig
, x
, y
); }
311 else if ( isSigDownSample(sig
, x
, y
) ) { return generateDownSample(sig
, x
, y
); }
315 printf("Error in compiling signal, unrecognized signal : ");
320 return "error in generate code";
324 /*****************************************************************************
326 *****************************************************************************/
329 string
ScalarCompiler::generateNumber (Tree sig
, const string
& exp
)
332 Occurences
* o
= fOccMarkup
.retrieve(sig
);
334 // check for number occuring in delays
335 if (o
->getMaxDelay()>0) {
336 getTypedNames(getCertifiedSigType(sig
), "Vec", ctype
, vname
);
337 generateDelayVec(sig
, exp
, ctype
, vname
, o
->getMaxDelay());
342 /*****************************************************************************
344 *****************************************************************************/
347 string
ScalarCompiler::generateFConst (Tree sig
, const string
& file
, const string
& exp
)
350 Occurences
* o
= fOccMarkup
.retrieve(sig
);
352 addIncludeFile(file
);
354 if (o
->getMaxDelay()>0) {
355 getTypedNames(getCertifiedSigType(sig
), "Vec", ctype
, vname
);
356 generateDelayVec(sig
, exp
, ctype
, vname
, o
->getMaxDelay());
361 /*****************************************************************************
363 *****************************************************************************/
366 string
ScalarCompiler::generateFVar (Tree sig
, const string
& file
, const string
& exp
)
370 addIncludeFile(file
);
371 return generateCacheCode(sig
, exp
);
374 /*****************************************************************************
376 *****************************************************************************/
379 string
ScalarCompiler::generateInput (Tree sig
, const string
& idx
)
381 return generateCacheCode(sig
, subst("$1input$0[i]", idx
, icast()));
385 string
ScalarCompiler::generateOutput (Tree sig
, const string
& idx
, const string
& arg
)
387 string dst
= subst("output$0[i]", idx
);
388 fClass
->addExecCode(subst("$0 = $2$1;", dst
, arg
, xcast()));
393 /*****************************************************************************
395 *****************************************************************************/
397 string
ScalarCompiler::generateBinOp(Tree sig
, int opcode
, Tree arg1
, Tree arg2
)
399 return generateCacheCode(sig
, subst("($0 $1 $2)", CS(arg1
), gBinOpTable
[opcode
]->fName
, CS(arg2
)));
403 /*****************************************************************************
405 *****************************************************************************/
407 string
ScalarCompiler::generateFFun(Tree sig
, Tree ff
, Tree largs
)
409 addIncludeFile(ffincfile(ff
)); //printf("inc file %s\n", ffincfile(ff));
410 addLibrary(fflibfile(ff
)); //printf("lib file %s\n", fflibfile(ff));
412 string code
= ffname(ff
);
415 for (int i
= 0; i
< ffarity(ff
); i
++) {
417 code
+= CS(nth(largs
, i
));
421 return generateCacheCode(sig
, code
);
425 /*****************************************************************************
427 *****************************************************************************/
429 void ScalarCompiler::getTypedNames(Type t
, const string
& prefix
, string
& ctype
, string
& vname
)
431 if (t
->nature() == kInt
) {
432 ctype
= "int"; vname
= subst("i$0", getFreshID(prefix
));
434 ctype
= ifloat(); vname
= subst("f$0", getFreshID(prefix
));
438 string
ScalarCompiler::generateCacheCode(Tree sig
, const string
& exp
)
440 string vname
, ctype
, code
;
441 int sharing
= getSharingCount(sig
);
442 Occurences
* o
= fOccMarkup
.retrieve(sig
);
445 if (getCompiledExpression(sig
, code
)) {
449 // check for expression occuring in delays
450 if (o
->getMaxDelay()>0) {
452 getTypedNames(getCertifiedSigType(sig
), "Vec", ctype
, vname
);
454 return generateDelayVec(sig
, generateVariableStore(sig
,exp
), ctype
, vname
, o
->getMaxDelay());
456 return generateDelayVec(sig
, exp
, ctype
, vname
, o
->getMaxDelay());
459 } else if (sharing
== 1) {
463 } else if (sharing
> 1) {
465 return generateVariableStore(sig
, exp
);
468 cerr
<< "Error in sharing count (" << sharing
<< ") for " << *sig
<< endl
;
472 return "Error in generateCacheCode";
476 string
ScalarCompiler::generateVariableStore(Tree sig
, const string
& exp
)
479 Type t
= getCertifiedSigType(sig
);
481 switch (t
->variability()) {
485 getTypedNames(t
, "Const", ctype
, vname
);
486 fClass
->addDeclCode(subst("$0 \t$1;", ctype
, vname
));
487 fClass
->addInitCode(subst("$0 = $1;", vname
, exp
));
492 getTypedNames(t
, "Slow", ctype
, vname
);
493 fClass
->addFirstPrivateDecl(vname
);
494 fClass
->addZone2(subst("$0 \t$1 = $2;", ctype
, vname
, exp
));
499 getTypedNames(t
, "Temp", ctype
, vname
);
500 fClass
->addExecCode(subst("$0 $1 = $2;", ctype
, vname
, exp
));
507 /*****************************************************************************
509 *****************************************************************************/
512 string
ScalarCompiler::generateIntCast(Tree sig
, Tree x
)
514 return generateCacheCode(sig
, subst("int($0)", CS(x
)));
517 string
ScalarCompiler::generateFloatCast (Tree sig
, Tree x
)
519 return generateCacheCode(sig
, subst("$1($0)", CS(x
), ifloat()));
522 /*****************************************************************************
523 user interface elements
524 *****************************************************************************/
526 string
ScalarCompiler::generateButton(Tree sig
, Tree path
)
528 string varname
= getFreshID("fbutton");
529 fClass
->addDeclCode(subst("$1 \t$0;", varname
, xfloat()));
530 fClass
->addInitCode(subst("$0 = 0.0;", varname
));
531 addUIWidget(reverse(tl(path
)), uiWidget(hd(path
), tree(varname
), sig
));
532 return generateCacheCode(sig
, varname
);
535 string
ScalarCompiler::generateCheckbox(Tree sig
, Tree path
)
537 string varname
= getFreshID("fcheckbox");
538 fClass
->addDeclCode(subst("$1 \t$0;", varname
, xfloat()));
539 fClass
->addInitCode(subst("$0 = 0.0;", varname
));
540 addUIWidget(reverse(tl(path
)), uiWidget(hd(path
), tree(varname
), sig
));
541 return generateCacheCode(sig
, varname
);
545 string
ScalarCompiler::generateVSlider(Tree sig
, Tree path
, Tree cur
, Tree min
, Tree max
, Tree step
)
547 string varname
= getFreshID("fslider");
548 fClass
->addDeclCode(subst("$1 \t$0;", varname
, xfloat()));
549 fClass
->addInitCode(subst("$0 = $1;", varname
, T(tree2float(cur
))));
550 addUIWidget(reverse(tl(path
)), uiWidget(hd(path
), tree(varname
), sig
));
551 return generateCacheCode(sig
, varname
);
554 string
ScalarCompiler::generateHSlider(Tree sig
, Tree path
, Tree cur
, Tree min
, Tree max
, Tree step
)
556 string varname
= getFreshID("fslider");
557 fClass
->addDeclCode(subst("$1 \t$0;", varname
, xfloat()));
558 fClass
->addInitCode(subst("$0 = $1;", varname
, T(tree2float(cur
))));
559 addUIWidget(reverse(tl(path
)), uiWidget(hd(path
), tree(varname
), sig
));
560 return generateCacheCode(sig
, varname
);
563 string
ScalarCompiler::generateNumEntry(Tree sig
, Tree path
, Tree cur
, Tree min
, Tree max
, Tree step
)
565 string varname
= getFreshID("fentry");
566 fClass
->addDeclCode(subst("$1 \t$0;", varname
, xfloat()));
567 fClass
->addInitCode(subst("$0 = $1;", varname
, T(tree2float(cur
))));
568 addUIWidget(reverse(tl(path
)), uiWidget(hd(path
), tree(varname
), sig
));
569 return generateCacheCode(sig
, varname
);
573 string
ScalarCompiler::generateVBargraph(Tree sig
, Tree path
, Tree min
, Tree max
, const string
& exp
)
575 string varname
= getFreshID("fbargraph");
576 fClass
->addDeclCode(subst("$1 \t$0;", varname
, xfloat()));
577 addUIWidget(reverse(tl(path
)), uiWidget(hd(path
), tree(varname
), sig
));
579 Type t
= getCertifiedSigType(sig
);
580 switch (t
->variability()) {
583 fClass
->addInitCode(subst("$0 = $1;", varname
, exp
));
587 fClass
->addZone2(subst("$0 = $1;", varname
, exp
));
591 fClass
->addExecCode(subst("$0 = $1;", varname
, exp
));
596 return generateCacheCode(sig
, varname
);
600 string
ScalarCompiler::generateHBargraph(Tree sig
, Tree path
, Tree min
, Tree max
, const string
& exp
)
602 string varname
= getFreshID("fbargraph");
603 fClass
->addDeclCode(subst("$1 \t$0;", varname
, xfloat()));
604 addUIWidget(reverse(tl(path
)), uiWidget(hd(path
), tree(varname
), sig
));
606 Type t
= getCertifiedSigType(sig
);
607 switch (t
->variability()) {
610 fClass
->addInitCode(subst("$0 = $1;", varname
, exp
));
614 fClass
->addZone2(subst("$0 = $1;", varname
, exp
));
618 fClass
->addExecCode(subst("$0 = $1;", varname
, exp
));
623 return generateCacheCode(sig
, varname
);
629 /*****************************************************************************
631 *****************************************************************************/
635 /*----------------------------------------------------------------------------
636 sigGen : initial table content
637 ----------------------------------------------------------------------------*/
639 string
ScalarCompiler::generateSigGen(Tree sig
, Tree content
)
641 string klassname
= getFreshID("SIG");
642 string signame
= getFreshID("sig");
644 fClass
->addSubKlass(signal2klass(klassname
, content
));
645 fClass
->addInitCode(subst("$0 $1;", klassname
, signame
));
646 fInstanceInitProperty
.set(content
, pair
<string
,string
>(klassname
,signame
));
651 string
ScalarCompiler::generateStaticSigGen(Tree sig
, Tree content
)
653 string klassname
= getFreshID("SIG");
654 string signame
= getFreshID("sig");
656 fClass
->addSubKlass(signal2klass(klassname
, content
));
657 fClass
->addStaticInitCode(subst("$0 $1;", klassname
, signame
));
658 fStaticInitProperty
.set(content
, pair
<string
,string
>(klassname
,signame
));
664 /*----------------------------------------------------------------------------
665 sigTable : table declaration
666 ----------------------------------------------------------------------------*/
668 string
ScalarCompiler::generateTable(Tree sig
, Tree tsize
, Tree content
)
670 string
generator(CS(content
));
676 // already compiled but check if we need to add declarations
678 assert ( isSigGen(content
, g
) );
679 pair
<string
,string
> kvnames
;
680 if ( ! fInstanceInitProperty
.get(g
, kvnames
)) {
681 // not declared here, we add a declaration
682 bool b
= fStaticInitProperty
.get(g
, kvnames
);
684 fClass
->addInitCode(subst("$0 $1;", kvnames
.first
, kvnames
.second
));
687 if (!isSigInt(tsize
, &size
)) {
688 //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
689 cerr
<< "error in ScalarCompiler::generateTable() : "
691 << " is not a constant integer table size expression "
695 // definition du nom et du type de la table
696 // A REVOIR !!!!!!!!!
697 Type t
= getCertifiedSigType(content
);//, tEnv);
698 if (t
->nature() == kInt
) {
699 vname
= getFreshID("itbl");
702 vname
= getFreshID("ftbl");
706 // declaration de la table
707 fClass
->addDeclCode(subst("$0 \t$1[$2];", ctype
, vname
, T(size
)));
709 // initialisation du generateur de contenu
710 fClass
->addInitCode(subst("$0.init(samplingFreq);", generator
));
711 // remplissage de la table
712 fClass
->addInitCode(subst("$0.fill($1,$2);", generator
, T(size
), vname
));
714 // on retourne le nom de la table
718 string
ScalarCompiler::generateStaticTable(Tree sig
, Tree tsize
, Tree content
)
720 //string generator(CS(content));
726 assert ( isSigGen(content
, g
) );
728 if (!getCompiledExpression(content
, cexp
)) {
729 cexp
= setCompiledExpression(content
, generateStaticSigGen(content
, g
));
731 // already compiled but check if we need to add declarations
732 pair
<string
,string
> kvnames
;
733 if ( ! fStaticInitProperty
.get(g
, kvnames
)) {
734 // not declared here, we add a declaration
735 bool b
= fInstanceInitProperty
.get(g
, kvnames
);
737 fClass
->addStaticInitCode(subst("$0 $1;", kvnames
.first
, kvnames
.second
));
741 if (!isSigInt(tsize
, &size
)) {
742 //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
743 cerr
<< "error in ScalarCompiler::generateTable() : "
745 << " is not a constant integer table size expression "
749 // definition du nom et du type de la table
750 // A REVOIR !!!!!!!!!
751 Type t
= getCertifiedSigType(content
);//, tEnv);
752 if (t
->nature() == kInt
) {
753 vname
= getFreshID("itbl");
756 vname
= getFreshID("ftbl");
760 // declaration de la table
761 fClass
->addDeclCode(subst("static $0 \t$1[$2];", ctype
, vname
, T(size
)));
762 fClass
->addStaticFields(subst("$0 \t$1::$2[$3];", ctype
, fClass
->getClassName(), vname
, T(size
) ));
764 // initialisation du generateur de contenu
765 fClass
->addStaticInitCode(subst("$0.init(samplingFreq);", cexp
));
766 // remplissage de la table
767 fClass
->addStaticInitCode(subst("$0.fill($1,$2);", cexp
, T(size
), vname
));
769 // on retourne le nom de la table
774 /*----------------------------------------------------------------------------
775 sigWRTable : table assignement
776 ----------------------------------------------------------------------------*/
778 string
ScalarCompiler::generateWRTbl(Tree sig
, Tree tbl
, Tree idx
, Tree data
)
780 string
tblName(CS(tbl
));
781 fClass
->addExecCode(subst("$0[$1] = $2;", tblName
, CS(idx
), CS(data
)));
786 /*----------------------------------------------------------------------------
787 sigRDTable : table access
788 ----------------------------------------------------------------------------*/
790 string
ScalarCompiler::generateRDTbl(Tree sig
, Tree tbl
, Tree idx
)
792 // YO le 21/04/05 : La lecture des tables n'�ait pas mise dans le cache
793 // et donc le code �ait dupliqu�(dans tester.dsp par exemple)
794 //return subst("$0[$1]", CS(tEnv, tbl), CS(tEnv, idx));
796 //cerr << "generateRDTable " << *sig << endl;
797 // test the special case of a read only table that can be compiled
798 // has a static member
799 Tree id
, size
, content
;
800 if( isSigTable(tbl
, id
, size
, content
) ) {
802 if (!getCompiledExpression(tbl
, tblname
)) {
803 tblname
= setCompiledExpression(tbl
, generateStaticTable(tbl
, size
, content
));
805 return generateCacheCode(sig
, subst("$0[$1]", tblname
, CS(idx
)));
807 return generateCacheCode(sig
, subst("$0[$1]", CS(tbl
), CS(idx
)));
813 /*****************************************************************************
815 *****************************************************************************/
819 * Generate code for a projection of a group of mutually recursive definitions
821 string
ScalarCompiler::generateRecProj(Tree sig
, Tree r
, int i
)
826 if ( ! getVectorNameProperty(sig
, vname
)) {
827 assert(isRec(r
, var
, le
));
828 generateRec(r
, var
, le
);
829 assert(getVectorNameProperty(sig
, vname
));
831 return "[[UNUSED EXP]]"; // make sure the resulting expression is never used in the generated code
836 * Generate code for a group of mutually recursive definitions
838 void ScalarCompiler::generateRec(Tree sig
, Tree var
, Tree le
)
842 vector
<bool> used(N
);
843 vector
<int> delay(N
);
844 vector
<string
> vname(N
);
845 vector
<string
> ctype(N
);
847 // prepare each element of a recursive definition
848 for (int i
=0; i
<N
; i
++) {
849 Tree e
= sigProj(i
,sig
); // recreate each recursive definition
850 if (fOccMarkup
.retrieve(e
)) {
851 // this projection is used
853 getTypedNames(getCertifiedSigType(e
), "Rec", ctype
[i
], vname
[i
]);
854 setVectorNameProperty(e
, vname
[i
]);
855 delay
[i
] = fOccMarkup
.retrieve(e
)->getMaxDelay();
857 // this projection is not used therefore
858 // we should not generate code for it
863 // generate delayline for each element of a recursive definition
864 for (int i
=0; i
<N
; i
++) {
866 generateDelayLine(ctype
[i
], vname
[i
], delay
[i
], CS(nth(le
,i
)));
872 /*****************************************************************************
873 PREFIX, DELAY A PREFIX VALUE
874 *****************************************************************************/
876 string
ScalarCompiler::generatePrefix (Tree sig
, Tree x
, Tree e
)
878 Type te
= getCertifiedSigType(sig
);//, tEnv);
880 string vperm
= getFreshID("M");
881 string vtemp
= getFreshID("T");
883 string type
= cType(te
);
885 fClass
->addDeclCode(subst("$0 \t$1;", type
, vperm
));
886 fClass
->addInitCode(subst("$0 = $1;", vperm
, CS(x
)));
888 fClass
->addExecCode(subst("$0 $1 = $2;", type
, vtemp
, vperm
));
889 fClass
->addExecCode(subst("$0 = $1;", vperm
, CS(e
)));
894 /*****************************************************************************
896 *****************************************************************************/
897 static bool isPowerOf2(int n
)
899 return !(n
& (n
- 1));
902 string
ScalarCompiler::generateIota (Tree sig
, Tree n
)
905 if (!isSigInt(n
, &size
)) { fprintf(stderr
, "error in generateIota\n"); exit(1); }
907 string vperm
= getFreshID("iota");
909 fClass
->addDeclCode(subst("int \t$0;", vperm
));
910 fClass
->addInitCode(subst("$0 = 0;", vperm
));
912 if (isPowerOf2(size
)) {
913 fClass
->addExecCode(subst("$0 = ($0+1)&$1;", vperm
, T(size
-1)));
915 fClass
->addExecCode(subst("if (++$0 == $1) $0=0;", vperm
, T(size
)));
922 // a revoir en utilisant la lecture de table et en partageant la construction de la paire de valeurs
926 * Generate a select2 code
929 string
ScalarCompiler::generateSelect2 (Tree sig
, Tree sel
, Tree s1
, Tree s2
)
931 return generateCacheCode(sig
, subst( "(($0)?$1:$2)", CS(sel
), CS(s2
), CS(s1
) ) );
936 * Generate a select3 code (using if-then-else)
937 * ((int n = sel==0)? s0 : ((sel==1)? s1 : s2))
938 * int nn; ((nn=sel) ? ((nn==1)? s1 : s2) : s0);
940 string
ScalarCompiler::generateSelect3 (Tree sig
, Tree sel
, Tree s1
, Tree s2
, Tree s3
)
942 return generateCacheCode(sig
, subst( "(($0==0)? $1 : (($0==1)?$2:$3) )", CS(sel
), CS(s1
), CS(s2
), CS(s3
) ) );
946 string
ScalarCompiler::generateSelect3 (Tree sig
, Tree sel
, Tree s1
, Tree s2
, Tree s3
)
948 Type t
= getCertifiedSigType(sig
);
949 Type t1
= getCertifiedSigType(s1
);
950 Type t2
= getCertifiedSigType(s2
);
951 Type t3
= getCertifiedSigType(s3
);
952 Type w
= min(t1
,min(t2
,t3
));
954 string type
= cType(t
);
955 string var
= getFreshID("S");
957 switch (w
->variability())
960 fClass
->addDeclCode(subst("$0 \t$1[3];", type
, var
));
963 //fClass->addLocalDecl(type, subst("$0[3]", var));
964 //fClass->addLocalVecDecl(type, var, 3);
965 fClass
->addSharedDecl(var
);
966 fClass
->addZone1(subst("$0 \t$1[3];", type
, var
));
969 fClass
->addExecCode(subst("$0 \t$1[3];", type
, var
));
973 switch (t1
->variability())
976 fClass
->addInitCode(subst("$0[0] = $1;", var
, CS(s1
)));
979 fClass
->addZone2b(subst("$0[0] = $1;", var
, CS(s1
)));
982 fClass
->addExecCode(subst("$0[0] = $1;", var
, CS(s1
)));
986 switch (t2
->variability())
989 fClass
->addInitCode(subst("$0[1] = $1;", var
, CS(s2
)));
992 fClass
->addZone2b(subst("$0[1] = $1;", var
, CS(s2
)));
995 fClass
->addExecCode(subst("$0[1] = $1;", var
, CS(s2
)));
999 switch (t3
->variability())
1002 fClass
->addInitCode(subst("$0[2] = $1;", var
, CS(s3
)));
1005 fClass
->addZone2b(subst("$0[2] = $1;", var
, CS(s3
)));
1008 fClass
->addExecCode(subst("$0[2] = $1;", var
, CS(s3
)));
1012 return generateCacheCode(sig
, subst("$0[$1]", var
, CS(sel
)));
1017 * retrieve the type annotation of sig
1018 * @param sig the signal we want to know the type
1020 string
ScalarCompiler::generateXtended (Tree sig
)
1022 xtended
* p
= (xtended
*) getUserData(sig
);
1023 vector
<string
> args
;
1026 for (int i
=0; i
<sig
->arity(); i
++) {
1027 args
.push_back(CS(sig
->branch(i
)));
1028 types
.push_back(getCertifiedSigType(sig
->branch(i
)));
1031 if (p
->needCache()) {
1032 return generateCacheCode(sig
, p
->generateCode(fClass
, args
, types
));
1034 return p
->generateCode(fClass
, args
, types
);
1040 //------------------------------------------------------------------------------------------------
1043 /*****************************************************************************
1044 vector name property
1045 *****************************************************************************/
1048 * Set the vector name property of a signal, the name of the vector used to
1049 * store the previous values of the signal to implement a delay.
1050 * @param sig the signal expression.
1051 * @param vecname the string representing the vector name.
1052 * @return true is already compiled
1054 void ScalarCompiler::setVectorNameProperty(Tree sig
, const string
& vecname
)
1056 fVectorProperty
.set(sig
, vecname
);
1061 * Get the vector name property of a signal, the name of the vector used to
1062 * store the previous values of the signal to implement a delay.
1063 * @param sig the signal expression.
1064 * @param vecname the string where to store the vector name.
1065 * @return true if the signal has this property, false otherwise
1068 bool ScalarCompiler::getVectorNameProperty(Tree sig
, string
& vecname
)
1070 return fVectorProperty
.get(sig
, vecname
);
1075 * Compute the minimal power of 2 greater than x
1078 int ScalarCompiler::pow2limit(int x
)
1081 while (n
< x
) { n
= 2*n
; }
1085 /*****************************************************************************
1086 N-SAMPLE FIXED DELAY : sig = exp@delay
1088 case 1-sample max delay :
1090 Temp Var gLessTempSwitch = false
1091 V[0] V[1] gLessTempSwitch = true
1093 case max delay < gMaxCopyDelay :
1094 Y(t-0) Y(t-1) Y(t-2) ...
1095 Temp V[0] V[1] ... gLessTempSwitch = false
1096 V[0] V[1] V[2] ... gLessTempSwitch = true
1098 case max delay >= gMaxCopyDelay :
1099 Y(t-0) Y(t-1) Y(t-2) ...
1104 *****************************************************************************/
1107 * Generate code for accessing a delayed signal. The generated code depend of
1108 * the maximum delay attached to exp and the gLessTempSwitch.
1111 string
ScalarCompiler::generateFixDelay (Tree sig
, Tree exp
, Tree delay
)
1116 //cerr << "ScalarCompiler::generateFixDelay sig = " << *sig << endl;
1117 //cerr << "ScalarCompiler::generateFixDelay exp = " << *exp << endl;
1118 //cerr << "ScalarCompiler::generateFixDelay del = " << *delay << endl;
1120 CS(exp
); // ensure exp is compiled to have a vector name
1122 mxd
= fOccMarkup
.retrieve(exp
)->getMaxDelay();
1124 if (! getVectorNameProperty(exp
, vecname
)) {
1125 cerr
<< "No vector name for : " << ppsig(exp
) << endl
;
1130 // not a real vector name but a scalar name
1133 } else if (mxd
< gMaxCopyDelay
) {
1134 if (isSigInt(delay
, &d
)) {
1135 return subst("$0[$1]", vecname
, CS(delay
));
1137 return generateCacheCode(sig
, subst("$0[$1]", vecname
, CS(delay
)));
1142 // long delay : we use a ring buffer of size 2^x
1143 int N
= pow2limit( mxd
+1 );
1144 return generateCacheCode(sig
, subst("$0[(IOTA-$1)&$2]", vecname
, CS(delay
), T(N
-1)));
1150 * Generate code for the delay mecchanism. The generated code depend of the
1151 * maximum delay attached to exp and the "less temporaries" switch
1154 string
ScalarCompiler::generateDelayVec(Tree sig
, const string
& exp
, const string
& ctype
, const string
& vname
, int mxd
)
1156 string s
= generateDelayVecNoTemp(sig
, exp
, ctype
, vname
, mxd
);
1157 if (getCertifiedSigType(sig
)->variability() < kSamp
) {
1165 * Generate code for the delay mecchanism without using temporary variables
1168 string
ScalarCompiler::generateDelayVecNoTemp(Tree sig
, const string
& exp
, const string
& ctype
, const string
& vname
, int mxd
)
1172 //bool odocc = fOccMarkup.retrieve(sig)->hasOutDelayOccurences();
1174 if (mxd
< gMaxCopyDelay
) {
1176 // short delay : we copy
1177 fClass
->addDeclCode(subst("$0 \t$1[$2];", ctype
, vname
, T(mxd
+1)));
1178 fClass
->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname
, T(mxd
+1)));
1179 fClass
->addExecCode(subst("$0[0] = $1;", vname
, exp
));
1181 // generate post processing copy code to update delay values
1183 fClass
->addPostCode(subst("$0[1] = $0[0];", vname
));
1184 } else if (mxd
== 2) {
1185 //fClass->addPostCode(subst("$0[2] = $0[1];", vname));
1186 fClass
->addPostCode(subst("$0[2] = $0[1]; $0[1] = $0[0];", vname
));
1188 fClass
->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd
), vname
));
1190 setVectorNameProperty(sig
, vname
);
1191 return subst("$0[0]", vname
);
1195 // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
1196 int N
= pow2limit(mxd
+1);
1198 // we need a iota index
1202 fClass
->addDeclCode(subst("$0 \t$1[$2];", ctype
, vname
, T(N
)));
1203 fClass
->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname
, T(N
)));
1206 fClass
->addExecCode(subst("$0[IOTA&$1] = $2;", vname
, T(N
-1), exp
));
1207 setVectorNameProperty(sig
, vname
);
1208 return subst("$0[IOTA&$1]", vname
, T(N
-1));
1213 * Generate code for the delay mecchanism without using temporary variables
1216 void ScalarCompiler::generateDelayLine(const string
& ctype
, const string
& vname
, int mxd
, const string
& exp
)
1220 // cerr << "MXD==0 : " << vname << " := " << exp << endl;
1221 // no need for a real vector
1222 fClass
->addExecCode(subst("$0 \t$1 = $2;", ctype
, vname
, exp
));
1225 } else if (mxd
< gMaxCopyDelay
) {
1226 // cerr << "small delay : " << vname << "[" << mxd << "]" << endl;
1228 // short delay : we copy
1229 fClass
->addDeclCode(subst("$0 \t$1[$2];", ctype
, vname
, T(mxd
+1)));
1230 fClass
->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname
, T(mxd
+1)));
1231 fClass
->addExecCode(subst("$0[0] = $1;", vname
, exp
));
1233 // generate post processing copy code to update delay values
1235 fClass
->addPostCode(subst("$0[1] = $0[0];", vname
));
1236 } else if (mxd
== 2) {
1237 fClass
->addPostCode(subst("$0[2] = $0[1]; $0[1] = $0[0];", vname
));
1239 fClass
->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd
), vname
));
1244 // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
1245 int N
= pow2limit(mxd
+1);
1247 // we need a iota index
1251 fClass
->addDeclCode(subst("$0 \t$1[$2];", ctype
, vname
, T(N
)));
1252 fClass
->addInitCode(subst("for (int i=0; i<$1; i++) $0[i] = 0;", vname
, T(N
)));
1255 fClass
->addExecCode(subst("$0[IOTA&$1] = $2;", vname
, T(N
-1), exp
));
1260 * Generate up sampling code
1263 string
ScalarCompiler::generateUpSample(Tree sig
, Tree w
, Tree x
)
1269 * Generate down sampling code
1272 string
ScalarCompiler::generateDownSample(Tree sig
, Tree w
, Tree x
)
1279 * Generate code for a unique IOTA variable increased at each sample
1280 * and used to index ring buffers.
1282 void ScalarCompiler::ensureIotaCode()
1286 fClass
->addDeclCode("int \tIOTA;");
1287 fClass
->addInitCode("IOTA = 0;");
1288 fClass
->addPostCode("IOTA = IOTA+1;");