/************************************************************************ ************************************************************************ FAUST compiler Copyright (C) 2003-2018 GRAME, Centre National de Creation Musicale --------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************************************************************ ************************************************************************/ #ifndef _CPP_INSTRUCTIONS_H #define _CPP_INSTRUCTIONS_H using namespace std; #include "text_instructions.hh" #include "type_manager.hh" #include "struct_manager.hh" class CPPInstVisitor : public TextInstVisitor { private: /* Global functions names table as a static variable in the visitor so that each function prototype is generated at most once in the module. */ static map gFunctionSymbolTable; // Polymorphic math functions map gPolyMathLibTable; string cast2FAUSTFLOAT(const string& str) { return "FAUSTFLOAT(" + str + ")"; } public: using TextInstVisitor::visit; CPPInstVisitor(std::ostream* out, int tab = 0) : TextInstVisitor(out, "->", new CStringTypeManager(xfloat(), "*"), tab) { // Mark all math.h functions as generated... gFunctionSymbolTable["abs"] = true; gFunctionSymbolTable["max_i"] = true; gFunctionSymbolTable["min_i"] = true; // Float version gFunctionSymbolTable["fabsf"] = true; gFunctionSymbolTable["acosf"] = true; gFunctionSymbolTable["asinf"] = true; gFunctionSymbolTable["atanf"] = true; gFunctionSymbolTable["atan2f"] = true; gFunctionSymbolTable["ceilf"] = true; gFunctionSymbolTable["cosf"] = true; gFunctionSymbolTable["expf"] = true; gFunctionSymbolTable["exp10f"] = true; gFunctionSymbolTable["floorf"] = true; gFunctionSymbolTable["fmodf"] = true; gFunctionSymbolTable["logf"] = true; gFunctionSymbolTable["log10f"] = true; gFunctionSymbolTable["powf"] = true; gFunctionSymbolTable["remainderf"] = true; gFunctionSymbolTable["rintf"] = true; gFunctionSymbolTable["roundf"] = true; gFunctionSymbolTable["sinf"] = true; gFunctionSymbolTable["sqrtf"] = true; gFunctionSymbolTable["tanf"] = true; // Double version gFunctionSymbolTable["fabs"] = true; gFunctionSymbolTable["acos"] = true; gFunctionSymbolTable["asin"] = true; gFunctionSymbolTable["atan"] = true; gFunctionSymbolTable["atan2"] = true; gFunctionSymbolTable["ceil"] = true; gFunctionSymbolTable["cos"] = true; gFunctionSymbolTable["exp"] = true; gFunctionSymbolTable["exp10"] = true; gFunctionSymbolTable["floor"] = true; gFunctionSymbolTable["fmod"] = true; gFunctionSymbolTable["log"] = true; gFunctionSymbolTable["log10"] = true; gFunctionSymbolTable["pow"] = true; gFunctionSymbolTable["remainder"] = true; gFunctionSymbolTable["rint"] = true; gFunctionSymbolTable["round"] = true; gFunctionSymbolTable["sin"] = true; gFunctionSymbolTable["sqrt"] = true; gFunctionSymbolTable["tan"] = true; // Quad version gFunctionSymbolTable["fabsl"] = true; gFunctionSymbolTable["acosl"] = true; gFunctionSymbolTable["asinl"] = true; gFunctionSymbolTable["atanl"] = true; gFunctionSymbolTable["atan2l"] = true; gFunctionSymbolTable["ceill"] = true; gFunctionSymbolTable["cosl"] = true; gFunctionSymbolTable["expl"] = true; gFunctionSymbolTable["exp10l"] = true; gFunctionSymbolTable["floorl"] = true; gFunctionSymbolTable["fmodl"] = true; gFunctionSymbolTable["logl"] = true; gFunctionSymbolTable["log10l"] = true; gFunctionSymbolTable["powl"] = true; gFunctionSymbolTable["remainderl"] = true; gFunctionSymbolTable["rintl"] = true; gFunctionSymbolTable["roundl"] = true; gFunctionSymbolTable["sinl"] = true; gFunctionSymbolTable["sqrtl"] = true; gFunctionSymbolTable["tanl"] = true; // Polymath mapping int version gPolyMathLibTable["abs"] = "std::abs"; gPolyMathLibTable["max_i"] = "std::max"; gPolyMathLibTable["min_i"] = "std::min"; // Polymath mapping float version gPolyMathLibTable["max_f"] = "std::max"; gPolyMathLibTable["min_f"] = "std::min"; gPolyMathLibTable["fabsf"] = "std::fabs"; gPolyMathLibTable["acosf"] = "std::acos"; gPolyMathLibTable["asinf"] = "std::asin"; gPolyMathLibTable["atanf"] = "std::atan"; gPolyMathLibTable["atan2f"] = "std::atan2"; gPolyMathLibTable["ceilf"] = "std::ceil"; gPolyMathLibTable["cosf"] = "std::cos"; gPolyMathLibTable["expf"] = "std::exp"; gPolyMathLibTable["exp2f"] = "std::exp2"; gPolyMathLibTable["exp10f"] = "exp10f"; gPolyMathLibTable["floorf"] = "std::floor"; gPolyMathLibTable["fmodf"] = "std::fmod"; gPolyMathLibTable["logf"] = "std::log"; gPolyMathLibTable["log2f"] = "std::log2"; gPolyMathLibTable["log10f"] = "std::log10"; gPolyMathLibTable["powf"] = "std::pow"; gPolyMathLibTable["remainderf"] = "std::remainder"; gPolyMathLibTable["rintf"] = "std::rint"; gPolyMathLibTable["roundf"] = "std::round"; gPolyMathLibTable["sinf"] = "std::sin"; gPolyMathLibTable["sqrtf"] = "std::sqrt"; gPolyMathLibTable["tanf"] = "std::tan"; // Polymath mapping double version gPolyMathLibTable["max_"] = "std::max"; gPolyMathLibTable["min_"] = "std::min"; gPolyMathLibTable["fabs"] = "std::fabs"; gPolyMathLibTable["acos"] = "std::acos"; gPolyMathLibTable["asin"] = "std::asin"; gPolyMathLibTable["atan"] = "std::atan"; gPolyMathLibTable["atan2"] = "std::atan2"; gPolyMathLibTable["ceil"] = "std::ceil"; gPolyMathLibTable["cos"] = "std::cos"; gPolyMathLibTable["exp"] = "std::exp"; gPolyMathLibTable["exp2"] = "std::exp2"; gPolyMathLibTable["exp10"] = "exp10"; gPolyMathLibTable["floor"] = "std::floor"; gPolyMathLibTable["fmod"] = "std::fmod"; gPolyMathLibTable["log"] = "std::log"; gPolyMathLibTable["log2"] = "std::log2"; gPolyMathLibTable["log10"] = "std::log10"; gPolyMathLibTable["pow"] = "std::pow"; gPolyMathLibTable["remainder"] = "std::remainder"; gPolyMathLibTable["rint"] = "std::rint"; gPolyMathLibTable["round"] = "std::round"; gPolyMathLibTable["sin"] = "std::sin"; gPolyMathLibTable["sqrt"] = "std::sqrt"; gPolyMathLibTable["tan"] = "std::tan"; // Polymath mapping quad version gPolyMathLibTable["max_l"] = "std::max"; gPolyMathLibTable["min_l"] = "std::min"; gPolyMathLibTable["fabsl"] = "std::fabs"; gPolyMathLibTable["acosl"] = "std::acos"; gPolyMathLibTable["asinl"] = "std::asin"; gPolyMathLibTable["atanl"] = "std::atan"; gPolyMathLibTable["atan2l"] = "std::atan2"; gPolyMathLibTable["ceill"] = "std::ceil"; gPolyMathLibTable["cosl"] = "std::cos"; gPolyMathLibTable["expl"] = "std::exp"; gPolyMathLibTable["exp2l"] = "std::exp2"; gPolyMathLibTable["exp10l"] = "exp10"; gPolyMathLibTable["floorl"] = "std::floor"; gPolyMathLibTable["fmodl"] = "std::fmod"; gPolyMathLibTable["logl"] = "std::log"; gPolyMathLibTable["log2l"] = "std::log2"; gPolyMathLibTable["log10l"] = "std::log10"; gPolyMathLibTable["powl"] = "std::pow"; gPolyMathLibTable["remainderl"] = "std::remainder"; gPolyMathLibTable["rintl"] = "std::rint"; gPolyMathLibTable["roundl"] = "std::round"; gPolyMathLibTable["sinl"] = "std::sin"; gPolyMathLibTable["sqrtl"] = "std::sqrt"; gPolyMathLibTable["tanl"] = "std::tan"; } virtual ~CPPInstVisitor() {} virtual void visit(AddMetaDeclareInst* inst) { // Special case if (inst->fZone == "0") { *fOut << "ui_interface->declare(" << inst->fZone << ", " << quote(inst->fKey) << ", " << quote(inst->fValue) << ")"; } else { *fOut << "ui_interface->declare(&" << inst->fZone << ", " << quote(inst->fKey) << ", " << quote(inst->fValue) << ")"; } EndLine(); } virtual void visit(OpenboxInst* inst) { string name; switch (inst->fOrient) { case OpenboxInst::kVerticalBox: name = "ui_interface->openVerticalBox("; break; case OpenboxInst::kHorizontalBox: name = "ui_interface->openHorizontalBox("; break; case OpenboxInst::kTabBox: name = "ui_interface->openTabBox("; break; } *fOut << name << quote(inst->fName) << ")"; EndLine(); } virtual void visit(CloseboxInst* inst) { *fOut << "ui_interface->closeBox();"; tab(fTab, *fOut); } virtual void visit(AddButtonInst* inst) { if (inst->fType == AddButtonInst::kDefaultButton) { *fOut << "ui_interface->addButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")"; } else { *fOut << "ui_interface->addCheckButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")"; } EndLine(); } virtual void visit(AddSliderInst* inst) { string name; switch (inst->fType) { case AddSliderInst::kHorizontal: name = "ui_interface->addHorizontalSlider"; break; case AddSliderInst::kVertical: name = "ui_interface->addVerticalSlider"; break; case AddSliderInst::kNumEntry: name = "ui_interface->addNumEntry"; break; } *fOut << name << "(" << quote(inst->fLabel) << ", " << "&" << inst->fZone << ", " << cast2FAUSTFLOAT(checkReal(inst->fInit)) << ", " << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", " << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ", " << cast2FAUSTFLOAT(checkReal(inst->fStep)) << ")"; EndLine(); } virtual void visit(AddBargraphInst* inst) { string name; switch (inst->fType) { case AddBargraphInst::kHorizontal: name = "ui_interface->addHorizontalBargraph"; break; case AddBargraphInst::kVertical: name = "ui_interface->addVerticalBargraph"; break; } *fOut << name << "(" << quote(inst->fLabel) << ", &" << inst->fZone << ", " << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", " << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ")"; EndLine(); } virtual void visit(AddSoundfileInst* inst) { *fOut << "ui_interface->addSoundfile(" << quote(inst->fLabel) << ", " << quote(inst->fURL) << ", &" << inst->fSFZone << ")"; EndLine(); } virtual void visit(DeclareVarInst* inst) { if (inst->fAddress->getAccess() & Address::kConst) { *fOut << "const "; } if (inst->fAddress->getAccess() & Address::kStaticStruct) { *fOut << "static "; } if (inst->fAddress->getAccess() & Address::kVolatile) { *fOut << "volatile "; } *fOut << fTypeManager->generateType(inst->fType, inst->fAddress->getName()); if (inst->fValue) { *fOut << " = "; inst->fValue->accept(this); } EndLine(); } virtual void visit(DeclareFunInst* inst) { // Already generated if (gFunctionSymbolTable.find(inst->fName) != gFunctionSymbolTable.end()) { return; } else { gFunctionSymbolTable[inst->fName] = true; } // Defined as macro in the architecture file... if (checkMinMax(inst->fName)) { return; } // Prototype arguments if (inst->fType->fAttribute & FunTyped::kInline) { *fOut << "inline "; } if (inst->fType->fAttribute & FunTyped::kVirtual) { *fOut << "virtual "; } if (inst->fType->fAttribute & FunTyped::kLocal || inst->fType->fAttribute & FunTyped::kStatic) { *fOut << "static "; } // Prototype *fOut << fTypeManager->generateType(inst->fType->fResult, generateFunName(inst->fName)); generateFunDefArgs(inst); generateFunDefBody(inst); } virtual void visit(LoadVarAddressInst* inst) { *fOut << "&"; inst->fAddress->accept(this); } virtual void visit(BinopInst* inst) { // Special case for 'logical right-shift' if (strcmp(gBinOpTable[inst->fOpcode]->fName, ">>>") == 0) { TypingVisitor typing; inst->fInst1->accept(&typing); if (isInt64Type(typing.fCurType)) { *fOut << "(int64_t(uint64_t("; } else if (isInt32Type(typing.fCurType)) { *fOut << "(int32_t(uint32_t("; } else { faustassert(false); } inst->fInst1->accept(this); *fOut << ") >> "; inst->fInst2->accept(this); *fOut << "))w"; } else { TextInstVisitor::visit(inst); } } virtual void visit(FixedPointNumInst* inst) { *fOut << "fixpoint_t(" << checkFloat(inst->fNum) << ")"; } virtual void visit(FixedPointArrayNumInst* inst) { char sep = '{'; for (size_t i = 0; i < inst->fNumTable.size(); i++) { *fOut << sep << "fixpoint_t(" << checkFloat(inst->fNumTable[i]) << ")"; sep = ','; } *fOut << '}'; } virtual void visit(::CastInst* inst) { string type = fTypeManager->generateType(inst->fType); if (endWith(type, "*")) { *fOut << "static_cast<" << type << ">("; inst->fInst->accept(this); *fOut << ")"; } else { *fOut << type << "("; inst->fInst->accept(this); *fOut << ")"; } } virtual void visit(BitcastInst* inst) { switch (inst->fType->getType()) { case Typed::kInt32: *fOut << "*reinterpret_cast(&"; inst->fInst->accept(this); *fOut << ")"; break; case Typed::kInt64: *fOut << "*reinterpret_cast(&"; inst->fInst->accept(this); *fOut << ")"; break; case Typed::kFloat: *fOut << "*reinterpret_cast(&"; inst->fInst->accept(this); *fOut << ")"; break; case Typed::kDouble: *fOut << "*reinterpret_cast(&"; inst->fInst->accept(this); *fOut << ")"; break; default: faustassert(false); break; } } virtual void visit(FunCallInst* inst) { string name = gGlobal->getMathFunction(inst->fName); name = (gPolyMathLibTable.find(name) != gPolyMathLibTable.end()) ? gPolyMathLibTable[name] : name; generateFunCall(inst, name); } virtual void visit(ForLoopInst* inst) { // Don't generate empty loops... if (inst->fCode->size() == 0) return; if (gGlobal->gClang && !inst->fIsRecursive) { *fOut << "#pragma clang loop vectorize(enable) interleave(enable)"; tab(fTab, *fOut); } TextInstVisitor::visit(inst); } static void cleanup() { gFunctionSymbolTable.clear(); } }; // Used for -os mode (TODO : does not work with 'soundfile') class CPPInstVisitor1 : public CPPInstVisitor { private: StructInstVisitor fStructVisitor; bool fZoneAddress; // If a zone address is currently written bool fIndexedAddress; // If an indexed address is currently written public: CPPInstVisitor1(std::ostream* out, int tab = 0) :CPPInstVisitor(out, tab), fZoneAddress(false), fIndexedAddress(false) {} virtual void visit(AddSoundfileInst* inst) { // Not supported for now throw faustexception("ERROR : AddSoundfileInst not supported for -os mode\n"); } virtual void visit(DeclareVarInst* inst) { Address::AccessType access = inst->fAddress->getAccess(); string name = inst->fAddress->getName(); bool is_control = startWith(name, "fButton") || startWith(name, "fCheckbox") || startWith(name, "fVslider") || startWith(name, "fHslider") || startWith(name, "fEntry") || startWith(name, "fVbargraph") || startWith(name, "fHbargraph") || name == "fSampleRate"; if (((access & Address::kStruct) || (access & Address::kStaticStruct)) && !is_control) { fStructVisitor.visit(inst); } else { CPPInstVisitor::visit(inst); } } virtual void visit(NamedAddress* named) { Typed::VarType type; if (fStructVisitor.hasField(named->fName, type)) { // Zone address zone[id][index] are rewritten as zone[id+index] fZoneAddress = true; if (type == Typed::kInt32) { *fOut << "iZone[" << fStructVisitor.getFieldIntOffset(named->fName)/sizeof(int); } else { *fOut << "fZone[" << fStructVisitor.getFieldRealOffset(named->fName)/ifloatsize(); } if (!fIndexedAddress) { *fOut << "]"; } } else { fZoneAddress = false; *fOut << named->fName; } } /* Indexed address can actually be values in an array or fields in a struct type */ virtual void visit(IndexedAddress* indexed) { fIndexedAddress = true; indexed->fAddress->accept(this); DeclareStructTypeInst* struct_type = isStructType(indexed->getName()); if (struct_type) { Int32NumInst* field_index = static_cast(indexed->fIndex); *fOut << "->" << struct_type->fType->getName(field_index->fNum); } else { // Zone address zone[id][index] are rewritten as zone[id+index] if (fZoneAddress) { *fOut << "+"; } else { *fOut << "["; } fIndexedAddress = false; fZoneAddress = false; indexed->fIndex->accept(this); *fOut << "]"; } } // Size is expressed in unit of the actual type (so 'int' or 'float/double') int getIntZoneSize() { return fStructVisitor.getStructIntSize()/sizeof(int); } int getRealZoneSize() { return fStructVisitor.getStructRealSize()/ifloatsize(); } }; class CPPVecInstVisitor : public CPPInstVisitor { public: CPPVecInstVisitor(std::ostream* out, int tab = 0) : CPPInstVisitor(out, tab) {} }; #endif