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