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 <fstream>
23 #include <string>
24 
25 #include "code_container.hh"
26 #include "fir_to_fir.hh"
27 #include "floats.hh"
28 #include "global.hh"
29 #include "recursivness.hh"
30 #include "text_instructions.hh"
31 #include "type_manager.hh"
32 
33 using namespace std;
34 
initialize(int numInputs,int numOutputs)35 void CodeContainer::initialize(int numInputs, int numOutputs)
36 {
37     fNumInputs  = numInputs;
38     fNumOutputs = numOutputs;
39 }
40 
CodeContainer()41 CodeContainer::CodeContainer()
42     : fParentContainer(0),
43       fNumInputs(-1),
44       fNumOutputs(-1),
45       fNumActives(0),
46       fNumPassives(0),
47       fSubContainerType(kInt),
48       fGeneratedSR(false),
49       fExtGlobalDeclarationInstructions(InstBuilder::genBlockInst()),
50       fGlobalDeclarationInstructions(InstBuilder::genBlockInst()),
51       fDeclarationInstructions(InstBuilder::genBlockInst()),
52       fInitInstructions(InstBuilder::genBlockInst()),
53       fResetUserInterfaceInstructions(InstBuilder::genBlockInst()),
54       fClearInstructions(InstBuilder::genBlockInst()),
55       fPostInitInstructions(InstBuilder::genBlockInst()),
56       fAllocateInstructions(InstBuilder::genBlockInst()),
57       fDestroyInstructions(InstBuilder::genBlockInst()),
58       fStaticInitInstructions(InstBuilder::genBlockInst()),
59       fPostStaticInitInstructions(InstBuilder::genBlockInst()),
60       fStaticDestroyInstructions(InstBuilder::genBlockInst()),
61       fComputeBlockInstructions(InstBuilder::genBlockInst()),
62       fPostComputeBlockInstructions(InstBuilder::genBlockInst()),
63       fComputeFunctions(InstBuilder::genBlockInst()),
64       fUserInterfaceInstructions(InstBuilder::genBlockInst()),
65       fInt32ControlNum(0),
66       fRealControlNum(0)
67 {
68     fCurLoop = new CodeLoop(0, gGlobal->getFreshID("i"));
69 }
70 
~CodeContainer()71 CodeContainer::~CodeContainer()
72 {}
73 
transformDAG(DispatchVisitor * visitor)74 void CodeContainer::transformDAG(DispatchVisitor* visitor)
75 {
76     lclgraph G;
77     CodeLoop::sortGraph(fCurLoop, G);
78     for (int l = int(G.size() - 1); l >= 0; l--) {
79         for (const auto& p : G[l]) {
80             p->transform(visitor);
81         }
82     }
83 }
84 
85 /**
86  * Store the loop used to compute a signal
87  */
setLoopProperty(Tree sig,CodeLoop * l)88 void CodeContainer::setLoopProperty(Tree sig, CodeLoop* l)
89 {
90     fLoopProperty.set(sig, l);
91 }
92 
93 /**
94  * Returns the loop used to compute a signal
95  */
getLoopProperty(Tree sig,CodeLoop * & l)96 bool CodeContainer::getLoopProperty(Tree sig, CodeLoop*& l)
97 {
98     faustassert(sig);
99     return fLoopProperty.get(sig, l);
100 }
101 
listAllLoopProperties(Tree sig,set<CodeLoop * > & L,set<Tree> & visited)102 void CodeContainer::listAllLoopProperties(Tree sig, set<CodeLoop*>& L, set<Tree>& visited)
103 {
104     if (visited.count(sig) == 0) {
105         visited.insert(sig);
106         CodeLoop* l;
107         if (getLoopProperty(sig, l)) {
108             L.insert(l);
109         } else {
110             // we go down the expression
111             vector<Tree> subsigs;
112             int          n = getSubSignals(sig, subsigs, false);
113             for (int i = 0; i < n; i++) {
114                 listAllLoopProperties(subsigs[i], L, visited);
115             }
116         }
117     }
118 }
119 
120 /**
121  * Open a non-recursive loop on top of the stack of open loops.
122  * @param size the number of iterations of the loop
123  */
openLoop(const string & index_name,int size)124 void CodeContainer::openLoop(const string& index_name, int size)
125 {
126     fCurLoop = new CodeLoop(fCurLoop, index_name, size);
127 }
128 
129 /**
130  * Open a recursive loop on top of the stack of open loops.
131  * @param recsymbol the recursive symbol defined in this loop
132  * @param size the number of iterations of the loop
133  */
openLoop(Tree recsymbol,const string & index_name,int size)134 void CodeContainer::openLoop(Tree recsymbol, const string& index_name, int size)
135 {
136     fCurLoop = new CodeLoop(recsymbol, fCurLoop, index_name, size);
137 }
138 
139 /**
140  * Close the top loop and either keep it
141  * or absorb it within its enclosing loop.
142  */
closeLoop(Tree sig)143 void CodeContainer::closeLoop(Tree sig)
144 {
145     faustassert(fCurLoop);
146 
147     // fix the missing dependencies
148     set<CodeLoop*> L;
149     set<Tree> V;
150     listAllLoopProperties(sig, L, V);
151     for (CodeLoop* l : L) {
152         fCurLoop->fBackwardLoopDependencies.insert(l);
153     }
154 
155     CodeLoop* l = fCurLoop;
156     fCurLoop    = l->fEnclosingLoop;
157     faustassert(fCurLoop);
158 
159     Tree S = symlist(sig);
160     if (l->isEmpty() || fCurLoop->hasRecDependencyIn(S)) {
161         fCurLoop->absorb(l);
162     } else {
163         // cout << " will NOT absorb" << endl;
164         // we have an independent loop
165         setLoopProperty(sig, l);  // associate the signal
166         fCurLoop->fBackwardLoopDependencies.insert(l);
167         // we need to indicate that all recursive symbols defined
168         // in this loop are defined in this loop
169         for (Tree lsym = l->fRecSymbolSet; !isNil(lsym); lsym = tl(lsym)) {
170             this->setLoopProperty(hd(lsym), l);
171             // cerr << "loop " << l << " defines " << *hd(lsym) << endl;
172         }
173     }
174 }
175 
176 /**
177  * Print the required C++ libraries as comments in source code
178  */
printLibrary(ostream & fout)179 void CodeContainer::printLibrary(ostream& fout)
180 {
181     set<string>           S;
182     set<string>::iterator f;
183 
184     string sep;
185     collectLibrary(S);
186     if (S.size() > 0) {
187         fout << "/* link with ";
188         for (f = S.begin(), sep = ": "; f != S.end(); f++, sep = ", ") {
189             fout << sep << *f;
190         }
191         fout << " */\n";
192     }
193 }
194 
195 /**
196  * Print the required include files
197  */
printIncludeFile(ostream & fout)198 void CodeContainer::printIncludeFile(ostream& fout)
199 {
200     set<string>           S;
201     set<string>::iterator f;
202 
203     collectIncludeFile(S);
204     for (f = S.begin(); f != S.end(); f++) {
205         string inc = *f;
206         // Only print non-empty include (inc is actually quoted)
207         if (inc.size() > 2) {
208             fout << "#include " << *f << "\n";
209         }
210     }
211 }
212 
213 /**
214  * Print the loop graph in dot format
215  */
printGraphDotFormat(ostream & fout)216 void CodeContainer::printGraphDotFormat(ostream& fout)
217 {
218     lclgraph G;
219     CodeLoop::sortGraph(fCurLoop, G);
220 
221     fout << "strict digraph loopgraph {" << endl;
222     fout << '\t' << "rankdir=LR;" << endl;
223     fout << '\t' << "node[color=blue, fillcolor=lightblue, style=filled, fontsize=9];" << endl;
224 
225     int lnum = 0;  // used for loop numbers
226     // for each level of the graph
227     for (int l = int(G.size() - 1); l >= 0; l--) {
228         // for each task in the level
229         for (const auto& t : G[l]) {
230             // print task label "Lxxx : 0xffffff"
231             fout << '\t' << 'L' << t << "[label=<<font face=\"verdana,bold\">L"
232                  << lnum++ << "</font> : " << t
233                  << ">];" << endl;
234             // for each source of the task
235             for (const auto& src : t->fBackwardLoopDependencies) {
236                 // print the connection Lxxx -> Lyyy;
237                 fout << '\t' << 'L' << src << "->" << 'L' << t << ';' << endl;
238             }
239         }
240     }
241     fout << "}" << endl;
242 }
243 
244 /**
245  *  Adds forward dependencies in the DAG and returns loop count
246  */
computeForwardDAG(lclgraph dag,int & loop_count,vector<int> & ready_loop)247 void CodeContainer::computeForwardDAG(lclgraph dag, int& loop_count, vector<int>& ready_loop)
248 {
249 #define START_TASK_MAX 2
250 
251     int loop_index = START_TASK_MAX;  // First index to be used for remaining tasks
252 
253     for (int l = int(dag.size() - 1); l >= 0; l--) {
254         for (const auto& p : dag[l]) {
255             // Setup forward dependancy
256             for (const auto& p1 : p->fBackwardLoopDependencies) {
257                 p1->fForwardLoopDependencies.insert(p);
258             }
259 
260             // Setup loop index
261             p->fIndex = loop_index;
262             loop_index++;
263 
264             // Keep ready loops
265             if (p->getBackwardLoopDependencies().size() == 0) {
266                 ready_loop.push_back(p->getIndex());
267             }
268         }
269     }
270 
271     loop_count = loop_index;
272 }
273 
pushFunction(const string & name,Typed::VarType result,vector<Typed::VarType> & types,const list<ValueInst * > & args)274 ValueInst* CodeContainer::pushFunction(const string& name, Typed::VarType result, vector<Typed::VarType>& types,
275                                        const list<ValueInst*>& args)
276 {
277     list<NamedTyped*> named_args;
278     for (size_t i = 0; i < types.size(); i++) {
279         named_args.push_back(InstBuilder::genNamedTyped("dummy" + to_string(i), InstBuilder::genBasicTyped(types[i])));
280     }
281     pushGlobalDeclare(InstBuilder::genDeclareFunInst(name, InstBuilder::genFunTyped(named_args, InstBuilder::genBasicTyped(result))));
282     return InstBuilder::genFunCallInst(name, args);
283 }
284 
sortDeepFirstDAG(CodeLoop * l,set<CodeLoop * > & visited,list<CodeLoop * > & result)285 void CodeContainer::sortDeepFirstDAG(CodeLoop* l, set<CodeLoop*>& visited, list<CodeLoop*>& result)
286 {
287     // Avoid printing already printed loops
288     if (isElement(visited, l)) return;
289 
290     // Remember we have printed this loop
291     visited.insert(l);
292 
293     // Compute the dependencies loops (that need to be computed before this one)
294     for (const auto& p : l->fBackwardLoopDependencies) {
295         sortDeepFirstDAG(p, visited, result);
296     }
297 
298     // Keep the non-empty loops in result
299     if (!l->isEmpty()) {
300         result.push_back(l);
301     }
302 }
303 
304 // Functions are coded with a "class" prefix, so to stay separated in "gGlobalTable"
produceInfoFunctions(int tabs,const string & classname,const string & obj,bool ismethod,bool isvirtual,TextInstVisitor * producer)305 void CodeContainer::produceInfoFunctions(int tabs, const string& classname, const string& obj, bool ismethod,
306                                          bool isvirtual, TextInstVisitor* producer)
307 {
308     // Input/Output method
309     producer->Tab(tabs);
310     generateGetInputs(subst("getNumInputs$0", classname), obj, ismethod, isvirtual)->accept(producer);
311     generateGetOutputs(subst("getNumOutputs$0", classname), obj, ismethod, isvirtual)->accept(producer);
312 }
313 
generateDAGLoopInternal(CodeLoop * loop,BlockInst * block,DeclareVarInst * count,bool omp)314 void CodeContainer::generateDAGLoopInternal(CodeLoop* loop, BlockInst* block, DeclareVarInst* count, bool omp)
315 {
316     loop->generateDAGScalarLoop(block, count, omp);
317 }
318 
generateDAGLoopAux(CodeLoop * loop,BlockInst * loop_code,DeclareVarInst * count,int loop_num,bool omp)319 void CodeContainer::generateDAGLoopAux(CodeLoop* loop, BlockInst* loop_code, DeclareVarInst* count, int loop_num,
320                                        bool omp)
321 {
322     if (gGlobal->gFunTaskSwitch) {
323         BlockInst* block = InstBuilder::genBlockInst();
324         // Generates scalar or vectorized loop
325         generateDAGLoopInternal(loop, block, count, omp);
326         Loop2FunctionBuider builder(subst("fun$0" + getClassName(), T(loop_num)), block, gGlobal->gDSPStruct);
327         pushOtherComputeMethod(builder.fFunctionDef);
328         loop_code->pushBackInst(InstBuilder::genLabelInst((loop->fIsRecursive)
329                                                               ? subst("/* Recursive function $0 */", T(loop_num))
330                                                               : subst("/* Vectorizable function $0 */", T(loop_num))));
331         loop_code->pushBackInst(builder.fFunctionCall);
332     } else {
333         loop_code->pushBackInst(InstBuilder::genLabelInst((loop->fIsRecursive)
334                                                               ? subst("/* Recursive loop $0 */", T(loop_num))
335                                                               : subst("/* Vectorizable loop $0 */", T(loop_num))));
336         // Generates scalar or vectorized loop
337         generateDAGLoopInternal(loop, loop_code, count, omp);
338     }
339 }
340 
generateDAGLoop(BlockInst * block,DeclareVarInst * count)341 void CodeContainer::generateDAGLoop(BlockInst* block, DeclareVarInst* count)
342 {
343     int loop_num = 0;
344 
345     if (gGlobal->gDeepFirstSwitch) {
346         set<CodeLoop*>  visited;
347         list<CodeLoop*> result;
348         sortDeepFirstDAG(fCurLoop, visited, result);
349         for (const auto& p : result) {
350             generateDAGLoopAux(p, block, count, loop_num++);
351         }
352     } else {
353         lclgraph G;
354         CodeLoop::sortGraph(fCurLoop, G);
355         for (int l = int(G.size() - 1); l >= 0; l--) {
356             for (const auto& p : G[l]) {
357                 generateDAGLoopAux(p, block, count, loop_num++);
358             }
359         }
360     }
361 }
362 
processFIR(void)363 void CodeContainer::processFIR(void)
364 {
365     // Types used in 'compute' prototype
366     gGlobal->setVarType("count", Typed::kInt32);
367     gGlobal->setVarType("inputs", Typed::kFloatMacro_ptr_ptr);
368     gGlobal->setVarType("outputs", Typed::kFloatMacro_ptr_ptr);
369 
370     // Types used in 'compute' prototype in -os mode
371     gGlobal->setVarType("iControl", Typed::kInt32_ptr);
372     gGlobal->setVarType("fControl", Typed::kFloatMacro_ptr);
373 
374     // Possibly add "fSamplingRate" field
375     generateSR();
376 
377     // Possibly groups tasks (used by VectorCodeContainer, OpenMPCodeContainer and WSSCodeContainer)
378     if (gGlobal->gGroupTaskSwitch) {
379         CodeLoop::computeUseCount(fCurLoop);
380         set<CodeLoop*> visited;
381         CodeLoop::groupSeqLoops(fCurLoop, visited);
382     }
383 
384     // Sort struct fields by size and type
385     // 05/16/17 : deactivated since it slows down the code...
386     /*
387      fDeclarationInstructions->fCode.sort(sortArrayDeclarations);
388      fDeclarationInstructions->fCode.sort(sortTypeDeclarations);
389      */
390 }
391 
flattenFIR(void)392 BlockInst* CodeContainer::flattenFIR(void)
393 {
394     BlockInst* global_block = InstBuilder::genBlockInst();
395 
396     // Declaration part
397     global_block->pushBackInst(InstBuilder::genLabelInst("========== Declaration part =========="));
398     global_block->merge(fExtGlobalDeclarationInstructions);
399     global_block->merge(fGlobalDeclarationInstructions);
400     global_block->merge(fDeclarationInstructions);
401 
402     // Init method
403     global_block->pushBackInst(InstBuilder::genLabelInst("========== Init method =========="));
404     global_block->merge(fInitInstructions);
405     global_block->merge(fResetUserInterfaceInstructions);
406     global_block->merge(fClearInstructions);
407     global_block->merge(fPostInitInstructions);
408 
409     // Static init method
410     global_block->pushBackInst(InstBuilder::genLabelInst("========== Static init method =========="));
411     global_block->merge(fStaticInitInstructions);
412     global_block->merge(fPostStaticInitInstructions);
413 
414     // Subcontainers
415     global_block->pushBackInst(InstBuilder::genLabelInst("========== Subcontainers =========="));
416     for (const auto& it : fSubContainers) {
417         global_block->merge(it->flattenFIR());
418     }
419 
420     // Compute method
421     global_block->pushBackInst(InstBuilder::genLabelInst("========== Compute control =========="));
422     global_block->merge(fComputeBlockInstructions);
423     global_block->pushBackInst(InstBuilder::genLabelInst("========== Compute DSP =========="));
424     global_block->pushBackInst(fCurLoop->generateScalarLoop(fFullCount));
425     global_block->pushBackInst(InstBuilder::genLabelInst("========== Post compute DSP =========="));
426     global_block->merge(fPostComputeBlockInstructions);
427 
428     return global_block;
429 }
430 
inlineSubcontainersFunCalls(BlockInst * block)431 BlockInst* CodeContainer::inlineSubcontainersFunCalls(BlockInst* block)
432 {
433     // Rename 'sig' in 'dsp' and remove 'dsp' allocation
434     block = DspRenamer().getCode(block);
435     //dump2FIR(block);
436 
437     // Inline subcontainers 'instanceInit' and 'fill' function call
438     for (const auto& it : fSubContainers) {
439         // Build the function to be inlined (prototype and code)
440         DeclareFunInst* inst_init_fun = it->generateInstanceInitFun("instanceInit" + it->getClassName(), "dsp", true, false);
441         //dump2FIR(inst_init_fun);
442         block = FunctionCallInliner(inst_init_fun).getCode(block);
443         //dump2FIR(block);
444 
445         // Build the function to be inlined (prototype and code)
446         DeclareFunInst* fill_fun = it->generateFillFun("fill" + it->getClassName(), "dsp", true, false);
447         //dump2FIR(fill_fun);
448         block = FunctionCallInliner(fill_fun).getCode(block);
449         //dump2FIR(block);
450     }
451     // dump2FIR(block);
452 
453     // Rename all loop variables name to avoid name clash
454     LoopVariableRenamer loop_renamer;
455     block = loop_renamer.getCode(block);
456     return block;
457 }
458 
printMacros(ostream & fout,int n)459 void CodeContainer::printMacros(ostream& fout, int n)
460 {
461     // generate user interface macros if needed
462     if (gGlobal->gUIMacroSwitch) {
463         if (gGlobal->gOutputLang == "c" || gGlobal->gOutputLang == "cpp") {
464             tab(n, fout);
465             fout << "#ifdef FAUST_UIMACROS";
466             tab(n + 1, fout);
467             tab(n + 1, fout);
468             for (const auto& it : gGlobal->gMetaDataSet) {
469                 if (it.first == tree("filename")) {
470                     fout << "#define FAUST_FILE_NAME " << **(it.second.begin());
471                     break;
472                 }
473             }
474             tab(n + 1, fout);
475             fout << "#define FAUST_CLASS_NAME " << "\"" << fKlassName << "\"";
476             tab(n + 1, fout);
477             fout << "#define FAUST_INPUTS " << fNumInputs;
478             tab(n + 1, fout);
479             fout << "#define FAUST_OUTPUTS " << fNumOutputs;
480             tab(n + 1, fout);
481             fout << "#define FAUST_ACTIVES " << fNumActives;
482             tab(n + 1, fout);
483             fout << "#define FAUST_PASSIVES " << fNumPassives;
484             tab(n, fout);
485             printlines(n + 1, fUIMacro, fout);
486             tab(n, fout);
487             tab(n, fout);
488             {
489                 fout << "\t" << "#define FAUST_LIST_ACTIVES(p) \\";
490                 printlines(n + 2, fUIMacroActives, fout);
491                 tab(n, fout);
492                 tab(n, fout);
493             }
494             {
495                 fout << "\t" << "#define FAUST_LIST_PASSIVES(p) \\";
496                 printlines(n + 2, fUIMacroPassives, fout);
497                 tab(n, fout);
498                 tab(n, fout);
499             }
500             fout << "#endif" << endl;
501         } else if (gGlobal->gOutputLang == "rust") {
502             fout << "pub const FAUST_INPUTS: i32 = " << fNumInputs << ";";
503             tab(n, fout);
504             fout << "pub const FAUST_OUTPUTS: i32 = " << fNumOutputs << ";";
505             tab(n, fout);
506             fout << "pub const FAUST_ACTIVES: i32 = " << fNumActives << ";";
507             tab(n, fout);
508             fout << "pub const FAUST_PASSIVES: i32 = " << fNumPassives << ";";
509             tab(n, fout);
510         } else {
511             faustassert(false);
512         }
513     }
514 }
515 
516 // DSP API generation
517 
generateGetIO(const string & name,const string & obj,int io,bool ismethod,bool isvirtual)518 DeclareFunInst* CodeContainer::generateGetIO(const string& name, const string& obj, int io, bool ismethod,
519                                              bool isvirtual)
520 {
521     list<NamedTyped*> args;
522     if (!ismethod) {
523         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
524     }
525     BlockInst* block = InstBuilder::genBlockInst();
526     block->pushBackInst(InstBuilder::genRetInst(InstBuilder::genInt32NumInst(io)));
527 
528     // Creates function
529     FunTyped* fun_type = InstBuilder::genFunTyped(args, InstBuilder::genInt32Typed(),
530                                                   (isvirtual) ? FunTyped::kVirtual : FunTyped::kDefault);
531     return InstBuilder::genDeclareFunInst(name, fun_type, block);
532 }
533 
generateGetInputs(const string & name,const string & obj,bool ismethod,bool isvirtual)534 DeclareFunInst* CodeContainer::generateGetInputs(const string& name, const string& obj, bool ismethod, bool isvirtual)
535 {
536     return generateGetIO(name, obj, fNumInputs, ismethod, isvirtual);
537 }
538 
generateGetOutputs(const string & name,const string & obj,bool ismethod,bool isvirtual)539 DeclareFunInst* CodeContainer::generateGetOutputs(const string& name, const string& obj, bool ismethod, bool isvirtual)
540 {
541     return generateGetIO(name, obj, fNumOutputs, ismethod, isvirtual);
542 }
543 
generateAllocate(const string & name,const string & obj,bool ismethod,bool isvirtual)544 DeclareFunInst* CodeContainer::generateAllocate(const string& name, const string& obj, bool ismethod, bool isvirtual)
545 {
546     list<NamedTyped*> args;
547     if (!ismethod) {
548         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
549     }
550 
551     BlockInst* block = InstBuilder::genBlockInst();
552     block->pushBackInst(fAllocateInstructions);
553 
554     // Explicit return
555     block->pushBackInst(InstBuilder::genRetInst());
556 
557     // Creates function
558     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
559 }
560 
generateDestroy(const string & name,const string & obj,bool ismethod,bool isvirtual)561 DeclareFunInst* CodeContainer::generateDestroy(const string& name, const string& obj, bool ismethod, bool isvirtual)
562 {
563     list<NamedTyped*> args;
564     if (!ismethod) {
565         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
566     }
567 
568     BlockInst* block = InstBuilder::genBlockInst();
569     block->pushBackInst(fDestroyInstructions);
570 
571     // Explicit return
572     block->pushBackInst(InstBuilder::genRetInst());
573 
574     // Creates function
575     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
576 }
577 
generateGetIORate(const string & name,const string & obj,vector<int> & io,bool ismethod,bool isvirtual)578 DeclareFunInst* CodeContainer::generateGetIORate(const string& name, const string& obj, vector<int>& io, bool ismethod,
579                                                  bool isvirtual)
580 {
581     list<NamedTyped*> args;
582     if (!ismethod) {
583         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
584     }
585     args.push_back(InstBuilder::genNamedTyped("channel", Typed::kInt32));
586 
587     BlockInst*    block        = InstBuilder::genBlockInst();
588     ValueInst*    switch_cond  = InstBuilder::genLoadFunArgsVar("channel");
589     ::SwitchInst* switch_block = InstBuilder::genSwitchInst(switch_cond);
590     block->pushBackInst(InstBuilder::genDecStackVar("rate", InstBuilder::genInt32Typed()));
591     block->pushBackInst(switch_block);
592 
593     int i = 0;
594     for (const auto& it : io) {
595         // Creates "case" block
596         BlockInst* case_block = InstBuilder::genBlockInst();
597         // Compiles "case" block
598         case_block->pushBackInst(InstBuilder::genStoreStackVar("rate", InstBuilder::genInt32NumInst(it)));
599         // Add it into the switch
600         switch_block->addCase(i++, case_block);
601     }
602 
603     // Default case
604     BlockInst* default_case_block = InstBuilder::genBlockInst();
605     default_case_block->pushBackInst(InstBuilder::genStoreStackVar("rate", InstBuilder::genInt32NumInst(-1)));
606     switch_block->addCase(-1, default_case_block);
607 
608     // Return "rate" result
609     block->pushBackInst(InstBuilder::genRetInst(InstBuilder::genLoadStackVar("rate")));
610 
611     // Creates function
612     FunTyped* fun_type = InstBuilder::genFunTyped(args, InstBuilder::genInt32Typed(),
613                                                   (isvirtual) ? FunTyped::kVirtual : FunTyped::kDefault);
614     return InstBuilder::genDeclareFunInst(name, fun_type, block);
615 }
616 
generateInstanceClear(const string & name,const string & obj,bool ismethod,bool isvirtual)617 DeclareFunInst* CodeContainer::generateInstanceClear(const string& name, const string& obj, bool ismethod,
618                                                      bool isvirtual)
619 {
620     list<NamedTyped*> args;
621     if (!ismethod) {
622         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
623     }
624 
625     BlockInst* block = InstBuilder::genBlockInst();
626     block->pushBackInst(fClearInstructions);
627 
628     // Explicit return
629     block->pushBackInst(InstBuilder::genRetInst());
630 
631     // Creates function
632     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
633 }
634 
generateInstanceConstants(const string & name,const string & obj,bool ismethod,bool isvirtual)635 DeclareFunInst* CodeContainer::generateInstanceConstants(const string& name, const string& obj, bool ismethod,
636                                                          bool isvirtual)
637 {
638     list<NamedTyped*> args;
639     if (!ismethod) {
640         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
641     }
642     args.push_back(InstBuilder::genNamedTyped("sample_rate", Typed::kInt32));
643 
644     BlockInst* block = InstBuilder::genBlockInst();
645     block->pushBackInst(fInitInstructions);
646 
647     // Explicit return
648     block->pushBackInst(InstBuilder::genRetInst());
649 
650     // Creates function
651     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
652 }
653 
generateStaticInitFun(const string & name,bool isstatic)654 DeclareFunInst* CodeContainer::generateStaticInitFun(const string& name, bool isstatic)
655 {
656     list<NamedTyped*> args;
657     args.push_back(InstBuilder::genNamedTyped("sample_rate", Typed::kInt32));
658 
659     BlockInst* block = InstBuilder::genBlockInst();
660     block->pushBackInst(fStaticInitInstructions);
661     block->pushBackInst(fPostStaticInitInstructions);
662 
663     //  20/11/16 : added in generateInstanceInitFun, is this needed here ?
664     /*
665     init_block->pushBackInst(fResetUserInterfaceInstructions);
666     init_block->pushBackInst(fClearInstructions);
667     */
668 
669     // Explicit return
670     block->pushBackInst(InstBuilder::genRetInst());
671 
672     // Creates function
673     FunTyped* fun_type = InstBuilder::genFunTyped(args, InstBuilder::genVoidTyped(),
674                                                   (isstatic) ? FunTyped::kStatic : FunTyped::kDefault);
675     return InstBuilder::genDeclareFunInst(name, fun_type, block);
676 }
677 
generateInstanceInitFun(const string & name,const string & obj,bool ismethod,bool isvirtual)678 DeclareFunInst* CodeContainer::generateInstanceInitFun(const string& name, const string& obj, bool ismethod,
679                                                        bool isvirtual)
680 {
681     list<NamedTyped*> args;
682     if (!ismethod) {
683         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
684     }
685     args.push_back(InstBuilder::genNamedTyped("sample_rate", Typed::kInt32));
686 
687     BlockInst* init_block = InstBuilder::genBlockInst();
688     init_block->pushBackInst(fInitInstructions);
689     init_block->pushBackInst(fPostInitInstructions);
690     init_block->pushBackInst(fResetUserInterfaceInstructions);
691     init_block->pushBackInst(fClearInstructions);
692 
693     // Explicit return
694     init_block->pushBackInst(InstBuilder::genRetInst());
695 
696     // Creates function
697     return InstBuilder::genVoidFunction(name, args, init_block, isvirtual);
698 }
699 
generateFillFun(const string & name,const string & obj,bool ismethod,bool isvirtual)700 DeclareFunInst* CodeContainer::generateFillFun(const string& name, const string& obj, bool ismethod, bool isvirtual)
701 {
702     list<NamedTyped*> args;
703     if (!ismethod) {
704         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
705     }
706     args.push_back(InstBuilder::genNamedTyped("count", Typed::kInt32));
707     if (fSubContainerType == kInt) {
708         args.push_back(InstBuilder::genNamedTyped(fTableName, Typed::kInt32_ptr));
709     } else {
710         args.push_back(InstBuilder::genNamedTyped(fTableName, itfloatptr()));
711     }
712 
713     BlockInst* block = InstBuilder::genBlockInst();
714     block->pushBackInst(fComputeBlockInstructions);
715     // Hack for Julia
716     if (gGlobal->gOutputLang == "julia") {
717         block->pushBackInst(fCurLoop->generateSimpleScalarLoop("count"));
718     } else {
719         block->pushBackInst(fCurLoop->generateScalarLoop("count"));
720     }
721 
722     // Explicit return
723     block->pushBackInst(InstBuilder::genRetInst());
724 
725     // Creates function
726     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
727 }
728 
generateInit(const string & name,const string & obj,bool ismethod,bool isvirtual)729 DeclareFunInst* CodeContainer::generateInit(const string& name, const string& obj, bool ismethod, bool isvirtual)
730 {
731     list<NamedTyped*> args;
732     if (!ismethod) {
733         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
734     }
735     args.push_back(InstBuilder::genNamedTyped("sample_rate", Typed::kInt32));
736 
737     BlockInst* block = InstBuilder::genBlockInst();
738     {
739         list<ValueInst*> args1;
740         if (!ismethod) {
741             args1.push_back(InstBuilder::genLoadFunArgsVar(obj));
742         }
743         args1.push_back(InstBuilder::genLoadFunArgsVar("sample_rate"));
744         block->pushBackInst(InstBuilder::genVoidFunCallInst("classInit", args1));
745     }
746 
747     {
748         list<ValueInst*> args1;
749         if (!ismethod) {
750             args1.push_back(InstBuilder::genLoadFunArgsVar(obj));
751         }
752         args1.push_back(InstBuilder::genLoadFunArgsVar("sample_rate"));
753         block->pushBackInst(InstBuilder::genVoidFunCallInst("instanceInit", args1));
754     }
755 
756     // Creates function
757     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
758 }
759 
generateInstanceInit(const string & name,const string & obj,bool ismethod,bool isvirtual)760 DeclareFunInst* CodeContainer::generateInstanceInit(const string& name, const string& obj, bool ismethod,
761                                                     bool isvirtual)
762 {
763     list<NamedTyped*> args;
764     if (!ismethod) {
765         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
766     }
767     args.push_back(InstBuilder::genNamedTyped("sample_rate", Typed::kInt32));
768 
769     BlockInst* block = InstBuilder::genBlockInst();
770     {
771         list<ValueInst*> args1;
772         if (!ismethod) {
773             args1.push_back(InstBuilder::genLoadFunArgsVar(obj));
774         }
775         args1.push_back(InstBuilder::genLoadFunArgsVar("sample_rate"));
776         block->pushBackInst(InstBuilder::genVoidFunCallInst("instanceConstants", args1));
777     }
778 
779     {
780         list<ValueInst*> args1;
781         if (!ismethod) {
782             args1.push_back(InstBuilder::genLoadFunArgsVar(obj));
783         }
784         block->pushBackInst(InstBuilder::genVoidFunCallInst("instanceResetUserInterface", args1));
785     }
786 
787     {
788         list<ValueInst*> args1;
789         if (!ismethod) {
790             args1.push_back(InstBuilder::genLoadFunArgsVar(obj));
791         }
792         block->pushBackInst(InstBuilder::genVoidFunCallInst("instanceClear", args1));
793     }
794 
795     // Creates function
796     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
797 }
798 
generateGetSampleRate(const string & name,const string & obj,bool ismethod,bool isvirtual)799 DeclareFunInst* CodeContainer::generateGetSampleRate(const string& name, const string& obj, bool ismethod,
800                                                      bool isvirtual)
801 {
802     list<NamedTyped*> args;
803     if (!ismethod) {
804         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
805     }
806 
807     BlockInst* block = InstBuilder::genBlockInst();
808     block->pushBackInst(InstBuilder::genRetInst(InstBuilder::genLoadStructVar("fSampleRate")));
809 
810     // Creates function
811     FunTyped* fun_type = InstBuilder::genFunTyped(args, InstBuilder::genInt32Typed(),
812                                                   (isvirtual) ? FunTyped::kVirtual : FunTyped::kDefault);
813     return InstBuilder::genDeclareFunInst(name, fun_type, block);
814 }
815 
generateComputeFun(const string & name,const string & obj,bool ismethod,bool isvirtual)816 DeclareFunInst* CodeContainer::generateComputeFun(const string& name, const string& obj, bool ismethod, bool isvirtual)
817 {
818     list<NamedTyped*> args;
819     if (!ismethod) {
820         args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
821     }
822     args.push_back(InstBuilder::genNamedTyped("count", Typed::kInt32));
823     args.push_back(InstBuilder::genNamedTyped("inputs", Typed::kFloatMacro_ptr_ptr));
824     args.push_back(InstBuilder::genNamedTyped("outputs", Typed::kFloatMacro_ptr_ptr));
825 
826     // Generates control + DSP block
827     BlockInst* block = generateComputeAux();
828 
829     // Explicit return
830     block->pushBackInst(InstBuilder::genRetInst());
831 
832     // Creates function
833     return InstBuilder::genVoidFunction(name, args, block, isvirtual);
834 }
835 
836 // Memory
837 
generateCalloc()838 DeclareFunInst* CodeContainer::generateCalloc()
839 {
840     list<NamedTyped*> args;
841     args.push_back(InstBuilder::genNamedTyped("count", Typed::kInt64));
842     args.push_back(InstBuilder::genNamedTyped("size", Typed::kInt64));
843 
844     // Creates function
845     FunTyped* fun_type =
846         InstBuilder::genFunTyped(args, InstBuilder::genBasicTyped(Typed::kVoid_ptr), FunTyped::kDefault);
847     return InstBuilder::genDeclareFunInst("calloc", fun_type);
848 }
849 
generateFree()850 DeclareFunInst* CodeContainer::generateFree()
851 {
852     list<NamedTyped*> args;
853     args.push_back(InstBuilder::genNamedTyped("ptr", Typed::kVoid_ptr));
854 
855     // Creates function
856     FunTyped* fun_type = InstBuilder::genFunTyped(args, InstBuilder::genBasicTyped(Typed::kVoid), FunTyped::kDefault);
857     return InstBuilder::genDeclareFunInst("free", fun_type);
858 }
859 
generateNewDsp(const string & name,int size)860 DeclareFunInst* CodeContainer::generateNewDsp(const string& name, int size)
861 {
862     list<NamedTyped*> args;
863 
864     BlockInst* block = InstBuilder::genBlockInst();
865     {
866         list<ValueInst*> args1;
867         args1.push_back(InstBuilder::genInt64NumInst(1));
868         args1.push_back(InstBuilder::genInt64NumInst(size));
869         block->pushBackInst(InstBuilder::genRetInst(InstBuilder::genCastInst(
870             InstBuilder::genFunCallInst("calloc", args1), InstBuilder::genBasicTyped(Typed::kObj_ptr))));
871     }
872 
873     // Creates function
874     FunTyped* fun_type = InstBuilder::genFunTyped(args, InstBuilder::genBasicTyped(Typed::kObj_ptr), FunTyped::kLocal);
875     return InstBuilder::genDeclareFunInst(name, fun_type, block);
876 }
877 
generateDeleteDsp(const string & name,const string & obj)878 DeclareFunInst* CodeContainer::generateDeleteDsp(const string& name, const string& obj)
879 {
880     list<NamedTyped*> args;
881     args.push_back(InstBuilder::genNamedTyped(obj, Typed::kObj_ptr));
882 
883     BlockInst* block = InstBuilder::genBlockInst();
884     {
885         list<ValueInst*> args1;
886         args1.push_back(InstBuilder::genCastInst(InstBuilder::genLoadFunArgsVar(obj),
887                                                 InstBuilder::genBasicTyped(Typed::kVoid_ptr)));
888         block->pushBackInst(InstBuilder::genDropInst(InstBuilder::genFunCallInst("free", args1)));
889     }
890 
891     // Explicit return
892     block->pushBackInst(InstBuilder::genRetInst());
893 
894     // Creates function
895     FunTyped* fun_type = InstBuilder::genFunTyped(args, InstBuilder::genBasicTyped(Typed::kVoid), FunTyped::kLocal);
896     return InstBuilder::genDeclareFunInst(name, fun_type, block);
897 }
898