First cleaning step in "dsp_files" directory.
[Faustine.git] / interpretor / faust-0.9.47mr3 / compiler / generator / compile_scal.cpp
1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
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.
10
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.
15
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 ************************************************************************/
21
22 /*****************************************************************************
23 HISTORY
24 22/01/05 : corrected bug on bool signals cached in float variables
25 *****************************************************************************/
26
27
28 #include "compile_scal.hh"
29 #include "timing.hh"
30
31 #include "compile.hh"
32 #include "sigtype.hh"
33
34 #include <stdio.h>
35 #include <iostream>
36 #include <fstream>
37 #include <sstream>
38 #include <vector>
39 #include <math.h>
40
41 #include "floats.hh"
42 #include "sigprint.hh"
43 #include "sigtyperules.hh"
44 #include "recursivness.hh"
45 #include "simplify.hh"
46 #include "privatise.hh"
47 #include "prim2.hh"
48 #include "xtended.hh"
49
50 #include "compatibility.hh"
51 #include "ppsig.hh"
52 #include "sigToGraph.hh"
53
54 using namespace std;
55
56 extern bool gDrawSignals;
57 extern bool gLessTempSwitch;
58 extern int gMaxCopyDelay;
59 extern string gClassName;
60 extern string gMasterDocument;
61
62 static Klass* signal2klass (const string& name, Tree sig)
63 {
64 Type t = getCertifiedSigType(sig); //, NULLENV);
65 if (t->nature() == kInt) {
66
67 ScalarCompiler C( new SigIntGenKlass(name) );
68 C.compileSingleSignal(sig);
69 return C.getClass();
70
71 } else {
72
73 ScalarCompiler C( new SigFloatGenKlass(name) );
74 C.compileSingleSignal(sig);
75 return C.getClass();
76
77 }
78 }
79
80
81 /*****************************************************************************
82 getFreshID
83 *****************************************************************************/
84
85 map<string, int> ScalarCompiler::fIDCounters;
86
87 string ScalarCompiler::getFreshID(const string& prefix)
88 {
89 if (fIDCounters.find(prefix) == fIDCounters.end()) {
90 fIDCounters[prefix]=0;
91 }
92 int n = fIDCounters[prefix];
93 fIDCounters[prefix] = n+1;
94 return subst("$0$1", prefix, T(n));
95 }
96
97
98 /*****************************************************************************
99 prepare
100 *****************************************************************************/
101
102 extern bool gDumpNorm;
103
104 Tree ScalarCompiler::prepare(Tree LS)
105 {
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
112
113 // dump normal form
114 if (gDumpNorm) {
115 cout << ppsig(L3) << endl;
116 exit(0);
117 }
118
119 recursivnessAnnotation(L3); // Annotate L3 with recursivness information
120
121 startTiming("typeAnnotation");
122 typeAnnotation(L3); // Annotate L3 with type information
123 endTiming("typeAnnotation");
124
125 sharingAnalysis(L3); // annotate L3 with sharing count
126 fOccMarkup.mark(L3); // annotate L3 with occurences analysis
127 //annotationStatistics();
128 endTiming("ScalarCompiler::prepare");
129
130 fRates = new RateInferrer(L3);
131 if (gDrawSignals) {
132 ofstream dotfile(subst("$0-sig.dot", gMasterDocument).c_str());
133 sigToGraph(L3, dotfile, fRates);
134 }
135 return L3;
136 }
137
138 Tree ScalarCompiler::prepare2(Tree L0)
139 {
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");
146
147 return L0;
148 }
149
150 /*****************************************************************************
151 compileMultiSignal
152 *****************************************************************************/
153
154 void ScalarCompiler::compileMultiSignal (Tree L)
155 {
156 //contextor recursivness(0);
157 L = prepare(L); // optimize, share and annotate expression
158
159 for (int i = 0; i < fClass->inputs(); i++) {
160 fClass->addZone3(subst("$1* input$0 = input[$0];", T(i), xfloat()));
161 }
162 for (int i = 0; i < fClass->outputs(); i++) {
163 fClass->addZone3(subst("$1* output$0 = output[$0];", T(i), xfloat()));
164 }
165
166 for (int i = 0; isList(L); L = tl(L), i++) {
167 Tree sig = hd(L);
168 fClass->addExecCode(subst("output$0[i] = $2$1;", T(i), CS(sig), xcast()));
169 }
170 generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot));
171 generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
172 if (fDescription) {
173 fDescription->ui(prepareUserInterfaceTree(fUIRoot));
174 }
175 }
176
177
178 /*****************************************************************************
179 compileSingleSignal
180 *****************************************************************************/
181
182 void ScalarCompiler::compileSingleSignal (Tree sig)
183 {
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));
189 if (fDescription) {
190 fDescription->ui(prepareUserInterfaceTree(fUIRoot));
191 }
192 }
193
194
195 /*****************************************************************************
196 CS : compile a signal
197 *****************************************************************************/
198
199 /**
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
204 */
205 bool ScalarCompiler::getCompiledExpression(Tree sig, string& cexp)
206 {
207 return fCompileProperty.get(sig, cexp);
208 }
209
210 /**
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)
215 */
216 string ScalarCompiler::setCompiledExpression(Tree sig, const string& cexp)
217 {
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;
221 exit(1);
222 }
223 fCompileProperty.set(sig, cexp);
224 return cexp;
225 }
226
227 /**
228 * Compile a signal
229 * @param sig the signal expression to compile.
230 * @return the C code translation of sig as a string
231 */
232 string ScalarCompiler::CS (Tree sig)
233 {
234 //contextor contextRecursivness;
235 string code;
236
237 if (!getCompiledExpression(sig, code)) {
238 // not compiled yet
239 /* if (getRecursivness(sig) != contextRecursivness.get()) {
240 contextRecursivness.set(getRecursivness(sig));
241 }*/
242 code = generateCode(sig);
243 setCompiledExpression(sig, code);
244 }
245 return code;
246 }
247
248 /*****************************************************************************
249 generateCode : dispatch according to signal
250 *****************************************************************************/
251 /**
252 * Main code generator dispatch.
253 * @param sig the signal expression to compile.
254 * @return the C code translation of sig
255 */
256
257 string ScalarCompiler::generateCode (Tree sig)
258 {
259 #if 0
260 fprintf(stderr, "CALL generateCode(");
261 printSignal(sig, stderr);
262 fprintf(stderr, ")\n");
263 #endif
264
265 int i;
266 double r;
267 Tree c, sel, x, y, z, label, id, ff, largs, type, name, file;
268
269 //printf("compilation of %p : ", sig); print(sig); printf("\n");
270
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));}
276
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); }
280
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)); }
285
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); }
289
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); }
292
293 else if ( isSigGen(sig, x) ) { return generateSigGen (sig, x); }
294
295 else if ( isProj(sig, &i, x) ) { return generateRecProj (sig, x, i); }
296
297 else if ( isSigIntCast(sig, x) ) { return generateIntCast (sig, x); }
298 else if ( isSigFloatCast(sig, x) ) { return generateFloatCast (sig, x); }
299
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); }
305
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)); }
309
310 else if ( isSigUpSample(sig, x, y) ) { return generateUpSample(sig, x, y); }
311 else if ( isSigDownSample(sig, x, y) ) { return generateDownSample(sig, x, y); }
312
313
314 else {
315 printf("Error in compiling signal, unrecognized signal : ");
316 print(sig);
317 printf("\n");
318 exit(1);
319 }
320 return "error in generate code";
321 }
322
323
324 /*****************************************************************************
325 NUMBERS
326 *****************************************************************************/
327
328
329 string ScalarCompiler::generateNumber (Tree sig, const string& exp)
330 {
331 string ctype, vname;
332 Occurences* o = fOccMarkup.retrieve(sig);
333
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());
338 }
339 return exp;
340 }
341
342 /*****************************************************************************
343 FOREIGN CONSTANTS
344 *****************************************************************************/
345
346
347 string ScalarCompiler::generateFConst (Tree sig, const string& file, const string& exp)
348 {
349 string ctype, vname;
350 Occurences* o = fOccMarkup.retrieve(sig);
351
352 addIncludeFile(file);
353
354 if (o->getMaxDelay()>0) {
355 getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
356 generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
357 }
358 return exp;
359 }
360
361 /*****************************************************************************
362 FOREIGN VARIABLES
363 *****************************************************************************/
364
365
366 string ScalarCompiler::generateFVar (Tree sig, const string& file, const string& exp)
367 {
368 string ctype, vname;
369
370 addIncludeFile(file);
371 return generateCacheCode(sig, exp);
372 }
373
374 /*****************************************************************************
375 INPUTS - OUTPUTS
376 *****************************************************************************/
377
378
379 string ScalarCompiler::generateInput (Tree sig, const string& idx)
380 {
381 return generateCacheCode(sig, subst("$1input$0[i]", idx, icast()));
382 }
383
384
385 string ScalarCompiler::generateOutput (Tree sig, const string& idx, const string& arg)
386 {
387 string dst = subst("output$0[i]", idx);
388 fClass->addExecCode(subst("$0 = $2$1;", dst, arg, xcast()));
389 return dst;
390 }
391
392
393 /*****************************************************************************
394 BINARY OPERATION
395 *****************************************************************************/
396
397 string ScalarCompiler::generateBinOp(Tree sig, int opcode, Tree arg1, Tree arg2)
398 {
399 return generateCacheCode(sig, subst("($0 $1 $2)", CS(arg1), gBinOpTable[opcode]->fName, CS(arg2)));
400 }
401
402
403 /*****************************************************************************
404 Primitive Operations
405 *****************************************************************************/
406
407 string ScalarCompiler::generateFFun(Tree sig, Tree ff, Tree largs)
408 {
409 addIncludeFile(ffincfile(ff)); //printf("inc file %s\n", ffincfile(ff));
410 addLibrary(fflibfile(ff)); //printf("lib file %s\n", fflibfile(ff));
411
412 string code = ffname(ff);
413 code += '(';
414 string sep = "";
415 for (int i = 0; i< ffarity(ff); i++) {
416 code += sep;
417 code += CS(nth(largs, i));
418 sep = ", ";
419 }
420 code += ')';
421 return generateCacheCode(sig, code);
422 }
423
424
425 /*****************************************************************************
426 CACHE CODE
427 *****************************************************************************/
428
429 void ScalarCompiler::getTypedNames(Type t, const string& prefix, string& ctype, string& vname)
430 {
431 if (t->nature() == kInt) {
432 ctype = "int"; vname = subst("i$0", getFreshID(prefix));
433 } else {
434 ctype = ifloat(); vname = subst("f$0", getFreshID(prefix));
435 }
436 }
437
438 string ScalarCompiler::generateCacheCode(Tree sig, const string& exp)
439 {
440 string vname, ctype, code;
441 int sharing = getSharingCount(sig);
442 Occurences* o = fOccMarkup.retrieve(sig);
443
444 // check reentrance
445 if (getCompiledExpression(sig, code)) {
446 return code;
447 }
448
449 // check for expression occuring in delays
450 if (o->getMaxDelay()>0) {
451
452 getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
453 if (sharing>1) {
454 return generateDelayVec(sig, generateVariableStore(sig,exp), ctype, vname, o->getMaxDelay());
455 } else {
456 return generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay());
457 }
458
459 } else if (sharing == 1) {
460
461 return exp;
462
463 } else if (sharing > 1) {
464
465 return generateVariableStore(sig, exp);
466
467 } else {
468 cerr << "Error in sharing count (" << sharing << ") for " << *sig << endl;
469 exit(1);
470 }
471
472 return "Error in generateCacheCode";
473 }
474
475
476 string ScalarCompiler::generateVariableStore(Tree sig, const string& exp)
477 {
478 string vname, ctype;
479 Type t = getCertifiedSigType(sig);
480
481 switch (t->variability()) {
482
483 case kKonst :
484
485 getTypedNames(t, "Const", ctype, vname);
486 fClass->addDeclCode(subst("$0 \t$1;", ctype, vname));
487 fClass->addInitCode(subst("$0 = $1;", vname, exp));
488 break;
489
490 case kBlock :
491
492 getTypedNames(t, "Slow", ctype, vname);
493 fClass->addFirstPrivateDecl(vname);
494 fClass->addZone2(subst("$0 \t$1 = $2;", ctype, vname, exp));
495 break;
496
497 case kSamp :
498
499 getTypedNames(t, "Temp", ctype, vname);
500 fClass->addExecCode(subst("$0 $1 = $2;", ctype, vname, exp));
501 break;
502 }
503 return vname;
504 }
505
506
507 /*****************************************************************************
508 CASTING
509 *****************************************************************************/
510
511
512 string ScalarCompiler::generateIntCast(Tree sig, Tree x)
513 {
514 return generateCacheCode(sig, subst("int($0)", CS(x)));
515 }
516
517 string ScalarCompiler::generateFloatCast (Tree sig, Tree x)
518 {
519 return generateCacheCode(sig, subst("$1($0)", CS(x), ifloat()));
520 }
521
522 /*****************************************************************************
523 user interface elements
524 *****************************************************************************/
525
526 string ScalarCompiler::generateButton(Tree sig, Tree path)
527 {
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);
533 }
534
535 string ScalarCompiler::generateCheckbox(Tree sig, Tree path)
536 {
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);
542 }
543
544
545 string ScalarCompiler::generateVSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
546 {
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);
552 }
553
554 string ScalarCompiler::generateHSlider(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
555 {
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);
561 }
562
563 string ScalarCompiler::generateNumEntry(Tree sig, Tree path, Tree cur, Tree min, Tree max, Tree step)
564 {
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);
570 }
571
572
573 string ScalarCompiler::generateVBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
574 {
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));
578
579 Type t = getCertifiedSigType(sig);
580 switch (t->variability()) {
581
582 case kKonst :
583 fClass->addInitCode(subst("$0 = $1;", varname, exp));
584 break;
585
586 case kBlock :
587 fClass->addZone2(subst("$0 = $1;", varname, exp));
588 break;
589
590 case kSamp :
591 fClass->addExecCode(subst("$0 = $1;", varname, exp));
592 break;
593 }
594
595 //return varname;
596 return generateCacheCode(sig, varname);
597 }
598
599
600 string ScalarCompiler::generateHBargraph(Tree sig, Tree path, Tree min, Tree max, const string& exp)
601 {
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));
605
606 Type t = getCertifiedSigType(sig);
607 switch (t->variability()) {
608
609 case kKonst :
610 fClass->addInitCode(subst("$0 = $1;", varname, exp));
611 break;
612
613 case kBlock :
614 fClass->addZone2(subst("$0 = $1;", varname, exp));
615 break;
616
617 case kSamp :
618 fClass->addExecCode(subst("$0 = $1;", varname, exp));
619 break;
620 }
621
622 //return varname;
623 return generateCacheCode(sig, varname);
624 }
625
626
627
628
629 /*****************************************************************************
630 TABLES
631 *****************************************************************************/
632
633
634
635 /*----------------------------------------------------------------------------
636 sigGen : initial table content
637 ----------------------------------------------------------------------------*/
638
639 string ScalarCompiler::generateSigGen(Tree sig, Tree content)
640 {
641 string klassname = getFreshID("SIG");
642 string signame = getFreshID("sig");
643
644 fClass->addSubKlass(signal2klass(klassname, content));
645 fClass->addInitCode(subst("$0 $1;", klassname, signame));
646 fInstanceInitProperty.set(content, pair<string,string>(klassname,signame));
647
648 return signame;
649 }
650
651 string ScalarCompiler::generateStaticSigGen(Tree sig, Tree content)
652 {
653 string klassname = getFreshID("SIG");
654 string signame = getFreshID("sig");
655
656 fClass->addSubKlass(signal2klass(klassname, content));
657 fClass->addStaticInitCode(subst("$0 $1;", klassname, signame));
658 fStaticInitProperty.set(content, pair<string,string>(klassname,signame));
659
660 return signame;
661 }
662
663
664 /*----------------------------------------------------------------------------
665 sigTable : table declaration
666 ----------------------------------------------------------------------------*/
667
668 string ScalarCompiler::generateTable(Tree sig, Tree tsize, Tree content)
669 {
670 string generator(CS(content));
671 Tree g;
672 string cexp;
673 string ctype, vname;
674 int size;
675
676 // already compiled but check if we need to add declarations
677
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);
683 assert(b);
684 fClass->addInitCode(subst("$0 $1;", kvnames.first, kvnames.second));
685 }
686
687 if (!isSigInt(tsize, &size)) {
688 //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
689 cerr << "error in ScalarCompiler::generateTable() : "
690 << *tsize
691 << " is not a constant integer table size expression "
692 << endl;
693 exit(1);
694 }
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");
700 ctype = "int";
701 } else {
702 vname = getFreshID("ftbl");
703 ctype = ifloat();
704 }
705
706 // declaration de la table
707 fClass->addDeclCode(subst("$0 \t$1[$2];", ctype, vname, T(size)));
708
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));
713
714 // on retourne le nom de la table
715 return vname;
716 }
717
718 string ScalarCompiler::generateStaticTable(Tree sig, Tree tsize, Tree content)
719 {
720 //string generator(CS(content));
721 Tree g;
722 string cexp;
723 string ctype, vname;
724 int size;
725
726 assert ( isSigGen(content, g) );
727
728 if (!getCompiledExpression(content, cexp)) {
729 cexp = setCompiledExpression(content, generateStaticSigGen(content, g));
730 } else {
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);
736 assert(b);
737 fClass->addStaticInitCode(subst("$0 $1;", kvnames.first, kvnames.second));
738 }
739 }
740
741 if (!isSigInt(tsize, &size)) {
742 //fprintf(stderr, "error in ScalarCompiler::generateTable()\n"); exit(1);
743 cerr << "error in ScalarCompiler::generateTable() : "
744 << *tsize
745 << " is not a constant integer table size expression "
746 << endl;
747 exit(1);
748 }
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");
754 ctype = "int";
755 } else {
756 vname = getFreshID("ftbl");
757 ctype = ifloat();
758 }
759
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) ));
763
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));
768
769 // on retourne le nom de la table
770 return vname;
771 }
772
773
774 /*----------------------------------------------------------------------------
775 sigWRTable : table assignement
776 ----------------------------------------------------------------------------*/
777
778 string ScalarCompiler::generateWRTbl(Tree sig, Tree tbl, Tree idx, Tree data)
779 {
780 string tblName(CS(tbl));
781 fClass->addExecCode(subst("$0[$1] = $2;", tblName, CS(idx), CS(data)));
782 return tblName;
783 }
784
785
786 /*----------------------------------------------------------------------------
787 sigRDTable : table access
788 ----------------------------------------------------------------------------*/
789
790 string ScalarCompiler::generateRDTbl(Tree sig, Tree tbl, Tree idx)
791 {
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));
795
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) ) {
801 string tblname;
802 if (!getCompiledExpression(tbl, tblname)) {
803 tblname = setCompiledExpression(tbl, generateStaticTable(tbl, size, content));
804 }
805 return generateCacheCode(sig, subst("$0[$1]", tblname, CS(idx)));
806 } else {
807 return generateCacheCode(sig, subst("$0[$1]", CS(tbl), CS(idx)));
808 }
809 }
810
811
812
813 /*****************************************************************************
814 RECURSIONS
815 *****************************************************************************/
816
817
818 /**
819 * Generate code for a projection of a group of mutually recursive definitions
820 */
821 string ScalarCompiler::generateRecProj(Tree sig, Tree r, int i)
822 {
823 string vname;
824 Tree var, le;
825
826 if ( ! getVectorNameProperty(sig, vname)) {
827 assert(isRec(r, var, le));
828 generateRec(r, var, le);
829 assert(getVectorNameProperty(sig, vname));
830 }
831 return "[[UNUSED EXP]]"; // make sure the resulting expression is never used in the generated code
832 }
833
834
835 /**
836 * Generate code for a group of mutually recursive definitions
837 */
838 void ScalarCompiler::generateRec(Tree sig, Tree var, Tree le)
839 {
840 int N = len(le);
841
842 vector<bool> used(N);
843 vector<int> delay(N);
844 vector<string> vname(N);
845 vector<string> ctype(N);
846
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
852 used[i] = true;
853 getTypedNames(getCertifiedSigType(e), "Rec", ctype[i], vname[i]);
854 setVectorNameProperty(e, vname[i]);
855 delay[i] = fOccMarkup.retrieve(e)->getMaxDelay();
856 } else {
857 // this projection is not used therefore
858 // we should not generate code for it
859 used[i] = false;
860 }
861 }
862
863 // generate delayline for each element of a recursive definition
864 for (int i=0; i<N; i++) {
865 if (used[i]) {
866 generateDelayLine(ctype[i], vname[i], delay[i], CS(nth(le,i)));
867 }
868 }
869 }
870
871
872 /*****************************************************************************
873 PREFIX, DELAY A PREFIX VALUE
874 *****************************************************************************/
875
876 string ScalarCompiler::generatePrefix (Tree sig, Tree x, Tree e)
877 {
878 Type te = getCertifiedSigType(sig);//, tEnv);
879
880 string vperm = getFreshID("M");
881 string vtemp = getFreshID("T");
882
883 string type = cType(te);
884
885 fClass->addDeclCode(subst("$0 \t$1;", type, vperm));
886 fClass->addInitCode(subst("$0 = $1;", vperm, CS(x)));
887
888 fClass->addExecCode(subst("$0 $1 = $2;", type, vtemp, vperm));
889 fClass->addExecCode(subst("$0 = $1;", vperm, CS(e)));
890 return vtemp;
891 }
892
893
894 /*****************************************************************************
895 IOTA(n)
896 *****************************************************************************/
897 static bool isPowerOf2(int n)
898 {
899 return !(n & (n - 1));
900 }
901
902 string ScalarCompiler::generateIota (Tree sig, Tree n)
903 {
904 int size;
905 if (!isSigInt(n, &size)) { fprintf(stderr, "error in generateIota\n"); exit(1); }
906
907 string vperm = getFreshID("iota");
908
909 fClass->addDeclCode(subst("int \t$0;", vperm));
910 fClass->addInitCode(subst("$0 = 0;", vperm));
911
912 if (isPowerOf2(size)) {
913 fClass->addExecCode(subst("$0 = ($0+1)&$1;", vperm, T(size-1)));
914 } else {
915 fClass->addExecCode(subst("if (++$0 == $1) $0=0;", vperm, T(size)));
916 }
917 return vperm;
918 }
919
920
921
922 // a revoir en utilisant la lecture de table et en partageant la construction de la paire de valeurs
923
924
925 /**
926 * Generate a select2 code
927 */
928
929 string ScalarCompiler::generateSelect2 (Tree sig, Tree sel, Tree s1, Tree s2)
930 {
931 return generateCacheCode(sig, subst( "(($0)?$1:$2)", CS(sel), CS(s2), CS(s1) ) );
932 }
933
934
935 /**
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);
939 */
940 string ScalarCompiler::generateSelect3 (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3)
941 {
942 return generateCacheCode(sig, subst( "(($0==0)? $1 : (($0==1)?$2:$3) )", CS(sel), CS(s1), CS(s2), CS(s3) ) );
943 }
944
945 #if 0
946 string ScalarCompiler::generateSelect3 (Tree sig, Tree sel, Tree s1, Tree s2, Tree s3)
947 {
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));
953
954 string type = cType(t);
955 string var = getFreshID("S");
956
957 switch (w->variability())
958 {
959 case kKonst :
960 fClass->addDeclCode(subst("$0 \t$1[3];", type, var));
961 break;
962 case kBlock :
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));
967 break;
968 case kSamp :
969 fClass->addExecCode(subst("$0 \t$1[3];", type, var));
970 break;
971 }
972
973 switch (t1->variability())
974 {
975 case kKonst :
976 fClass->addInitCode(subst("$0[0] = $1;", var, CS(s1)));
977 break;
978 case kBlock :
979 fClass->addZone2b(subst("$0[0] = $1;", var, CS(s1)));
980 break;
981 case kSamp :
982 fClass->addExecCode(subst("$0[0] = $1;", var, CS(s1)));
983 break;
984 }
985
986 switch (t2->variability())
987 {
988 case kKonst :
989 fClass->addInitCode(subst("$0[1] = $1;", var, CS(s2)));
990 break;
991 case kBlock :
992 fClass->addZone2b(subst("$0[1] = $1;", var, CS(s2)));
993 break;
994 case kSamp :
995 fClass->addExecCode(subst("$0[1] = $1;", var, CS(s2)));
996 break;
997 }
998
999 switch (t3->variability())
1000 {
1001 case kKonst :
1002 fClass->addInitCode(subst("$0[2] = $1;", var, CS(s3)));
1003 break;
1004 case kBlock :
1005 fClass->addZone2b(subst("$0[2] = $1;", var, CS(s3)));
1006 break;
1007 case kSamp :
1008 fClass->addExecCode(subst("$0[2] = $1;", var, CS(s3)));
1009 break;
1010 }
1011
1012 return generateCacheCode(sig, subst("$0[$1]", var, CS(sel)));
1013 }
1014 #endif
1015
1016 /**
1017 * retrieve the type annotation of sig
1018 * @param sig the signal we want to know the type
1019 */
1020 string ScalarCompiler::generateXtended (Tree sig)
1021 {
1022 xtended* p = (xtended*) getUserData(sig);
1023 vector<string> args;
1024 vector<Type> types;
1025
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)));
1029 }
1030
1031 if (p->needCache()) {
1032 return generateCacheCode(sig, p->generateCode(fClass, args, types));
1033 } else {
1034 return p->generateCode(fClass, args, types);
1035 }
1036 }
1037
1038
1039
1040 //------------------------------------------------------------------------------------------------
1041
1042
1043 /*****************************************************************************
1044 vector name property
1045 *****************************************************************************/
1046
1047 /**
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
1053 */
1054 void ScalarCompiler::setVectorNameProperty(Tree sig, const string& vecname)
1055 {
1056 fVectorProperty.set(sig, vecname);
1057 }
1058
1059
1060 /**
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
1066 */
1067
1068 bool ScalarCompiler::getVectorNameProperty(Tree sig, string& vecname)
1069 {
1070 return fVectorProperty.get(sig, vecname);
1071 }
1072
1073
1074 /**
1075 * Compute the minimal power of 2 greater than x
1076 */
1077
1078 int ScalarCompiler::pow2limit(int x)
1079 {
1080 int n = 2;
1081 while (n < x) { n = 2*n; }
1082 return n;
1083 }
1084
1085 /*****************************************************************************
1086 N-SAMPLE FIXED DELAY : sig = exp@delay
1087
1088 case 1-sample max delay :
1089 Y(t-0) Y(t-1)
1090 Temp Var gLessTempSwitch = false
1091 V[0] V[1] gLessTempSwitch = true
1092
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
1097
1098 case max delay >= gMaxCopyDelay :
1099 Y(t-0) Y(t-1) Y(t-2) ...
1100 Temp V[0] V[1] ...
1101 V[0] V[1] V[2] ...
1102
1103
1104 *****************************************************************************/
1105
1106 /**
1107 * Generate code for accessing a delayed signal. The generated code depend of
1108 * the maximum delay attached to exp and the gLessTempSwitch.
1109 */
1110
1111 string ScalarCompiler::generateFixDelay (Tree sig, Tree exp, Tree delay)
1112 {
1113 int mxd, d;
1114 string vecname;
1115
1116 //cerr << "ScalarCompiler::generateFixDelay sig = " << *sig << endl;
1117 //cerr << "ScalarCompiler::generateFixDelay exp = " << *exp << endl;
1118 //cerr << "ScalarCompiler::generateFixDelay del = " << *delay << endl;
1119
1120 CS(exp); // ensure exp is compiled to have a vector name
1121
1122 mxd = fOccMarkup.retrieve(exp)->getMaxDelay();
1123
1124 if (! getVectorNameProperty(exp, vecname)) {
1125 cerr << "No vector name for : " << ppsig(exp) << endl;
1126 assert(0);
1127 }
1128
1129 if (mxd == 0) {
1130 // not a real vector name but a scalar name
1131 return vecname;
1132
1133 } else if (mxd < gMaxCopyDelay) {
1134 if (isSigInt(delay, &d)) {
1135 return subst("$0[$1]", vecname, CS(delay));
1136 } else {
1137 return generateCacheCode(sig, subst("$0[$1]", vecname, CS(delay)));
1138 }
1139
1140 } else {
1141
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)));
1145 }
1146 }
1147
1148
1149 /**
1150 * Generate code for the delay mecchanism. The generated code depend of the
1151 * maximum delay attached to exp and the "less temporaries" switch
1152 */
1153
1154 string ScalarCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
1155 {
1156 string s = generateDelayVecNoTemp(sig, exp, ctype, vname, mxd);
1157 if (getCertifiedSigType(sig)->variability() < kSamp) {
1158 return exp;
1159 } else {
1160 return s;
1161 }
1162 }
1163
1164 /**
1165 * Generate code for the delay mecchanism without using temporary variables
1166 */
1167
1168 string ScalarCompiler::generateDelayVecNoTemp(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
1169 {
1170 assert(mxd > 0);
1171
1172 //bool odocc = fOccMarkup.retrieve(sig)->hasOutDelayOccurences();
1173
1174 if (mxd < gMaxCopyDelay) {
1175
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));
1180
1181 // generate post processing copy code to update delay values
1182 if (mxd == 1) {
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));
1187 } else {
1188 fClass->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd), vname));
1189 }
1190 setVectorNameProperty(sig, vname);
1191 return subst("$0[0]", vname);
1192
1193 } else {
1194
1195 // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
1196 int N = pow2limit(mxd+1);
1197
1198 // we need a iota index
1199 ensureIotaCode();
1200
1201 // declare and init
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)));
1204
1205 // execute
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));
1209 }
1210 }
1211
1212 /**
1213 * Generate code for the delay mecchanism without using temporary variables
1214 */
1215
1216 void ScalarCompiler::generateDelayLine(const string& ctype, const string& vname, int mxd, const string& exp)
1217 {
1218 //assert(mxd > 0);
1219 if (mxd == 0) {
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));
1223
1224
1225 } else if (mxd < gMaxCopyDelay) {
1226 // cerr << "small delay : " << vname << "[" << mxd << "]" << endl;
1227
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));
1232
1233 // generate post processing copy code to update delay values
1234 if (mxd == 1) {
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));
1238 } else {
1239 fClass->addPostCode(subst("for (int i=$0; i>0; i--) $1[i] = $1[i-1];", T(mxd), vname));
1240 }
1241
1242 } else {
1243
1244 // generate code for a long delay : we use a ring buffer of size N = 2**x > mxd
1245 int N = pow2limit(mxd+1);
1246
1247 // we need a iota index
1248 ensureIotaCode();
1249
1250 // declare and init
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)));
1253
1254 // execute
1255 fClass->addExecCode(subst("$0[IOTA&$1] = $2;", vname, T(N-1), exp));
1256 }
1257 }
1258
1259 /**
1260 * Generate up sampling code
1261 */
1262
1263 string ScalarCompiler::generateUpSample(Tree sig, Tree w, Tree x)
1264 {
1265 return CS(x);
1266 }
1267
1268 /**
1269 * Generate down sampling code
1270 */
1271
1272 string ScalarCompiler::generateDownSample(Tree sig, Tree w, Tree x)
1273 {
1274 return CS(x);
1275 }
1276
1277
1278 /**
1279 * Generate code for a unique IOTA variable increased at each sample
1280 * and used to index ring buffers.
1281 */
1282 void ScalarCompiler::ensureIotaCode()
1283 {
1284 if (!fHasIota) {
1285 fHasIota = true;
1286 fClass->addDeclCode("int \tIOTA;");
1287 fClass->addInitCode("IOTA = 0;");
1288 fClass->addPostCode("IOTA = IOTA+1;");
1289 }
1290 }