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 #ifndef _C_INSTRUCTIONS_H
23 #define _C_INSTRUCTIONS_H
24 
25 #include <string>
26 
27 #include "text_instructions.hh"
28 #include "struct_manager.hh"
29 
30 using namespace std;
31 
32 class CInstVisitor : public TextInstVisitor {
33    private:
34     /*
35      Global functions names table as a static variable in the visitor
36      so that each function prototype is generated as most once in the module.
37      */
38     static map<string, bool> gFunctionSymbolTable;
39 
40     // Polymorphic math functions
41     map<string, string> gPolyMathLibTable;
42 
cast2FAUSTFLOAT(const string & str)43     string cast2FAUSTFLOAT(const string& str) { return "(FAUSTFLOAT)" + str; }
44 
45    public:
46     using TextInstVisitor::visit;
47 
CInstVisitor(std::ostream * out,const string & struct_name,int tab=0)48     CInstVisitor(std::ostream* out, const string& struct_name, int tab = 0)
49         : TextInstVisitor(out, "->", new CStringTypeManager(xfloat(), "*", struct_name), tab)
50     {
51         // Mark all math.h functions as generated...
52         gFunctionSymbolTable["abs"] = true;
53 
54         gFunctionSymbolTable["min_i"] = true;
55         gFunctionSymbolTable["max_i"] = true;
56 
57         // Float version
58         gFunctionSymbolTable["fabsf"]      = true;
59         gFunctionSymbolTable["acosf"]      = true;
60         gFunctionSymbolTable["asinf"]      = true;
61         gFunctionSymbolTable["atanf"]      = true;
62         gFunctionSymbolTable["atan2f"]     = true;
63         gFunctionSymbolTable["ceilf"]      = true;
64         gFunctionSymbolTable["cosf"]       = true;
65         gFunctionSymbolTable["expf"]       = true;
66         gFunctionSymbolTable["exp10f"]     = true;
67         gFunctionSymbolTable["floorf"]     = true;
68         gFunctionSymbolTable["fmodf"]      = true;
69         gFunctionSymbolTable["logf"]       = true;
70         gFunctionSymbolTable["log10f"]     = true;
71         gFunctionSymbolTable["powf"]       = true;
72         gFunctionSymbolTable["remainderf"] = true;
73         gFunctionSymbolTable["rintf"]      = true;
74         gFunctionSymbolTable["roundf"]     = true;
75         gFunctionSymbolTable["sinf"]       = true;
76         gFunctionSymbolTable["sqrtf"]      = true;
77         gFunctionSymbolTable["tanf"]       = true;
78 
79         // Double version
80         gFunctionSymbolTable["fabs"]      = true;
81         gFunctionSymbolTable["acos"]      = true;
82         gFunctionSymbolTable["asin"]      = true;
83         gFunctionSymbolTable["atan"]      = true;
84         gFunctionSymbolTable["atan2"]     = true;
85         gFunctionSymbolTable["ceil"]      = true;
86         gFunctionSymbolTable["cos"]       = true;
87         gFunctionSymbolTable["exp"]       = true;
88         gFunctionSymbolTable["exp10"]     = true;
89         gFunctionSymbolTable["floor"]     = true;
90         gFunctionSymbolTable["fmod"]      = true;
91         gFunctionSymbolTable["log"]       = true;
92         gFunctionSymbolTable["log10"]     = true;
93         gFunctionSymbolTable["pow"]       = true;
94         gFunctionSymbolTable["remainder"] = true;
95         gFunctionSymbolTable["rint"]      = true;
96         gFunctionSymbolTable["round"]     = true;
97         gFunctionSymbolTable["sin"]       = true;
98         gFunctionSymbolTable["sqrt"]      = true;
99         gFunctionSymbolTable["tan"]       = true;
100 
101         // Quad version
102         gFunctionSymbolTable["fabsl"]      = true;
103         gFunctionSymbolTable["acosl"]      = true;
104         gFunctionSymbolTable["asinl"]      = true;
105         gFunctionSymbolTable["atanl"]      = true;
106         gFunctionSymbolTable["atan2l"]     = true;
107         gFunctionSymbolTable["ceill"]      = true;
108         gFunctionSymbolTable["cosl"]       = true;
109         gFunctionSymbolTable["expl"]       = true;
110         gFunctionSymbolTable["exp10l"]     = true;
111         gFunctionSymbolTable["floorl"]     = true;
112         gFunctionSymbolTable["fmodl"]      = true;
113         gFunctionSymbolTable["logl"]       = true;
114         gFunctionSymbolTable["log10l"]     = true;
115         gFunctionSymbolTable["powl"]       = true;
116         gFunctionSymbolTable["remainderl"] = true;
117         gFunctionSymbolTable["rintl"]      = true;
118         gFunctionSymbolTable["roundl"]     = true;
119         gFunctionSymbolTable["sinl"]       = true;
120         gFunctionSymbolTable["sqrtl"]      = true;
121         gFunctionSymbolTable["tanl"]       = true;
122 
123         // Polymath mapping int version
124         gPolyMathLibTable["min_i"] = "min";
125         gPolyMathLibTable["max_i"] = "max";
126 
127         // Polymath mapping float version
128         gPolyMathLibTable["min_f"]  = "fminf";
129         gPolyMathLibTable["max_f"]  = "fmaxf";
130 
131         // Polymath mapping double version
132         gPolyMathLibTable["min_"]   = "fmin";
133         gPolyMathLibTable["max_"]   = "fmax";
134 
135         // Polymath mapping quad version
136         gPolyMathLibTable["min_l"]  = "fminl";
137         gPolyMathLibTable["max_l"]  = "fmaxl";
138     }
139 
~CInstVisitor()140     virtual ~CInstVisitor() {}
141 
visit(AddMetaDeclareInst * inst)142     virtual void visit(AddMetaDeclareInst* inst)
143     {
144         // Special case
145         if (inst->fZone == "0") {
146             *fOut << "ui_interface->declare(ui_interface->uiInterface, " << inst->fZone << ", " << quote(inst->fKey)
147                   << ", " << quote(inst->fValue) << ")";
148         } else {
149             *fOut << "ui_interface->declare(ui_interface->uiInterface, &dsp->" << inst->fZone << ", "
150                   << quote(inst->fKey) << ", " << quote(inst->fValue) << ")";
151         }
152         EndLine();
153     }
154 
visit(OpenboxInst * inst)155     virtual void visit(OpenboxInst* inst)
156     {
157         string name;
158         switch (inst->fOrient) {
159             case OpenboxInst::kVerticalBox:
160                 name = "ui_interface->openVerticalBox(";
161                 break;
162             case OpenboxInst::kHorizontalBox:
163                 name = "ui_interface->openHorizontalBox(";
164                 break;
165             case OpenboxInst::kTabBox:
166                 name = "ui_interface->openTabBox(";
167                 break;
168         }
169         *fOut << name << "ui_interface->uiInterface, " << quote(inst->fName) << ")";
170         EndLine();
171     }
172 
visit(CloseboxInst * inst)173     virtual void visit(CloseboxInst* inst)
174     {
175         *fOut << "ui_interface->closeBox(ui_interface->uiInterface);";
176         tab(fTab, *fOut);
177     }
178 
visit(AddButtonInst * inst)179     virtual void visit(AddButtonInst* inst)
180     {
181         string name;
182         if (inst->fType == AddButtonInst::kDefaultButton) {
183             name = "ui_interface->addButton(";
184         } else {
185             name = "ui_interface->addCheckButton(";
186         }
187         *fOut << name << "ui_interface->uiInterface, " << quote(inst->fLabel) << ", &dsp->" << inst->fZone << ")";
188         EndLine();
189     }
190 
visit(AddSliderInst * inst)191     virtual void visit(AddSliderInst* inst)
192     {
193         string name;
194         switch (inst->fType) {
195             case AddSliderInst::kHorizontal:
196                 name = "ui_interface->addHorizontalSlider(";
197                 break;
198             case AddSliderInst::kVertical:
199                 name = "ui_interface->addVerticalSlider(";
200                 break;
201             case AddSliderInst::kNumEntry:
202                 name = "ui_interface->addNumEntry(";
203                 break;
204         }
205         *fOut << name << "ui_interface->uiInterface, " << quote(inst->fLabel) << ", &dsp->" << inst->fZone << ", "
206               << cast2FAUSTFLOAT(checkReal(inst->fInit)) << ", "
207               << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", "
208               << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ", "
209               << cast2FAUSTFLOAT(checkReal(inst->fStep)) << ")";
210         EndLine();
211     }
212 
visit(AddBargraphInst * inst)213     virtual void visit(AddBargraphInst* inst)
214     {
215         string name;
216         switch (inst->fType) {
217             case AddBargraphInst::kHorizontal:
218                 name = "ui_interface->addHorizontalBargraph(";
219                 break;
220             case AddBargraphInst::kVertical:
221                 name = "ui_interface->addVerticalBargraph(";
222                 break;
223         }
224         *fOut << name << "ui_interface->uiInterface, " << quote(inst->fLabel) << ", &dsp->" << inst->fZone << ", "
225               << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", "
226               << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ")";
227         EndLine();
228     }
229 
visit(AddSoundfileInst * inst)230     virtual void visit(AddSoundfileInst* inst)
231     {
232         *fOut << "ui_interface->addSoundfile(ui_interface->uiInterface, " << quote(inst->fLabel) << ", "
233               << quote(inst->fURL) << ", &dsp->" << inst->fSFZone << ")";
234         EndLine();
235     }
236 
visit(DeclareVarInst * inst)237     virtual void visit(DeclareVarInst* inst)
238     {
239         if (inst->fAddress->getAccess() & Address::kStaticStruct) {
240             *fOut << "static ";
241         }
242 
243         if (inst->fAddress->getAccess() & Address::kVolatile) {
244             *fOut << "volatile ";
245         }
246 
247         *fOut << fTypeManager->generateType(inst->fType, inst->fAddress->getName());
248         if (inst->fValue) {
249             *fOut << " = ";
250             inst->fValue->accept(this);
251         }
252         EndLine();
253     }
254 
visit(DeclareFunInst * inst)255     virtual void visit(DeclareFunInst* inst)
256     {
257         // Already generated
258         if (gFunctionSymbolTable.find(inst->fName) != gFunctionSymbolTable.end()) {
259             return;
260         } else {
261             gFunctionSymbolTable[inst->fName] = true;
262         }
263 
264         // Defined as macro in the architecture file...
265         if (checkMinMax(inst->fName)) {
266             return;
267         }
268 
269         // Prototype
270         if (inst->fType->fAttribute & FunTyped::kInline) {
271             *fOut << "inline ";
272         }
273 
274         if (inst->fType->fAttribute & FunTyped::kLocal || inst->fType->fAttribute & FunTyped::kStatic) {
275             *fOut << "static ";
276         }
277 
278         *fOut << fTypeManager->generateType(inst->fType->fResult, inst->fName);
279         generateFunDefArgs(inst);
280         generateFunDefBody(inst);
281     }
282 
visit(NamedAddress * named)283     virtual void visit(NamedAddress* named)
284     {
285         if (named->getAccess() & Address::kStruct) {
286             *fOut << "dsp->";
287         }
288         *fOut << named->fName;
289     }
290 
visit(LoadVarAddressInst * inst)291     virtual void visit(LoadVarAddressInst* inst)
292     {
293         *fOut << "&";
294         inst->fAddress->accept(this);
295     }
296 
visit(BinopInst * inst)297     virtual void visit(BinopInst* inst)
298     {
299         // Special case for 'logical right-shift'
300         if (strcmp(gBinOpTable[inst->fOpcode]->fName, ">>>") == 0) {
301             TypingVisitor typing;
302             inst->fInst1->accept(&typing);
303             if (isInt64Type(typing.fCurType)) {
304                 *fOut << "((int64_t)((uint64_t)";
305             } else if (isInt32Type(typing.fCurType)) {
306                 *fOut << "((int32_t)(uint32_t)";
307             } else {
308                 faustassert(false);
309             }
310             inst->fInst1->accept(this);
311             *fOut << " >> ";
312             inst->fInst2->accept(this);
313             *fOut << "))";
314         } else {
315             TextInstVisitor::visit(inst);
316         }
317     }
visit(FixedPointNumInst * inst)318     virtual void visit(FixedPointNumInst* inst) { *fOut << "(fixpoint_t)" << checkFloat(inst->fNum); }
319 
visit(FixedPointArrayNumInst * inst)320     virtual void visit(FixedPointArrayNumInst* inst)
321     {
322         char sep = '{';
323         for (size_t i = 0; i < inst->fNumTable.size(); i++) {
324             *fOut << sep << "(fixpoint_t)" << checkFloat(inst->fNumTable[i]);
325             sep = ',';
326         }
327         *fOut << '}';
328     }
329 
visit(::CastInst * inst)330     virtual void visit(::CastInst* inst)
331     {
332         *fOut << "(" << fTypeManager->generateType(inst->fType) << ")";
333         inst->fInst->accept(this);
334     }
335 
336     // TODO : does not work, put this code in a function
visit(BitcastInst * inst)337     virtual void visit(BitcastInst* inst)
338     {
339         switch (inst->fType->getType()) {
340             case Typed::kInt32:
341                 *fOut << "*((int*)&";
342                 inst->fInst->accept(this);
343                 *fOut << ")";
344                 break;
345             case Typed::kInt64:
346                 *fOut << "*((int64_t*)&";
347                 inst->fInst->accept(this);
348                 *fOut << ")";
349                 break;
350             case Typed::kFloat:
351                 *fOut << "*((float*)&";
352                 inst->fInst->accept(this);
353                 *fOut << ")";
354                 break;
355             case Typed::kDouble:
356                 *fOut << "*((double*)&";
357                 inst->fInst->accept(this);
358                 *fOut << ")";
359                 break;
360             default:
361                 faustassert(false);
362                 break;
363         }
364     }
365 
366     // Generate standard funcall (not 'method' like funcall...)
visit(FunCallInst * inst)367     virtual void visit(FunCallInst* inst)
368     {
369         string name = (gPolyMathLibTable.find(inst->fName) != gPolyMathLibTable.end()) ? gPolyMathLibTable[inst->fName] : inst->fName;
370         *fOut << gGlobal->getMathFunction(name) << "(";
371 
372         // Compile parameters
373         generateFunCallArgs(inst->fArgs.begin(), inst->fArgs.end(), inst->fArgs.size());
374         *fOut << ")";
375     }
376 
visit(ForLoopInst * inst)377     virtual void visit(ForLoopInst* inst)
378     {
379         // Don't generate empty loops...
380         if (inst->fCode->size() == 0) return;
381 
382         DeclareVarInst* c99_declare_inst = dynamic_cast<DeclareVarInst*>(inst->fInit);
383         StoreVarInst*   c99_init_inst    = nullptr;
384 
385         if (c99_declare_inst) {
386             InstBuilder::genLabelInst("/* C99 loop */")->accept(this);
387             *fOut << "{";
388             fTab++;
389             tab(fTab, *fOut);
390 
391             // To generate C99 compatible loops...
392             c99_init_inst    = InstBuilder::genStoreStackVar(c99_declare_inst->getName(), c99_declare_inst->fValue);
393             c99_declare_inst = InstBuilder::genDecStackVar(c99_declare_inst->getName(), InstBuilder::genInt32Typed());
394             // C99 loop variable declared outside the loop
395             c99_declare_inst->accept(this);
396         }
397 
398         if (gGlobal->gClang && !inst->fIsRecursive) {
399             *fOut << "#pragma clang loop vectorize(enable) interleave(enable)";
400             tab(fTab, *fOut);
401         }
402 
403         *fOut << "for (";
404         fFinishLine = false;
405         if (c99_declare_inst) {
406             // C99 loop initialized here
407             c99_init_inst->accept(this);
408         } else {
409             // Index already defined
410             inst->fInit->accept(this);
411         }
412         *fOut << "; ";
413         inst->fEnd->accept(this);
414         *fOut << "; ";
415         inst->fIncrement->accept(this);
416         fFinishLine = true;
417         *fOut << ") {";
418         fTab++;
419         tab(fTab, *fOut);
420         inst->fCode->accept(this);
421         fTab--;
422         back(1, *fOut);
423         *fOut << "}";
424         tab(fTab, *fOut);
425 
426         if (c99_declare_inst) {
427             fTab--;
428             back(1, *fOut);
429             *fOut << "}";
430             tab(fTab, *fOut);
431         }
432     }
433 
cleanup()434     static void cleanup() { gFunctionSymbolTable.clear(); }
435 };
436 
437 // Used for -os mode (TODO : does not work with 'soundfile')
438 class CInstVisitor1 : public CInstVisitor {
439 
440     private:
441 
442         StructInstVisitor fStructVisitor;
443         bool fZoneAddress;      // If a zone address is currently written
444         bool fIndexedAddress;   // If an indexed address is currently written
445 
446     public:
447 
CInstVisitor1(std::ostream * out,const string & structname,int tab=0)448         CInstVisitor1(std::ostream* out, const string& structname, int tab = 0)
449         :CInstVisitor(out, structname, tab), fZoneAddress(false), fIndexedAddress(false)
450         {}
451 
visit(AddSoundfileInst * inst)452         virtual void visit(AddSoundfileInst* inst)
453         {
454             // Not supported for now
455             throw faustexception("ERROR : AddSoundfileInst not supported for -os mode\n");
456         }
457 
visit(DeclareVarInst * inst)458         virtual void visit(DeclareVarInst* inst)
459         {
460             Address::AccessType access = inst->fAddress->getAccess();
461             string name = inst->fAddress->getName();
462             bool is_control = startWith(name, "fButton")
463                 || startWith(name, "fCheckbox")
464                 || startWith(name, "fVslider")
465                 || startWith(name, "fHslider")
466                 || startWith(name, "fEntry")
467                 || startWith(name, "fVbargraph")
468                 || startWith(name, "fHbargraph")
469                 || name == "fSampleRate";
470             if (((access & Address::kStruct) || (access & Address::kStaticStruct)) && !is_control) {
471                 fStructVisitor.visit(inst);
472             } else {
473                 CInstVisitor::visit(inst);
474             }
475         }
476 
visit(NamedAddress * named)477         virtual void visit(NamedAddress* named)
478         {
479             Typed::VarType type;
480             if (fStructVisitor.hasField(named->fName, type)) {
481                 // Zone address zone[id][index] are rewritten as zone[id+index]
482                 fZoneAddress = true;
483                 if (type == Typed::kInt32) {
484                     *fOut << "iZone[" << fStructVisitor.getFieldIntOffset(named->fName)/sizeof(int);
485                 } else {
486                     *fOut << "fZone[" << fStructVisitor.getFieldRealOffset(named->fName)/ifloatsize();
487                 }
488                 if (!fIndexedAddress) { *fOut << "]"; }
489             } else {
490                 fZoneAddress = false;
491                 if (named->getAccess() & Address::kStruct) {
492                     *fOut << "dsp->";
493                 }
494                 *fOut << named->fName;
495             }
496         }
497 
498         /*
499          Indexed address can actually be values in an array or fields in a struct type
500          */
visit(IndexedAddress * indexed)501         virtual void visit(IndexedAddress* indexed)
502         {
503             fIndexedAddress = true;
504             indexed->fAddress->accept(this);
505             DeclareStructTypeInst* struct_type = isStructType(indexed->getName());
506             if (struct_type) {
507                 Int32NumInst* field_index = static_cast<Int32NumInst*>(indexed->fIndex);
508                 *fOut << "->" << struct_type->fType->getName(field_index->fNum);
509             } else {
510                 // Zone address zone[id][index] are rewritten as zone[id+index]
511                 if (fZoneAddress) { *fOut << "+"; } else { *fOut << "["; }
512                 fIndexedAddress = false;
513                 fZoneAddress = false;
514                 indexed->fIndex->accept(this);
515                 *fOut << "]";
516             }
517         }
518 
519         // Size is expressed in unit of the actual type (so 'int' or 'float/double')
getIntZoneSize()520         int getIntZoneSize() { return fStructVisitor.getStructIntSize()/sizeof(int); }
getRealZoneSize()521         int getRealZoneSize() { return fStructVisitor.getStructRealSize()/ifloatsize(); }
522 
523 };
524 
525 #endif
526