1 /************************************************************************
2 ************************************************************************
3 FAUST compiler
4 Copyright (C) 2003-2018 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 #include "cpp_code_container.hh"
23 #include "Text.hh"
24 #include "cpp_gpu_code_container.hh"
25 #include "exception.hh"
26 #include "fir_to_fir.hh"
27 #include "floats.hh"
28 #include "global.hh"
29
30 using namespace std;
31
32 /*
33 C++ backend and module description:
34 - in -os mode:
35 - subcontainers are merged in the main class
36 - CPPScalarOneSampleCodeContainer1 (used in -os0) separates the DSP control state in iControl and fControl (possibly to be allocated elsewhere)
37 - CPPScalarOneSampleCodeContainer2 (used in -os1) separates the DSP control state in iControl and fControl and the DSP state in iZone and fZone (possibly to be allocated elsewhere)
38 */
39
40 map<string, bool> CPPInstVisitor::gFunctionSymbolTable;
41
produceFactory()42 dsp_factory_base* CPPCodeContainer::produceFactory()
43 {
44 return new text_dsp_factory_aux(
45 fKlassName, "", "",
46 ((dynamic_cast<ostringstream*>(fOut)) ? dynamic_cast<ostringstream*>(fOut)->str() : ""), "");
47 }
48
createScalarContainer(const string & name,int sub_container_type)49 CodeContainer* CPPCodeContainer::createScalarContainer(const string& name, int sub_container_type)
50 {
51 if (gGlobal->gOneSample == 0) {
52 return new CPPScalarOneSampleCodeContainer1(name, "", 0, 1, fOut, sub_container_type);
53 } else if (gGlobal->gOneSample == 1) {
54 return new CPPScalarOneSampleCodeContainer1(name, "", 0, 1, fOut, sub_container_type);
55 } else {
56 return new CPPScalarCodeContainer(name, "", 0, 1, fOut, sub_container_type);
57 }
58 }
59
createContainer(const string & name,const string & super,int numInputs,int numOutputs,ostream * dst)60 CodeContainer* CPPCodeContainer::createContainer(const string& name, const string& super, int numInputs, int numOutputs,
61 ostream* dst)
62 {
63 CodeContainer* container;
64
65 if (gGlobal->gOpenCLSwitch) {
66 if (gGlobal->gFunTaskSwitch) {
67 throw faustexception("ERROR : -fun not yet supported in OpenCL mode\n");
68 }
69 if (gGlobal->gVectorSwitch) {
70 container = new CPPOpenCLVectorCodeContainer(name, super, numInputs, numOutputs, dst);
71 } else {
72 container = new CPPOpenCLCodeContainer(name, super, numInputs, numOutputs, dst);
73 }
74 } else if (gGlobal->gCUDASwitch) {
75 if (gGlobal->gFunTaskSwitch) {
76 throw faustexception("ERROR : -fun not yet supported in CUDA mode\n");
77 }
78 if (gGlobal->gVectorSwitch) {
79 container = new CPPCUDAVectorCodeContainer(name, super, numInputs, numOutputs, dst);
80 } else {
81 container = new CPPCUDACodeContainer(name, super, numInputs, numOutputs, dst);
82 }
83 } else if (gGlobal->gOpenMPSwitch) {
84 container = new CPPOpenMPCodeContainer(name, super, numInputs, numOutputs, dst);
85 } else if (gGlobal->gSchedulerSwitch) {
86 container = new CPPWorkStealingCodeContainer(name, super, numInputs, numOutputs, dst);
87 } else if (gGlobal->gVectorSwitch) {
88 container = new CPPVectorCodeContainer(name, super, numInputs, numOutputs, dst);
89 } else {
90 if (gGlobal->gOneSample == 0) {
91 container = new CPPScalarOneSampleCodeContainer1(name, super, numInputs, numOutputs, dst, kInt);
92 } else if (gGlobal->gOneSample == 1) {
93 container = new CPPScalarOneSampleCodeContainer2(name, super, numInputs, numOutputs, dst, kInt);
94 } else {
95 container = new CPPScalarCodeContainer(name, super, numInputs, numOutputs, dst, kInt);
96 }
97 }
98
99 return container;
100 }
101
102 // Scalar
CPPScalarCodeContainer(const string & name,const string & super,int numInputs,int numOutputs,std::ostream * out,int sub_container_type)103 CPPScalarCodeContainer::CPPScalarCodeContainer(const string& name, const string& super, int numInputs, int numOutputs,
104 std::ostream* out, int sub_container_type)
105 : CPPCodeContainer(name, super, numInputs, numOutputs, out)
106 {
107 fSubContainerType = sub_container_type;
108 }
109
produceMetadata(int tabs)110 void CPPCodeContainer::produceMetadata(int tabs)
111 {
112 tab(tabs, *fOut);
113 *fOut << "void metadata(Meta* m) { ";
114
115 // We do not want to accumulate metadata from all hierachical levels, so the upper level only is kept
116 for (const auto& i : gGlobal->gMetaDataSet) {
117 if (i.first != tree("author")) {
118 tab(tabs + 1, *fOut);
119 *fOut << "m->declare(\"" << *(i.first) << "\", " << **(i.second.begin()) << ");";
120 } else {
121 // But the "author" meta data is accumulated, the upper level becomes the main author and sub-levels become
122 // "contributor"
123 for (set<Tree>::iterator j = i.second.begin(); j != i.second.end(); j++) {
124 if (j == i.second.begin()) {
125 tab(tabs + 1, *fOut);
126 *fOut << "m->declare(\"" << *(i.first) << "\", " << **j << ");";
127 } else {
128 tab(tabs + 1, *fOut);
129 *fOut << "m->declare(\""
130 << "contributor"
131 << "\", " << **j << ");";
132 }
133 }
134 }
135 }
136
137 tab(tabs, *fOut);
138 *fOut << "}" << endl;
139 }
140
produceInit(int tabs)141 void CPPCodeContainer::produceInit(int tabs)
142 {
143 if (gGlobal->gMemoryManager) {
144 tab(tabs, *fOut);
145 *fOut << "virtual void init(int sample_rate) {}";
146 } else {
147 tab(tabs, *fOut);
148 *fOut << "virtual void init(int sample_rate) {";
149 tab(tabs + 1, *fOut);
150 *fOut << "classInit(sample_rate);";
151 tab(tabs + 1, *fOut);
152 *fOut << "instanceInit(sample_rate);";
153 tab(tabs, *fOut);
154 *fOut << "}";
155 }
156
157 tab(tabs, *fOut);
158 *fOut << "virtual void instanceInit(int sample_rate) {";
159 tab(tabs + 1, *fOut);
160 *fOut << "instanceConstants(sample_rate);";
161 tab(tabs + 1, *fOut);
162 *fOut << "instanceResetUserInterface();";
163 tab(tabs + 1, *fOut);
164 *fOut << "instanceClear();";
165 tab(tabs, *fOut);
166 *fOut << "}";
167 }
168
produceInternal()169 void CPPCodeContainer::produceInternal()
170 {
171 int n = 0;
172
173 // Global declarations
174 tab(n, *fOut);
175
176 fCodeProducer->Tab(n);
177 generateGlobalDeclarations(fCodeProducer);
178
179 *fOut << "class " << fKlassName << " {";
180
181 tab(n + 1, *fOut);
182
183 if (gGlobal->gUIMacroSwitch) {
184 tab(n, *fOut);
185 *fOut << " public:";
186 } else {
187 tab(n, *fOut);
188 *fOut << " private:";
189 }
190 tab(n + 1, *fOut);
191 tab(n + 1, *fOut);
192
193 // Fields
194 fCodeProducer->Tab(n + 1);
195 generateDeclarations(fCodeProducer);
196
197 tab(n, *fOut);
198 *fOut << " public:";
199
200 tab(n + 1, *fOut);
201 tab(n + 1, *fOut);
202
203 // fKlassName used in method naming for subclasses
204 produceInfoFunctions(n + 1, fKlassName, "dsp", true, false, fCodeProducer);
205
206 // TODO
207 // generateInstanceInitFun("instanceInit" + fKlassName, true, false)->accept(fCodeProducer);
208
209 // Inits
210 tab(n + 1, *fOut);
211 *fOut << "void instanceInit" << fKlassName << "(int sample_rate) {";
212 tab(n + 2, *fOut);
213 fCodeProducer->Tab(n + 2);
214 generateInit(fCodeProducer);
215 generateResetUserInterface(fCodeProducer);
216 generateClear(fCodeProducer);
217 back(1, *fOut);
218 *fOut << "}";
219
220 // Fill
221 string counter = "count";
222 tab(n + 1, *fOut);
223 if (fSubContainerType == kInt) {
224 tab(n + 1, *fOut);
225 *fOut << "void fill" << fKlassName << subst("(int $0, int* " + fTableName + ") {", counter);
226 } else {
227 tab(n + 1, *fOut);
228 *fOut << "void fill" << fKlassName << subst("(int $0, $1* " + fTableName + ") {", counter, ifloat());
229 }
230 tab(n + 2, *fOut);
231 fCodeProducer->Tab(n + 2);
232 generateComputeBlock(fCodeProducer);
233 ForLoopInst* loop = fCurLoop->generateScalarLoop(counter);
234 loop->accept(fCodeProducer);
235 back(1, *fOut);
236 *fOut << "}";
237
238 /*
239 tab(n+1, *fOut);
240 fCodeProducer->Tab(n+1);
241 generateFillFun("fill" + fKlassName, true, false)->accept(fCodeProducer);
242 */
243
244 tab(n, *fOut);
245 tab(n, *fOut);
246 *fOut << "};" << endl;
247
248 // Memory methods (as globals)
249 if (gGlobal->gMemoryManager) {
250 tab(n, *fOut);
251 *fOut << "static " << fKlassName << "* "
252 << "new" << fKlassName << "(dsp_memory_manager* manager) {"
253 << " return (" << fKlassName << "*)new(manager->allocate(sizeof(" << fKlassName << "))) " << fKlassName
254 << "(); }";
255 tab(n, *fOut);
256 *fOut << "static void delete" << fKlassName << "(" << fKlassName << "* dsp, dsp_memory_manager* manager) { dsp->~"
257 << fKlassName << "(); manager->destroy(dsp); }";
258 } else {
259 tab(n, *fOut);
260 *fOut << "static " << fKlassName << "* "
261 << "new" << fKlassName << "() {"
262 << " return (" << fKlassName << "*)new " << fKlassName << "(); }";
263 tab(n, *fOut);
264 *fOut << "static void delete" << fKlassName << "(" << fKlassName << "* dsp) { delete dsp; }";
265 }
266 tab(n, *fOut);
267 }
268
produceClass()269 void CPPCodeContainer::produceClass()
270 {
271 int n = 0;
272
273 // Libraries
274 printLibrary(*fOut);
275 printIncludeFile(*fOut);
276
277 if (gGlobal->gNameSpace != "" && gGlobal->gArchFile == "") {
278 tab(n, *fOut);
279 *fOut << "namespace " << gGlobal->gNameSpace << " {" << endl;
280 }
281
282 // Generate gub containers
283 generateSubContainers();
284
285 // Global declarations
286 tab(n, *fOut);
287 fCodeProducer->Tab(n);
288 generateGlobalDeclarations(fCodeProducer);
289
290 tab(n, *fOut);
291 *fOut << "#ifndef FAUSTCLASS " << endl;
292 *fOut << "#define FAUSTCLASS " << fKlassName << endl;
293 *fOut << "#endif" << endl;
294 tab(n, *fOut);
295
296 *fOut << "#ifdef __APPLE__ " << endl;
297 *fOut << "#define exp10f __exp10f" << endl;
298 *fOut << "#define exp10 __exp10" << endl;
299 *fOut << "#endif" << endl;
300
301 tab(n, *fOut);
302 *fOut << "class " << fKlassName << " : public " << fSuperKlassName << " {";
303 tab(n + 1, *fOut);
304
305 if (gGlobal->gUIMacroSwitch) {
306 tab(n, *fOut);
307 *fOut << " public:";
308 } else {
309 tab(n, *fOut);
310 *fOut << " private:";
311 }
312 tab(n + 1, *fOut);
313
314 // Fields
315 fCodeProducer->Tab(n + 1);
316 tab(n + 1, *fOut);
317 generateDeclarations(fCodeProducer);
318
319 if (fAllocateInstructions->fCode.size() > 0) {
320 tab(n + 1, *fOut);
321 *fOut << "void allocate() {";
322 tab(n + 2, *fOut);
323 fCodeProducer->Tab(n + 2);
324 generateAllocate(fCodeProducer);
325 back(1, *fOut);
326 *fOut << "}";
327 tab(n + 1, *fOut);
328 }
329
330 if (fDestroyInstructions->fCode.size() > 0) {
331 tab(n + 1, *fOut);
332 *fOut << "void destroy() {";
333 tab(n + 2, *fOut);
334 fCodeProducer->Tab(n + 2);
335 generateDestroy(fCodeProducer);
336 back(1, *fOut);
337 *fOut << "}";
338 tab(n + 1, *fOut);
339 }
340
341 tab(n, *fOut);
342 *fOut << " public:";
343
344 if (gGlobal->gMemoryManager) {
345 tab(n + 1, *fOut);
346 *fOut << "static dsp_memory_manager* fManager;";
347 }
348
349 // Print metadata declaration
350 tab(n + 1, *fOut);
351 produceMetadata(n + 1);
352
353 if (fAllocateInstructions->fCode.size() > 0) {
354 tab(n + 1, *fOut);
355 *fOut << fKlassName << "() {";
356 tab(n + 2, *fOut);
357 *fOut << "allocate();";
358 tab(n + 1, *fOut);
359 *fOut << "}" << endl;
360 }
361
362 if (fDestroyInstructions->fCode.size() > 0) {
363 tab(n + 1, *fOut);
364 *fOut << "virtual ~" << fKlassName << "() {";
365 tab(n + 2, *fOut);
366 *fOut << "destroy();";
367 tab(n + 1, *fOut);
368 *fOut << "}" << endl;
369 }
370
371 tab(n + 1, *fOut);
372 // No class name for main class
373 produceInfoFunctions(n + 1, "", "dsp", true, true, fCodeProducer); // Inits
374
375 // TODO
376 /*
377 generateStaticInitFun("classInit", true)->accept(fCodeProducer);
378 generateInstanceInitFun("instanceInit", true, true)->accept(fCodeProducer);
379 */
380
381 tab(n + 1, *fOut);
382 *fOut << "static void classInit(int sample_rate) {";
383 tab(n + 2, *fOut);
384 fCodeProducer->Tab(n + 2);
385 generateStaticInit(fCodeProducer);
386 back(1, *fOut);
387 *fOut << "}";
388
389 if (gGlobal->gMemoryManager) {
390 tab(n + 1, *fOut);
391 *fOut << "static void classDestroy() {";
392 tab(n + 2, *fOut);
393 fCodeProducer->Tab(n + 2);
394 generateStaticDestroy(fCodeProducer);
395 back(1, *fOut);
396 *fOut << "}";
397 }
398
399 // TEST
400 /*
401 // Start inline
402 {
403 DspRenamer renamer;
404 BlockInst* res1 = renamer.getCode(fStaticInitInstructions);
405
406 list<CodeContainer*>::const_iterator it;
407 for (it = fSubContainers.begin(); it != fSubContainers.end(); it++) {
408 DeclareFunInst* inst_init_fun = (*it)->generateInstanceInitFun("instanceInit" + (*it)->getClassName(), true,
409 false);
410 InlineVoidFunctionCall inliner1(inst_init_fun);
411 res1 = inliner1.getCode(res1);
412 DeclareFunInst* fill_fun = (*it)->generateFillFun("fill" + (*it)->getClassName(), true, false);
413 InlineVoidFunctionCall inliner2(fill_fun);
414 res1 = inliner2.getCode(res1);
415 }
416
417 tab(n+1, *fOut);
418 *fOut << "static void classInit(int sample_rate) {";
419 tab(n+2, *fOut);
420 fCodeProducer->Tab(n+2);
421 res1->accept(fCodeProducer);
422 tab(n+1, *fOut); *fOut << "}";
423 }
424 // End inline
425 */
426
427 tab(n + 1, *fOut);
428 tab(n + 1, *fOut);
429 *fOut << "virtual void instanceConstants(int sample_rate) {";
430 tab(n + 2, *fOut);
431 fCodeProducer->Tab(n + 2);
432 generateInit(fCodeProducer);
433 back(1, *fOut);
434 *fOut << "}";
435 tab(n + 1, *fOut);
436
437 tab(n + 1, *fOut);
438 *fOut << "virtual void instanceResetUserInterface() {";
439 tab(n + 2, *fOut);
440 fCodeProducer->Tab(n + 2);
441 generateResetUserInterface(fCodeProducer);
442 back(1, *fOut);
443 *fOut << "}";
444 tab(n + 1, *fOut);
445
446 tab(n + 1, *fOut);
447 *fOut << "virtual void instanceClear() {";
448 tab(n + 2, *fOut);
449 fCodeProducer->Tab(n + 2);
450 generateClear(fCodeProducer);
451 back(1, *fOut);
452 *fOut << "}";
453 tab(n + 1, *fOut);
454
455 // TEST
456 /*
457 // Start inline
458 {
459 DspRenamer renamer;
460 BlockInst* res1 = renamer.getCode(fInitInstructions);
461 BlockInst* res2 = renamer.getCode(fPostInitInstructions);
462
463 list<CodeContainer*>::const_iterator it;
464 for (it = fSubContainers.begin(); it != fSubContainers.end(); it++) {
465 DeclareFunInst* inst_init_fun = (*it)->generateInstanceInitFun("instanceInit" + (*it)->getClassName(), true,false);
466 InlineVoidFunctionCall inliner1(inst_init_fun);
467 res1 = inliner1.getCode(res1);
468 res2 = inliner1.getCode(res2);
469 DeclareFunInst* fill_fun = (*it)->generateFillFun("fill" + (*it)->getClassName(), true, false);
470 InlineVoidFunctionCall inliner2(fill_fun);
471 res1 = inliner2.getCode(res1);
472 res2 = inliner2.getCode(res2);
473 }
474
475 tab(n+1, *fOut);
476 *fOut << "virtual void instanceInit(int sample_rate) {";
477 tab(n+2, *fOut);
478 fCodeProducer->Tab(n+2);
479 res1->accept(fCodeProducer);
480 res2->accept(fCodeProducer);
481 tab(n+1, *fOut); *fOut << "}";
482 }
483 // End inline
484 */
485
486 // Init
487 produceInit(n + 1);
488
489 tab(n + 1, *fOut);
490 tab(n + 1, *fOut);
491 *fOut << "virtual " << fKlassName << "* clone() {";
492 tab(n + 2, *fOut);
493 *fOut << "return new " << fKlassName << "();";
494 tab(n + 1, *fOut);
495 *fOut << "}";
496
497 tab(n + 1, *fOut);
498 fCodeProducer->Tab(n + 1);
499 tab(n + 1, *fOut);
500 generateGetSampleRate("getSampleRate", "dsp", true, true)->accept(fCodeProducer);
501
502 // User interface
503 tab(n + 1, *fOut);
504 *fOut << "virtual void buildUserInterface(UI* ui_interface) {";
505 tab(n + 2, *fOut);
506 fCodeProducer->Tab(n + 2);
507 generateUserInterface(fCodeProducer);
508 back(1, *fOut);
509 *fOut << "}";
510
511 // Compute
512 generateCompute(n);
513 tab(n, *fOut);
514 tab(n, *fOut);
515 *fOut << "};" << endl;
516
517 // To improve (generalization for all backends...)
518 if (gGlobal->gMemoryManager) {
519 tab(n, *fOut);
520 *fOut << "dsp_memory_manager* " << fKlassName << "::fManager = 0;" << endl;
521 }
522
523 // Generate user interface macros if needed
524 printMacros(*fOut, n);
525
526 if (gGlobal->gNameSpace != "" && gGlobal->gArchFile == "") {
527 tab(n, *fOut);
528 *fOut << "} // namespace " << gGlobal->gNameSpace << endl;
529 }
530 }
531
532 // Used with -os0 option
produceClass()533 void CPPScalarOneSampleCodeContainer1::produceClass()
534 {
535 int n = 0;
536
537 // Libraries
538 printLibrary(*fOut);
539 printIncludeFile(*fOut);
540
541 if (gGlobal->gNameSpace != "" && gGlobal->gArchFile == "") {
542 tab(n, *fOut);
543 *fOut << "namespace " << gGlobal->gNameSpace << " {" << endl;
544 }
545
546 // Sub containers are merged in the main class
547 mergeSubContainers();
548
549 // Global declarations
550 tab(n, *fOut);
551 fCodeProducer->Tab(n);
552 generateGlobalDeclarations(fCodeProducer);
553
554 tab(n, *fOut);
555 *fOut << "#ifndef FAUSTCLASS " << endl;
556 *fOut << "#define FAUSTCLASS " << fKlassName << endl;
557 *fOut << "#endif" << endl;
558 tab(n, *fOut);
559
560 *fOut << "#ifdef __APPLE__ " << endl;
561 *fOut << "#define exp10f __exp10f" << endl;
562 *fOut << "#define exp10 __exp10" << endl;
563 *fOut << "#endif" << endl;
564 tab(n, *fOut);
565
566 *fOut << "#if defined(_WIN32)" << endl;
567 *fOut << "#define RESTRICT __restrict" << endl;
568 *fOut << "#else" << endl;
569 *fOut << "#define RESTRICT __restrict__" << endl;
570 *fOut << "#endif" << endl;
571 tab(n, *fOut);
572
573 *fOut << "#define FAUST_INT_CONTROLS " << fInt32ControlNum << endl;
574 *fOut << "#define FAUST_REAL_CONTROLS " << fRealControlNum;
575 tab(n, *fOut);
576
577 tab(n, *fOut);
578 fSuperKlassName = "one_sample_dsp";
579 *fOut << "class " << fKlassName << " : public " << fSuperKlassName << " {";
580 tab(n + 1, *fOut);
581
582 if (gGlobal->gUIMacroSwitch) {
583 tab(n, *fOut);
584 *fOut << " public:";
585 } else {
586 tab(n, *fOut);
587 *fOut << " private:";
588 }
589 tab(n + 1, *fOut);
590
591 // Fields
592 fCodeProducer->Tab(n + 1);
593 tab(n + 1, *fOut);
594 generateDeclarations(fCodeProducer);
595
596 if (fAllocateInstructions->fCode.size() > 0) {
597 tab(n + 1, *fOut);
598 *fOut << "void allocate() {";
599 tab(n + 2, *fOut);
600 fCodeProducer->Tab(n + 2);
601 generateAllocate(fCodeProducer);
602 back(1, *fOut);
603 *fOut << "}";
604 tab(n + 1, *fOut);
605 }
606
607 if (fDestroyInstructions->fCode.size() > 0) {
608 tab(n + 1, *fOut);
609 *fOut << "void destroy() {";
610 tab(n + 2, *fOut);
611 fCodeProducer->Tab(n + 2);
612 generateDestroy(fCodeProducer);
613 back(1, *fOut);
614 *fOut << "}";
615 tab(n + 1, *fOut);
616 }
617
618 tab(n, *fOut);
619 *fOut << " public:";
620
621 if (gGlobal->gMemoryManager) {
622 tab(n + 1, *fOut);
623 *fOut << "static dsp_memory_manager* fManager;";
624 }
625
626 // Print metadata declaration
627 tab(n + 1, *fOut);
628 produceMetadata(n + 1);
629
630 if (fAllocateInstructions->fCode.size() > 0) {
631 tab(n + 1, *fOut);
632 *fOut << fKlassName << "() {";
633 tab(n + 2, *fOut);
634 *fOut << "allocate();";
635 tab(n + 1, *fOut);
636 *fOut << "}" << endl;
637 }
638
639 if (fDestroyInstructions->fCode.size() > 0) {
640 tab(n + 1, *fOut);
641 *fOut << "virtual ~" << fKlassName << "() {";
642 tab(n + 2, *fOut);
643 *fOut << "destroy();";
644 tab(n + 1, *fOut);
645 *fOut << "}" << endl;
646 }
647
648 // Constructor
649 tab(n + 1, *fOut);
650 *fOut << fKlassName << "() {}";
651 tab(n + 1, *fOut);
652 *fOut << fKlassName << "(int* icontrol, FAUSTFLOAT* fcontrol)";
653 *fOut << ":one_sample_dsp(icontrol, fcontrol) {}";
654 tab(n + 1, *fOut);
655
656 tab(n + 1, *fOut);
657 // No class name for main class
658 produceInfoFunctions(n + 1, "", "dsp", true, true, fCodeProducer); // Inits
659
660 // Dummy
661 tab(n + 1, *fOut);
662 *fOut << "static void classInit(int sample_rate) {}";
663 tab(n, *fOut);
664
665 tab(n + 1, *fOut);
666 *fOut << "void staticInit(int sample_rate) {";
667 {
668 tab(n + 2, *fOut);
669 fCodeProducer->Tab(n + 2);
670 // Rename 'sig' in 'dsp', remove 'dsp' allocation, inline subcontainers 'instanceInit' and 'fill' function call
671 inlineSubcontainersFunCalls(fStaticInitInstructions)->accept(fCodeProducer);
672 }
673 back(1, *fOut);
674 *fOut << "}";
675
676 if (gGlobal->gMemoryManager) {
677 tab(n + 1, *fOut);
678 *fOut << "static void classDestroy() {";
679 tab(n + 2, *fOut);
680 fCodeProducer->Tab(n + 2);
681 generateStaticDestroy(fCodeProducer);
682 back(1, *fOut);
683 *fOut << "}";
684 }
685
686 tab(n + 1, *fOut);
687 tab(n + 1, *fOut);
688 *fOut << "virtual void instanceConstants(int sample_rate) {";
689 tab(n + 2, *fOut);
690 fCodeProducer->Tab(n + 2);
691 generateInit(fCodeProducer);
692 back(1, *fOut);
693 *fOut << "}";
694 tab(n + 1, *fOut);
695
696 tab(n + 1, *fOut);
697 *fOut << "virtual void instanceResetUserInterface() {";
698 tab(n + 2, *fOut);
699 fCodeProducer->Tab(n + 2);
700 generateResetUserInterface(fCodeProducer);
701 back(1, *fOut);
702 *fOut << "}";
703 tab(n + 1, *fOut);
704
705 tab(n + 1, *fOut);
706 *fOut << "virtual void instanceClear() {";
707 tab(n + 2, *fOut);
708 fCodeProducer->Tab(n + 2);
709 generateClear(fCodeProducer);
710 back(1, *fOut);
711 *fOut << "}";
712 tab(n + 1, *fOut);
713
714 // Init
715 if (gGlobal->gMemoryManager) {
716 tab(n + 1, *fOut);
717 *fOut << "virtual void init(int sample_rate) {}";
718 } else {
719 tab(n + 1, *fOut);
720 *fOut << "virtual void init(int sample_rate) {";
721 tab(n + 2, *fOut);
722 *fOut << "instanceInit(sample_rate);";
723 tab(n + 1, *fOut);
724 *fOut << "}";
725 }
726 tab(n + 1, *fOut);
727
728 tab(n + 1, *fOut);
729 *fOut << "virtual void instanceInit(int sample_rate) {";
730 // staticInit has to be called for each instance since the tables are actually not shared between instances
731 tab(n + 2, *fOut);
732 *fOut << "staticInit(sample_rate);";
733 tab(n + 2, *fOut);
734 *fOut << "instanceConstants(sample_rate);";
735 tab(n + 2, *fOut);
736 *fOut << "instanceResetUserInterface();";
737 tab(n + 2, *fOut);
738 *fOut << "instanceClear();";
739 tab(n + 1, *fOut);
740 *fOut << "}";
741 tab(n + 1, *fOut);
742
743 tab(n + 1, *fOut);
744 *fOut << "virtual " << fKlassName << "* clone() {";
745 tab(n + 2, *fOut);
746 *fOut << "return new " << fKlassName << "();";
747 tab(n + 1, *fOut);
748 *fOut << "}";
749
750 tab(n + 1, *fOut);
751 fCodeProducer->Tab(n + 1);
752 tab(n + 1, *fOut);
753 generateGetSampleRate("getSampleRate", "dsp", true, true)->accept(fCodeProducer);
754
755 // User interface
756 tab(n + 1, *fOut);
757 *fOut << "virtual void buildUserInterface(UI* ui_interface) {";
758 tab(n + 2, *fOut);
759 fCodeProducer->Tab(n + 2);
760 generateUserInterface(fCodeProducer);
761 back(1, *fOut);
762 *fOut << "}";
763 tab(n + 1, *fOut);
764
765 tab(n + 1, *fOut);
766 *fOut << subst("virtual void control(int* RESTRICT iControl, $0* RESTRICT fControl) {", xfloat());
767 tab(n + 2, *fOut);
768 fCodeProducer->Tab(n + 2);
769 // Generates local variables declaration and setup
770 generateComputeBlock(fCodeProducer);
771 back(1, *fOut);
772 *fOut << "}" << endl;
773
774 tab(n + 1, *fOut);
775 *fOut << "virtual int getNumIntControls() { return " << fInt32ControlNum << "; }";
776 tab(n + 1, *fOut);
777 *fOut << "virtual int getNumRealControls() { return " << fRealControlNum << "; }";
778
779 // Compute
780 generateCompute(n);
781 tab(n, *fOut);
782 tab(n, *fOut);
783 *fOut << "};" << endl;
784
785 // To improve (generalization for all backends...)
786 if (gGlobal->gMemoryManager) {
787 tab(n, *fOut);
788 *fOut << "dsp_memory_manager* " << fKlassName << "::fManager = 0;" << endl;
789 }
790
791 // Generate user interface macros if needed
792 printMacros(*fOut, n);
793
794 if (gGlobal->gNameSpace != "" && gGlobal->gArchFile == "") {
795 tab(n, *fOut);
796 *fOut << "} // namespace " << gGlobal->gNameSpace << endl;
797 }
798 }
799
800 // Used with -os1 option
produceClass()801 void CPPScalarOneSampleCodeContainer2::produceClass()
802 {
803 int n = 0;
804
805 // Libraries
806 printLibrary(*fOut);
807 printIncludeFile(*fOut);
808
809 if (gGlobal->gNameSpace != "" && gGlobal->gArchFile == "") {
810 tab(n, *fOut);
811 *fOut << "namespace " << gGlobal->gNameSpace << " {" << endl;
812 }
813
814 // Sub containers are merged in the main class
815 mergeSubContainers();
816
817 // Global declarations
818 tab(n, *fOut);
819 fCodeProducer->Tab(n);
820 generateGlobalDeclarations(fCodeProducer);
821
822 tab(n, *fOut);
823 *fOut << "#ifndef FAUSTCLASS " << endl;
824 *fOut << "#define FAUSTCLASS " << fKlassName << endl;
825 *fOut << "#endif" << endl;
826 tab(n, *fOut);
827
828 *fOut << "#ifdef __APPLE__ " << endl;
829 *fOut << "#define exp10f __exp10f" << endl;
830 *fOut << "#define exp10 __exp10" << endl;
831 *fOut << "#endif" << endl;
832 tab(n, *fOut);
833
834 *fOut << "#if defined(_WIN32)" << endl;
835 *fOut << "#define RESTRICT __restrict" << endl;
836 *fOut << "#else" << endl;
837 *fOut << "#define RESTRICT __restrict__" << endl;
838 *fOut << "#endif" << endl;
839
840 tab(n, *fOut);
841 fSuperKlassName = "one_sample_dsp_real<" + string(ifloat()) + ">";
842 *fOut << "class " << fKlassName << " : public " << fSuperKlassName << " {";
843 tab(n + 1, *fOut);
844
845 if (gGlobal->gUIMacroSwitch) {
846 tab(n, *fOut);
847 *fOut << " public:";
848 } else {
849 tab(n, *fOut);
850 *fOut << " private:";
851 }
852 tab(n + 1, *fOut);
853
854 // Fields
855 fCodeProducer->Tab(n + 1);
856 tab(n + 1, *fOut);
857 generateDeclarations(fCodeProducer);
858
859 // Kept here because staticInit incorrectly change the size later on
860 int int_zone_size = static_cast<CPPInstVisitor1*>(fCodeProducer)->getIntZoneSize();
861 int real_zone_size = static_cast<CPPInstVisitor1*>(fCodeProducer)->getRealZoneSize();
862
863 if (fAllocateInstructions->fCode.size() > 0) {
864 tab(n + 1, *fOut);
865 *fOut << "void allocate() {";
866 tab(n + 2, *fOut);
867 fCodeProducer->Tab(n + 2);
868 generateAllocate(fCodeProducer);
869 back(1, *fOut);
870 *fOut << "}";
871 tab(n + 1, *fOut);
872 }
873
874 if (fDestroyInstructions->fCode.size() > 0) {
875 tab(n + 1, *fOut);
876 *fOut << "void destroy() {";
877 tab(n + 2, *fOut);
878 fCodeProducer->Tab(n + 2);
879 generateDestroy(fCodeProducer);
880 back(1, *fOut);
881 *fOut << "}";
882 tab(n + 1, *fOut);
883 }
884
885 tab(n, *fOut);
886 *fOut << " public:";
887
888 if (gGlobal->gMemoryManager) {
889 tab(n + 1, *fOut);
890 *fOut << "static dsp_memory_manager* fManager;";
891 }
892
893 // Print metadata declaration
894 tab(n + 1, *fOut);
895 produceMetadata(n + 1);
896
897 if (fAllocateInstructions->fCode.size() > 0) {
898 tab(n + 1, *fOut);
899 *fOut << fKlassName << "() {";
900 tab(n + 2, *fOut);
901 *fOut << "allocate();";
902 tab(n + 1, *fOut);
903 *fOut << "}" << endl;
904 }
905
906 if (fDestroyInstructions->fCode.size() > 0) {
907 tab(n + 1, *fOut);
908 *fOut << "virtual ~" << fKlassName << "() {";
909 tab(n + 2, *fOut);
910 *fOut << "destroy();";
911 tab(n + 1, *fOut);
912 *fOut << "}" << endl;
913 }
914
915 // Constructor
916 tab(n + 1, *fOut);
917 *fOut << fKlassName << "() {}";
918 tab(n + 1, *fOut);
919 *fOut << fKlassName << "(int* icontrol, FAUSTFLOAT* fcontrol, int* izone, " << ifloat() << "* fzone)";
920 *fOut << ":one_sample_dsp_real(icontrol, fcontrol, izone, fzone) {}";
921 tab(n + 1, *fOut);
922
923 tab(n + 1, *fOut);
924 // No class name for main class
925 produceInfoFunctions(n + 1, "", "dsp", true, true, fCodeProducer); // Inits
926
927 // Dummy
928 tab(n + 1, *fOut);
929 *fOut << "static void classInit(int sample_rate) {}";
930 tab(n + 1, *fOut);
931
932 tab(n + 1, *fOut);
933 *fOut << "void staticInit(int sample_rate, " << subst("int* iZone, $0* fZone) {", ifloat());
934 {
935 tab(n + 2, *fOut);
936 fCodeProducer->Tab(n + 2);
937 // For waveform
938 MoveVariablesInFront3().getCode(fGlobalDeclarationInstructions)->accept(fCodeProducer);
939 // Rename 'sig' in 'dsp', remove 'dsp' allocation, inline subcontainers 'instanceInit' and 'fill' function call
940 inlineSubcontainersFunCalls(fStaticInitInstructions)->accept(fCodeProducer);
941 }
942 back(1, *fOut);
943 *fOut << "}";
944
945 if (gGlobal->gMemoryManager) {
946 tab(n + 1, *fOut);
947 *fOut << "static void classDestroy() {";
948 tab(n + 2, *fOut);
949 fCodeProducer->Tab(n + 2);
950 generateStaticDestroy(fCodeProducer);
951 back(1, *fOut);
952 *fOut << "}";
953 }
954
955 tab(n + 1, *fOut);
956 tab(n + 1, *fOut);
957 *fOut << "virtual void instanceConstants(int sample_rate, " << subst("int* iZone, $0* fZone) {", ifloat());
958 tab(n + 2, *fOut);
959 fCodeProducer->Tab(n + 2);
960 generateInit(fCodeProducer);
961 back(1, *fOut);
962 *fOut << "}";
963 tab(n + 1, *fOut);
964
965 tab(n + 1, *fOut);
966 *fOut << "virtual void instanceResetUserInterface() {";
967 tab(n + 2, *fOut);
968 fCodeProducer->Tab(n + 2);
969 generateResetUserInterface(fCodeProducer);
970 back(1, *fOut);
971 *fOut << "}";
972 tab(n + 1, *fOut);
973
974 tab(n + 1, *fOut);
975 *fOut << "virtual void instanceClear(" << subst("int* iZone, $0* fZone) {", ifloat());
976 tab(n + 2, *fOut);
977 fCodeProducer->Tab(n + 2);
978 generateClear(fCodeProducer);
979 back(1, *fOut);
980 *fOut << "}";
981 tab(n + 1, *fOut);
982
983 // Init
984 if (gGlobal->gMemoryManager) {
985 tab(n + 1, *fOut);
986 *fOut << "virtual void init(int sample_rate, " << subst("int* iZone, $0* fZone) {", ifloat());
987 } else {
988 tab(n + 1, *fOut);
989 *fOut << "virtual void init(int sample_rate, " << subst("int* iZone, $0* fZone) {", ifloat());
990 tab(n + 2, *fOut);
991 *fOut << "instanceInit(sample_rate, iZone, fZone);";
992 tab(n + 1, *fOut);
993 *fOut << "}";
994 }
995 tab(n + 1, *fOut);
996
997 tab(n + 1, *fOut);
998 *fOut << "virtual void instanceInit(int sample_rate, " << subst("int* iZone, $0* fZone) {", ifloat());
999 // staticInit has to be called for each instance since the tables are actually not shared between instances
1000 tab(n + 2, *fOut);
1001 *fOut << "staticInit(sample_rate, iZone, fZone);";
1002 tab(n + 2, *fOut);
1003 *fOut << "instanceConstants(sample_rate, iZone, fZone);";
1004 tab(n + 2, *fOut);
1005 *fOut << "instanceResetUserInterface();";
1006 tab(n + 2, *fOut);
1007 *fOut << "instanceClear(iZone, fZone);";
1008 tab(n + 1, *fOut);
1009 *fOut << "}";
1010 tab(n + 1, *fOut);
1011
1012 tab(n + 1, *fOut);
1013 *fOut << "virtual " << fKlassName << "* clone() {";
1014 tab(n + 2, *fOut);
1015 *fOut << "return new " << fKlassName << "();";
1016 tab(n + 1, *fOut);
1017 *fOut << "}";
1018
1019 tab(n + 1, *fOut);
1020 fCodeProducer->Tab(n + 1);
1021 tab(n + 1, *fOut);
1022 generateGetSampleRate("getSampleRate", "dsp", true, true)->accept(fCodeProducer);
1023
1024 // User interface
1025 tab(n + 1, *fOut);
1026 *fOut << "virtual void buildUserInterface(UI* ui_interface) {";
1027 tab(n + 2, *fOut);
1028 fCodeProducer->Tab(n + 2);
1029 generateUserInterface(fCodeProducer);
1030 back(1, *fOut);
1031 *fOut << "}";
1032 tab(n + 1, *fOut);
1033
1034 tab(n + 1, *fOut);
1035 *fOut << subst("virtual void control(int* RESTRICT iControl, $0* RESTRICT fControl, int* RESTRICT iZone, $1* RESTRICT fZone) {", xfloat(), ifloat());
1036 tab(n + 2, *fOut);
1037 fCodeProducer->Tab(n + 2);
1038 // Generates local variables declaration and setup
1039 generateComputeBlock(fCodeProducer);
1040 back(1, *fOut);
1041 *fOut << "}" << endl;
1042
1043 tab(n + 1, *fOut);
1044 *fOut << "virtual int getNumIntControls() { return " << fInt32ControlNum << "; }";
1045 tab(n + 1, *fOut);
1046
1047 *fOut << "virtual int getNumRealControls() { return " << fRealControlNum << "; }";
1048 tab(n + 1, *fOut);
1049
1050 tab(n + 1, *fOut);
1051 *fOut << "virtual int getiZoneSize() { return " << int_zone_size << "; }";
1052
1053 tab(n + 1, *fOut);
1054 *fOut << "virtual int getfZoneSize() { return " << real_zone_size << "; }";
1055
1056 // Compute
1057 generateCompute(n);
1058 tab(n, *fOut);
1059 tab(n, *fOut);
1060 *fOut << "};" << endl;
1061
1062 tab(n, *fOut);
1063 *fOut << "#define FAUST_INT_CONTROLS " << fInt32ControlNum << endl;
1064 *fOut << "#define FAUST_REAL_CONTROLS " << fRealControlNum << endl;
1065
1066 tab(n, *fOut);
1067 *fOut << "#define FAUST_INT_ZONE " << int_zone_size << endl;
1068 *fOut << "#define FAUST_FLOAT_ZONE " << real_zone_size;
1069 tab(n, *fOut);
1070
1071 // To improve (generalization for all backends...)
1072 if (gGlobal->gMemoryManager) {
1073 tab(n, *fOut);
1074 *fOut << "dsp_memory_manager* " << fKlassName << "::fManager = 0;" << endl;
1075 }
1076
1077 // Generate user interface macros if needed
1078 printMacros(*fOut, n);
1079
1080 if (gGlobal->gNameSpace != "" && gGlobal->gArchFile == "") {
1081 tab(n, *fOut);
1082 *fOut << "} // namespace " << gGlobal->gNameSpace << endl;
1083 }
1084 }
1085
generateCompute(int n)1086 void CPPScalarCodeContainer::generateCompute(int n)
1087 {
1088 // Generates declaration
1089 tab(n + 1, *fOut);
1090 tab(n + 1, *fOut);
1091 *fOut << subst("virtual void compute(int $0, $1** inputs, $1** outputs) {", fFullCount, xfloat());
1092 tab(n + 2, *fOut);
1093 fCodeProducer->Tab(n + 2);
1094
1095 // Generates local variables declaration and setup
1096 generateComputeBlock(fCodeProducer);
1097
1098 // Generates one single scalar loop
1099 ForLoopInst* loop = fCurLoop->generateScalarLoop(fFullCount);
1100 loop->accept(fCodeProducer);
1101
1102 /*
1103 // TODO : atomic switch
1104 // Currently for soundfile management
1105 */
1106 generatePostComputeBlock(fCodeProducer);
1107
1108 back(1, *fOut);
1109 *fOut << "}";
1110 }
1111
1112 // Used with -os0 option
generateCompute(int n)1113 void CPPScalarOneSampleCodeContainer1::generateCompute(int n)
1114 {
1115 // Generates declaration
1116 tab(n + 1, *fOut);
1117 tab(n + 1, *fOut);
1118 if (gGlobal->gInPlace) {
1119 *fOut << subst("virtual void compute($0* inputs, $0* outputs, int* RESTRICT iControl, $0* RESTRICT fControl) {", xfloat());
1120 } else {
1121 *fOut << subst("virtual void compute($0* RESTRICT inputs, $0* RESTRICT outputs, int* RESTRICT iControl, $0* RESTRICT fControl) {", xfloat());
1122 }
1123 tab(n + 2, *fOut);
1124 fCodeProducer->Tab(n + 2);
1125
1126 // Generates one sample computation
1127 BlockInst* block = fCurLoop->generateOneSample();
1128 block->accept(fCodeProducer);
1129
1130 /*
1131 // TODO : atomic switch
1132 // Currently for soundfile management
1133 */
1134 generatePostComputeBlock(fCodeProducer);
1135
1136 back(1, *fOut);
1137 *fOut << "}";
1138 }
1139
1140 // Used with -os1 option
generateCompute(int n)1141 void CPPScalarOneSampleCodeContainer2::generateCompute(int n)
1142 {
1143 // Generates declaration
1144 tab(n + 1, *fOut);
1145 tab(n + 1, *fOut);
1146 if (gGlobal->gInPlace) {
1147 *fOut << subst("virtual void compute($0* inputs, $0* outputs, int* RESTRICT iControl, $0* RESTRICT fControl, int* RESTRICT iZone, $1* RESTRICT fZone) {", xfloat(), ifloat());
1148 } else {
1149 *fOut << subst("virtual void compute($0* RESTRICT inputs, $0* RESTRICT outputs, int* RESTRICT iControl, $0* RESTRICT fControl, int* RESTRICT iZone, $1* RESTRICT fZone) {", xfloat(), ifloat());
1150 }
1151 tab(n + 2, *fOut);
1152 fCodeProducer->Tab(n + 2);
1153
1154 // Generates one sample computation
1155 BlockInst* block = fCurLoop->generateOneSample();
1156 block->accept(fCodeProducer);
1157
1158 /*
1159 // TODO : atomic switch
1160 // Currently for soundfile management
1161 */
1162 generatePostComputeBlock(fCodeProducer);
1163
1164 back(1, *fOut);
1165 *fOut << "}";
1166 }
1167
1168 // Vector
CPPVectorCodeContainer(const string & name,const string & super,int numInputs,int numOutputs,std::ostream * out)1169 CPPVectorCodeContainer::CPPVectorCodeContainer(const string& name, const string& super, int numInputs, int numOutputs,
1170 std::ostream* out)
1171 : VectorCodeContainer(numInputs, numOutputs), CPPCodeContainer(name, super, numInputs, numOutputs, out)
1172 {
1173 }
1174
generateCompute(int n)1175 void CPPVectorCodeContainer::generateCompute(int n)
1176 {
1177 // Possibly generate separated functions
1178 fCodeProducer->Tab(n + 1);
1179 tab(n + 1, *fOut);
1180 generateComputeFunctions(fCodeProducer);
1181
1182 // Generates declaration
1183 tab(n + 1, *fOut);
1184 *fOut << subst("virtual void compute(int $0, $1** inputs, $1** outputs) {", fFullCount, xfloat());
1185 tab(n + 2, *fOut);
1186 fCodeProducer->Tab(n + 2);
1187
1188 // Generates local variables declaration and setup
1189 generateComputeBlock(fCodeProducer);
1190
1191 // Generates the DSP loop
1192 fDAGBlock->accept(fCodeProducer);
1193
1194 back(1, *fOut);
1195 *fOut << "}";
1196 }
1197
1198 // OpenMP
CPPOpenMPCodeContainer(const string & name,const string & super,int numInputs,int numOutputs,std::ostream * out)1199 CPPOpenMPCodeContainer::CPPOpenMPCodeContainer(const string& name, const string& super, int numInputs, int numOutputs,
1200 std::ostream* out)
1201 : OpenMPCodeContainer(numInputs, numOutputs), CPPCodeContainer(name, super, numInputs, numOutputs, out)
1202 {
1203 }
1204
generateCompute(int n)1205 void CPPOpenMPCodeContainer::generateCompute(int n)
1206 {
1207 // Possibly generate separated functions
1208 fCodeProducer->Tab(n + 1);
1209 tab(n + 1, *fOut);
1210 generateComputeFunctions(fCodeProducer);
1211
1212 // Generates declaration
1213 tab(n + 1, *fOut);
1214 *fOut << subst("virtual void compute(int $0, $1** inputs, $1** outputs) {", fFullCount, xfloat());
1215 tab(n + 2, *fOut);
1216 fCodeProducer->Tab(n + 2);
1217
1218 // Generates local variables declaration and setup
1219 generateComputeBlock(fCodeProducer);
1220
1221 // Generate DSP loop
1222 fGlobalLoopBlock->accept(fCodeProducer);
1223
1224 back(1, *fOut);
1225 *fOut << "}";
1226 }
1227
1228 // Works stealing scheduler
CPPWorkStealingCodeContainer(const string & name,const string & super,int numInputs,int numOutputs,std::ostream * out)1229 CPPWorkStealingCodeContainer::CPPWorkStealingCodeContainer(const string& name, const string& super, int numInputs,
1230 int numOutputs, std::ostream* out)
1231 : WSSCodeContainer(numInputs, numOutputs, "this"), CPPCodeContainer(name, super, numInputs, numOutputs, out)
1232 {
1233 }
1234
produceClass()1235 void CPPWorkStealingCodeContainer::produceClass()
1236 {
1237 int n = 0;
1238
1239 // Inherited method
1240 CPPCodeContainer::produceClass();
1241
1242 tab(n, *fOut);
1243 *fOut << "extern \"C\" void computeThreadExternal(void* dsp, int num_thread) {";
1244 tab(n + 1, *fOut);
1245 *fOut << "static_cast<" << fKlassName << "*>(dsp)->computeThread" << fKlassName << "(num_thread);";
1246 tab(n, *fOut);
1247 *fOut << "}" << endl;
1248 }
1249
generateCompute(int n)1250 void CPPWorkStealingCodeContainer::generateCompute(int n)
1251 {
1252 // Possibly generate separated functions
1253 fCodeProducer->Tab(n + 1);
1254 tab(n + 1, *fOut);
1255 generateComputeFunctions(fCodeProducer);
1256
1257 // Generates declaration
1258 tab(n + 1, *fOut);
1259 *fOut << subst("virtual void compute(int $0, $1** inputs, $1** outputs) {", fFullCount, xfloat());
1260 tab(n + 2, *fOut);
1261 fCodeProducer->Tab(n + 2);
1262
1263 // Generates local variables declaration and setup
1264 generateComputeBlock(fCodeProducer);
1265
1266 //tab(n + 1, *fOut);
1267 back(1, *fOut);
1268 *fOut << "}" << endl;
1269
1270 // Generates "computeThread" code
1271 tab(n + 1, *fOut);
1272 *fOut << "void computeThread" << fKlassName << "(int num_thread) {";
1273 tab(n + 2, *fOut);
1274 fCodeProducer->Tab(n + 2);
1275
1276 // Generate it
1277 faustassert(fThreadLoopBlock);
1278 fThreadLoopBlock->accept(fCodeProducer);
1279
1280 back(1, *fOut);
1281 *fOut << "}";
1282 }
1283