/************************************************************************ ************************************************************************ FAUST compiler Copyright (C) 2003-2022 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 Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************************************************************ ************************************************************************/ #include #include #include "absprim.hh" #include "acosprim.hh" #include "asinprim.hh" #include "atan2prim.hh" #include "atanprim.hh" #include "binop.hh" #include "ceilprim.hh" #include "cosprim.hh" #include "enrobage.hh" #include "exepath.hh" #include "exp10prim.hh" #include "expprim.hh" #include "floats.hh" #include "floorprim.hh" #include "fmodprim.hh" #include "global.hh" #include "instructions.hh" #include "log10prim.hh" #include "logprim.hh" #include "maxprim.hh" #include "minprim.hh" #include "occur.hh" #include "powprim.hh" #include "remainderprim.hh" #include "rintprim.hh" #include "roundprim.hh" #include "sinprim.hh" #include "sourcereader.hh" #include "sqrtprim.hh" #include "tanprim.hh" #include "timing.hh" #include "tree.hh" #ifdef WIN32 #pragma warning(disable : 4996) #endif #ifdef C_BUILD #include "c_code_container.hh" #endif #ifdef CODEBOX_BUILD #include "codebox_code_container.hh" #endif #ifdef CPP_BUILD #include "cpp_code_container.hh" #include "cpp_gpu_code_container.hh" #endif #ifdef CSHARP_BUILD #include "csharp_code_container.hh" #endif #ifdef FIR_BUILD #include "fir_code_container.hh" #endif #ifdef LLVM_BUILD #include "llvm_dsp_aux.hh" #endif #ifdef INTERP_BUILD #include "interpreter_instructions.hh" #endif #ifdef JAVA_BUILD #include "java_code_container.hh" #endif #ifdef RUST_BUILD #include "rust_code_container.hh" #endif #ifdef DLANG_BUILD #include "dlang_code_container.hh" #endif #ifdef JULIA_BUILD #include "julia_code_container.hh" #endif #ifdef JSFX_BUILD #include "jsfx_code_container.hh" #endif #ifdef JAX_BUILD #include "jax_code_container.hh" #endif #ifdef ASSEMBLYSCRIPT_BUILD #include "assemblyscript_code_container.hh" #endif #ifdef TEMPLATE_BUILD #include "template_code_container.hh" #endif using namespace std; #ifndef AP_INT_MAX_W #define AP_INT_MAX_W 1024 #endif // Globals for flex/bison parser extern FILE* FAUSTin; extern const char* FAUSTfilename; // Garbageable globals list global::gRawObjectTable; list global::gArrayObjectTable; bool global::gHeapCleanup = false; // Just after gRawObjectTable/gArrayObjectTable initialisation for FaustAlgebra constructor to // correctly work itv::interval_algebra gAlgebra; global::global() : TABBER(1), gLoopDetector(1024, 400), gStackOverflowDetector(MAX_STACK_SIZE), gNextFreeColor(1) { CTree::init(); Symbol::init(); // Part of the state that needs to be initialized between consecutive calls to Box/Signal API reset(); EVALPROPERTY = symbol("EvalProperty"); PMPROPERTYNODE = symbol("PMPROPERTY"); // Fastmath mapping float version gFastMathLibTable["fabsf"] = "fast_fabsf"; gFastMathLibTable["acosf"] = "fast_acosf"; gFastMathLibTable["asinf"] = "fast_asinf"; gFastMathLibTable["atanf"] = "fast_atanf"; gFastMathLibTable["atan2f"] = "fast_atan2f"; gFastMathLibTable["ceilf"] = "fast_ceilf"; gFastMathLibTable["cosf"] = "fast_cosf"; gFastMathLibTable["expf"] = "fast_expf"; gFastMathLibTable["exp2f"] = "fast_exp2f"; gFastMathLibTable["exp10f"] = "fast_exp10f"; gFastMathLibTable["floorf"] = "fast_floorf"; gFastMathLibTable["fmodf"] = "fast_fmodf"; gFastMathLibTable["logf"] = "fast_logf"; gFastMathLibTable["log2f"] = "fast_log2f"; gFastMathLibTable["log10f"] = "fast_log10f"; gFastMathLibTable["powf"] = "fast_powf"; gFastMathLibTable["remainderf"] = "fast_remainderf"; gFastMathLibTable["rintf"] = "fast_rintf"; gFastMathLibTable["roundf"] = "fast_roundf"; gFastMathLibTable["sinf"] = "fast_sinf"; gFastMathLibTable["sqrtf"] = "fast_sqrtf"; gFastMathLibTable["tanf"] = "fast_tanf"; // Fastmath mapping double version gFastMathLibTable["fabs"] = "fast_fabs"; gFastMathLibTable["acos"] = "fast_acos"; gFastMathLibTable["asin"] = "fast_asin"; gFastMathLibTable["atan"] = "fast_atan"; gFastMathLibTable["atan2"] = "fast_atan2"; gFastMathLibTable["ceil"] = "fast_ceil"; gFastMathLibTable["cos"] = "fast_cos"; gFastMathLibTable["exp"] = "fast_exp"; gFastMathLibTable["exp2"] = "fast_exp2"; gFastMathLibTable["exp10"] = "fast_exp10"; gFastMathLibTable["floor"] = "fast_floor"; gFastMathLibTable["fmod"] = "fast_fmod"; gFastMathLibTable["log"] = "fast_log"; gFastMathLibTable["log2"] = "fast_log2"; gFastMathLibTable["log10"] = "fast_log10"; gFastMathLibTable["pow"] = "fast_pow"; gFastMathLibTable["remainder"] = "fast_remainder"; gFastMathLibTable["rint"] = "fast_rint"; gFastMathLibTable["round"] = "fast_round"; gFastMathLibTable["sin"] = "fast_sin"; gFastMathLibTable["sqrt"] = "fast_sqrt"; gFastMathLibTable["tan"] = "fast_tan"; // Fastmath mapping quad version gFastMathLibTable["fabsl"] = "fast_fabs"; gFastMathLibTable["acosl"] = "fast_acos"; gFastMathLibTable["asinl"] = "fast_asin"; gFastMathLibTable["atanl"] = "fast_atan"; gFastMathLibTable["atan2l"] = "fast_atan2"; gFastMathLibTable["ceill"] = "fast_ceil"; gFastMathLibTable["cosl"] = "fast_cos"; gFastMathLibTable["expl"] = "fast_exp"; gFastMathLibTable["exp2l"] = "fast_exp2"; gFastMathLibTable["exp10l"] = "fast_exp10"; gFastMathLibTable["floorl"] = "fast_floor"; gFastMathLibTable["fmodl"] = "fast_fmod"; gFastMathLibTable["logl"] = "fast_log"; gFastMathLibTable["log2l"] = "fast_log2"; gFastMathLibTable["log10l"] = "fast_log10"; gFastMathLibTable["powl"] = "fast_pow"; gFastMathLibTable["remainderl"] = "fast_remainder"; gFastMathLibTable["rintl"] = "fast_rint"; gFastMathLibTable["roundl"] = "fast_round"; gFastMathLibTable["sinl"] = "fast_sin"; gFastMathLibTable["sqrtl"] = "fast_sqrt"; gFastMathLibTable["tanl"] = "fast_tan"; // Fastmath mapping fx version gFastMathLibTable["fabsfx"] = "fast_fabs"; gFastMathLibTable["acosfx"] = "fast_acos"; gFastMathLibTable["asinfx"] = "fast_asin"; gFastMathLibTable["atanfx"] = "fast_atan"; gFastMathLibTable["atan2fx"] = "fast_atan2"; gFastMathLibTable["ceilfx"] = "fast_ceil"; gFastMathLibTable["cosfx"] = "fast_cos"; gFastMathLibTable["expfx"] = "fast_exp"; gFastMathLibTable["exp2fx"] = "fast_exp2"; gFastMathLibTable["exp10fx"] = "fast_exp10"; gFastMathLibTable["floorfx"] = "fast_floor"; gFastMathLibTable["fmodfx"] = "fast_fmod"; gFastMathLibTable["logfx"] = "fast_log"; gFastMathLibTable["log2fx"] = "fast_log2"; gFastMathLibTable["log10fx"] = "fast_log10"; gFastMathLibTable["powfx"] = "fast_pow"; gFastMathLibTable["remainderfx"] = "fast_remainder"; gFastMathLibTable["rintfx"] = "fast_rint"; gFastMathLibTable["roundfx"] = "fast_round"; gFastMathLibTable["sinfx"] = "fast_sin"; gFastMathLibTable["sqrtfx"] = "fast_sqrt"; gFastMathLibTable["tanfx"] = "fast_tan"; gAbsPrim = new AbsPrim(); gAcosPrim = new AcosPrim(); gTanPrim = new TanPrim(); gSqrtPrim = new SqrtPrim(); gSinPrim = new SinPrim(); gRintPrim = new RintPrim(); gRoundPrim = new RoundPrim(); gRemainderPrim = new RemainderPrim(); gPowPrim = new PowPrim(); gMinPrim = new MinPrim(); gMaxPrim = new MaxPrim(); gLogPrim = new LogPrim(); gLog10Prim = new Log10Prim(); gFmodPrim = new FmodPrim(); gFloorPrim = new FloorPrim(); gExpPrim = new ExpPrim(); gExp10Prim = new Exp10Prim(); gCosPrim = new CosPrim(); gCeilPrim = new CeilPrim(); gAtanPrim = new AtanPrim(); gAtan2Prim = new Atan2Prim(); gAsinPrim = new AsinPrim(); BOXIDENT = symbol("BoxIdent"); BOXCUT = symbol("BoxCut"); BOXWAVEFORM = symbol("BoxWaveform"); BOXROUTE = symbol("BoxRoute"); BOXWIRE = symbol("BoxWire"); BOXSLOT = symbol("BoxSlot"); BOXSYMBOLIC = symbol("BoxSymbolic"); BOXSEQ = symbol("BoxSeq"); BOXPAR = symbol("BoxPar"); BOXREC = symbol("BoxRec"); BOXSPLIT = symbol("BoxSplit"); BOXMERGE = symbol("BoxMerge"); BOXIPAR = symbol("BoxIPar"); BOXISEQ = symbol("BoxISeq"); BOXISUM = symbol("BoxISum"); BOXIPROD = symbol("BoxIProd"); BOXABSTR = symbol("BoxAbstr"); BOXMODULATION = symbol("BoxModulation"); BOXAPPL = symbol("BoxAppl"); CLOSURE = symbol("Closure"); BOXERROR = symbol("BoxError"); BOXACCESS = symbol("BoxAccess"); BOXWITHLOCALDEF = symbol("BoxWithLocalDef"); BOXMODIFLOCALDEF = symbol("BoxModifLocalDef"); BOXENVIRONMENT = symbol("BoxEnvironment"); BOXCOMPONENT = symbol("BoxComponent"); BOXLIBRARY = symbol("BoxLibrary"); IMPORTFILE = symbol("ImportFile"); BOXPRIM0 = symbol("BoxPrim0"); BOXPRIM1 = symbol("BoxPrim1"); BOXPRIM2 = symbol("BoxPrim2"); BOXPRIM3 = symbol("BoxPrim3"); BOXPRIM4 = symbol("BoxPrim4"); BOXPRIM5 = symbol("BoxPrim5"); BOXFFUN = symbol("BoxFFun"); BOXFCONST = symbol("BoxFConst"); BOXFVAR = symbol("BoxFVar"); BOXBUTTON = symbol("BoxButton"); BOXCHECKBOX = symbol("BoxCheckbox"); BOXHSLIDER = symbol("BoxHSlider"); BOXVSLIDER = symbol("BoxVSlider"); BOXNUMENTRY = symbol("BoxNumEntry"); BOXHGROUP = symbol("BoxHGroup"); BOXVGROUP = symbol("BoxVGroup"); BOXTGROUP = symbol("BoxTGroup"); BOXHBARGRAPH = symbol("BoxHBargraph"); BOXVBARGRAPH = symbol("BoxVBargraph"); BOXCASE = symbol("BoxCase"); BOXPATMATCHER = symbol("BoxPatMatcher"); BOXPATVAR = symbol("BoxPatVar"); BOXINPUTS = symbol("BoxInputs"); BOXOUTPUTS = symbol("BoxOutputs"); BOXSOUNDFILE = symbol("boxSoundfile"); BOXMETADATA = symbol("boxMetadata"); DOCEQN = symbol("DocEqn"); DOCDGM = symbol("DocDgm"); DOCNTC = symbol("DocNtc"); DOCLST = symbol("DocLst"); DOCMTD = symbol("DocMtd"); DOCTXT = symbol("DocTxt"); BARRIER = symbol("BARRIER"); UIFOLDER = symbol("uiFolder"); UIWIDGET = symbol("uiWidget"); PATHROOT = symbol("/"); PATHPARENT = symbol(".."); PATHCURRENT = symbol("."); FFUN = symbol("ForeignFunction"); SIGINPUT = symbol("SigInput"); SIGOUTPUT = symbol("SigOutput"); SIGDELAY1 = symbol("SigDelay1"); SIGDELAY = symbol("SigDelay"); SIGPREFIX = symbol("SigPrefix"); SIGRDTBL = symbol("SigRDTbl"); SIGWRTBL = symbol("SigWRTbl"); SIGGEN = symbol("SigGen"); SIGDOCONSTANTTBL = symbol("SigDocConstantTbl"); SIGDOCWRITETBL = symbol("SigDocWriteTbl"); SIGDOCACCESSTBL = symbol("SigDocAccessTbl"); SIGSELECT2 = symbol("SigSelect2"); SIGASSERTBOUNDS = symbol("sigAssertBounds"); SIGHIGHEST = symbol("sigHighest"); SIGLOWEST = symbol("sigLowest"); SIGBINOP = symbol("SigBinOp"); SIGFFUN = symbol("SigFFun"); SIGFCONST = symbol("SigFConst"); SIGFVAR = symbol("SigFVar"); SIGPROJ = symbol("SigProj"); SIGINTCAST = symbol("SigIntCast"); SIGBITCAST = symbol("SigBitCast"); SIGFLOATCAST = symbol("SigFloatCast"); SIGBUTTON = symbol("SigButton"); SIGCHECKBOX = symbol("SigCheckbox"); SIGWAVEFORM = symbol("SigWaveform"); SIGHSLIDER = symbol("SigHSlider"); SIGVSLIDER = symbol("SigVSlider"); SIGNUMENTRY = symbol("SigNumEntry"); SIGHBARGRAPH = symbol("SigHBargraph"); SIGVBARGRAPH = symbol("SigVBargraph"); SIGATTACH = symbol("SigAttach"); SIGENABLE = symbol("SigEnable"); SIGCONTROL = symbol("SigControl"); SIGSOUNDFILE = symbol("SigSoundfile"); SIGSOUNDFILELENGTH = symbol("SigSoundfileLength"); SIGSOUNDFILERATE = symbol("SigSoundfileRate"); SIGSOUNDFILEBUFFER = symbol("SigSoundfileBuffer"); SIGREGISTER = symbol("SigRegister"); // for FPGA Retiming SIGTUPLE = symbol("SigTuple"); SIGTUPLEACCESS = symbol("SigTupleAccess"); SIMPLETYPE = symbol("SimpleType"); TABLETYPE = symbol("TableType"); TUPLETTYPE = symbol("TupletType"); // recursive trees DEBRUIJN = symbol("DEBRUIJN"); DEBRUIJNREF = symbol("DEBRUIJNREF"); SUBSTITUTE = symbol("SUBSTITUTE"); SYMREC = symbol("SYMREC"); SYMRECREF = symbol("SYMRECREF"); SYMLIFTN = symbol("LIFTN"); gMachineFloatSize = sizeof(float); gMachineInt32Size = sizeof(int); gMachineInt64Size = sizeof(long int); gMachineDoubleSize = sizeof(double); gMachineQuadSize = sizeof(long double); gMachineFixedPointSize = gMachineFloatSize; gMachineBoolSize = sizeof(bool); // Assuming we are compiling for a 64 bits machine gMachinePtrSize = sizeof(nullptr); #if defined(ANDROID) && INTPTR_MAX == INT32_MAX // Hack for 32Bit Android Architectures ; sizeof(nullptr) == 4 but LLVM // DataLayout.GetPointerSize() == 8 gMachinePtrSize *= 2; #endif gMachineMaxStackSize = MAX_MACHINE_STACK_SIZE; gIntZone = nullptr; gRealZone = nullptr; } // Part of the state that needs to be initialized between consecutive calls to Box/Signal API void global::reset() { gAllWarning = false; gWarningMessages.clear(); gResult = nullptr; gExpandedDefList = nullptr; gDetailsSwitch = false; gDrawSignals = false; gDrawRetiming = false; gDrawRouteFrame = false; gShadowBlur = false; // note: svg2pdf doesn't like the blur filter gScaledSVG = false; gStripDocSwitch = false; // Strip content from doc listings. gFoldThreshold = 25; gFoldComplexity = 2; gMaxNameSize = 40; gSimpleNames = false; gSimplifyDiagrams = false; gMaxCopyDelay = 16; // Maximal delay too choose a copy representation gMaxDenseDelay = 1024; // Maximal delay too choose a dense representation gMinDensity = 33; // Minimal density d/100 to choose a dense representation gVectorSwitch = false; gDeepFirstSwitch = false; gVecSize = 32; gVectorLoopVariant = 0; gOpenMPSwitch = false; gOpenMPLoop = false; gSchedulerSwitch = false; gOpenCLSwitch = false; gCUDASwitch = false; gGroupTaskSwitch = false; gFunTaskSwitch = false; gUIMacroSwitch = false; gRustNoTraitSwitch = false; gRustNoLibm = false; gDumpNorm = -1; gFTZMode = 0; gRangeUI = false; gFreezeUI = false; gFloatSize = 1; // -single by default gFixedPointSize = AP_INT_MAX_W; // Special -1 value will be used to generate fixpoint_t type gFixedPointMSB = 0; gFixedPointLSB = 0; gPrintFileListSwitch = false; gInlineArchSwitch = false; gDSPStruct = false; gLightMode = false; gClang = false; gNoVirtual = false; gCheckTable = true; gMathExceptions = false; gClassName = "mydsp"; gSuperClassName = "dsp"; gProcessName = "process"; gDSPFactory = nullptr; gInputString = ""; gInputFiles.clear(); // Backend configuration : default values gAllowForeignFunction = true; gAllowForeignConstant = true; gAllowForeignVar = true; gComputeIOTA = false; gFAUSTFLOAT2Internal = false; gInPlace = false; gStrictSelect = false; gHasExp10 = false; gLoopVarInBytes = false; gUseMemmove = false; gWaveformInDSP = false; gUseDefaultSound = true; gHasTeeLocal = false; gMathApprox = false; gNeedManualPow = true; gRemoveVarAddress = false; gOneSample = false; gOneSampleIO = false; gExtControl = false; gInlineTable = false; gComputeMix = false; gBool2Int = false; gFastMathLib = ""; gNamespace = ""; gFullParentheses = false; gCheckIntRange = false; gReprC = true; gNarrowingLimit = 0; gWideningLimit = 0; gLstDependenciesSwitch = true; // mdoc listing management. gLstMdocTagsSwitch = true; // mdoc listing management. gLstDistributedSwitch = true; // mdoc listing management. gAutoDifferentiate = false; gLatexDocSwitch = true; // Only LaTeX outformat is handled for the moment. gFileNum = 0; gBoxCounter = 0; gSignalCounter = 0; gCountInferences = 0; gCountMaximal = 0; #ifdef FIR_BUILD gStats.reset(); // Reset compiler statistics #endif gDummyInput = 10000; gBoxSlotNumber = 0; gMemoryManager = -1; gLocalCausalityCheck = false; gCausality = false; gOccurrences = nullptr; gFoldingFlag = false; gDevSuffix = nullptr; gSTEP = 1; // unique compilation step number gOutputLang = ""; #ifdef WASM_BUILD gWASMVisitor = nullptr; // Will be (possibly) allocated in WebAssembly backend gWASTVisitor = nullptr; // Will be (possibly) allocated in WebAssembly backend #endif #if defined(INTERP_BUILD) || defined(INTERP_COMP_BUILD) gInterpreterVisitor = nullptr; // Will be (possibly) allocated in Interp backend #endif #ifdef JULIA_BUILD gJuliaVisitor = nullptr; // Will be (possibly) allocated in Julia backend #endif #ifdef JSFX_BUILD gJSFXVisitor = nullptr; // Will be (possibly) allocated in JSFX backend #endif #ifdef CMAJOR_BUILD gTableSizeVisitor = nullptr; // Will be (possibly) allocated in Cmajor backend #endif #ifdef JAX_BUILD gJAXVisitor = nullptr; // Will be (possibly) allocated in JAX backend #endif #ifdef ASSEMBLYSCRIPT_BUILD gAssemblyScriptVisitor = nullptr; // Will be (possibly) allocated in AssemblyScript backend #endif #ifdef TEMPLATE_BUILD gTemplateVisitor = nullptr; // Will be (possibly) allocated in Template backend #endif #ifdef CODEBOX_BUILD gCodeboxVisitor = nullptr; // Will be (possibly) allocated in Codebox backend #endif gHelpSwitch = false; gVersionSwitch = false; gLibDirSwitch = false; gIncludeDirSwitch = false; gArchDirSwitch = false; gDspDirSwitch = false; gPathListSwitch = false; gGraphSwitch = false; gDrawPSSwitch = false; gDrawSVGSwitch = false; gVHDLTrace = false; gVHDLFloatEncoding = false; gFPGAMemory = 0; gFPGAMemoryThreshold = 4; gPrintXMLSwitch = false; gPrintJSONSwitch = false; gPrintDocSwitch = false; gArchFile = ""; gExportDSP = false; gTimeout = 120; // Time out to abort compiler (in seconds) gErrorCount = 0; gErrorMessage = ""; // By default use "cpp" output gOutputLang = (getenv("FAUST_DEFAULT_BACKEND")) ? string(getenv("FAUST_DEFAULT_BACKEND")) : "cpp"; } // Done after contructor since part of the following allocations need the "global" object to be // fully built void global::init() { // Default init initFaustFloat(); gPureRoutingProperty = new property(); gSymbolicBoxProperty = new property(); gSimplifiedBoxProperty = new property(); gSymListProp = new property(); // Essential predefined types gMemoizedTypes = new property(); gAllocationCount = 0; gMaskDelayLineThreshold = INT_MAX; // True by default but only usable with -lang ocpp backend gEnableFlag = true; // Essential predefined types TINPUT = makeSimpleType(kReal, kSamp, kExec, kVect, kNum, interval(-1, 1)); TGUI = makeSimpleType(kReal, kBlock, kExec, kVect, kNum, interval()); TREC = makeSimpleType(kInt, kSamp, kInit, kScal, kNum, interval(0, 0)); // !!! TRECMAX Maximal only in the last component of the type lattice TRECMAX = makeSimpleType(kInt, kSamp, kInit, kScal, kNum, interval(-HUGE_VAL, HUGE_VAL)); // Predefined symbols CONS and NIL CONS = symbol("cons"); NIL = symbol("nil"); // Predefined nil tree nil = tree(NIL); PROCESS = symbol("process"); BOXTYPEPROP = tree(symbol("boxTypeProp")); NUMERICPROPERTY = tree(symbol("NUMERICPROPERTY")); DEFLINEPROP = tree(symbol("DefLineProp")); USELINEPROP = tree(symbol("UseLineProp")); SIMPLIFIED = tree(symbol("sigSimplifiedProp")); DOCTABLES = tree(symbol("DocTablesProp")); NULLENV = tree(symbol("NullRenameEnv")); COLORPROPERTY = tree(symbol("ColorProperty")); ORDERPROP = tree(symbol("OrderProp")); RECURSIVNESS = tree(symbol("RecursivnessProp")); NULLTYPEENV = tree(symbol("NullTypeEnv")); RECDEF = tree(symbol("RECDEF")); DEBRUIJN2SYM = tree(symbol("deBruijn2Sym")); NORMALFORM = tree(symbol("NormalForm")); DEFNAMEPROPERTY = tree(symbol("DEFNAMEPROPERTY")); NICKNAMEPROPERTY = tree(symbol("NICKNAMEPROPERTY")); BCOMPLEXITY = tree("BCOMPLEXITY"); LETRECBODY = boxIdent("RECURSIVEBODY"); PROPAGATEPROPERTY = symbol("PropagateProperty"); // FAUSTfilename is defined in errormsg.cpp but must be redefined at each compilation. FAUSTfilename = ""; FAUSTin = nullptr; gLatexheaderfilename = "latexheader.tex"; gDocTextsDefaultFile = "mathdoctexts-default.txt"; gCurrentLocal = setlocale(LC_ALL, NULL); if (gCurrentLocal != NULL) { gCurrentLocal = strdup(gCurrentLocal); } // Setup standard "C" local // (workaround for a bug in bitcode generation : // http://lists.cs.uiuc.edu/pipermail/llvmbugs/2012-May/023530.html) setlocale(LC_ALL, "C"); // Source file injection gInjectFlag = false; // inject an external source file into the architecture file gInjectFile = ""; // instead of a compiled dsp file // Create type declaration for external 'soundfile' type vector sf_type_fields; sf_type_fields.push_back(IB::genNamedTyped("fBuffers", IB::genBasicTyped(Typed::kVoid_ptr))); sf_type_fields.push_back(IB::genNamedTyped("fLength", IB::genBasicTyped(Typed::kInt32_ptr))); sf_type_fields.push_back(IB::genNamedTyped("fSR", IB::genBasicTyped(Typed::kInt32_ptr))); sf_type_fields.push_back(IB::genNamedTyped("fOffset", IB::genBasicTyped(Typed::kInt32_ptr))); sf_type_fields.push_back(IB::genNamedTyped("fChannels", IB::genInt32Typed())); sf_type_fields.push_back(IB::genNamedTyped("fParts", IB::genInt32Typed())); sf_type_fields.push_back(IB::genNamedTyped("fIsDouble", IB::genInt32Typed())); gExternalStructTypes[Typed::kSound] = IB::genDeclareStructTypeInst(IB::genStructTyped("Soundfile", sf_type_fields)); // Foreign math functions supported by the Interp, Cmajor, codebox, wasm/wast backends gMathForeignFunctions["acoshf"] = true; gMathForeignFunctions["acosh"] = true; gMathForeignFunctions["acoshl"] = true; gMathForeignFunctions["asinhf"] = true; gMathForeignFunctions["asinh"] = true; gMathForeignFunctions["asinhl"] = true; gMathForeignFunctions["atanhf"] = true; gMathForeignFunctions["atanh"] = true; gMathForeignFunctions["atanhl"] = true; gMathForeignFunctions["coshf"] = true; gMathForeignFunctions["cosh"] = true; gMathForeignFunctions["coshl"] = true; gMathForeignFunctions["sinhf"] = true; gMathForeignFunctions["sinh"] = true; gMathForeignFunctions["sinhl"] = true; gMathForeignFunctions["tanhf"] = true; gMathForeignFunctions["tanh"] = true; gMathForeignFunctions["tanhl"] = true; gMathForeignFunctions["isnanf"] = true; gMathForeignFunctions["isnan"] = true; gMathForeignFunctions["isnanl"] = true; gMathForeignFunctions["isinff"] = true; gMathForeignFunctions["isinf"] = true; gMathForeignFunctions["isinfl"] = true; gMathForeignFunctions["copysignf"] = true; gMathForeignFunctions["copysign"] = true; gMathForeignFunctions["copysignl"] = true; // internal state during drawing gInverter[0] = boxSeq(boxPar(boxWire(), boxInt(-1)), boxPrim2(sigMul)); gInverter[1] = boxSeq(boxPar(boxInt(-1), boxWire()), boxPrim2(sigMul)); gInverter[2] = boxSeq(boxPar(boxWire(), boxReal(-1.0)), boxPrim2(sigMul)); gInverter[3] = boxSeq(boxPar(boxReal(-1.0), boxWire()), boxPrim2(sigMul)); gInverter[4] = boxSeq(boxPar(boxInt(0), boxWire()), boxPrim2(sigSub)); gInverter[5] = boxSeq(boxPar(boxReal(0.0), boxWire()), boxPrim2(sigSub)); } string global::printFloat() { switch (gFloatSize) { case 1: return "-single "; case 2: return "-double "; case 3: return "-quad "; case 4: return "-fx -fx-size " + std::to_string(gFixedPointSize) + " "; default: faustassert(false); return ""; } } void global::printCompilationOptions(stringstream& dst, bool backend) { if (gAutoDifferentiate) { dst << "-diff "; } if (gArchFile != "") { dst << "-a " << gArchFile << " "; } if (backend) { #ifdef LLVM_BUILD if (gOutputLang == "llvm") { dst << "-lang " << gOutputLang << " " << LLVM_VERSION << " "; } else { dst << "-lang " << gOutputLang << " "; } #else dst << "-lang " << gOutputLang << " "; #endif } if (gInlineArchSwitch) { dst << "-i "; } if (gInPlace) { dst << "-inpl "; } if (gStrictSelect) { dst << "-sts "; } if (gFPGAMemory > 0) { dst << "-fpga-mem " << gFPGAMemory << " "; } if (gFPGAMemoryThreshold > 0) { dst << "-fpga-mem-th " << gFPGAMemoryThreshold << " "; } if (gOneSample) { dst << "-os "; } if (gLightMode) { dst << "-light "; } if (gMemoryManager >= 0) { dst << "-mem" << gMemoryManager << " "; } if (gComputeMix) { dst << "-cm "; } if (gInlineTable) { dst << "-it "; } if (gRangeUI) { dst << "-rui "; } if (gNoVirtual) { dst << "-nvi "; } if (gFullParentheses) { dst << "-fp "; } if (gCheckIntRange) { dst << "-cir "; } if (gExtControl) { dst << "-ec "; } dst << "-ct " << gCheckTable << " "; if (gMathApprox) { dst << "-mapp "; } if (gMathExceptions) { dst << "-me "; } if (gFastMathLib != "") { dst << "-fm " << gFastMathLib << " "; } if (gVHDLTrace) { dst << "-vhdl-trace"; } if (gVHDLFloatEncoding) { dst << "-vhdl-float"; } if (gClassName != "mydsp") { dst << "-cn " << gClassName << " "; } if (gSuperClassName != "dsp") { dst << "-scn " << gSuperClassName << " "; } if (gProcessName != "process") { dst << "-pn " << gProcessName << " "; } if (gMaskDelayLineThreshold != INT_MAX) { dst << "-dtl " << gMaskDelayLineThreshold << " "; } dst << "-es " << gEnableFlag << " "; if (gHasExp10) { dst << "-exp10 "; } if (gSchedulerSwitch) { dst << "-sch "; } if (gOpenMPSwitch) { dst << "-omp " << ((gOpenMPLoop) ? "-pl " : ""); } dst << "-mcd " << gMaxCopyDelay << " "; dst << "-mdd " << gMaxDenseDelay << " "; dst << "-mdy " << gMinDensity << " "; if (gUIMacroSwitch) { dst << "-uim "; } dst << printFloat(); dst << "-ftz " << gFTZMode << " "; if (gVectorSwitch) { dst << "-vec " << "-lv " << gVectorLoopVariant << " " << "-vs " << gVecSize << " " << ((gFunTaskSwitch) ? "-fun " : "") << ((gGroupTaskSwitch) ? "-g " : "") << ((gDeepFirstSwitch) ? "-dfs " : ""); } // Add 'compile_options' metadata string res = dst.str(); gMetaDataSet[tree("compile_options")].insert(tree("\"" + res.substr(0, res.size() - 1) + "\"")); } string global::printCompilationOptions1() { stringstream dst; printCompilationOptions(dst, true); string res = dst.str(); return res.substr(0, res.size() - 1); } void global::initTypeSizeMap() { // Init type size table (in bytes) gTypeSizeMap[Typed::kFloat] = gMachineFloatSize; gTypeSizeMap[Typed::kFloat_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kFloat_ptr_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kFloat_vec] = gMachineFloatSize * gVecSize; gTypeSizeMap[Typed::kFloat_vec_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kDouble] = gMachineDoubleSize; gTypeSizeMap[Typed::kDouble_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kDouble_ptr_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kDouble_vec] = gMachineDoubleSize * gVecSize; gTypeSizeMap[Typed::kDouble_vec_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kQuad] = gMachineQuadSize; gTypeSizeMap[Typed::kQuad_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kQuad_ptr_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kQuad_vec] = gMachineQuadSize * gVecSize; gTypeSizeMap[Typed::kQuad_vec_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kFixedPoint] = gMachineFixedPointSize; gTypeSizeMap[Typed::kFixedPoint_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kFixedPoint_ptr_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kFixedPoint_vec] = gMachineFixedPointSize * gVecSize; gTypeSizeMap[Typed::kFixedPoint_vec_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kInt32] = gMachineInt32Size; gTypeSizeMap[Typed::kInt32_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kInt32_vec] = gMachineInt32Size * gVecSize; gTypeSizeMap[Typed::kInt32_vec_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kInt64] = gMachineInt64Size; gTypeSizeMap[Typed::kInt64_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kInt64_vec] = gMachineInt64Size * gVecSize; gTypeSizeMap[Typed::kInt64_vec_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kBool] = gMachineBoolSize; gTypeSizeMap[Typed::kBool_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kBool_vec] = gMachineBoolSize * gVecSize; gTypeSizeMap[Typed::kBool_vec_ptr] = gMachinePtrSize; // Takes the type of internal real gTypeSizeMap[Typed::kFloatMacro] = gTypeSizeMap[itfloat()]; gTypeSizeMap[Typed::kFloatMacro_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kFloatMacro_ptr_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kVoid_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kObj_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kSound_ptr] = gMachinePtrSize; gTypeSizeMap[Typed::kUint_ptr] = gMachinePtrSize; } int global::audioSampleSize() { return int(pow(2.f, float(gFloatSize + 1))); } bool global::hasForeignFunction(const string& name, const string& inc_file) { #ifdef LLVM_BUILD // LLVM backend can use 'standard' foreign linked functions static vector inc_list = {"", "", ""}; bool is_inc = find(begin(inc_list), end(inc_list), inc_file) != inc_list.end(); // or custom added ones bool is_ff = llvm_dsp_factory_aux::gForeignFunctions.count(name) > 0; bool is_linkable = (gOutputLang == "llvm") && (is_inc || is_ff); #else bool is_linkable = false; #endif bool internal_math_ff = ((gOutputLang == "llvm") || startWith(gOutputLang, "wast") || startWith(gOutputLang, "wasm") || (gOutputLang == "interp") || startWith(gOutputLang, "cmajor") || startWith(gOutputLang, "codebox") || (gOutputLang == "dlang") || (gOutputLang == "csharp") || (gOutputLang == "rust") || (gOutputLang == "julia") || startWith(gOutputLang, "jsfx") || (gOutputLang == "jax") || (gOutputLang == "asc")); return (internal_math_ff && (gMathForeignFunctions.find(name) != gMathForeignFunctions.end())) || is_linkable; } BasicTyped* global::genBasicTyped(Typed::VarType type) { // Possibly force FAUSTFLOAT type (= kFloatMacro) to internal real Typed::VarType new_type = ((type == Typed::kFloatMacro) && gFAUSTFLOAT2Internal) ? itfloat() : type; // If not defined, add the type in the table if (gTypeTable.find(new_type) == gTypeTable.end()) { gTypeTable[new_type] = new BasicTyped(new_type); } return gTypeTable[new_type]; } void global::clearVarTypeTable() { gVarTypeTable.clear(); } Typed* global::findVarType(const string& name) const { auto it = gVarTypeTable.find(name); return (it != gVarTypeTable.end()) ? it->second : nullptr; } void global::registerVarType(const string& name, Typed* type) { gVarTypeTable[name] = type; } void global::setVarType(const string& name, Typed::VarType type) { registerVarType(name, genBasicTyped(type)); } Typed::VarType global::getVarType(const string& name) { Typed* var_type = findVarType(name); faustassert(var_type); return var_type->getType(); } global::~global() { Garbageable::cleanup(); BasicTyped::cleanup(); DeclareVarInst::cleanup(); setlocale(LC_ALL, gCurrentLocal); free(gCurrentLocal); // Cleanup #ifdef C_BUILD CInstVisitor::cleanup(); #endif #ifdef CPP_BUILD CPPInstVisitor::cleanup(); #endif #ifdef CODEBOX_BUILD CodeboxInstVisitor::cleanup(); #endif #ifdef CSHARP_BUILD CSharpInstVisitor::cleanup(); #endif #ifdef DLANG_BUILD DLangInstVisitor::cleanup(); #endif #ifdef FIR_BUILD FIRInstVisitor::cleanup(); #endif #ifdef JAVA_BUILD JAVAInstVisitor::cleanup(); #endif #ifdef JULIA_BUILD JuliaInstVisitor::cleanup(); #endif #ifdef JSFX_BUILD JSFXInstVisitor::cleanup(); #endif #ifdef JAX_BUILD JAXInstVisitor::cleanup(); #endif #ifdef ASSEMBLYSCRIPT_BUILD AssemblyScriptInstVisitor::cleanup(); #endif #ifdef TEMPLATE_BUILD TemplateInstVisitor::cleanup(); #endif #ifdef RUST_BUILD RustInstVisitor::cleanup(); #endif } void global::allocate() { gGlobal = new global(); gGlobal->init(); } void global::destroy() { #ifdef EMCC if (faustexception::gJSExceptionMsg) { free((void*)faustexception::gJSExceptionMsg); faustexception::gJSExceptionMsg = nullptr; } #endif delete gGlobal; gGlobal = nullptr; } string global::makeDrawPath() { if (gOutputDir != "") { return gOutputDir + "/" + gMasterName + ".dsp"; } else { return gMasterDocument; } } string global::makeDrawPathNoExt() { if (gOutputDir != "") { return gOutputDir + "/" + gMasterName; } else if (gMasterDocument.length() >= 4 && gMasterDocument.substr(gMasterDocument.length() - 4) == ".dsp") { return gMasterDocument.substr(0, gMasterDocument.length() - 4); } else { return gMasterDocument; } } /***************************************************************************** getFreshID *****************************************************************************/ string global::getFreshID(const string& prefix) { if (gIDCounters.find(prefix) == gIDCounters.end()) { gIDCounters[prefix] = 0; } int n = gIDCounters[prefix]; gIDCounters[prefix] = n + 1; return subst("$0$1", prefix, T(n)); } bool global::isDebug(const string& debug_val) { string debug_var = (getenv("FAUST_DEBUG")) ? string(getenv("FAUST_DEBUG")) : ""; return debug_var == debug_val; } int global::getDebug(const string& debug_var, int def_val) { if (getenv(debug_var.c_str())) { return std::stoi(getenv(debug_var.c_str())); } else { return def_val; } } bool global::isOpt(const string& opt_val) { string opt_var = (getenv("FAUST_OPT")) ? string(getenv("FAUST_OPT")) : ""; return opt_var == opt_val; } /**************************************************************** Command line tools and arguments *****************************************************************/ // Timing can be used outside of the scope of 'gGlobal' extern bool gTimingSwitch; static bool isCmd(const char* cmd, const char* kw1) { return (strcmp(cmd, kw1) == 0); } static bool isCmd(const char* cmd, const char* kw1, const char* kw2) { return (strcmp(cmd, kw1) == 0) || (strcmp(cmd, kw2) == 0); } bool global::processCmdline(int argc, const char* argv[]) { int i = 1; int err = 0; stringstream parse_error; bool float_size = false; /* for (int i = 0; i < argc; i++) { cerr << "processCmdline i = " << i << " cmd = " << argv[i] << "\n"; } */ while (i < argc) { if (isCmd(argv[i], "-h", "--help")) { gHelpSwitch = true; i += 1; } else if (isCmd(argv[i], "-lang", "--language") && (i + 1 < argc)) { gOutputLang = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-v", "--version")) { gVersionSwitch = true; i += 1; } else if (isCmd(argv[i], "-libdir", "--libdir")) { gLibDirSwitch = true; i += 1; } else if (isCmd(argv[i], "-includedir", "--includedir")) { gIncludeDirSwitch = true; i += 1; } else if (isCmd(argv[i], "-archdir", "--archdir")) { gArchDirSwitch = true; i += 1; } else if (isCmd(argv[i], "-dspdir", "--dspdir")) { gDspDirSwitch = true; i += 1; } else if (isCmd(argv[i], "-pathslist", "--pathslist")) { gPathListSwitch = true; i += 1; } else if (isCmd(argv[i], "-d", "--details")) { gDetailsSwitch = true; i += 1; } else if (isCmd(argv[i], "-a", "--architecture") && (i + 1 < argc)) { gArchFile = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-inj", "--inject") && (i + 1 < argc)) { gInjectFlag = true; gInjectFile = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-o") && (i + 1 < argc)) { gOutputFile = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-wi", "--widening-iterations") && (i + 1 < argc)) { gWideningLimit = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-ni", "--narrowing-iterations") && (i + 1 < argc)) { gNarrowingLimit = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-ps", "--postscript")) { gDrawPSSwitch = true; i += 1; } else if (isCmd(argv[i], "-xml", "--xml")) { gPrintXMLSwitch = true; i += 1; } else if (isCmd(argv[i], "-json", "--json")) { gPrintJSONSwitch = true; i += 1; } else if (isCmd(argv[i], "-tg", "--task-graph")) { gGraphSwitch = true; i += 1; } else if (isCmd(argv[i], "-sg", "--signal-graph")) { gDrawSignals = true; i += 1; } else if (isCmd(argv[i], "-rg", "--retiming-graph")) { gDrawRetiming = true; i += 1; } else if (isCmd(argv[i], "-drf", "--draw-route-frame")) { gDrawRouteFrame = true; i += 1; } else if (isCmd(argv[i], "-blur", "--shadow-blur")) { gShadowBlur = true; i += 1; } else if (isCmd(argv[i], "-sc", "--scaled-svg")) { gScaledSVG = true; i += 1; } else if (isCmd(argv[i], "-svg", "--svg")) { gDrawSVGSwitch = true; i += 1; } else if (isCmd(argv[i], "-vhdl-trace", "--vhdl-trace")) { gVHDLTrace = true; i += 1; } else if (isCmd(argv[i], "-vhdl-float", "--vhdl-float")) { gVHDLFloatEncoding = true; i += 1; } else if (isCmd(argv[i], "-vhdl-components", "--vhdl-components") && (i + 1 < argc)) { gVHDLComponentsFile = std::string(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-fpga-mem", "--fpga-mem") && (i + 1 < argc)) { gFPGAMemory = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-fpga-mem-th", "--fpga-mem-th") && (i + 1 < argc)) { gFPGAMemoryThreshold = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-style", "--svgstyle")) { gStyleFile = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-f", "--fold") && (i + 1 < argc)) { gFoldThreshold = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-fc", "--fold-complexity") && (i + 1 < argc)) { gFoldComplexity = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-mns", "--max-name-size") && (i + 1 < argc)) { gMaxNameSize = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-sn", "--simple-names")) { gSimpleNames = true; i += 1; } else if (isCmd(argv[i], "-mcd", "--max-copy-delay") && (i + 1 < argc)) { gMaxCopyDelay = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-mdd", "--max-dense-delay") && (i + 1 < argc)) { gMaxDenseDelay = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-mdy", "--min-density") && (i + 1 < argc)) { gMinDensity = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-dlt", "-delay-line-threshold") && (i + 1 < argc)) { gMaskDelayLineThreshold = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-mem", "--memory-manager") || isCmd(argv[i], "-mem0", "--memory-manager0")) { gMemoryManager = 0; i += 1; } else if (isCmd(argv[i], "-mem1", "--memory-manager1")) { gMemoryManager = 1; i += 1; } else if (isCmd(argv[i], "-mem2", "--memory-manager2")) { gMemoryManager = 2; i += 1; } else if (isCmd(argv[i], "-mem3", "--memory-manager3")) { gMemoryManager = 3; i += 1; } else if (isCmd(argv[i], "-sd", "--simplify-diagrams")) { gSimplifyDiagrams = true; i += 1; } else if (isCmd(argv[i], "-vec", "--vectorize")) { gVectorSwitch = true; i += 1; } else if (isCmd(argv[i], "-scal", "--scalar")) { gVectorSwitch = false; i += 1; } else if (isCmd(argv[i], "-dfs", "--deepFirstScheduling")) { gDeepFirstSwitch = true; i += 1; } else if (isCmd(argv[i], "-vs", "--vec-size") && (i + 1 < argc)) { gVecSize = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-lv", "--loop-variant") && (i + 1 < argc)) { gVectorLoopVariant = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-omp", "--openmp")) { gOpenMPSwitch = true; i += 1; } else if (isCmd(argv[i], "-pl", "--par-loop")) { gOpenMPLoop = true; i += 1; } else if (isCmd(argv[i], "-sch", "--scheduler")) { gSchedulerSwitch = true; i += 1; } else if (isCmd(argv[i], "-ocl", "--openCL")) { gOpenCLSwitch = true; i += 1; } else if (isCmd(argv[i], "-cuda", "--CUDA")) { gCUDASwitch = true; i += 1; } else if (isCmd(argv[i], "-g", "--groupTasks")) { gGroupTaskSwitch = true; i += 1; } else if (isCmd(argv[i], "-fun", "--funTasks")) { gFunTaskSwitch = true; i += 1; } else if (isCmd(argv[i], "-uim", "--user-interface-macros")) { gUIMacroSwitch = true; i += 1; } else if (isCmd(argv[i], "-rnt", "--rust-no-faustdsp-trait")) { gRustNoTraitSwitch = true; i += 1; } else if (isCmd(argv[i], "-rnlm", "--rust-no-libm")) { gRustNoLibm = true; i += 1; } else if (isCmd(argv[i], "-t", "--timeout") && (i + 1 < argc)) { gTimeout = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-time", "--compilation-time")) { gTimingSwitch = true; i += 1; // 'real' options } else if (isCmd(argv[i], "-single", "--single-precision-floats")) { if (float_size && gFloatSize != 1) { throw faustexception( "ERROR : cannot using -single, -double, -quad or -fx at the same time\n"); } else { float_size = true; } gFloatSize = 1; i += 1; } else if (isCmd(argv[i], "-double", "--double-precision-floats")) { if (float_size && gFloatSize != 2) { throw faustexception( "ERROR : cannot using -single, -double, -quad or -fx at the same time\n"); } else { float_size = true; } gFloatSize = 2; i += 1; } else if (isCmd(argv[i], "-quad", "--quad-precision-floats")) { if (float_size && gFloatSize != 3) { throw faustexception( "ERROR : cannot using -single, -double, -quad or -fx at the same time\n"); } else { float_size = true; } gFloatSize = 3; i += 1; } else if (isCmd(argv[i], "-fx", "--fixed-point")) { if (float_size && gFloatSize != 4) { throw faustexception( "ERROR : cannot using -single, -double, -quad or -fx at the same time\n"); } else { float_size = true; } gFloatSize = 4; i += 1; } else if (isCmd(argv[i], "-fx-size", "--fixed-point-size")) { gFixedPointSize = std::atoi(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-mdoc", "--mathdoc")) { gPrintDocSwitch = true; i += 1; } else if (isCmd(argv[i], "-mdlang", "--mathdoc-lang") && (i + 1 < argc)) { gDocLang = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-stripmdoc", "--strip-mdoc-tags")) { gStripDocSwitch = true; i += 1; } else if (isCmd(argv[i], "-flist", "--file-list")) { gPrintFileListSwitch = true; i += 1; } else if (isCmd(argv[i], "-norm", "--normalized-form")) { gDumpNorm = 0; i += 1; } else if (isCmd(argv[i], "-norm1", "--normalized-form1")) { gDumpNorm = 1; i += 1; } else if (isCmd(argv[i], "-norm2", "--normalized-form2")) { gDumpNorm = 2; i += 1; } else if (isCmd(argv[i], "-norm3", "--normalized-form3")) { gDumpNorm = 3; i += 1; } else if (isCmd(argv[i], "-cn", "--class-name") && (i + 1 < argc)) { vector rep = {'@', ' ', '(', ')', '/', '\\', '.'}; gClassName = replaceCharList(argv[i + 1], rep, '_'); i += 2; } else if (isCmd(argv[i], "-scn", "--super-class-name") && (i + 1 < argc)) { gSuperClassName = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-pn", "--process-name") && (i + 1 < argc)) { gProcessName = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-i", "--inline-architecture-files")) { gInlineArchSwitch = true; i += 1; } else if (isCmd(argv[i], "-e", "--export-dsp")) { gExportDSP = true; i += 1; } else if (isCmd(argv[i], "-exp10", "--generate-exp10")) { gHasExp10 = true; i += 1; } else if (isCmd(argv[i], "-os", "--one-sample")) { gOneSample = true; i += 1; } else if (isCmd(argv[i], "-ec", "--external-control")) { gExtControl = true; i += 1; } else if (isCmd(argv[i], "-it", "--inline-table")) { gInlineTable = true; i += 1; } else if (isCmd(argv[i], "-cm", "--compute-mix")) { gComputeMix = true; i += 1; } else if (isCmd(argv[i], "-ftz", "--flush-to-zero")) { gFTZMode = std::atoi(argv[i + 1]); if ((gFTZMode > 2) || (gFTZMode < 0)) { stringstream error; error << "ERROR : invalid -ftz option: " << gFTZMode << endl; throw faustexception(error.str()); } i += 2; } else if (isCmd(argv[i], "-rui", "--range-ui")) { gRangeUI = true; i += 1; } else if (isCmd(argv[i], "-fui", "--freeze-ui")) { gFreezeUI = true; i += 1; } else if (isCmd(argv[i], "-fm", "--fast-math")) { gFastMathLib = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-mapp", "--math-approximation")) { gMathApprox = true; i += 1; } else if (isCmd(argv[i], "-ns", "--namespace")) { gNamespace = argv[i + 1]; i += 2; } else if (isCmd(argv[i], "-fp", "--full-parentheses")) { gFullParentheses = true; i += 1; } else if (isCmd(argv[i], "-cir", "--check-integer-range")) { gCheckIntRange = true; i += 1; } else if (isCmd(argv[i], "-noreprc", "--no-reprc")) { gReprC = false; i += 1; } else if (isCmd(argv[i], "-I", "--import-dir") && (i + 1 < argc)) { if ((strstr(argv[i + 1], "http://") != 0) || (strstr(argv[i + 1], "https://") != 0)) { // We want to search user given directories *before* the standard ones, so insert at // the beginning gImportDirList.insert(gImportDirList.begin(), argv[i + 1]); } else { char temp[PATH_MAX + 1]; char* path = realpath(argv[i + 1], temp); if (path) { // We want to search user given directories *before* the standard ones, so // insert at the beginning gImportDirList.insert(gImportDirList.begin(), path); } } i += 2; } else if (isCmd(argv[i], "-A", "--architecture-dir") && (i + 1 < argc)) { if ((strstr(argv[i + 1], "http://") != 0) || (strstr(argv[i + 1], "https://") != 0)) { gArchitectureDirList.push_back(argv[i + 1]); } else { char temp[PATH_MAX + 1]; char* path = realpath(argv[i + 1], temp); if (path) { gArchitectureDirList.push_back(path); } } i += 2; } else if (isCmd(argv[i], "-L", "--library") && (i + 1 < argc)) { gLibraryList.push_back(argv[i + 1]); i += 2; } else if (isCmd(argv[i], "-O", "--output-dir") && (i + 1 < argc)) { char temp[PATH_MAX + 1]; char* path = realpath(argv[i + 1], temp); if (path == 0) { stringstream error; error << "ERROR : invalid directory path " << argv[i + 1] << endl; throw faustexception(error.str()); } else { gOutputDir = path; } i += 2; } else if (isCmd(argv[i], "-inpl", "--in-place")) { gInPlace = true; i += 1; } else if (isCmd(argv[i], "-sts", "--strict-select")) { gStrictSelect = true; i += 1; } else if (isCmd(argv[i], "-es", "--enable-semantics")) { gEnableFlag = (std::atoi(argv[i + 1]) == 1); i += 2; } else if (isCmd(argv[i], "-lcc", "--local-causality-check")) { gLocalCausalityCheck = true; i += 1; } else if (isCmd(argv[i], "-light", "--light-mode")) { gLightMode = true; i += 1; } else if (isCmd(argv[i], "-clang", "--clang")) { gClang = true; i += 1; } else if (isCmd(argv[i], "-nvi", "--no-virtual")) { gNoVirtual = true; i += 1; } else if (isCmd(argv[i], "-ct", "--check-table")) { gCheckTable = (std::atoi(argv[i + 1]) == 1); i += 2; } else if (isCmd(argv[i], "-wall", "--warning-all")) { gAllWarning = true; i += 1; } else if (isCmd(argv[i], "-me", "--math-exceptions")) { gMathExceptions = true; i += 1; } else if (isCmd(argv[i], "-diff", "--auto-differentiate")) { gAutoDifferentiate = true; i += 1; } else if (isCmd(argv[i], "-lm", "--local-machine") || isCmd(argv[i], "-rm", "--remote-machine") || isCmd(argv[i], "-poly", "--polyphonic-mode") || isCmd(argv[i], "-voices", "--polyphonic-voices") || isCmd(argv[i], "-group", "--polyphonic-group")) { // Ignore arg i += 2; } else if (argv[i][0] != '-') { const char* url = argv[i]; if (checkURL(url)) { gInputFiles.push_back(url); } i++; } else { if (err == 0) { parse_error << "unrecognized option(s) : \"" << argv[i] << "\""; } else { parse_error << ",\"" << argv[i] << "\""; } i++; err++; } } // ======================== // Adjust related options // ======================== if (gOpenMPSwitch || gSchedulerSwitch) { gVectorSwitch = true; } if (gMemoryManager >= 1) { gWaveformInDSP = true; } // ======================== // Check options coherency // ======================== if (gRustNoTraitSwitch && gOutputLang != "rust") { throw faustexception("ERROR : '-rnt' option can only be used with 'rust' backend\n"); } if (gRustNoLibm && gOutputLang != "rust") { throw faustexception("ERROR : '-rnlm' option can only be used with 'rust' backend\n"); } if (!gRustNoTraitSwitch && gInPlace && gOutputLang == "rust") { throw faustexception( "ERROR : for 'rust' the '-inpl' flag must be combined with '-rnt' flag\n"); } if (gInPlace && gVectorSwitch) { throw faustexception("ERROR : '-inpl' option can only be used in scalar mode\n"); } #if 0 if (gOutputLang == "ocpp" && gVectorSwitch) { throw faustexception("ERROR : 'ocpp' backend can only be used in scalar mode\n"); } #endif if (gOneSample && gOutputLang != "cpp" && gOutputLang != "c" && gOutputLang != "dlang" && !startWith(gOutputLang, "cmajor") && gOutputLang != "fir" && gOutputLang != "rust") { throw faustexception( "ERROR : '-os' option can only be used with 'cpp', 'c', 'cmajor', 'dlang', 'fir' or " "'rust' backends\n"); } if (gExtControl && gOutputLang != "cpp" && gOutputLang != "c" && gOutputLang != "cmajor" && gOutputLang != "rust") { throw faustexception( "ERROR : '-ec' option can only be used with 'cpp', 'c', 'cmajor' or 'rust' " "backends\n"); } if (gOneSample && gVectorSwitch) { throw faustexception("ERROR : '-os' option can only be used in scalar mode\n"); } if (gVectorLoopVariant < 0 || gVectorLoopVariant > 2) { stringstream error; error << "ERROR : invalid loop variant [-lv = " << gVectorLoopVariant << "] should be 0 or 1" << endl; throw faustexception(error.str()); } if (gVecSize < 4) { stringstream error; error << "ERROR : invalid vector size [-vs = " << gVecSize << "] should be at least 4" << endl; throw faustexception(error.str()); } if (gFunTaskSwitch) { if (!(gOutputLang == "c" || gOutputLang == "cpp" || gOutputLang == "llvm" || gOutputLang == "fir")) { throw faustexception( "ERROR : -fun can only be used with 'c', 'cpp', 'llvm' or 'fir' backends\n"); } } if (gFastMathLib != "") { if (!(gOutputLang == "c" || gOutputLang == "cpp" || gOutputLang == "llvm" || startWith(gOutputLang, "wast") || startWith(gOutputLang, "wasm"))) { throw faustexception( "ERROR : -fm can only be used with 'c', 'cpp', 'llvm' or 'wast/wast' backends\n"); } } if (gNamespace != "" && gOutputLang != "cpp" && gOutputLang != "dlang") { throw faustexception("ERROR : -ns can only be used with the 'cpp' or 'dlang' backend\n"); } if (gMaskDelayLineThreshold < INT_MAX && (gVectorSwitch || (gOutputLang == "ocpp"))) { throw faustexception( "ERROR : '-dlt < INT_MAX' option can only be used in scalar mode and not with the " "'ocpp' backend\n"); } // gInlinetable check if (gInlineTable && (gOutputLang != "cpp" && gOutputLang != "c" && gOutputLang != "llvm" && gOutputLang != "rust")) { throw faustexception("ERROR : -it can only be used with 'cpp', 'c', 'llvm' and 'rust' backends\n"); } // gMemoryManager check if (gMemoryManager == 0 && gInlineTable) { throw faustexception("ERROR : '-it' and '-mem' cannot be used together\n"); } if ((gMemoryManager >= 1) && !gInlineTable) { throw faustexception("ERROR : -mem1/-mem2/-mem3 has to be used with -it\n"); } if ((gMemoryManager == 3) && gOutputLang != "c") { throw faustexception("ERROR : -mem3 can only be used with 'c' backend\n"); } if ((gMemoryManager == 3) && !gExtControl) { throw faustexception("ERROR : -mem3 has to be used with -ec\n"); } if ((gMemoryManager == 3) && gVectorSwitch && gVectorLoopVariant != 2) { throw faustexception("ERROR : -mem3 and -vec has to be used with -lv 2\n"); } if ((gMemoryManager == 0 || gMemoryManager == 1) && (gOutputLang == "c")) { throw faustexception("ERROR : -mem0/-mem1 cannot be used with 'c' backend\n"); } // gComputeMix check if (gComputeMix && gOutputLang == "ocpp") { throw faustexception("ERROR : -cm cannot be used with the 'ocpp' backend\n"); } if (gComputeMix && gOutputLang == "interp") { throw faustexception("ERROR : -cm cannot be used with the 'interp' backend\n"); } if (gComputeMix && gOutputLang == "cmajor") { throw faustexception("ERROR : -cm cannot be used with the 'cmajor' backend\n"); } if (gFloatSize == 4 && gOutputLang != "cpp" && gOutputLang != "ocpp" && gOutputLang != "c" && gOutputLang != "fir") { throw faustexception( "ERROR : -fx can only be used with 'c', 'cpp', 'ocpp' or 'fir' backends\n"); } if (gFTZMode == 2 && gOutputLang != "cpp" && gOutputLang != "ocpp" && gOutputLang != "c" && gOutputLang != "llvm" && startWith(gOutputLang, "wast") && startWith(gOutputLang, "wasm")) { throw faustexception( "ERROR : -ftz 2 can only be used with 'c', 'cpp', 'ocpp', 'llvm' or wast/wasm " "backends\n"); } if (gClang && gOutputLang != "cpp" && gOutputLang != "ocpp" && gOutputLang != "c") { throw faustexception( "ERROR : -clang can only be used with 'c', 'cpp' or 'ocpp' backends\n"); } if (gNoVirtual && gOutputLang != "cpp" && gOutputLang != "ocpp" && gOutputLang != "c") { throw faustexception("ERROR : -nvi can only be used with 'c', 'cpp' or 'ocpp' backends\n"); } if (gMemoryManager >= 0 && gOutputLang != "cpp" && gOutputLang != "ocpp" && gOutputLang != "c") { throw faustexception("ERROR : -mem can only be used with 'cpp', 'c', or 'ocpp' backends\n"); } if (gArchFile != "" && ((gOutputLang == "wast") || (gOutputLang == "wasm") || (gOutputLang == "interp") || (gOutputLang == "llvm") || (gOutputLang == "fir"))) { throw faustexception( "ERROR : -a can only be used with 'asc', 'c', 'cpp', 'ocpp', 'rust' and 'cmajor' " "backends\n"); } if (gClassName == "") { throw faustexception("ERROR : -cn used with empty string \n"); } if (err != 0) { stringstream error; error << "WARNING : " << parse_error.str() << endl; gErrorMessage = error.str(); } // When -lang has been set initFaustFloat(); return (err == 0); } /** * transform a filename "faust/example/noise.dsp" into * the corresponding fx name "noise" */ static string fxName(const string& filename) { // determine position right after the last '/' or 0 size_t p1 = 0; for (size_t i = 0; i < filename.size(); i++) { if (filename[i] == '/') { p1 = i + 1; } } // determine position of the last '.' size_t p2 = filename.size(); for (size_t i = p1; i < filename.size(); i++) { if (filename[i] == '.') { p2 = i; } } return filename.substr(p1, p2 - p1); } void global::initDocumentNames() { if (gInputFiles.empty()) { gMasterDocument = "Unknown"; gMasterDirectory = "."; gMasterName = "faustfx"; gDocName = "faustdoc"; } else { gMasterDocument = *gInputFiles.begin(); gMasterDirectory = fileDirname(gMasterDocument); gMasterName = fxName(gMasterDocument); gDocName = fxName(gMasterDocument); } // Add gMasterDirectory in gImportDirList and gArchitectureDirList gImportDirList.push_back(gMasterDirectory); gArchitectureDirList.push_back(gMasterDirectory); } void global::initDirectories(int argc, const char* argv[]) { #if !defined(FAUST_SELF_CONTAINED_LIB) char s[1024]; getFaustPathname(s, 1024); gFaustExeDir = exepath::get(argv[0]); gFaustRootDir = exepath::dirup(gFaustExeDir); gFaustDirectory = fileDirname(s); gFaustSuperDirectory = fileDirname(gFaustDirectory); gFaustSuperSuperDirectory = fileDirname(gFaustSuperDirectory); //------------------------------------------------------------------------------------- // init gImportDirList : a list of path where to search .lib files //------------------------------------------------------------------------------------- if (char* envpath = getenv("FAUST_LIB_PATH")) { gImportDirList.push_back(envpath); } #ifdef INSTALL_PREFIX gImportDirList.push_back(INSTALL_PREFIX "/share/faust"); #endif gImportDirList.push_back(exepath::dirup(gFaustExeDir) + "/share/faust"); gImportDirList.push_back("/usr/local/share/faust"); gImportDirList.push_back("/usr/share/faust"); //------------------------------------------------------------------------------------- // init gArchitectureDirList : a list of path where to search architectures files //------------------------------------------------------------------------------------- if (char* envpath = getenv("FAUST_ARCH_PATH")) { gArchitectureDirList.push_back(envpath); } gArchitectureDirList.push_back(gFaustDirectory + "/architecture"); gArchitectureDirList.push_back(gFaustSuperDirectory + "/architecture"); gArchitectureDirList.push_back(gFaustSuperSuperDirectory + "/architecture"); #ifdef INSTALL_PREFIX gArchitectureDirList.push_back(INSTALL_PREFIX "/share/faust"); gArchitectureDirList.push_back(INSTALL_PREFIX "/include"); #endif gArchitectureDirList.push_back(exepath::dirup(gFaustExeDir) + "/share/faust"); gArchitectureDirList.push_back(exepath::dirup(gFaustExeDir) + "/include"); gArchitectureDirList.push_back("/usr/local/share/faust"); gArchitectureDirList.push_back("/usr/share/faust"); gArchitectureDirList.push_back("/usr/local/include"); gArchitectureDirList.push_back("/usr/include"); // for debugging purposes // cerr << "gArchitectureDirList:\n"; // for (const auto& d : gArchitectureDirList) { // cerr << "\t" << d << "\n"; // } // cerr << endl; #endif } void global::printDeclareHeader(ostream& dst) { for (const auto& i : gMetaDataSet) { if (i.first != tree("author")) { dst << "declare "; stringstream key; key << *(i.first); vector rep{'.', ':', '/'}; dst << replaceCharList(key.str(), rep, '_'); dst << " " << **(i.second.begin()) << ";" << endl; } else { for (set::iterator j = i.second.begin(); j != i.second.end(); ++j) { if (j == i.second.begin()) { dst << "declare " << *(i.first) << " " << **j << ";" << endl; } else { dst << "declare contributor " << **j << ";" << endl; } } } } } void global::parseSourceFiles() { startTiming("parser"); list::iterator s; Tree result = nil; gReader.init(); if (!gInjectFlag && gInputFiles.begin() == gInputFiles.end()) { throw faustexception("ERROR : no files specified; for help type \"faust --help\"\n"); } for (s = gInputFiles.begin(); s != gInputFiles.end(); s++) { if (s == gInputFiles.begin()) { gMasterDocument = *s; } result = cons(importFile(tree(s->c_str())), result); } gExpandedDefList = gReader.expandList(result); endTiming("parser"); } /**************************************************************** Faust directories information *****************************************************************/ #ifdef WIN32 #define kPSEP '\\' #else #define kPSEP '/' #endif #ifndef LIBDIR #define LIBDIR "lib" #endif static void enumBackends(ostream& out) { const char* dspto = " DSP to "; #ifdef ASSEMBLYSCRIPT_BUILD out << dspto << "AssemblyScript" << endl; #endif #ifdef C_BUILD out << dspto << "C" << endl; #endif #ifdef CPP_BUILD out << dspto << "C++" << endl; #endif #ifdef CMAJOR_BUILD out << dspto << "Cmajor" << endl; #endif #ifdef CODEBOX_BUILD out << dspto << "Codebox" << endl; #endif #ifdef CSHARP_BUILD out << dspto << "CSharp" << endl; #endif #ifdef DLANG_BUILD out << dspto << "DLang" << endl; #endif #ifdef FIR_BUILD out << dspto << "FIR" << endl; #endif #if defined(INTERP_BUILD) || defined(INTERP_COMP_BUILD) out << dspto << "Interpreter" << endl; #endif #ifdef JAVA_BUILD out << dspto << "Java" << endl; #endif #ifdef JAX_BUILD out << dspto << "JAX" << endl; #endif #ifdef JULIA_BUILD out << dspto << "Julia" << endl; #endif #ifdef JSFX_BUILD out << dspto << "JSFX" << endl; #endif #ifdef LLVM_BUILD out << dspto << "LLVM IR" << endl; #endif #ifdef OCPP_BUILD out << dspto << "old C++" << endl; #endif #ifdef RUST_BUILD out << dspto << "Rust" << endl; #endif #ifdef SDF3_BUILD out << dspto << "SDF3" << endl; #endif #ifdef TEMPLATE_BUILD out << dspto << "Template" << endl; #endif #ifdef VHDL_BUILD out << dspto << "VHDL" << endl; #endif #ifdef WASM_BUILD out << dspto << "WebAssembly (wast/wasm)" << endl; #endif } /**************************************************************** Help and Version information *****************************************************************/ string global::printVersion() { stringstream sstr; sstr << "FAUST Version " << FAUSTVERSION << "\n"; sstr << "Embedded backends: \n"; enumBackends(sstr); #ifdef LLVM_BUILD sstr << "Build with LLVM version " << LLVM_VERSION << "\n"; #endif sstr << "Copyright (C) 2002-2026, GRAME - Centre National de Creation Musicale. All rights " "reserved. \n"; return sstr.str(); } string global::printHelp() { stringstream sstr; const char* tab = " "; const char* line = "\n---------------------------------------\n"; sstr << "FAUST compiler version " << FAUSTVERSION << "\n"; sstr << "usage : faust [options] file1 [file2 ...]." << endl; #ifndef EMCC sstr << " where options represent zero or more compiler options \n\tand fileN " "represents a Faust source " "file (.dsp extension)." << endl; #endif sstr << endl << "Input options:" << line; #ifndef EMCC sstr << tab << "-a wrapper architecture file." << endl; sstr << tab << "-i --inline-architecture-files inline architecture files." << endl; sstr << tab << "-A --architecture-dir add the directory to the architecture " "search path." << endl; sstr << tab << "-I --import-dir add the directory to the libraries " "search path." << endl; sstr << tab << "-L --library link with the LLVM module ." << endl; #endif #ifndef EMCC sstr << endl << "Output options:" << line; sstr << tab << "-o the output file." << endl; sstr << tab << "-e --export-dsp export expanded DSP (with all included " "libraries)." << endl; sstr << tab << "-uim --user-interface-macros add user interface macro definitions to the " "output code." << endl; sstr << tab << "-xml generate an XML description file." << endl; sstr << tab << "-json generate a JSON description file." << endl; sstr << tab << "-O --output-dir specify the relative directory of the " "generated output code and " "of additional generated files (SVG, XML...)." << endl; #endif sstr << endl << "Code generation options:" << line; #ifndef EMCC sstr << tab << "-lang --language select output language," << endl; sstr << tab << " 'lang' should be asc, c, cpp (default), " "cmajor, " "codebox, csharp, " "dlang, fir, interp, java, jax, jsfx, julia, llvm, " "ocpp, rust, sdf3, vhdl or wast/wasm." << endl; #endif sstr << tab << "-single --single-precision-floats use single precision floats for internal " "computations (default)." << endl; sstr << tab << "-double --double-precision-floats use double precision floats for internal " "computations." << endl; #ifndef EMCC sstr << tab << "-quad --quad-precision-floats use quad precision floats for internal " "computations." << endl; #endif sstr << tab << "-fx --fixed-point use fixed-point for internal computations." << endl; sstr << tab << "-fx-size --fixed-point-size fixed-point number total size in bits (-1 is " "used to generate a unique fixpoint_t type)." << endl; sstr << tab << "-es 1|0 --enable-semantics 1|0 use enable semantics when 1 (default), and " "simple multiplication " "otherwise." << endl; sstr << tab << "-lcc --local-causality-check check causality also at local level." << endl; #ifndef EMCC sstr << tab << "-light --light-mode do not generate the entire DSP API." << endl; sstr << tab << "-clang --clang when compiled with clang/clang++, adds " "specific #pragma for " "auto-vectorization." << endl; sstr << tab << "-nvi --no-virtual when compiled with the C++ backend, does not " "add the 'virtual' " "keyword." << endl; sstr << tab << "-fp --full-parentheses always add parentheses around binops." << endl; sstr << tab << "-cir --check-integer-range check float to integer range conversion." << endl; sstr << tab << "-exp10 --generate-exp10 pow(10,x) replaced by possibly faster exp10(x)." << endl; sstr << tab << "-os --one-sample generate one sample computation." << endl; sstr << tab << "-ec --external-control separated 'control' and 'compute' functions." << endl; sstr << tab << "-it --inline-table inline rdtable/rwtable code in the main class." << endl; sstr << tab << "-cm --compute-mix mix in outputs buffers." << endl; sstr << tab << "-ct --check-table check rtable/rwtable index range and generate " "safe access code " "[0/1: 1 by default]." << endl; sstr << tab << "-cn --class-name specify the name of the dsp class to be used " "instead of mydsp." << endl; sstr << tab << "-scn --super-class-name specify the name of the super class to be " "used instead of dsp." << endl; sstr << tab << "-pn --process-name specify the name of the dsp entry-point " "instead of process." << endl; sstr << tab << "-mcd --max-copy-delay use a copy delay up to max delay and a " "dense delay above " "(ocpp only) " "or a ring buffer (defaut 16 samples)." << endl; sstr << tab << "-mdd --max-dense-delay use a dense delay up to max delay (if " "enough density) and a " "ring " "buffer delay above (ocpp only, default 1024)." << endl; sstr << tab << "-mdy --min-density minimal density (100*number of delays/max " "delay) to use a dense " "delays " "(ocpp only, default 33)." << endl; sstr << tab << "-dlt --delay-line-threshold use a mask-based ring buffer delays up to max " "delay and a " "select based ring buffers above (default INT_MAX samples)." << endl; #endif #ifndef EMCC sstr << tab << "-mem --memory-manager allocations done using a custom memory manager." << endl; sstr << tab << "-mem1 --memory-manager1 allocations done using a custom memory manager," " using the iControl/fControl and iZone/fZone model." << endl; sstr << tab << "-mem2 --memory-manager2 use iControl/fControl, iZone/fZone model and " "no explicit memory manager." << endl; sstr << tab << "-mem3 --memory-manager3 use iControl/fControl, iZone/fZone model and " "no explicit memory manager with access as function parameters." << endl; #endif sstr << tab << "-ftz --flush-to-zero code added to recursive signals [0:no " "(default), 1:fabs based, " "2:mask based (fastest)]." << endl; #ifndef EMCC sstr << tab << "-rui --range-ui whether to generate code to constraint " "vslider/hslider/nentry " "values " "in [min..max] range." << endl; sstr << tab << "-fui --freeze-ui whether to freeze vslider/hslider/nentry to a " "given value (init " "value by default)." << endl; sstr << tab << "-inj --inject inject source file into architecture file " "instead of compiling " "a dsp file." << endl; sstr << tab << "-scal --scalar generate non-vectorized code (default)." << endl; sstr << tab << "-inpl --in-place generates code working when input and output " "buffers are the same " "(scalar mode only)." << endl; sstr << tab << "-vec --vectorize generate easier to vectorize code." << endl; sstr << tab << "-vs --vec-size size of the vector (default 32 samples)." << endl; sstr << tab << "-lv --loop-variant [0:fastest, fixed vector size and a remaining " "loop (default), " "1:simple, variable vector size, 2:fixed, fixed vector size]." << endl; sstr << tab << "-omp --openmp generate OpenMP pragmas, activates " "--vectorize option." << endl; sstr << tab << "-pl --par-loop generate parallel loops in --openmp mode." << endl; sstr << tab << "-sch --scheduler generate tasks and use a Work Stealing " "scheduler, activates " "--vectorize option." << endl; sstr << tab << "-ocl --opencl generate tasks with OpenCL (experimental)." << endl; sstr << tab << "-cuda --cuda generate tasks with CUDA (experimental)." << endl; sstr << tab << "-dfs --deep-first-scheduling schedule vector loops in deep first order." << endl; sstr << tab << "-g --group-tasks group single-threaded sequential tasks " "together when -omp or -sch " "is used." << endl; sstr << tab << "-fun --fun-tasks separate tasks code as separated functions " "(in -vec, -sch, or " "-omp mode)." << endl; sstr << tab << "-fm --fast-math use optimized versions of mathematical " "functions implemented in " ", use 'faust/dsp/fastmath.cpp' when file is 'def', assume functions are defined " "in the architecture " "file when file is 'arch'." << endl; sstr << tab << "-mapp --math-approximation simpler/faster versions of " "'floor/ceil/fmod/remainder' functions." << endl; sstr << tab << "-noreprc --no-reprc (Rust only) Don't force dsp struct layout to " "follow C ABI." << endl; sstr << tab << "-ns --namespace generate C++ or D code in a namespace ." << endl; sstr << tab << "-vhdl-trace --vhdl-trace activate trace." << endl; sstr << tab << "-vhdl-float --vhdl-float uses IEEE-754 format for samples instead of " "fixed point." << endl; sstr << tab << "-vhdl-components --vhdl-components path to a file describing custom " "components for the " "VHDL backend." << endl; sstr << tab << "-fpga-mem --fpga-mem FPGA block ram max size, used in -mem1/-mem2 " "mode." << endl; sstr << tab << "-fpga-mem-th --fpga-mem-th FPGA array size threshold (in unit of the " "memory type), used in -mem1/-mem2 " "mode." << endl; sstr << tab << "-wi --widening-iterations number of iterations before widening in " "signal bounding." << endl; sstr << tab << "-ni --narrowing-iterations number of iterations before stopping " "narrowing in signal bounding." << endl; sstr << tab << "-rnt --rust-no-faustdsp-trait (Rust only) Don't generate FaustDsp trait " "implementation." << endl; sstr << tab << "-rnlm --rust-no-libm (Rust only) Don't generate FFI calls to libm." << endl; #endif #ifndef EMCC sstr << endl << "Block diagram options:" << line; sstr << tab << "-ps --postscript print block-diagram to a postscript file." << endl; sstr << tab << "-svg --svg print block-diagram to a svg file." << endl; sstr << tab << "-sd --simplify-diagrams try to further simplify diagrams before " "drawing." << endl; sstr << tab << "-drf --draw-route-frame draw route frames instead of simple cables." << endl; sstr << tab << "-f --fold threshold to activate folding mode during " "block-diagram " "generation (default 25 elements)." << endl; sstr << tab << "-fc --fold-complexity complexity threshold to fold an expression in " "folding mode " "(default 2)." << endl; sstr << tab << "-mns --max-name-size threshold during block-diagram generation " "(default 40 char)." << endl; sstr << tab << "-sn --simple-names use simple names (without arguments) during " "block-diagram " "generation." << endl; sstr << tab << "-blur --shadow-blur add a shadow blur to SVG boxes." << endl; sstr << tab << "-sc --scaled-svg automatic scalable SVG." << endl; sstr << endl << "Math doc options:" << line; sstr << tab << "-mdoc --mathdoc print math documentation of the Faust program " "in LaTeX format in " "a -mdoc folder." << endl; sstr << tab << "-mdlang --mathdoc-lang if translation file exists ( = en, fr, ...)." << endl; sstr << tab << "-stripmdoc --strip-mdoc-tags strip mdoc tags when printing Faust -mdoc " "listings." << endl; sstr << endl << "Debug options:" << line; sstr << tab << "-d --details print compilation details." << endl; sstr << tab << "-time --compilation-time display compilation phases timing information." << endl; sstr << tab << "-flist --file-list print file list (including libraries) used to " "eval process." << endl; sstr << tab << "-tg --task-graph print the internal task graph in dot format." << endl; sstr << tab << "-sg --signal-graph print the internal signal graph in dot format." << endl; sstr << tab << "-rg --retiming-graph print the internal signal graph after " "retiming in dot format." << endl; sstr << tab << "-norm --normalized-form print signals in normalized form and exit." << endl; sstr << tab << "-norm1 --normalized-form1 print signals in normalized form with IDs for " "shared sub-expressions and exit." << endl; sstr << tab << "-me --math-exceptions check / for 0 as denominator and remainder, " "fmod, sqrt, log10, " "log, acos, asin functions domain." << endl; sstr << tab << "-sts --strict-select generate strict code for 'selectX' even for " "stateless branches " "(both are computed)." << endl; sstr << tab << "-wall --warning-all print all warnings." << endl; sstr << tab << "-t --timeout abort compilation after seconds " "(default 120)." << endl; sstr << endl << "Information options:" << line; sstr << tab << "-h --help print this help message." << endl; sstr << tab << "-v --version print version information and embedded " "backends list." << endl; sstr << tab << "-libdir --libdir print directory containing the Faust libraries." << endl; sstr << tab << "-includedir --includedir print directory containing the Faust headers." << endl; sstr << tab << "-archdir --archdir print directory containing the Faust " "architectures." << endl; sstr << tab << "-dspdir --dspdir print directory containing the Faust dsp " "libraries." << endl; sstr << tab << "-pathslist --pathslist print the architectures and dsp library paths." << endl; sstr << endl << "Environment variables:" << line; sstr << tab << "FAUST_DEBUG = FAUST_LLVM1 print LLVM IR before optimisation." << endl; sstr << tab << "FAUST_DEBUG = FAUST_LLVM2 print LLVM IR after optimisation." << endl; sstr << tab << "FAUST_DEBUG = FIR_PRINTER print FIR after generation." << endl; sstr << tab << "FAUST_DEBUG = FAUST_LLVM_NO_FM deactivate fast-math optimisation in LLVM IR." << endl; sstr << tab << "FAUST_OPT = FAUST_SIG_NO_NORM deactivate signal normalisation." << endl; sstr << endl << "Example:" << line; sstr << "faust -a jack-gtk.cpp -o myfx.cpp myfx.dsp" << endl; #endif return sstr.str(); } string global::printLibDir() { stringstream sstr; sstr << gFaustRootDir << kPSEP << LIBDIR << endl; return sstr.str(); } string global::printIncludeDir() { stringstream sstr; sstr << gFaustRootDir << kPSEP << "include" << endl; return sstr.str(); } string global::printArchDir() { stringstream sstr; sstr << gFaustRootDir << kPSEP << "share" << kPSEP << "faust" << endl; return sstr.str(); } string global::printDspDir() { stringstream sstr; sstr << gFaustRootDir << kPSEP << "share" << kPSEP << "faust" << endl; return sstr.str(); } string global::printPaths() { stringstream sstr; sstr << "FAUST dsp library paths:" << endl; for (const auto& path : gImportDirList) { sstr << path << endl; } sstr << "\nFAUST architectures paths:" << endl; for (const auto& path : gArchitectureDirList) { sstr << path << endl; } sstr << endl; return sstr.str(); } void global::printDirectories() { if (gHelpSwitch) { cout << printHelp(); throw faustexception(); } if (gVersionSwitch) { cout << printVersion(); throw faustexception(); } if (gLibDirSwitch) { cout << printLibDir(); throw faustexception(); } if (gIncludeDirSwitch) { cout << printIncludeDir(); throw faustexception(); } if (gArchDirSwitch) { cout << printArchDir(); throw faustexception(); } if (gDspDirSwitch) { cout << printDspDir(); throw faustexception(); } if (gPathListSwitch) { cout << printPaths(); throw faustexception(); } } // For box/sig generation void global::clear() { gBoxCounter = 0; gBoxTable.clear(); gBoxTrace.clear(); gSignalCounter = 0; gSignalTable.clear(); gSignalTrace.clear(); } #ifdef FIR_BUILD void statsTreeCreated() { gGlobal->gStats.fTreesCreated++; } void statsTreeReused() { gGlobal->gStats.fTreesReused++; } void statsPropertySet() { gGlobal->gStats.fPropertySets++; } void statsPropertyGet() { gGlobal->gStats.fPropertyGets++; } // Print compiler statistics for performance analysis void CompilerStats::print(std::ostream& out) const { out << "\n========== COMPILER STATISTICS ==========\n"; out << "\n--- Phase 1: Parsing ---\n"; out << " (not instrumented)\n"; out << "\n--- Phase 2: Box Evaluation ---\n"; out << " eval() calls: " << fEvalCalls << "\n"; out << " eval() cache hits: " << fEvalCacheHits; if (fEvalCalls > 0) { out << " (" << (100.0 * fEvalCacheHits / fEvalCalls) << "%)"; } out << "\n"; out << " eval() cache misses: " << fEvalCacheMisses << "\n"; out << " Loop detector calls: " << fLoopDetectorCalls << "\n"; out << " Stack detector calls: " << fStackDetectorCalls << "\n"; out << "\n--- Phase 3: Propagation ---\n"; out << " propagate() calls: " << fPropagateCalls << "\n"; out << " propagate() cache hits: " << fPropagateCacheHits; if (fPropagateCalls > 0) { out << " (" << (100.0 * fPropagateCacheHits / fPropagateCalls) << "%)"; } out << "\n"; out << " propagate() cache misses:" << fPropagateCacheMisses << "\n"; out << "\n--- Box Type Computation ---\n"; out << " getBoxType() calls: " << fGetBoxTypeCalls << "\n"; out << " getBoxType() cache hits: " << fGetBoxTypeCacheHits; if (fGetBoxTypeCalls > 0) { out << " (" << (100.0 * fGetBoxTypeCacheHits / fGetBoxTypeCalls) << "%)"; } out << "\n"; out << " getBoxType() computed: " << fGetBoxTypeComputed << "\n"; out << "\n--- Environment Operations ---\n"; out << " Environment lookups: " << fEnvLookups << "\n"; if (fEnvLookups > 0) { out << " Average lookup depth: " << (1.0 * fEnvLookupTotalDepth / fEnvLookups) << "\n"; } out << " Env layers pushed: " << fEnvLayersPushed << "\n"; out << "\n--- Pattern Matching ---\n"; out << " build automaton calls: " << fPatternMatcherBuildCalls << "\n"; out << " build total time (ms): " << fPatternMatcherBuildTimeMs << "\n"; if (fPatternMatcherBuildCalls > 0) { out << " build avg time (ms): " << (fPatternMatcherBuildTimeMs / fPatternMatcherBuildCalls) << "\n"; } out << " apply calls: " << fPatternMatcherApplyCalls << "\n"; out << " apply total time (ms): " << fPatternMatcherApplyTimeMs << "\n"; if (fPatternMatcherApplyCalls > 0) { out << " apply avg time (ms): " << (fPatternMatcherApplyTimeMs / fPatternMatcherApplyCalls) << "\n"; } out << "\n--- Tree Operations ---\n"; out << " Trees created: " << fTreesCreated << "\n"; out << " Trees reused (hash): " << fTreesReused; if (fTreesCreated + fTreesReused > 0) { out << " (" << (100.0 * fTreesReused / (fTreesCreated + fTreesReused)) << "% reuse rate)"; } out << "\n"; out << " Property set ops: " << fPropertySets << "\n"; out << " Property get ops: " << fPropertyGets << "\n"; out << "\n--- Iteration Constructs ---\n"; out << " par() iterations: " << fParIterations << "\n"; out << " seq() iterations: " << fSeqIterations << "\n"; out << " sum() iterations: " << fSumIterations << "\n"; out << " prod() iterations: " << fProdIterations << "\n"; out << "\n==========================================\n"; } #endif // Memory management #ifdef _WIN32 void Garbageable::cleanup() { list::iterator it; // Here removing the deleted pointer from the list is pointless // and takes time, thus we don't do it. global::gHeapCleanup = true; for (it = global::gRawObjectTable.begin(); it != global::gRawObjectTable.end(); it++) { // Hack : "this" and actual pointer are not the same: destructor cannot be called... Garbageable::operator delete(*it); } // Reset to default state global::gRawObjectTable.clear(); global::gHeapCleanup = false; } void* Garbageable::operator new(size_t size) { // HACK : add 16 bytes to avoid unsolved memory smashing bug... Garbageable* res = (Garbageable*)malloc(size + 16); global::gRawObjectTable.push_front(res); return res; } void Garbageable::operator delete(void* ptr) { // We may have cases when a pointer will be deleted during // a compilation, thus the pointer has to be removed from the list. if (!global::gHeapCleanup) { global::gRawObjectTable.remove(static_cast(ptr)); } free(ptr); } void* Garbageable::operator new[](size_t size) { // HACK : add 16 bytes to avoid unsolved memory smashing bug... Garbageable* res = (Garbageable*)malloc(size + 16); global::gRawObjectTable.push_front(res); return res; } void Garbageable::operator delete[](void* ptr) { // We may have cases when a pointer will be deleted during // a compilation, thus the pointer has to be removed from the list. if (!global::gHeapCleanup) { global::gRawObjectTable.remove(static_cast(ptr)); } free(ptr); } #else void Garbageable::cleanup() { // Here removing the deleted pointer from the list is pointless // and takes time, thus we don't do it. global::gHeapCleanup = true; for (Garbageable* obj : global::gRawObjectTable) { delete obj; } global::gRawObjectTable.clear(); for (Garbageable* obj : global::gArrayObjectTable) { delete[] obj; } global::gArrayObjectTable.clear(); // Reset to default state global::gHeapCleanup = false; } void* Garbageable::operator new(size_t size) { Garbageable* res = static_cast(::operator new(size)); global::gRawObjectTable.push_front(res); return res; } void Garbageable::operator delete(void* ptr) { if (!global::gHeapCleanup) { global::gRawObjectTable.remove(static_cast(ptr)); } ::operator delete(ptr); } void* Garbageable::operator new[](size_t size) { Garbageable* res = static_cast(::operator new[](size)); global::gArrayObjectTable.push_front(res); return res; } void Garbageable::operator delete[](void* ptr) { if (!global::gHeapCleanup) { global::gArrayObjectTable.remove(static_cast(ptr)); } ::operator delete[](ptr); } #endif /* Threaded calls API: the compilation code is executed in a separate thread so that the stack size can be raised to MAX_STACK_SIZE. */ void callFun(threaded_fun fun, void* arg) { #if defined(EMCC) // No thread support in JavaScript fun(arg); #elif defined(_WIN32) DWORD id; HANDLE thread = CreateThread(NULL, MAX_STACK_SIZE, LPTHREAD_START_ROUTINE(fun), arg, 0, &id); faustassert(thread != NULL); WaitForSingleObject(thread, INFINITE); #else pthread_t thread; pthread_attr_t attr; faustassert(pthread_attr_init(&attr) == 0); faustassert(pthread_attr_setstacksize(&attr, MAX_STACK_SIZE) == 0); faustassert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0); faustassert(pthread_create(&thread, &attr, fun, arg) == 0); faustassert(pthread_join(thread, nullptr) == 0); faustassert(pthread_attr_destroy(&attr) == 0); #endif }