FAUST compiler  0.9.9.6b8
compile_vect.cpp
Go to the documentation of this file.
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 
24 #include "compile_vect.hh"
25 #include "floats.hh"
26 #include "ppsig.hh"
27 
28 extern int gVecSize;
29 
31 {
32  //contextor recursivness(0);
33  L = prepare(L); // optimize, share and annotate expression
34 
35  for (int i = 0; i < fClass->inputs(); i++) {
36  fClass->addZone3(subst("$1* input$0 = &input[$0][index];", T(i), xfloat()));
37  }
38  for (int i = 0; i < fClass->outputs(); i++) {
39  fClass->addZone3(subst("$1* output$0 = &output[$0][index];", T(i), xfloat()));
40  }
41 
42  fClass->addSharedDecl("fullcount");
43  fClass->addSharedDecl("input");
44  fClass->addSharedDecl("output");
45 
46  for (int i = 0; isList(L); L = tl(L), i++) {
47  Tree sig = hd(L);
48  fClass->openLoop("count");
49  fClass->addExecCode(subst("output$0[i] = $2$1;", T(i), CS(sig), xcast()));
50  fClass->closeLoop(sig);
51  }
52 
55  if (fDescription) {
57  }
58 }
59 
60 
67 {
68  string code;
69  //cerr << "ENTER VectorCompiler::CS : "<< ppsig(sig) << endl;
70  if (!getCompiledExpression(sig, code)) {
71  code = generateCode(sig);
72  //cerr << "CS : " << code << " for " << ppsig(sig) << endl;
73  setCompiledExpression(sig, code);
74  } else {
75  // we require an already compiled expression
76  // therefore we must update the dependencies of
77  // the current loop
78  int i;
79  Tree x, d, r;
80  Loop* ls;
81  Loop* tl = fClass->topLoop();
82 
83  if (fClass->getLoopProperty(sig,ls)) {
84  // sig has a loop property
85  //cerr << "CASE SH : fBackwardLoopDependencies.insert : " << tl << " --depend(A)son--> " << ls << endl;
86  tl->fBackwardLoopDependencies.insert(ls);
87 
88  } else if (isSigFixDelay(sig, x, d) && fClass->getLoopProperty(x,ls)) {
89  //cerr << "CASE DL : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
90  tl->fBackwardLoopDependencies.insert(ls);
91 
92  } else if (isSigFixDelay(sig, x, d) && isProj(x, &i, r) && fClass->getLoopProperty(r,ls)) {
93  //cerr << "CASE DR : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
94  tl->fBackwardLoopDependencies.insert(ls);
95 
96  } else if (isProj(sig, &i, r) && fClass->getLoopProperty(r,ls)) {
97  //cerr << "CASE R* : fBackwardLoopDependencies.insert : " << tl << " --depend(B)son--> " << ls << endl;
98  tl->fBackwardLoopDependencies.insert(ls);
99 
100  } else {
101  if (isProj(sig, &i, r)) {
102  //cerr << "SYMBOL RECURSIF EN COURS ??? " << *r << endl;
103  } else if (getCertifiedSigType(sig)->variability()<kSamp) {
104  //cerr << "SLOW EXPRESSION " << endl;
105  } else {
106  //cerr << "Expression absorbĂ©e" << *sig << endl;
107  }
108 
109  }
110  }
111  //cerr << "EXIT VectorCompiler::CS : "<< ppsig(sig) << "---code---> " << code << endl;
112  return code;
113 }
114 
116 {
118  return generateCodeNonRec(sig);
119 }
120 
122 {
123  Tree id, body;
124  string code;
125  //cerr << "VectorCompiler::generateCodeRecursions( " << ppsig(sig) << " )" << endl;
126  if (getCompiledExpression(sig, code)) {
127  //cerr << "** ALREADY VISITED : " << code << " ===> " << ppsig(sig) << endl;
128  return;
129  } else if( isRec(sig, id, body) ) {
130  //cerr << "we have a recursive expression non compiled yet : " << ppsig(sig) << endl;
131  setCompiledExpression(sig, "[RecursionVisited]");
132  fClass->openLoop(sig, "count");
133  generateRec(sig, id, body);
134  fClass->closeLoop(sig);
135  } else {
136  // we go down the expression
137  vector<Tree> subsigs;
138  int n = getSubSignals(sig, subsigs, false);
139  for (int i=0; i<n; i++) { generateCodeRecursions(subsigs[i]); }
140  }
141 }
142 
144 {
145  string code;
146  if (getCompiledExpression(sig, code)) {
147  // already visited
148  return code;
149  } else {
150  //cerr << "VectorCompiler::generateCodeNonRec( " << ppsig(sig) << " )" << endl;
151  code = generateLoopCode(sig);
152  setCompiledExpression(sig, code);
153  return code;
154  }
155 }
156 
163 {
164  int i;
165  Tree x;
166  Loop* l;
167 
168  l = fClass->topLoop();
169  assert(l);
170  //cerr << "VectorCompiler::OLDgenerateCode " << ppsig(sig) << endl;
171  if (needSeparateLoop(sig)) {
172  // we need a separate loop unless it's an old recursion
173  if (isProj(sig, &i, x)) {
174  // projection of a recursive group x
175  if (l->hasRecDependencyIn(singleton(x))) {
176  // x is already in the loop stack
177  return ScalarCompiler::generateCode(sig);
178  } else {
179  // x must be defined
180  fClass->openLoop(x, "count");
181  string c = ScalarCompiler::generateCode(sig);
182  fClass->closeLoop(sig);
183  return c;
184  }
185  } else {
186  fClass->openLoop("count");
187  string c = ScalarCompiler::generateCode(sig);
188  fClass->closeLoop(sig);
189  return c;
190  }
191  } else {
192  return ScalarCompiler::generateCode(sig);
193  }
194 }
195 
196 
203 string VectorCompiler::generateCacheCode(Tree sig, const string& exp)
204 {
205  string vname, ctype;
206  int sharing = getSharingCount(sig);
207  Type t = getCertifiedSigType(sig);
208  Occurences* o = fOccMarkup.retrieve(sig);
209  int d = o->getMaxDelay();
210 
211  if (t->variability() < kSamp) {
212  if (d==0) {
213  // non-sample, not delayed : same as scalar cache
214  return ScalarCompiler::generateCacheCode(sig,exp);
215 
216  } else {
217  // it is a non-sample expressions but used delayed
218  // we need a delay line
219  getTypedNames(getCertifiedSigType(sig), "Vec", ctype, vname);
220  if ((sharing > 1) && !verySimple(sig)) {
221  // first cache this expression because it
222  // it is shared and complex
223  string cachedexp = generateVariableStore(sig, exp);
224  generateDelayLine(ctype, vname, d, cachedexp);
225  setVectorNameProperty(sig, vname);
226  return cachedexp;
227  } else {
228  // no need to cache this expression because
229  // it is either not shared or very simple
230  generateDelayLine(ctype, vname, d, exp);
231  setVectorNameProperty(sig, vname);
232  return exp;
233  }
234  }
235  } else {
236  // sample-rate signal
237  if (d > 0) {
238  // used delayed : we need a delay line
239  getTypedNames(getCertifiedSigType(sig), "Yec", ctype, vname);
240  generateDelayLine(ctype, vname, d, exp);
241  setVectorNameProperty(sig, vname);
242 
243  if (verySimple(sig)) {
244  return exp;
245  } else {
246  if (d < gMaxCopyDelay) {
247  return subst("$0[i]", vname);
248  } else {
249  // we use a ring buffer
250  string mask = T(pow2limit(d + gVecSize)-1);
251  return subst("$0[($0_idx+i) & $1]", vname, mask);
252  }
253  }
254  } else {
255  // not delayed
256  if ( sharing > 1 && ! verySimple(sig) ) {
257  // shared and not simple : we need a vector
258  // cerr << "ZEC : " << ppsig(sig) << endl;
259  getTypedNames(getCertifiedSigType(sig), "Zec", ctype, vname);
260  generateDelayLine(ctype, vname, d, exp);
261  setVectorNameProperty(sig, vname);
262  return subst("$0[i]", vname);
263  } else {
264  // not shared or simple : no cache needed
265  return exp;
266  }
267  }
268  }
269 }
270 
277 {
278  Occurences* o = fOccMarkup.retrieve(sig);
279  Type t = getCertifiedSigType(sig);
280  int c = getSharingCount(sig);
281  bool b;
282 
283  int i;
284  Tree x,y;
285 
286 
287  if (o->getMaxDelay()>0) {
288  //cerr << "DLY "; // delayed expressions require a separate loop
289  b = true;
290  } else if (verySimple(sig) || t->variability()<kSamp) {
291  b = false; // non sample computation never require a loop
292  } else if (isSigFixDelay(sig, x, y)) {
293  b = false; //
294  } else if (isProj(sig, &i ,x)) {
295  //cerr << "REC "; // recursive expressions require a separate loop
296  b = true;
297  } else if (c > 1) {
298  //cerr << "SHA(" << c << ") "; // expressions used several times required a separate loop
299  b = true;
300  } else {
301  // sample expressions that are not recursive, not delayed
302  // and not shared, doesn't require a separate loop.
303  b = false;
304  }
305 /* if (b) {
306  cerr << "Separate Loop for " << ppsig(sig) << endl;
307  } else {
308  cerr << "Same Loop for " << ppsig(sig) << endl;
309  }*/
310  return b;
311 }
312 
313 void VectorCompiler::generateDelayLine(const string& ctype, const string& vname, int mxd, const string& exp)
314 {
315  if (mxd == 0) {
316  vectorLoop(ctype, vname, exp);
317  } else {
318  dlineLoop(ctype, vname, mxd, exp);
319  }
320 }
321 
322 string VectorCompiler::generateVariableStore(Tree sig, const string& exp)
323 {
324  Type t = getCertifiedSigType(sig);
325 
326  if (getCertifiedSigType(sig)->variability() == kSamp) {
327  string vname, ctype;
328  getTypedNames(t, "Vector", ctype, vname);
329  vectorLoop(ctype, vname, exp);
330  return subst("$0[i]", vname);
331  } else {
332  return ScalarCompiler::generateVariableStore(sig, exp);
333  }
334 }
335 
336 
343 {
344  int mxd, d;
345  string vecname;
346 
347  //cerr << "VectorCompiler::generateFixDelay " << ppsig(sig) << endl;
348 
349  CS(exp); // ensure exp is compiled to have a vector name
350 
351  mxd = fOccMarkup.retrieve(exp)->getMaxDelay();
352 
353  if (! getVectorNameProperty(exp, vecname)) {
354  cerr << "ERROR no vector name for " << ppsig(exp) << endl;
355  exit(1);
356  }
357 
358  if (mxd == 0) {
359  // not a real vector name but a scalar name
360  return subst("$0[i]", vecname);
361 
362  } else if (mxd < gMaxCopyDelay){
363  if (isSigInt(delay, &d)) {
364  if (d == 0) {
365  return subst("$0[i]", vecname);
366  } else {
367  return subst("$0[i-$1]", vecname, T(d));
368  }
369  } else {
370  return subst("$0[i-$1]", vecname, CS(delay));
371  }
372 
373  } else {
374 
375  // long delay : we use a ring buffer of size 2^x
376  int N = pow2limit( mxd+gVecSize );
377 
378  if (isSigInt(delay, &d)) {
379  if (d == 0) {
380  return subst("$0[($0_idx+i)&$1]", vecname, T(N-1));
381  } else {
382  return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), T(d));
383  }
384  } else {
385  return subst("$0[($0_idx+i-$2)&$1]", vecname, T(N-1), CS(delay));
386  }
387  }
388 }
389 
390 
396 string VectorCompiler::generateDelayVec(Tree sig, const string& exp, const string& ctype, const string& vname, int mxd)
397 {
398  // it is a non-sample but used delayed
399  // we need a delay line
400  generateDelayLine(ctype, vname, mxd, exp);
401  setVectorNameProperty(sig, vname);
402  if (verySimple(sig)) {
403  return exp;
404  } else {
405  return subst("$0[i]", vname);
406  }
407 }
408 
409 #if 0
410 static int pow2limit(int x)
411 {
412  int n = 2;
413  while (n < x) { n = 2*n; }
414  return n;
415 }
416 #endif
417 
427 void VectorCompiler::vectorLoop (const string& tname, const string& vecname, const string& cexp)
428 {
429  // -- declare the vector
430  fClass->addSharedDecl(vecname);
431 
432  // -- variables moved as class fields...
433  fClass->addZone1(subst("$0 \t$1[$2];", tname, vecname, T(gVecSize)));
434 
435  // -- compute the new samples
436  fClass->addExecCode(subst("$0[i] = $1;", vecname, cexp));
437 }
438 
439 
449 void VectorCompiler::dlineLoop (const string& tname, const string& dlname, int delay, const string& cexp)
450 {
451  if (delay < gMaxCopyDelay) {
452 
453  // Implementation of a copy based delayline
454 
455  // create names for temporary and permanent storage
456  string buf = subst("$0_tmp", dlname);
457  string pmem= subst("$0_perm", dlname);
458 
459  // constraints delay size to be multiple of 4
460  delay = (delay+3)&-4;
461 
462  // allocate permanent storage for delayed samples
463  string dsize = T(delay);
464  fClass->addDeclCode(subst("$0 \t$1[$2];", tname, pmem, dsize));
465 
466  // init permanent memory
467  fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", pmem, dsize));
468 
469  // compute method
470 
471  // -- declare a buffer and a "shifted" vector
472  fClass->addSharedDecl(buf);
473 
474  // -- variables moved as class fields...
475  fClass->addZone1(subst("$0 \t$1[$2+$3];", tname, buf, T(gVecSize), dsize));
476 
477  fClass->addFirstPrivateDecl(dlname);
478  fClass->addZone2(subst("$0* \t$1 = &$2[$3];", tname, dlname, buf, dsize));
479 
480  // -- copy the stored samples to the delay line
481  fClass->addPreCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[i];", buf, pmem, dsize));
482 
483  // -- compute the new samples
484  fClass->addExecCode(subst("$0[i] = $1;", dlname, cexp));
485 
486  // -- copy back to stored samples
487  fClass->addPostCode(subst("for (int i=0; i<$2; i++) $0[i]=$1[count+i];", pmem, buf, dsize));
488 
489  } else {
490 
491  // Implementation of a ring-buffer delayline
492 
493  // the size should be large enough and aligned on a power of two
494  delay = pow2limit(delay + gVecSize);
495  string dsize = T(delay);
496  string mask = T(delay-1);
497 
498  // create names for temporary and permanent storage
499  string idx = subst("$0_idx", dlname);
500  string idx_save = subst("$0_idx_save", dlname);
501 
502  // allocate permanent storage for delayed samples
503  fClass->addDeclCode(subst("$0 \t$1[$2];", tname, dlname, dsize));
504  fClass->addDeclCode(subst("int \t$0;", idx));
505  fClass->addDeclCode(subst("int \t$0;", idx_save));
506 
507  // init permanent memory
508  fClass->addInitCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", dlname, dsize));
509  fClass->addInitCode(subst("$0 = 0;", idx));
510  fClass->addInitCode(subst("$0 = 0;", idx_save));
511 
512  // -- update index
513  fClass->addPreCode(subst("$0 = ($0+$1)&$2;", idx, idx_save, mask));
514 
515  // -- compute the new samples
516  fClass->addExecCode(subst("$0[($2+i)&$3] = $1;", dlname, cexp, idx, mask));
517 
518  // -- save index
519  fClass->addPostCode(subst("$0 = count;", idx_save));
520  }
521 }
522 
523 
525 {
526  string vname;
527  int size;
528 
529  declareWaveform(sig, vname, size);
530  fClass->addPostCode(subst("idx$0 = (idx$0 + count) % $1;", vname, T(size)) );
531  return generateCacheCode(sig, subst("$0[(idx$0+i)%$1]", vname, T(size)));
532 }
void addSharedDecl(const string &str)
Definition: klass.hh:165
int outputs()
Definition: klass.hh:210
virtual void compileMultiSignal(Tree L)
string setCompiledExpression(Tree sig, const string &name)
Set the string of a compiled expression is already compiled.
virtual string generateWaveform(Tree sig)
virtual string CS(Tree sig)
Compile a signal.
virtual string generateCode(Tree sig)
Main code generator dispatch.
Description * fDescription
Definition: compile.hh:56
Loop * topLoop()
Definition: klass.hh:133
void getTypedNames(Type t, const string &prefix, string &ctype, string &vname)
Klass * fClass
Definition: compile.hh:53
int pow2limit(int x)
Compute the minimal power of 2 greater than x.
void ui(Tree t)
void addExecCode(const string &str)
Definition: klass.hh:175
Tree prepareUserInterfaceTree(Tree t)
Remove fake root folder if not needed (that is if the UI is completely enclosed in one folder...
Definition: compile.cpp:133
void generateUserInterfaceTree(Tree t)
Generate buildUserInterface C++ lines of code corresponding to user interface element t...
Definition: compile.cpp:164
A CTree = (Node x [CTree]) is a Node associated with a list of subtrees called branches.
Definition: tree.hh:109
const char * xcast()
Definition: floats.cpp:50
void openLoop(const string &size)
Open a non-recursive loop on top of the stack of open loops.
Definition: klass.cpp:96
bool isSigFixDelay(Tree t, Tree &t0, Tree &t1)
Definition: signals.cpp:62
Tree hd(Tree l)
Definition: list.hh:133
const char * xfloat()
Definition: floats.cpp:49
virtual void generateDelayLine(const string &ctype, const string &vname, int mxd, const string &exp)
Generate code for the delay mecchanism without using temporary variables.
Occurences * retrieve(Tree t)
occurences of subtree t within root tree
Definition: occurences.cpp:81
virtual string generateCacheCode(Tree sig, const string &exp)
Generate cache code for a signal if needed.
void closeLoop(Tree sig)
Close the top loop and either keep it or absorb it within its enclosing loop.
Definition: klass.cpp:117
Tree fUIRoot
Definition: compile.hh:55
void addInitCode(const string &str)
Definition: klass.hh:151
void generateMacroInterfaceTree(const string &pathname, Tree t)
Generate user interface macros corresponding to user interface element t.
Definition: compile.cpp:312
bool needSeparateLoop(Tree sig)
Test if a signal need to be compiled in a separate loop.
virtual string generateCodeNonRec(Tree sig)
void addFirstPrivateDecl(const string &str)
Definition: klass.hh:166
virtual void dlineLoop(const string &tname, const string &dlname, int delay, const string &cexp)
Generate the code for a (short) delay line.
bool getVectorNameProperty(Tree sig, string &vecname)
Get the vector name property of a signal, the name of the vector used to store the previous values of...
bool getLoopProperty(Tree sig, Loop *&l)
Returns the loop used to compute a signal.
Definition: klass.cpp:87
Definition: ppsig.hh:48
void addPreCode(const string &str)
Definition: klass.hh:174
void addZone2(const string &str)
Definition: klass.hh:169
string subst(const string &model, const vector< string > &args)
Text substitution.
Definition: Text.cpp:47
int getSharingCount(Tree t)
Definition: sharing.cpp:62
bool isList(Tree l)
Definition: list.hh:138
bool getCompiledExpression(Tree sig, string &name)
Test if a signal is already compiled.
virtual void vectorLoop(const string &tname, const string &dlname, const string &cexp)
Generate the code for a (short) delay line.
virtual string generateVariableStore(Tree sig, const string &exp)
string T(char *c)
Definition: Text.cpp:158
Tree singleton(Tree e)
Definition: list.cpp:302
Tree prepare(Tree L0)
void addZone1(const string &str)
Definition: klass.hh:168
Definition: sigtype.hh:56
Type getCertifiedSigType(Tree sig)
Retrieve the type of sig and check it exists.
bool hasRecDependencyIn(Tree S)
returns true is this loop or its ancestors define a symbol in S
Definition: loop.cpp:63
void generateRec(Tree sig, Tree var, Tree le)
Generate code for a group of mutually recursive definitions.
bool verySimple(Tree exp)
Test if exp is very simple that is it can't be considered a real component.
Definition: signals.cpp:417
void addPostCode(const string &str)
Definition: klass.hh:176
bool isRec(Tree t, Tree &body)
is t a de Bruijn recursive tree
bool isSigInt(Tree t, int *i)
Definition: signals.cpp:41
OccMarkup fOccMarkup
Definition: compile_scal.hh:50
virtual string generateCacheCode(Tree sig, const string &exp)
int gMaxCopyDelay
Definition: main.cpp:131
virtual string generateDelayVec(Tree sig, const string &exp, const string &ctype, const string &vname, int mxd)
Generate code for the delay mecchanism.
virtual string generateFixDelay(Tree sig, Tree exp, Tree delay)
Generate code for accessing a delayed signal.
virtual string generateVariableStore(Tree sig, const string &exp)
int getMaxDelay() const
return the maximal delay collected
Definition: occurences.cpp:54
void declareWaveform(Tree sig, string &vname, int &size)
Generate code for a waveform.
void setVectorNameProperty(Tree sig, const string &vecname)
Set the vector name property of a signal, the name of the vector used to store the previous values of...
int gVecSize
Definition: main.cpp:140
virtual string generateLoopCode(Tree sig)
Compile a signal.
bool isProj(Tree t, int *i, Tree &rgroup)
Definition: signals.cpp:151
virtual void generateCodeRecursions(Tree sig)
int inputs()
Definition: klass.hh:209
Definition: loop.hh:52
virtual string generateCode(Tree sig)
Main code generator dispatch.
Tree tl(Tree l)
Definition: list.hh:134
void addZone3(const string &str)
Definition: klass.hh:172
int getSubSignals(Tree sig, vector< Tree > &vsigs, bool visitgen=true)
Extract the sub signals of a signal expression, that is not necesseraly all the subtrees.
Definition: subsignals.cpp:12
set< Loop * > fBackwardLoopDependencies
Loops that must be computed before this one.
Definition: loop.hh:59
void addDeclCode(const string &str)
Definition: klass.hh:149