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