From b7f25e8d2367841ddde7258df9331aeed9424156 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 27 Aug 2023 06:22:10 -0400 Subject: [PATCH 1/2] implement internal.{id,rate} NOTE: this patch touches compiler/parser/, so you obviously need "cd compiler/parser; make" before "make" to build the compiler. This patch adds the new keyword `internal` which returns the builtin environment with 2 primitives (so far): 1. id(sig) - sig->serial() 2. rate(sig) - getSigOrder(sig) Note that they compute the returned value at compile time. //------------------------------------------------------------------- rate(sig) - returns the computability Example: process = sin(1), ma.SR/2, nentry("",0,0,10,1), ba.time : par(i,4,internal.rate); outputs output0[i0] = FAUSTFLOAT(0); // compile time const output1[i0] = FAUSTFLOAT(1); // run time const output2[i0] = FAUSTFLOAT(2); // block output3[i0] = FAUSTFLOAT(3); // sample //------------------------------------------------------------------- id(sig) - returns the unique signal id. If the compiler can detect that sig1 and sig2 are "equal", id(sig1) == id(sig2). Example. Suppose we have a = +(1); s = -(1); as = a : s; sa = s : a; id = internal.id; Now, process = _ <: id, id(as), id(sa); or process = _ <: _, as, sa : par(i,3,id); outputs output0[i0] = FAUSTFLOAT(241); output1[i0] = FAUSTFLOAT(241); output2[i0] = FAUSTFLOAT(241); Another example: process = _ <: id(as-sa), id(0); outputs output0[i0] = FAUSTFLOAT(8); output1[i0] = FAUSTFLOAT(8); //------------------------------------------------------------------- Now a bit more useful example: isZero = internal.id(float) == internal.id(0.0); returns 1 if the input is compile time constant == 0 or 0.0, otherwise 0. Afaics, it is not possible to implement such a helper in faust. --- compiler/extended/internalprim.hh | 95 +++++++++++++++++++++++++++++++ compiler/global.cpp | 3 + compiler/global.hh | 4 +- compiler/parser/faustlexer.l | 2 + compiler/parser/faustparser.y | 3 + 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 compiler/extended/internalprim.hh diff --git a/compiler/extended/internalprim.hh b/compiler/extended/internalprim.hh new file mode 100644 index 0000000000..5546fda194 --- /dev/null +++ b/compiler/extended/internalprim.hh @@ -0,0 +1,95 @@ +/************************************************************************ + ************************************************************************ + 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 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 "xtended.hh" +#include "simplify.hh" +#include "sigorderrules.hh" + +enum InternalOp { kId, kRate }; + +class InternalPrim : public xtended { + private: + InternalOp fOp; + public: + InternalPrim(InternalOp op, const char *name) : xtended(name), fOp(op) {} + + virtual Tree computeSigOutput(const std::vector& args) + { + Tree sig = simplify(args[0]); + int ret = -1; + + switch (fOp) { + case kId: + ret = sig->serial(); + break; + case kRate: + ret = getSigOrder(sig); + break; + default: + faustassert(false); + } + + return tree(ret); + } + + virtual unsigned int arity() { return 1; } + + virtual bool needCache() { return true; } + + virtual ::Type inferSigType(ConstTypes args) + { + faustassert(false); return 0; + } + virtual int inferSigOrder(const std::vector& args) + { + faustassert(false); return 0; + } + virtual ValueInst* generateCode(CodeContainer* container, Values& args, ::Type result, ConstTypes types) + { + faustassert(false); return 0; + } + virtual std::string generateCode(Klass* klass, const std::vector& args, ConstTypes types) + { + faustassert(false); return 0; + } + virtual std::string generateLateq(Lateq* lateq, const std::vector& args, ConstTypes types) + { + return "TODO"; + } +}; + +static Tree add_internal_def(Tree defs, InternalOp op, const char *d_n) +{ + Tree id = boxIdent(d_n); + std::string x_n = std::string("internal.") + d_n; + InternalPrim *internal = new InternalPrim(op, x_n.c_str()); + return cons(cons(id, internal->box()), defs); +} + +static Tree mkInternalEnv() +{ + Tree defs = gGlobal->nil; + + defs = add_internal_def(defs, kId, "id"); + defs = add_internal_def(defs, kRate, "rate"); + + return boxWithLocalDef(boxEnvironment(), defs); +} diff --git a/compiler/global.cpp b/compiler/global.cpp index 54b372204e..9cae1b950e 100644 --- a/compiler/global.cpp +++ b/compiler/global.cpp @@ -49,6 +49,7 @@ #include "sourcereader.hh" #include "sqrtprim.hh" #include "tanprim.hh" +#include "internalprim.hh" #include "tree.hh" #include "occur.hh" #include "enrobage.hh" @@ -614,6 +615,8 @@ void global::init() // Predefined nil tree nil = tree(NIL); + gInternalEnv = mkInternalEnv(); + PROCESS = symbol("process"); BOXTYPEPROP = tree(symbol("boxTypeProp")); diff --git a/compiler/global.hh b/compiler/global.hh index 0be0ca213e..f780297bfb 100644 --- a/compiler/global.hh +++ b/compiler/global.hh @@ -326,7 +326,9 @@ struct global { xtended* gAtanPrim; xtended* gAtan2Prim; xtended* gAsinPrim; - + + Tree gInternalEnv; + // Signals Sym BOXIDENT; Sym BOXCUT; diff --git a/compiler/parser/faustlexer.l b/compiler/parser/faustlexer.l index 10871bd940..a1e4d25489 100644 --- a/compiler/parser/faustlexer.l +++ b/compiler/parser/faustlexer.l @@ -199,6 +199,8 @@ NSID {ID}("::"{ID})* "sum" return ISUM; "prod" return IPROD; +"internal" return INTERNAL; + "inputs" return INPUTS; "outputs" return OUTPUTS; diff --git a/compiler/parser/faustparser.y b/compiler/parser/faustparser.y index d11678a328..3c69d13c2c 100644 --- a/compiler/parser/faustparser.y +++ b/compiler/parser/faustparser.y @@ -218,6 +218,8 @@ inline Tree unquote(char* str) %token ISUM %token IPROD +%token INTERNAL + %token INPUTS %token OUTPUTS @@ -589,6 +591,7 @@ primitive : INT { $$ = boxInt(str2int(FAUSTtext) | ffunction { $$ = boxFFun($1); } | fconst { $$ = $1; } | fvariable { $$ = $1; } + | INTERNAL { $$ = gGlobal->gInternalEnv; } | COMPONENT LPAR uqstring RPAR { $$ = boxComponent($3); } | LIBRARY LPAR uqstring RPAR { $$ = boxLibrary($3); } | ENVIRONMENT LBRAQ stmtlist RBRAQ { $$ = boxWithLocalDef(boxEnvironment(),formatDefinitions($3)); } From b6e14cb0be97db947d21f0750f518a4aac6facf7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 27 Aug 2023 10:01:36 -0400 Subject: [PATCH 2/2] add internal.{lo,hi} This comes in a separate patch to a) show that it is very easy to add the new primitives, and b) add some documentation. So the new lo/hi primitives act as undocumented lowest/highest but actually work. Say, both process = lowest; and process = internal.lo; output output0[i0] = FAUSTFLOAT(-1.0f); But, say, process = +(1) : lowest; crashes the compiler, while process = +(1) : internal.lo; correctly outputs output0[i0] = FAUSTFLOAT(0.0f); (I guess the implementation of lowest/highest is not finished, with this patch this code can be removed). //------------------------------------------------------------ Example: ge(x,y) = internal.lo(x) >= internal.hi(y); returns 1 if the compiler can deduce at compile time that x >= y, otherwise 0. So process = _,_ <: _,_, +(1),-(1) : ge,ge; does not generate any code and outputs output0[i0] = FAUSTFLOAT(0); output1[i0] = FAUSTFLOAT(1); Again, I don't think it is possible to implement this in faust. --- compiler/extended/internalprim.hh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/extended/internalprim.hh b/compiler/extended/internalprim.hh index 5546fda194..86278e87a0 100644 --- a/compiler/extended/internalprim.hh +++ b/compiler/extended/internalprim.hh @@ -23,7 +23,7 @@ #include "simplify.hh" #include "sigorderrules.hh" -enum InternalOp { kId, kRate }; +enum InternalOp { kId, kRate, kLo, kHi }; class InternalPrim : public xtended { private: @@ -43,6 +43,11 @@ class InternalPrim : public xtended { case kRate: ret = getSigOrder(sig); break; + case kLo: case kHi: { + typeAnnotation(sig, false); + interval i = getCertifiedSigType(sig)->getInterval(); + return tree(fOp == kLo ? i.lo() : i.hi()); + } default: faustassert(false); } @@ -90,6 +95,8 @@ static Tree mkInternalEnv() defs = add_internal_def(defs, kId, "id"); defs = add_internal_def(defs, kRate, "rate"); + defs = add_internal_def(defs, kLo, "lo"); + defs = add_internal_def(defs, kHi, "hi"); return boxWithLocalDef(boxEnvironment(), defs); }