+++ /dev/null
-/************************************************************************
- ************************************************************************
- FAUST compiler
- Copyright (C) 2003-2004 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.
- ************************************************************************
- ************************************************************************/
-
-
-
-#include <stdio.h>
-#include <assert.h>
-#include <fstream>
-#include <time.h>
-
-
-#include "sigtype.hh"
-#include "sigprint.hh"
-#include "ppsig.hh"
-//#include "prim.hh"
-#include "prim2.hh"
-#include "xtended.hh"
-#include "recursivness.hh"
-
-#include "sigtyperules.hh"
-#include "sigraterules.hh"
-
-
-
-//--------------------------------------------------------------------------
-// Uncomment to activate type inference tracing
-
-//#define TRACE(x) x
-#define TRACE(x) 0;
-
-
-
-
-
-/**
-
-========================================== RATE INFERENCE =========================================
- [Public functions]
-
-
-*/
-
-/**************************************************************************************************
-
- Internal prototypes
-
- **************************************************************************************************/
-
-static Tree inferreMultiRates(Tree lsig1, bool& success);
-static ostream& printRateEnvironment(ostream& fout, Tree E);
-static ostream& printRateEnvironmentList(ostream& fout, Tree LE);
-static void doInferreRate(Tree sig, int* rate, Tree& renv);
-static void inferreRate(Tree sig, int* rate, Tree& E);
-static Tree addToMultiRates(Tree E1, Tree LE, bool& success);
-static Tree addRecursiveSignals(Tree lsig);
-static Tree doAddRecursiveSignals(Tree sig, Tree accSig);
-static Tree flatRateEnvironmentList(Tree lre);
-
-static int computeRate(Tree sig, Tree renv, property<int>& rateProperty);
-
-
-
-/**************************************************************************************************
- **************************************************************************************************
- **************************************************************************************************
-
- Public Functions
-
- **************************************************************************************************
- **************************************************************************************************
- **************************************************************************************************/
-
-/**
- * Inferre the rate of a list of signals.
- */
-Tree inferreMultiRates(Tree lsig1, bool& success)
-{
- vector<Tree> sigs;
- vector<Tree> envs;
- vector<int> rates;
-
- Tree lsig2 = addRecursiveSignals(lsig1);
- TRACE(cerr << "lsig2 = " << *lsig2 << endl);
-
- while (isList(lsig2)) {
- Tree s = hd(lsig2); lsig2 = tl(lsig2);
- Tree E; int r; inferreRate(s, &r, E);
- if (r==0) {
- success = false;
- cerr << "ERROR inferreMultiRates failed 1" << endl;
- return nil;
- }
- sigs.push_back(s);
- envs.push_back(E);
- rates.push_back(r);
- }
-
- // combines all the rate environements
- Tree LE = nil;
- success = true;
- for (unsigned int i=0; success && i<envs.size(); i++) {
- LE = addToMultiRates(envs[i], LE, success);
- }
- TRACE(cerr << "***multirates :"; printRateEnvironmentList(cerr, LE); cerr << endl);
- Tree RE = flatRateEnvironmentList(LE);
- TRACE(cerr << "***flat rate :"; printRateEnvironment(cerr, RE); cerr << endl);
-
- return RE;
-}
-
-
-/**
- * Print a rate environment
- */
-ostream& printRateEnvironment(ostream& fout, Tree E)
-{
- string sep = "";
- fout << "rates {";
- while (isList(E)) {
- fout << sep << ppsig(hd(hd(E))) << ":" << tree2int(tl(hd(E)));
- sep=",";
- E = tl(E);
- }
- fout << "}";
- return fout;
-}
-
-
-/**
- * Print a list of rate environments
- */
-ostream& printRateEnvironmentList(ostream& fout, Tree LE)
-{
- string sep = "";
- fout << "multi{";
- while (isList(LE)) {
- fout << sep; printRateEnvironment(fout, hd(LE));
- sep="++";
- LE = tl(LE);
- }
- fout << "}";
- return fout;
-}
-
-
-
-/**************************************************************************************************
- **************************************************************************************************
- **************************************************************************************************
-
- IMPLEMENTATION
-
- **************************************************************************************************
- **************************************************************************************************
- **************************************************************************************************/
-
-
-/**
- * Greatest common divisor
- */
-static int TRACED_gcd(int a, int b);
-
-static int gcd(int a, int b)
-{
- int r = TRACED_gcd(a,b);
- //cerr << TABBER << "gcd(" << a << ',' << b <<") = " << r << endl;
- return r;
-}
-
-
-static int TRACED_gcd(int a, int b)
-{
- return (b==0) ? a : gcd (b, a%b);
-}
-
-/**
- * Least common multiple
- */
-static int lcm(int a, int b)
-{
- int r = (a*b)/gcd(a,b);
- //cerr << TABBER << "lcm(" << a << ',' << b <<") = " << r << endl;
- return r;
-}
-
-
-/**
- * Add to a list of existing signals lsig the list of recursive signals apprearing in lsig
- */
-
-static Tree addRecursiveSignals(Tree lsig)
-{
- CTree::startNewVisit();
-
- Tree lsig2 = lsig;
- while (isList(lsig)) {
- lsig2 = doAddRecursiveSignals(hd(lsig), lsig2);
- lsig = tl(lsig);
- }
- return lsig2;
-}
-
-
-static Tree doAddRecursiveSignals(Tree sig, Tree accSig)
-{
- TRACE(cerr << ++TABBER << "doAddRecursiveSignals(" << *sig << ',' << *accSig << ')' << endl);
- if ( ! sig->isAlreadyVisited() ) {
- int i;
- Tree rsig, id, body;
- sig->setVisited();
- if (isProj(sig,&i,rsig) && isRec(rsig, id, body)) {
- Tree p = nth(body,i);
- accSig = doAddRecursiveSignals(p, cons(p,accSig));
- } else {
- assert(!isProj(sig,&i,rsig));
-
- vector<Tree> subsigs;
- getSubSignals(sig,subsigs,false);
- for (unsigned int i=0; i<subsigs.size(); i++) {
- accSig = doAddRecursiveSignals(subsigs[i], accSig);
- }
- }
- }
- TRACE(cerr << --TABBER << "doAddRecursiveSignals(" << *sig << ',' << *accSig << ") -> " << *accSig << endl);
- return accSig;
-}
-
-/** *********************************** RATE ENVIRONMENTS ************************************************
-
-A rate environement E = {(s1,r1), (s2,r2), ...} is a set of pairs associating a signal and a rate. The
-signals are unique : if (s1,r1) and (s2,r2) are in E then s1=s2 => r1=r2.
-
-The environment is kept ordered
-
-
-**********************************************************************************************************/
-
-
-
-
-/**
- * Add a pair signal s1 x rate r1 to rate environment E
- */
-static Tree addRateEnv(Tree s1, int r1, Tree E)
-{
- if (isList(E)) {
- Tree s2 = hd(hd(E));
- if (s1 < s2) {
- return cons(cons(s1,tree(r1)),E);
- } else if (s1 == s2) {
- return cons(cons(s1,tree(r1)),tl(E));
- } else {
- return cons(hd(E), addRateEnv(s1,r1,tl(E)));
- }
- } else {
- return cons(cons(s1,tree(r1)),nil);
- }
-}
-
-
-/**
- * multiply by n all the rates of rate environment E
- * E={(s1,r1),...} -> E'={(s1,n.r1),...}
- */
-static Tree TRACED_multRateEnv(int n, Tree E);
-
-static Tree multRateEnv(int n, Tree E)
-{
- TRACE(cerr << ++TABBER << "multRateEnv(" << n << ", " << *E << ")" << endl);
- Tree result = TRACED_multRateEnv(n, E);
- TRACE(cerr << --TABBER << "multRateEnv(" << n << ", " << *E << ") -> " << *result << endl);
- return result;
-
-}
-
-
-static Tree TRACED_multRateEnv(int n, Tree E)
-{
- if (isList(E)) {
- Tree p = hd(E);
- Tree k = hd(p);
- int r = tree2int(tl(p));
- Tree q = cons(k, tree(r*n));
- return cons(q, multRateEnv(n, tl(E)));
- } else {
- return nil;
- }
-}
-
-
-/**
- * Get value associated to key k in "function" l
- * returns true if a value was found.
- */
-
-static bool getRateEnv(Tree k, int* i, Tree l)
-{
- if (isNil(l)) {
- return false;
- } else {
- assert (isList(l));
- Tree r = hd(hd(l));
- if (k < r) {
- return false; // not found
- } else if (k == r) {
- *i = tree2int(tl(hd(l)));
- return true;
- } else {
- return getRateEnv(k,i,tl(l));
- }
- }
-}
-
-
-
-/**
- * two rate environments are compatible if common rates
- * are linked by the same ratio
- */
-
-static bool checkRatesCompatible(Tree R1, Tree R2, int n1, int n2)
-{
- if (isNil(R1) || isNil(R2)) {
- return true;
- } else {
- Tree p1 = hd (R1);
- Tree p2 = hd (R2);
-
- Tree k1 = hd (p1);
- Tree k2 = hd (p2);
-
- if (k1 < k2) {
- return checkRatesCompatible(tl(R1), R2, n1, n2);
- } else if (k1 > k2) {
- return checkRatesCompatible(R1, tl(R2), n1, n2);
- } else {
- Tree v1 = tl (p1);
- Tree v2 = tl (p2);
-
- if (tree2int(v1)*n1 == tree2int(v2)*n2) {
- return checkRatesCompatible(tl(R1), tl(R2), n1, n2);
- } else {
- return false;
- }
- }
- }
-}
-
-
-
-/**
- * Two rate environments are independent if they don't have any
- * signals in common
- */
-
-static bool areRatesIndependent(Tree R1, Tree R2)
-{
- if (isNil(R1) || isNil(R2)) {
- return true;
- } else {
- Tree p1 = hd (R1);
- Tree p2 = hd (R2);
-
- Tree s1 = hd (p1);
- Tree s2 = hd (p2);
-
- if (s1 < s2) {
- return areRatesIndependent(tl(R1), R2);
- } else if (s2 < s1) {
- return areRatesIndependent(R1, tl(R2));
- } else {
- return false; // s1 and s2 are in common
- }
- }
-}
-
-
-
-
-/**
- * Two rate environments are compatible if common rates
- * are linked by the same ratio
- */
-
-static bool areRatesCompatible(Tree R1, Tree R2, int& n1, int& n2)
-{
- if (isNil(R1) || isNil(R2)) {
-
- n1 = 1; n2 = 1;
- return true;
-
- } else {
-
- Tree p1 = hd (R1);
- Tree p2 = hd (R2);
-
- Tree k1 = hd (p1);
- Tree k2 = hd (p2);
-
- if (k1 < k2) {
-
- return areRatesCompatible(tl(R1), R2, n1, n2);
-
- } else if (k1 > k2) {
-
- return areRatesCompatible(R1, tl(R2), n1, n2);
-
- } else {
-
- // we have a common expression
- Tree v1 = tl (p1);
- Tree v2 = tl (p2);
-
- int r1 = tree2int(v1);
- int r2 = tree2int(v2);
-
- int m = lcm(r1, r2);
-
- // we update the n1 and n2 coefficients
- n1 = m/r1;
- n2 = m/r2;
-
- // and we check that the rest of the environments are compatible
- return checkRatesCompatible(tl(R1), tl(R2), n1, n2);
- }
- }
-}
-
-
-/**
- * Merge two compatible rate environments. Rate environments are
- * compatible if common expressions have same rate.
- * Returns the merge environment and success flag
- */
-static Tree TRACED_mergeRateEnvironment(Tree R1, Tree R2, bool& success);
-
-static Tree mergeRateEnvironment(Tree R1, Tree R2, bool& success)
-{
- TRACE(cerr << ++TABBER << "mergeRateEnvironment(" << *R1 << ", " << *R2 << ")" << endl);
- Tree result = TRACED_mergeRateEnvironment(R1, R2, success);
- if (success) {
- TRACE(cerr << --TABBER << "mergeRateEnvironment(" << *R1 << ", " << *R2 << ") -> " << *result << endl);
- } else {
- TRACE(cerr << --TABBER << "mergeRateEnvironment(" << *R1 << ", " << *R2 << ") -> FAILED" << endl);
- }
- return result;
-}
-
-
-
-
-static Tree TRACED_mergeRateEnvironment(Tree R1, Tree R2, bool& success)
-{
- if (isNil(R1)) {
-
- success = true;
- return R2;
-
- } else if (isNil(R2)) {
-
- success = true;
- return R1;
-
- } else {
-
- Tree p1 = hd (R1);
- Tree p2 = hd (R2);
-
- Tree k1 = hd (p1);
- Tree k2 = hd (p2);
-
- if (k1 < k2) {
-
- return cons(p1, mergeRateEnvironment(tl(R1), R2, success));
-
- } else if (k2 < k1) {
-
- return cons(p2, mergeRateEnvironment(R1, tl(R2), success));
-
- } else {
-
- // we have a common expression
- Tree r1 = tl (p1);
- Tree r2 = tl (p2);
-
- if (r1 == r2) {
- // fine, same rate
- return cons(p2, mergeRateEnvironment(tl(R1), tl(R2), success));
- } else {
- success = false;
- return nil;
- }
- }
- }
-}
-
-/**
- * Merge a list of independent rate environments into a single rate environment
- */
-static Tree flatRateEnvironmentList(Tree lre)
-{
- Tree e = nil;
- bool success = true;
- while (isList(lre)) {
- e = mergeRateEnvironment(hd(lre),e, success);
- assert(success); // can't failed if environments are independant
- lre = tl(lre);
- }
- return e;
-}
-
-/**
-
-========================================== RATE INFERENCE =========================================
-
-
-*/
-
-
-property<Tree> gInferreRateProperty;
-
-static void setInferreRateProperty(Tree sig, int rate, Tree renv)
-{
- gInferreRateProperty.set(sig, cons(tree(rate),renv));
-}
-
-static bool getInferreRateProperty(Tree sig, int* rate, Tree& renv)
-{
- Tree p;
- if (gInferreRateProperty.get(sig, p)) {
- *rate = tree2int(hd(p));
- renv = tl(p);
- return true;
- } else {
- return false;
- }
-}
-
-
-/**
- * Inferre rate (and rate environment) of a single signal.
- * Use a property to cache previous results
- */
-static void inferreRate(Tree sig, int* rate, Tree& E)
-{
- TRACE(cerr << ++TABBER << "inferreRate(" << ppsig(sig) << ")" << endl);
- if (! getInferreRateProperty(sig, rate, E)) {
- doInferreRate(sig, rate, E);
- setInferreRateProperty(sig, *rate, E);
- }
- TRACE(cerr << --TABBER << "inferreRate(" << ppsig(sig) << ") = " << *rate << " with " << *E << endl);
-}
-
-
-/**
- * Checks that w denotes a positive constant integer signal n
- * returns n or exit
- */
-static int checkSignalDenotesSize(Tree w, Tree sig)
-{
- // checks that w denotes a positive constant integer signal n
- SimpleType* st = isSimpleType(getCertifiedSigType(w));
-
- if (st && st->nature()==kInt) {
- interval i = st->getInterval();
- if (i.valid && i.lo >= 0 && i.lo == i.hi) {
- return int(i.lo);
- }
- }
- cerr << "ERROR in expression : " << ppsig(sig) << endl;
- cerr << *w << " is not a positive constant integer" << endl;
- exit(1);
-}
-
-/**
- * Inferre the rate (and the rate environment) of a signal.
- * A zero rate indicates an impossibility
- */
-static void doInferreRate(Tree sig, int* rate, Tree& E)
-{
- Tree w, x, rsig, id, body;
- int i, in;
-
- if ( isSigVectorize(sig, w, x) ) {
-
- // -- rate(vectorize(n,x)) = rate(x)/n
-
- VectorType* vt = isVectorType(getCertifiedSigType(sig)); assert(vt);
- int n = vt->size(); assert(n>0);
-
- int r; inferreRate(x, &r, E);
- if ((r%n) == 0) {
- // fine, the rate of x can be divided by n
- // (note: this is compatible with r==0 indicating that x has no rate)
- *rate = r/n;
- } else {
- // we need to scale the rates involved in x
- int m = lcm(n,r);
- *rate = m/n;
- E = multRateEnv(m/r, E);
- }
-
- } else if ( isSigDownSample(sig, w, x) ) {
-
- // -- rate(down(n,x) = rate(x)/n
-
- int n = checkSignalDenotesSize(w, sig);
-
- int r; inferreRate(x, &r, E);
-
- if ((r%n) == 0) {
- // fine, the rate of x can be divided by n
- // (note: this is compatible with r==0 indicating that x has no rate)
- *rate = r/n;
- } else {
- // we need to scale the rates involved in x
- int m = lcm(n,r);
- *rate = m/n;
- E = multRateEnv(m/r, E);
- }
-
- } else if ( isSigUpSample(sig, w, x) ) {
-
- // -- rate(up(n,x) = rate(x)*n
-
- int n = checkSignalDenotesSize(w, sig);
- int r; inferreRate(x, &r, E);
- *rate = r*n;
-
- } else if ( isSigSerialize(sig, x)) {
-
- // -- rate(serialize(x) = rate(x)*n [with Type(x) = vector(n,T)]
-
- VectorType* vt = isVectorType(getCertifiedSigType(x)); assert(vt);
-
- int r; inferreRate(x, &r, E);
- *rate = vt->size() * r;
-
- } else if ( isSigInput(sig, &in)) {
-
- // -- rate(input(x)) = 1
-
- *rate = 1;
- E = addRateEnv(sig,1,nil);
-
- } else if (isProj(sig,&i,rsig) && isRec(rsig, id, body)) {
-
- // -- rate(proj(i, x=(E0,E1,...))) = 1
-
- *rate = 1;
- E = addRateEnv(sig,1,nil);
-
- } else {
-
- // -- rate(op()) = 1
- // -- rate(op(s1, s2)) = lcm(rate(s1), rate(s2))
-
- vector<Tree> subsigs;
- unsigned int n = getSubSignals(sig, subsigs, false);
-
- if (n == 0) {
- // -- rate(op()) = 1
- *rate = 1;
- E = nil;
-
- } else {
- // -- rate(op(s1, s2)) = lcm(rate(s1), rate(s2))
-
- vector<int> subrates(n);
- vector<Tree> subenvs(n);
-
- int lcmrate = 1;
- for (unsigned int i=0; i<n; i++) {
- inferreRate(subsigs[i], &subrates[i], subenvs[i]);
- lcmrate = lcm(subrates[i], lcmrate);
- }
-
- // Try to merge all (scaled) rate environments
- Tree M = nil;
- bool success = false;
-
- for (unsigned int i=0; i<n; i++) {
- M = mergeRateEnvironment(M, multRateEnv(lcmrate/subrates[i], subenvs[i]), success);
- if (! success) {
- // merge failed
- *rate = 0; E = nil;
- return;
- }
- }
- // merge successful
- *rate = lcmrate; E = M;
- }
- }
-}
-
-
-/**
- * Try to add a rate environment E1 to a list of independent rate environments LE
- * Returns a list of independent rate environments
- */
-static Tree addToMultiRates(Tree E1, Tree LE, bool& success);
-static Tree TRACED_addToMultiRates(Tree E1, Tree LE, bool& success);
-
-static Tree addToMultiRates(Tree E1, Tree LE, bool& success)
-{
- TRACE(cerr << ++TABBER << "addToMultiRates(" << *E1 << ", " << *LE << ")" << endl);
- Tree result = TRACED_addToMultiRates(E1, LE, success);
- if (success) {
- TRACE(cerr << --TABBER << "addToMultiRates(" << *E1 << ", " << *LE << ") -> " << *result << endl);
- } else {
- TRACE(cerr << --TABBER << "addToMultiRates(" << *E1 << ", " << *LE << ") -> FAILED" << endl);
- }
- return result;
-}
-
-
-static Tree TRACED_addToMultiRates(Tree E1, Tree LE, bool& success)
-{
- if (isNil(LE)) {
- success = true;
- return cons(E1,nil);
- } else {
- Tree E2 = hd(LE);
- if (areRatesIndependent(E1,E2)) {
- return cons(E2, addToMultiRates(E1, tl(LE), success));
- } else {
- int n1, n2;
- if (areRatesCompatible(E1, E2, n1, n2)) {
- Tree M = mergeRateEnvironment(multRateEnv(n1,E1), multRateEnv(n2,E2), success);
- if (success) {
- return addToMultiRates(M, tl(LE), success);
- } else {
- return nil;
- }
- } else {
- return nil;
- }
- }
- }
-}
-
-
-
-RateInferrer::RateInferrer(Tree lsig)
-{
- TRACE(cerr << "ENTRE RateInferrer constructor of " << *lsig << endl);
- if (! (isList(lsig) | isNil(lsig))) {
- lsig = cons(lsig,nil);
- }
- fFullList = addRecursiveSignals(lsig);
- fRateEnv = inferreMultiRates(lsig, fSuccess);
- if (fSuccess) {
- // nit the rate properties for the expressions in the environment
- for (Tree L=fRateEnv; isList(L); L = tl(L)) {
- Tree p = hd(L);
- fRateProperty.set(hd(p),tree2int(tl(p)));
- }
- }
- TRACE(cerr << "EXIT RateInferrer constructor" << *lsig << endl);
-}
-
-// returns the rate of sig assuming that sig is a subexpression of lsig
-int RateInferrer::rate(Tree sig)
-{
- int r;
-
- if (!fSuccess) {
- return 0;
- } else if (fRateProperty.get(sig, r)) {
- return r;
- } else {
- r = computeRate(sig);
- fRateProperty.set(sig, r);
- return r;
- }
-}
-
-int RateInferrer::computeRate(Tree sig)
-{
- Tree n, x, rsig, id, body;
- int i;
-
- if ( isSigInput(sig, &i)) {
-
- TRACE(cerr << "ERROR: Input " << i << " should have a rate" << endl);
- return 0;
-
- } else if ( isProj(sig,&i,rsig) && isRec(rsig, id, body) ) {
-
- TRACE(cerr << "ERROR: Recursive signal " << *sig << " should have a rate" << endl);
- return 0;
-
- } else if ( isSigVectorize(sig, n, x) ) {
-
- VectorType* vt = isVectorType(getCertifiedSigType(sig));
- assert(vt);
- return rate(x) / vt->size();
-
- } else if ( isSigSerialize(sig, x)) {
-
- VectorType* vt = isVectorType(getCertifiedSigType(x));
- assert(vt);
- return vt->size() * rate(x);
-
- } else if ( isSigUpSample(sig, n, x) ) {
-
- int i = checkSignalDenotesSize(n,sig);
- return rate(x) * i;
-
- } else if ( isSigDownSample(sig, n, x) ) {
-
- int i = checkSignalDenotesSize(n,sig);
- int r = rate(x);
- assert(r%i == 0);
- return r/i;
-
- } else {
-
- vector<Tree> subsigs;
- vector<int> subrates;
- int n = getSubSignals(sig, subsigs, false);
- if (n == 0) {
- // we don't depend of any subsignals, then the rate is 1
- return 1;
- } else {
- // we depend on subsignals, the rate is the highest one
- // moreover the highest one is a multiple of all other
- // rates
- int maxrate = 1;
- int lcmrate = 1;
- for (unsigned int i=0; i<subsigs.size(); i++) {
- int r = rate(subsigs[i]);
- maxrate = max(r, maxrate);
- lcmrate = lcm(r, lcmrate);
- if (lcmrate != maxrate) {
- return 0; // rates of arguments are incompatible
- }
- }
- return maxrate;
- }
- }
-}
-
-