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