diff --git a/Makefile b/Makefile index 0909c6b63c..b15a906548 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,13 @@ -.PHONY: help install egg-herbie nightly index start-server deploy coverage +UNAME_S := $(shell uname -s) +LIB_EXT := so +LIB_FLAGS := -shared -fPIC + +ifeq ($(UNAME_S), Darwin) + LIB_EXT := dylib + LIB_FLAGS := -dynamiclib +endif + +.PHONY: help install egg-herbie nightly index start-server deploy coverage compile-accelerators time-ops evaluate-proj evaluate-basilisk evaluate-coolprop evaluate generate help: @echo "Type 'make install' to install Herbie" @@ -46,7 +55,51 @@ minimal-distribution: [ ! -f herbie ] || (raco distribute herbie-compiled herbie && rm herbie) nightly: - bash infra/nightly.sh bench reports --threads 2 + make generate + +generate: + bash growlibm/generate.sh + +time-ops: + mkdir -p growlibm/timing/drivers + make compile-accelerators + python3 growlibm/timing/time_ops.py + +evaluate: + make evaluate-proj + make evaluate-basilisk + make evaluate-coolprop + +evaluate-proj: + bash growlibm/evaluate.sh bench/proj/ reports proj + +evaluate-basilisk: + bash growlibm/evaluate.sh bench/orbital-motion.fpcore reports basilisk + +evaluate-coolprop: + bash growlibm/evaluate.sh bench/helmholtz.fpcore reports coolprop + +compile-accelerators: + clang $(LIB_FLAGS) -O3 -o growlibm/accelerators/libaccelerators.$(LIB_EXT) \ + growlibm/accelerators/accelerators.c \ + growlibm/accelerators/cosquot.c \ + growlibm/accelerators/e_rem_pio2.c \ + growlibm/accelerators/powcos.c \ + growlibm/accelerators/invgud.c \ + -lm + +generate-table: + make compile-accelerators + racket growlibm/eval/generate-table.rkt + pandoc growlibm/eval/accelerator-table.tex -o out.html + +make-graphs: + python3 growlibm/eval/evaluate-frontier.py reports/proj PROJ --accelerators-only --max-relative-speedup 1.5 + python3 growlibm/eval/evaluate-frontier.py reports/basilisk Basilisk --accelerators-only --max-relative-speedup 2.5 + python3 growlibm/eval/evaluate-frontier.py reports/coolprop CoolProp --accelerators-only --max-relative-speedup 2 + python3 growlibm/eval/evaluate-best-alt-bars.py reports/proj PROJ + python3 growlibm/eval/evaluate-best-alt-bars.py reports/basilisk Basilisk + python3 growlibm/eval/evaluate-best-alt-bars.py reports/coolprop CoolProp upgrade: git pull diff --git a/README.md b/README.md index dbb607f05a..8708baf89c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,14 @@ -![Herbie](logo.png) +# GROWLIBM + +## Install and Running Growlibm +Run `make generate` to install and run growlibm on the PBRT library + +## Dependencies +Racket v8.17 +rustc 1.91.0 +Python 3.14.0 + + diff --git a/growlibm/.gitignore b/growlibm/.gitignore new file mode 100644 index 0000000000..5429446213 --- /dev/null +++ b/growlibm/.gitignore @@ -0,0 +1,8 @@ +timing/ +chassis_tuning/ +benchmark +drivers/ + +libaccelerators.dylib +eval/accelerator-table.tex +accelerators/libaccelerators.dylib diff --git a/growlibm/BenchmarkInstructions.md b/growlibm/BenchmarkInstructions.md new file mode 100644 index 0000000000..c34cb3cd8e --- /dev/null +++ b/growlibm/BenchmarkInstructions.md @@ -0,0 +1,32 @@ +You are tasked with generating new benchmarks for Herbie, a numerical compiler that rewrites floating-point expressions to reduce error. + +When you receive a new source file: + +1. **Skim for numerically fragile code paths.** Focus on + - Branches guarding against domain violations (division by zero, `fabs` comparisons, overflow checks). + - Expressions wrapped in conditionals, iterative refinements, or polynomial corrections applied only to small ranges. + - Sequences of transcendental functions (`exp`, `asinh`, `atan2`, etc.) composed together. + +2. **Score candidate expressions.** Prefer ones that are + - Prone to catastrophic cancellation (differences of comparably sized terms, exponentials combined with reciprocals). + - Already noted as “exact”, “correction”, or “series expansion” code by the source comments. + +3. **Isolate the expression.** For each expression: + - Identify the minimal set of variables needed (pull intermediate definitions when helpful). + - Convert to FPCore using lisp syntax. + - Add a `:pre` condition mirroring parameter invarients. Don't worry about adding `:pre` conditions for mathematical domain checks as Herbie's sampler already takes care of this. + - Name the fpcores something reasonable but don't prefix the name with the name of the benchmark file. + - Use `let*` and `let` as needed. Make sure to wrap variable assignment in square brackets in `let` expressions. + - Ensure that `+` and `*` are only used as binary operations. + - Preserve structure instead of using algebraic simplifications. + +4. **Validate syntax.** Run + + ``` + racket -y src/main.rkt report --platform vanilla out + ``` + + Fix any syntax errors Herbie reports (missing parentheses, unsupported identifiers, missing preconditions). Rerun until the file parses cleanly. Warnings about improvement quality are fine; only syntax errors must be resolved. Make sure that the number of FPCores you + add to the file is the same number that appears in the report when you run this command. + +Aim for a set of 15–20 expressions that represent the numerical behaviors from the source file. Ideally, this collection will include hard expressions that Herbie has trouble improving. diff --git a/growlibm/accelerator-table.html b/growlibm/accelerator-table.html new file mode 100644 index 0000000000..6d2026deb8 --- /dev/null +++ b/growlibm/accelerator-table.html @@ -0,0 +1,36 @@ + + + + + growlibm Accelerators + + +

growlibm accelerators

+ + + + + + + + + + + + + + + + + + + + + + + + + +
nameoriginspeccostaccuracycost of specaccuracy of spec
cosprod(cos (* x y))1280087.99%678457.33%
hypot(sqrt (+ (* x x) (* y y)))320099.99%153654.45%
invgud(log (tan (* (+ (+ x x) (PI)) 1/4)))2500099.87%135684.05%
log1pmd(log (/ (+ 1 x) (- 1 x)))3200100.00%75528.86%
pow1ms(pow (* (- 1 x) (- 1 x)) y)832099.97%723273.80%
powcos(pow (cos x) y)64000100.00%1292893.19%
powcos2(pow (cos x) 2)6400099.70%1292899.72%
powcos4(pow (cos x) 4)6400099.42%1292899.38%
powcos6(pow (cos x) 6)6400099.08%1292899.03%
sinprodPROJ(sin (* x y))1280089.11%678458.58%
verdcos(- (cos (+ x x)) 1)960099.58%684876.48%
+ + diff --git a/growlibm/accelerators.c b/growlibm/accelerators.c new file mode 100644 index 0000000000..a84b46eed2 --- /dev/null +++ b/growlibm/accelerators.c @@ -0,0 +1,68 @@ +//clang -dynamiclib -O3 -o libaccelerators.dylib accelerators.c +#include +#include + +double sin_xy(double x, double y) { + double p = x * y; + double q = fma(x, y, -p); + + double sin_p, cos_p, sin_q, cos_q; + __sincos(p, &sin_p, &cos_p); + __sincos(q, &sin_q, &cos_q); + return fma(sin_p, cos_q, cos_p * sin_q); +} + +double cos_xy(double x, double y) { + double p = x * y; + double q = fma(x, y, -p); + + double sin_p, cos_p, sin_q, cos_q; + __sincos(p, &sin_p, &cos_p); + __sincos(q, &sin_q, &cos_q); + + return fma(cos_p, cos_q, -sin_p * sin_q); +} + +double sin_quotient_xy(double x, double y) { + double p = x / y; + double r = fma(-p, y, x); + double q = r / y; + + double sin_p, cos_p, sin_q, cos_q; + __sincos(p, &sin_p, &cos_p); + __sincos(q, &sin_q, &cos_q); + + return fma(sin_p, cos_q, cos_p * sin_q); +} + +double cos_quotient_xy(double x, double y) { + double p = x / y; + double r = fma(-p, y, x); + double q = r / y; + + double sin_p, cos_p, sin_q, cos_q; + __sincos(p, &sin_p, &cos_p); + __sincos(q, &sin_q, &cos_q); + + return fma(cos_p, cos_q, -sin_p * sin_q); +} + +// double approx_sin_xy(double x, double y) { +// double p = x * y; +// double q = fma(x, y, -p); + +// double sin_p, cos_p; +// __sincos(p, &sin_p, &cos_p); + +// return fma(sin_p, 1, cos_p); +// } + +// double approx_cos_xy(double x, double y) { +// double p = x * y; +// double q = fma(x, y, -p); + +// double sin_p, cos_p; +// __sincos(p, &sin_p, &cos_p); + +// return fma(cos_p, 1, -sin_p); +// } diff --git a/growlibm/accelerators/accelerators.c b/growlibm/accelerators/accelerators.c new file mode 100644 index 0000000000..8122aecd5f --- /dev/null +++ b/growlibm/accelerators/accelerators.c @@ -0,0 +1,415 @@ +/* +clang -dynamiclib -O3 -o growlibm/accelerators/libaccelerators.dylib \ +growlibm/accelerators/accelerators.c \ +growlibm/accelerators/cosquot.c \ +growlibm/accelerators/e_rem_pio2.c \ +growlibm/accelerators/powcos.c \ +growlibm/accelerators/invgud.c \ +-lm +*/ + + +#define _GNU_SOURCE +#include +#include +#include "fdlibm.h" +#include "accelerators.h" + +static inline void sincos_wrapper(double x, double* s, double* c) { +#if defined(__APPLE__) + __sincos(x, s, c); +#else + sincos(x, s, c); +#endif +} + +static inline void fast_two_sum(double a, double b, double *s, double *e) { + double sum = a + b; + double z = sum - a; + *s = sum; + *e = b - z; +} + +static inline void unsorted_two_sum(double a, double b, double *s, double *e) { + if (fabs(a) < fabs(b)) { + double tmp = a; a = b; b = tmp; + } + fast_two_sum(a, b, s, e); +} + +static inline double root5_positive(double x) { + const double one_fifth = 0.2; + int e; + double m = frexp(x, &e); + int q = e / 5; + int r = e % 5; + + if (r < 0) { + r += 5; + q -= 1; + } + + // x = 2^(5q) * s, with s in [0.5, 16). This keeps Newton updates stable. + double s = ldexp(m, r); + double u = exp(one_fifth * log1p(s - 1.0)); + + for (int i = 0; i < 2; ++i) { + double u2 = u * u; + double u4 = u2 * u2; + double ratio = s / u4; + u = one_fifth * fma(4.0, u, ratio); + } + + return ldexp(u, q); +} + + +double sinprod(double x, double y) { + double p = x * y; + double q = fma(x, y, -p); + + double sin_p, cos_p, sin_q, cos_q; + sincos_wrapper(p, &sin_p, &cos_p); + sincos_wrapper(q, &sin_q, &cos_q); + + return fma(sin_p, cos_q, cos_p * sin_q); +} + +double cosprod(double x, double y) { + double p = x * y; + double q = fma(x, y, -p); + + double sin_p, cos_p, sin_q, cos_q; + sincos_wrapper(p, &sin_p, &cos_p); + sincos_wrapper(q, &sin_q, &cos_q); + + return fma(cos_p, cos_q, -sin_p * sin_q); +} + +// double cos_quotient_xy(double x, double y) { +// double p = x / y; +// double r = fma(-p, y, x); +// double q = r / y; + +// double sin_p, cos_p, sin_q, cos_q; +// sincos_wrapper(p, &sin_p, &cos_p); +// sincos_wrapper(q, &sin_q, &cos_q); + +// return fma(cos_p, cos_q, -sin_p * sin_q); +// } + +double sindivpz(double x, double y, double z) { + // quotient p+q + double p = x / y; + double r = fma(-p, y, x); + double q = r / y; + + // p + z as (s_hi + s_lo) + double s_hi, s_lo; + unsorted_two_sum(p, z, &s_hi, &s_lo); + + // fold in q, then renormalize + double t = s_lo + q; + + double P, Q; + unsorted_two_sum(s_hi, t, &P, &Q); + + // sin(P+Q) + double sinP, cosP, sinQ, cosQ; + sincos_wrapper(P, &sinP, &cosP); + sincos_wrapper(Q, &sinQ, &cosQ); + + return fma(sinP, cosQ, cosP * sinQ); +} + +double cosdivpz(double x, double y, double z) { + // Step 1: quotient as p + q + double p = x / y; + double r = fma(-p, y, x); // remainder x - p*y (with one rounding) + double q = r / y; + + // Step 2: add z to p with compensated sum (via reordered FastTwoSum) + double s_hi, s_lo; + unsorted_two_sum(p, z, &s_hi, &s_lo); + + // Step 3: fold in quotient residual and renormalize + double t = s_lo + q; + + double P, Q; + unsorted_two_sum(s_hi, t, &P, &Q); + + // Step 4: cos(P+Q) = cos(P)cos(Q) - sin(P)sin(Q) + double sinP, cosP, sinQ, cosQ; + sincos_wrapper(P, &sinP, &cosP); + sincos_wrapper(Q, &sinQ, &cosQ); + + return fma(cosP, cosQ, -(sinP * sinQ)); +} + + +// double log1pmd(double x) { +// static const double +// Lp1 = 6.666666666666735130e-01, // 3FE55555 55555593 +// Lp2 = 3.999999999940941908e-01, // 3FD99999 9997FA04 +// Lp3 = 2.857142874366239149e-01, // 3FD24924 94229359 +// Lp4 = 2.222219843214978396e-01, // 3FCC71C5 1D8E78AF +// Lp5 = 1.818357216161805012e-01, // 3FC74664 96CB03DE +// Lp6 = 1.531383769920937332e-01, // 3FC39A09 D078C69F +// Lp7 = 1.479819860511658591e-01; // 3FC2F112 DF3E5244 + +// double z = x * x; + +// double R = z * (Lp1 + z * (Lp2 + z * (Lp3 + z * (Lp4 + z * (Lp5 + z * (Lp6 + z * Lp7)))))); + +// return 2.0 * x + x * R; +// } + +double log1pmd(double x) { + static const double + Lp1 = 6.666666666666735130e-01, Lp2 = 3.999999999940941908e-01, + Lp3 = 2.857142874366239149e-01, Lp4 = 2.222219843214978396e-01, + Lp5 = 1.818357216161805012e-01, Lp6 = 1.531383769920937332e-01, + Lp7 = 1.479819860511658591e-01; + + double z = x * x; + + double R = fma(z, fma(z, fma(z, fma(z, fma(z, fma(z, Lp7, Lp6), Lp5), Lp4), Lp3), Lp2), Lp1); + + return fma(x * z, R, 2.0 * x); +} + +// double log_tan(double x) { +// double y[2]; + +// int n = __ieee754_rem_pio2(x, y); +// double r = y[0] + y[1]; + +// const double r2 = r * r; + +// static const double c0 = 0x1.00000006d6ee1p0; +// static const double c2 = 0x1.5555340b483e1p-3; +// static const double c4 = 0x1.55627da178f7ap-5; +// static const double c6 = 0x1.8aa9f1d42a76cp-7; +// static const double c8 = 0x1.0b2c2f2c6a051p-8; +// static const double c10 = 0x1.6c82aa9a13c14p-11; +// static const double c12 = 0x1.07ef77f8abdfp-10; + +// double p = c12; +// p = fma(r2, p, c10); +// p = fma(r2, p, c8); +// p = fma(r2, p, c6); +// p = fma(r2, p, c4); +// p = fma(r2, p, c2); +// p = fma(r2, p, c0); + +// return r * p; +// } + + +/* @(#)e_hypot.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* __ieee754_hypot(x,y) + * + * Method : + * If (assume round-to-nearest) z=x*x+y*y + * has error less than sqrt(2)/2 ulp, than + * sqrt(z) has error less than 1 ulp (exercise). + * + * So, compute sqrt(x*x+y*y) with some care as + * follows to get the error below 1 ulp: + * + * Assume x>y>0; + * (if possible, set rounding to round-to-nearest) + * 1. if x > 2y use + * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y + * where x1 = x with lower 32 bits cleared, x2 = x-x1; else + * 2. if x <= 2y use + * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y)) + * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, + * y1= y with lower 32 bits chopped, y2 = y-y1. + * + * NOTE: scaling may be necessary if some argument is too + * large or too tiny + * + * Special cases: + * hypot(x,y) is INF if x or y is +INF or -INF; else + * hypot(x,y) is NAN if x or y is NAN. + * + * Accuracy: + * hypot(x,y) returns sqrt(x^2+y^2) with error less + * than 1 ulps (units in the last place) + */ + + +double hypot(double x, double y) +{ + double a=x,b=y,t1,t2,y1,y2,w; + int j,k,ha,hb; + + ha = __HI(x)&0x7fffffff; /* high word of x */ + hb = __HI(y)&0x7fffffff; /* high word of y */ + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} + __HI(a) = ha; /* a <- |a| */ + __HI(b) = hb; /* b <- |b| */ + if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */ + k=0; + if(ha > 0x5f300000) { /* a>2**500 */ + if(ha >= 0x7ff00000) { /* Inf or NaN */ + w = a+b; /* for sNaN */ + if(((ha&0xfffff)|__LO(a))==0) w = a; + if(((hb^0x7ff00000)|__LO(b))==0) w = b; + return w; + } + /* scale a and b by 2**-600 */ + ha -= 0x25800000; hb -= 0x25800000; k += 600; + __HI(a) = ha; + __HI(b) = hb; + } + if(hb < 0x20b00000) { /* b < 2**-500 */ + if(hb <= 0x000fffff) { /* subnormal b or 0 */ + if((hb|(__LO(b)))==0) return a; + t1=0; + __HI(t1) = 0x7fd00000; /* t1=2^1022 */ + b *= t1; + a *= t1; + k -= 1022; + } else { /* scale a and b by 2^600 */ + ha += 0x25800000; /* a *= 2^600 */ + hb += 0x25800000; /* b *= 2^600 */ + k -= 600; + __HI(a) = ha; + __HI(b) = hb; + } + } + /* medium size a and b */ + w = a-b; + if (w>b) { + t1 = 0; + __HI(t1) = ha; + t2 = a-t1; + w = sqrt(t1*t1-(b*(-b)-t2*(a+t1))); + } else { + a = a+a; + y1 = 0; + __HI(y1) = hb; + y2 = b - y1; + t1 = 0; + __HI(t1) = ha+0x00100000; + t2 = a - t1; + w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b))); + } + if(k!=0) { + t1 = 1.0; + __HI(t1) += (k<<20); + return t1*w; + } else return w; +} + + +// double approx_sin_xy(double x, double y) { +// double p = x * y; +// double q = fma(x, y, -p); + +// double sin_p, cos_p; +// __sincos(p, &sin_p, &cos_p); + +// return fma(sin_p, 1, cos_p); +// } + +// double approx_cos_xy(double x, double y) { +// double p = x * y; +// double q = fma(x, y, -p); + +// double sin_p, cos_p; +// __sincos(p, &sin_p, &cos_p); + +// return fma(cos_p, 1, -sin_p); +// } + + +double verdcos(double x){ + double sin_x = sin(x); + return -2.0 * sin_x * sin_x; +} + +double ncos1p(double z0) { + return tan((0.5 * z0)) * sin(z0); +} + +double pown2o3(double z0) { + double r = cbrt(z0); + return 1.0 / (r * r); +} + +double pow2o5(double z0) { + if (isnan(z0)) return z0 + z0; + if (z0 == 0.0) return 0.0; + if (isinf(z0)) return INFINITY; + + double r = root5_positive(fabs(z0)); + return r * r; +} + +double pow3o5(double z0) { + if (isnan(z0)) return z0 + z0; + if (z0 == 0.0) return z0; + if (isinf(z0)) return z0; + + double r = root5_positive(fabs(z0)); + double mag = r * r * r; + return (z0 < 0.0) ? -mag : mag; +} + +double pow5o3(double z0) { + double r = cbrt(z0); + return z0 * r * r; +} + +double pown16o5(double z0) { + if (isnan(z0)) return z0 + z0; + if (z0 == 0.0) return INFINITY; + if (isinf(z0)) return 0.0; + + double r = root5_positive(fabs(z0)); + int e; + double m = frexp(r, &e); + double m2 = m * m; + double m4 = m2 * m2; + double m8 = m4 * m4; + double m16 = m8 * m8; + return ldexp(1.0 / m16, -16 * e); +} + +double pow1ms(double x, double y) { + // (1 - x)^2 = 1 + x * (x - 2); use log1p for accuracy near 1. + if (y == 0.0) { + return 1.0; + } + + double ax = fabs(x); + if (ax > 0x1.0p+511) { + // Avoid overflow in x*(x-2); use log|1-x| = log|x| + log|1-1/x|. + double inv = 1.0 / x; + double log_base = 2.0 * (log(ax) + log1p(-inv)); + return exp(y * log_base); + } + + double delta = fma(x, x, -2.0 * x); + + if (delta < -1.0) { + delta = -1.0; + } + + double log_base = log1p(delta); + return exp(y * log_base); +} diff --git a/growlibm/accelerators/accelerators.h b/growlibm/accelerators/accelerators.h new file mode 100644 index 0000000000..ae0fbad37c --- /dev/null +++ b/growlibm/accelerators/accelerators.h @@ -0,0 +1,33 @@ +#ifndef GROWLIBM_ACCELERATORS_H +#define GROWLIBM_ACCELERATORS_H + +#ifdef __cplusplus +extern "C" { +#endif + +double sinprod(double x, double y); +double cosprod(double x, double y); +double sinquot(double x, double y); +double cosquot(double x, double y); +double log1pmd(double x); +double invgud(double x); +double logtan(double x); +double verdcos(double x); +double hypot(double x, double y); +double powcos(double x, double y); +double powcos2(double x); +double powcos4(double x); +double powcos6(double x); +double ncos1p(double x); +double pown2o3(double x); +double pow2o5(double x); +double pow3o5(double x); +double pow5o3(double x); +double pown16o5(double x); +double pow1ms(double x, double y); + +#ifdef __cplusplus +} +#endif + +#endif /* GROWLIBM_ACCELERATORS_H */ diff --git a/growlibm/accelerators/cos.c b/growlibm/accelerators/cos.c new file mode 100644 index 0000000000..2fa9cab7cc --- /dev/null +++ b/growlibm/accelerators/cos.c @@ -0,0 +1,2066 @@ +/* Correctly-rounded cosine function for binary64 value. + +Copyright (c) 2022-2025 Paul Zimmermann and Tom Hubrecht + +This file is part of the CORE-MATH project +(https://core-math.gitlabpages.inria.fr/). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include +#include // for fegetround, FE_TONEAREST, FE_DOWNWARD, FE_UPWARD +#include + +// Warning: clang also defines __GNUC__ +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif + +#pragma STDC FENV_ACCESS ON + +/******************** code copied from dint.h and pow.[ch] *******************/ + +#if (defined(__clang__) && __clang_major__ >= 14) || (defined(__GNUC__) && __GNUC__ >= 14 && __BITINT_MAXWIDTH__ && __BITINT_MAXWIDTH__ >= 128) +typedef unsigned _BitInt(128) u128; +#else +typedef unsigned __int128 u128; +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +typedef union { + struct { + u128 r; + int64_t _ex; + uint64_t _sgn; + }; + struct { + uint64_t lo; + uint64_t hi; + int64_t ex; + uint64_t sgn; + }; +} dint64_t; +#else +typedef union { + struct { + u128 r; + int64_t _ex; + uint64_t _sgn; + }; + struct { + uint64_t hi; + uint64_t lo; + int64_t ex; + uint64_t sgn; + }; +} dint64_t; +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +typedef union { + u128 r; + struct { + uint64_t l; + uint64_t h; + }; +} uint128_t; +#else +typedef union { + u128 r; + struct { + uint64_t h; + uint64_t l; + }; +} uint128_t; +#endif + +typedef union { + double f; + uint64_t u; +} f64_u; + +// Extract both the mantissa and exponent of a double +static inline void fast_extract (int64_t *e, uint64_t *m, double x) { + f64_u _x = {.f = x}; + + *e = (_x.u >> 52) & 0x7ff; + *m = (_x.u & (~0ull >> 12)) + (*e ? (1ull << 52) : 0); + *e = *e - 0x3fe; +} + +// Return non-zero if a = 0 +static inline int +dint_zero_p (const dint64_t *a) +{ + return a->hi == 0; +} + +static inline int cmp(int64_t a, int64_t b) { return (a > b) - (a < b); } + +static inline int cmpu128 (u128 a, u128 b) { return (a > b) - (a < b); } + +/* ZERO is a dint64_t representation of 0, which ensures that + dint_tod(ZERO) = 0 */ +static const dint64_t ZERO = {.hi = 0x0, .lo = 0x0, .ex = -1076, .sgn = 0x0}; +// MAGIC is a dint64_t representation of 1/2^11 +static const dint64_t MAGIC = {.hi = 0x8000000000000000, .lo = 0x0, .ex = -10, .sgn = 0x0}; + +// Compare the absolute values of a and b +// Return -1 if |a| < |b| +// Return 0 if |a| = |b| +// Return +1 if |a| > |b| +static inline signed char +cmp_dint_abs (const dint64_t *a, const dint64_t *b) { + if (dint_zero_p (a)) + return dint_zero_p (b) ? 0 : -1; + if (dint_zero_p (b)) + return +1; + char c1 = cmp (a->ex, b->ex); + return c1 ? c1 : cmpu128 (a->r, b->r); +} + +// Copy a dint64_t value +static inline void cp_dint(dint64_t *r, const dint64_t *a) { + r->ex = a->ex; + r->r = a->r; + r->sgn = a->sgn; +} + +// Add two dint64_t values, with error bounded by 2 ulps (ulp_128) +// (more precisely 1 ulp when a and b have same sign, 2 ulps otherwise) +// Moreover, when Sterbenz theorem applies, i.e., |b| <= |a| <= 2|b| +// and a,b are of different signs, there is no error, i.e., r = a-b. +static inline void +add_dint (dint64_t *r, const dint64_t *a, const dint64_t *b) { + if (!(a->hi | a->lo)) { + cp_dint (r, b); + return; + } + + switch (cmp_dint_abs (a, b)) { + case 0: + if (a->sgn ^ b->sgn) { + cp_dint (r, &ZERO); + return; + } + + cp_dint (r, a); + r->ex++; + return; + + case -1: // |A| < |B| + { + // swap operands + const dint64_t *tmp = a; a = b; b = tmp; + break; // fall through the case |A| > |B| + } + } + + // From now on, |A| > |B| thus a->ex >= b->ex + + u128 A = a->r, B = b->r; + uint64_t k = a->ex - b->ex; + + if (k > 0) { + /* Warning: the right shift x >> k is only defined for 0 <= k < n + where n is the bit-width of x. See for example + https://developer.arm.com/documentation/den0024/a/The-A64-instruction-set/Data-processing-instructions/Shift-operations + where it is said that k is interpreted modulo n. */ + B = (k < 128) ? B >> k : 0; + } + + u128 C; + unsigned char sgn = a->sgn; + + r->ex = a->ex; /* tentative exponent for the result */ + + if (a->sgn ^ b->sgn) { + /* a and b have different signs C = A + (-B) + Sterbenz case |a|/2 <= |b| <= |a| can occur only when: + * k=0: then B is not truncated, and C is exact below + * k=1 and ex>0 below: then we ensure C is exact + */ + C = A - B; + uint64_t ch = C >> 64; + /* We can't have C=0 here since we excluded the case |A| = |B|, + thus __builtin_clzll(C) is well-defined below. */ + uint64_t ex = ch ? __builtin_clzll(ch) : 64 + __builtin_clzll(C); + /* The error from the truncated part of B (1 ulp) is multiplied by 2^ex, + thus by 2 ulps when ex <= 1. */ + if (ex > 0) + { + if (k == 1) /* Sterbenz case */ + C = (A << ex) - (b->r << (ex - 1)); + else + C = (A << ex) - (B << ex); + /* If C0 is the previous value of C, we have: + (C0-1)*2^ex < A*2^ex-B*2^ex <= C0*2^ex + since some neglected bits from B might appear which contribute + a value less than ulp(C0)=1. + As a consequence since 2^(127-ex) <= C0 < 2^(128-ex), because C0 had + ex leading zero bits, we have 2^127-2^ex <= A*2^ex-B*2^ex < 2^128. + Thus the value of C, which is truncated to 128 bits, is the right + one (as if no truncation); moreover in some rare cases we need to + shift by 1 bit to the left. */ + r->ex -= ex; + ex = __builtin_clzll (C >> 64); + /* Fall through with the code for ex = 0. */ + } + C = C << ex; + r->ex -= ex; + /* The neglected part of B is bounded by 2 ulp(C) when ex=0, 1 ulp + when ex > 0 but ex=0 at the end, and by 2*ulp(C) when ex > 0 and there + is an extra shift at the end (in that case necessarily ex=1). */ + } else { + C = A + B; + if (C < A) + { + C = ((u128) 1 << 127) | (C >> 1); + r->ex ++; + } + } + + /* In the addition case, we loose the truncated part of B, which + contributes to at most 1 ulp. If there is an exponent shift, we + might also loose the least significant bit of C, which counts as + 1/2 ulp, but the truncated part of B is now less than 1/2 ulp too, + thus in all cases the error is less than 1 ulp(r). */ + + r->sgn = sgn; + r->r = C; +} + +// Multiply two dint64_t numbers, with error bounded by 6 ulps +// on the 128-bit floating-point numbers. +// Overlap between r and a is allowed +static inline void +mul_dint (dint64_t *r, const dint64_t *a, const dint64_t *b) { + u128 bh = b->hi, bl = b->lo; + + /* compute the two middle terms */ + u128 m1 = (u128)(a->hi) * bl; + u128 m2 = (u128)(a->lo) * bh; + + /* put the 128-bit product of the high terms in r */ + r->r = (u128)(a->hi) * bh; + + /* there can be no overflow in the following addition since r <= (B-1)^2 + with B=2^64, (m1>>64) <= B-1 and (m2>>64) <= B-1, thus the sum is + bounded by (B-1)^2+2*(B-1) = B^2-1 */ + r->r += (m1 >> 64) + (m2 >> 64); + + // Ensure that r->hi starts with a 1 + uint64_t ex = r->hi >> 63; + r->r = r->r << (1 - ex); + + // Exponent and sign + // if ex=1, then ex(r) = ex(a) + ex(b) + // if ex=0, then ex(r) = ex(a) + ex(b) - 1 + r->ex = a->ex + b->ex + ex - 1; + r->sgn = a->sgn ^ b->sgn; + + /* The ignored part can be as large as 3 ulps before the shift (one + for the low part of a->hi * bl, one for the low part of a->lo * bh, + and one for the neglected a->lo * bl term). After the shift this can + be as large as 6 ulps. */ +} + +// Multiply two dint64_t numbers, assuming the low part of b is zero +// with error bounded by 2 ulps +static inline void +mul_dint_21 (dint64_t *r, const dint64_t *a, const dint64_t *b) { + u128 bh = b->hi; + u128 hi = (u128) (a->hi) * bh; + u128 lo = (u128) (a->lo) * bh; + + /* put the 128-bit product of the high terms in r */ + r->r = hi; + + /* add the middle term */ + r->r += lo >> 64; + + // Ensure that r->hi starts with a 1 + uint64_t ex = r->hi >> 63; + r->r = r->r << (1 - ex); + + // Exponent and sign + r->ex = a->ex + b->ex + ex - 1; + r->sgn = a->sgn ^ b->sgn; + + /* The ignored part can be as large as 1 ulp before the shift (truncated + part of lo). After the shift this can be as large as 2 ulps. */ +} + +// Convert a non-zero double to the corresponding dint64_t value +static inline void dint_fromd (dint64_t *a, double b) { + fast_extract (&a->ex, &a->hi, b); + + /* |b| = 2^(ex-52)*hi */ + + uint32_t t = __builtin_clzll (a->hi); + + a->sgn = b < 0.0; + a->hi = a->hi << t; + a->ex = a->ex - (t > 11 ? t - 12 : 0); + /* b = 2^ex*hi/2^64 where 1/2 <= hi/2^64 < 1 */ + a->lo = 0; +} + +static inline void subnormalize_dint(dint64_t *a) { + if (a->ex > -1023) + return; + + uint64_t ex = -(1011 + a->ex); + + uint64_t hi = a->hi >> ex; + uint64_t md = (a->hi >> (ex - 1)) & 0x1; + uint64_t lo = (a->hi & (~0ull >> ex)) || a->lo; + + switch (fegetround()) { + case FE_TONEAREST: + hi += lo ? md : hi & md; + break; + case FE_DOWNWARD: + hi += a->sgn & (md | lo); + break; + case FE_UPWARD: + hi += (!a->sgn) & (md | lo); + break; + } + + a->hi = hi << ex; + a->lo = 0; + + if (!a->hi) { + a->ex++; + a->hi = (1ull << 63); + } +} + +// Convert a dint64_t value to a double +static inline double dint_tod(dint64_t *a) { + subnormalize_dint (a); + + f64_u r = {.u = (a->hi >> 11) | (0x3ffll << 52)}; + + double rd = 0.0; + if ((a->hi >> 10) & 0x1) + rd += 0x1p-53; + + if (a->hi & 0x3ff || a->lo) + rd += 0x1p-54; + + if (a->sgn) + rd = -rd; + + r.u = r.u | a->sgn << 63; + r.f += rd; + + f64_u e; + + if (a->ex > -1022) { // The result is a normal double + if (a->ex > 1024) + if (a->ex == 1025) { + r.f = r.f * 0x1p+1; + e.f = 0x1p+1023; + } else { + r.f = 0x1.fffffffffffffp+1023; + e.f = 0x1.fffffffffffffp+1023; + } + else + e.u = ((a->ex + 1022) & 0x7ff) << 52; + } else { + if (a->ex < -1073) { + if (a->ex == -1074) { + r.f = r.f * 0x1p-1; + e.f = 0x1p-1074; + } else { + r.f = 0x0.0000000000001p-1022; + e.f = 0x0.0000000000001p-1022; + } + } else { + e.u = 1l << (a->ex + 1073); + } + } + + return r.f * e.f; +} + +/**************** end of code copied from dint.h and pow.[ch] ****************/ + +/**************** the following is copied from sin.c *************************/ + +typedef union {double f; uint64_t u;} b64u64_u; + +/* This table approximates 1/(2pi) downwards with precision 1280: + 1/(2*pi) ~ T[0]/2^64 + T[1]/2^128 + ... + T[i]/2^((i+1)*64) + ... + Computed with computeT() from sin.sage. */ +static const uint64_t T[20] = { + 0x28be60db9391054a, // i=0 + 0x7f09d5f47d4d3770, + 0x36d8a5664f10e410, + 0x7f9458eaf7aef158, + 0x6dc91b8e909374b8, + 0x1924bba82746487, // i=5 + 0x3f877ac72c4a69cf, + 0xba208d7d4baed121, + 0x3a671c09ad17df90, + 0x4e64758e60d4ce7d, + 0x272117e2ef7e4a0e, // i=10 + 0xc7fe25fff7816603, + 0xfbcbc462d6829b47, + 0xdb4d9fb3c9f2c26d, + 0xd3d18fd9a797fa8b, + 0x5d49eeb1faf97c5e, // i=15 + 0xcf41ce7de294a4ba, + 0x9afed7ec47e35742, + 0x1580cc11bf1edaea, + 0xfc33ef0826bd0d87, // i=19 +}; + +/* Table containing 128-bit approximations of sin2pi(i/2^11) for 0 <= i < 256 + (to nearest). + Each entry is to be interpreted as (hi/2^64+lo/2^128)*2^ex*(-1)*sgn. + Generated with computeS() from sin.sage. */ +static const dint64_t S[256] = { + {.hi = 0x0, .lo = 0x0, .ex = 128, .sgn=0}, + {.hi = 0xc90fc5f66525d257, .lo = 0x480f7956b6470765, .ex = -8, .sgn=0}, + {.hi = 0xc90f87f3380388d5, .lo = 0xcb3ff35bd4d81baa, .ex = -7, .sgn=0}, + {.hi = 0x96cb587284b81770, .lo = 0xb767005691b9d9d1, .ex = -6, .sgn=0}, + {.hi = 0xc90e8fe6f63c2330, .lo = 0xf1d7d06db39ea9fc, .ex = -6, .sgn=0}, + {.hi = 0xfb514b55ccbe541a, .lo = 0xd784e031f9af76d6, .ex = -6, .sgn=0}, + {.hi = 0x96c9b5df1877e9b5, .lo = 0xf91ee371d6467dca, .ex = -5, .sgn=0}, + {.hi = 0xafea690fd5912ef3, .lo = 0xf56e3c87ae3c56df, .ex = -5, .sgn=0}, + {.hi = 0xc90aafbd1b33efc9, .lo = 0xc539edcbfda0cf2c, .ex = -5, .sgn=0}, + {.hi = 0xe22a7a6729d8e453, .lo = 0x850021e392744a4f, .ex = -5, .sgn=0}, + {.hi = 0xfb49b98e8e7807f6, .lo = 0xb21ccebc9caac3, .ex = -5, .sgn=0}, + {.hi = 0x8a342eda160bf5ae, .lo = 0xde5b1068d174be9c, .ex = -4, .sgn=0}, + {.hi = 0x96c32baca2ae68b4, .lo = 0x37b2dd49d5fca3c0, .ex = -4, .sgn=0}, + {.hi = 0xa351cb7fc30bc889, .lo = 0xb56007d16d4ad5a3, .ex = -4, .sgn=0}, + {.hi = 0xafe00694866a1b44, .lo = 0xcd34d2751c2e1da7, .ex = -4, .sgn=0}, + {.hi = 0xbc6dd52c3a342eb5, .lo = 0xf10bfca3d6464012, .ex = -4, .sgn=0}, + {.hi = 0xc8fb2f886ec09f37, .lo = 0x6a17954b2b7c5171, .ex = -4, .sgn=0}, + {.hi = 0xd5880deafc18b534, .lo = 0x73d1472472f4a390, .ex = -4, .sgn=0}, + {.hi = 0xe214689606bf1676, .lo = 0x438b4a73aecd2541, .ex = -4, .sgn=0}, + {.hi = 0xeea037cc04764844, .lo = 0xc4e92d01a2f42935, .ex = -4, .sgn=0}, + {.hi = 0xfb2b73cfc106ff68, .lo = 0xf0a0e36a000c7350, .ex = -4, .sgn=0}, + {.hi = 0x83db0a7231831d8f, .lo = 0x60e782313f6161af, .ex = -3, .sgn=0}, + {.hi = 0x8a2009a6b84d9402, .lo = 0x77724a2b2a669bc4, .ex = -3, .sgn=0}, + {.hi = 0x9064b3a76a22640c, .lo = 0x56e0a8b0d177b55d, .ex = -3, .sgn=0}, + {.hi = 0x96a9049670cfae65, .lo = 0xf77574094d3c35c4, .ex = -3, .sgn=0}, + {.hi = 0x9cecf8962d14c822, .lo = 0x50ffe4f5caa7f1fa, .ex = -3, .sgn=0}, + {.hi = 0xa3308bc93904ad69, .lo = 0xdec1b7f2768bdafa, .ex = -3, .sgn=0}, + {.hi = 0xa973ba526a6850d9, .lo = 0x76f8c63986598c79, .ex = -3, .sgn=0}, + {.hi = 0xafb68054d520c60b, .lo = 0xfdd2fc0936594c2d, .ex = -3, .sgn=0}, + {.hi = 0xb5f8d9f3cd8945d6, .lo = 0x924bef13600f9852, .ex = -3, .sgn=0}, + {.hi = 0xbc3ac352ead90abe, .lo = 0xeb13e106732687f1, .ex = -3, .sgn=0}, + {.hi = 0xc27c389609850433, .lo = 0xb228a03916371f6f, .ex = -3, .sgn=0}, + {.hi = 0xc8bd35e14da15f0e, .lo = 0xc7396c894bbf7389, .ex = -3, .sgn=0}, + {.hi = 0xcefdb7592542e1e9, .lo = 0x6b47b8c44e5b037e, .ex = -3, .sgn=0}, + {.hi = 0xd53db9224ae01bca, .lo = 0x7337412cf70716cb, .ex = -3, .sgn=0}, + {.hi = 0xdb7d3761c7b263b6, .lo = 0xbb286d23e11c8337, .ex = -3, .sgn=0}, + {.hi = 0xe1bc2e3cf616a7ac, .lo = 0x31883b30137c6e62, .ex = -3, .sgn=0}, + {.hi = 0xe7fa99d983ee098f, .lo = 0xeeb8f9c33340a2f2, .ex = -3, .sgn=0}, + {.hi = 0xee38765d74fe4897, .lo = 0xed16b994af6c18ae, .ex = -3, .sgn=0}, + {.hi = 0xf475bfef2551f5b9, .lo = 0x14e1a5488eaeab96, .ex = -3, .sgn=0}, + {.hi = 0xfab272b54b9871a2, .lo = 0x704729ae56d78a37, .ex = -3, .sgn=0}, + {.hi = 0x8077456b7dc2d967, .lo = 0x3eac8308f1113e5e, .ex = -2, .sgn=0}, + {.hi = 0x8395023dd418e919, .lo = 0xdb1f70118c9c2198, .ex = -2, .sgn=0}, + {.hi = 0x86b26de5933c2e8e, .lo = 0xc5a9decdfaad4db5, .ex = -2, .sgn=0}, + {.hi = 0x89cf8676d7abb55b, .lo = 0x97965c9860c34e44, .ex = -2, .sgn=0}, + {.hi = 0x8cec4a05f12739e8, .lo = 0xdcdca90cc73b116a, .ex = -2, .sgn=0}, + {.hi = 0x9008b6a763de75b7, .lo = 0xa6e3df5975cca9da, .ex = -2, .sgn=0}, + {.hi = 0x9324ca6fe9a04b4e, .lo = 0x899c4de737feec22, .ex = -2, .sgn=0}, + {.hi = 0x964083747309d113, .lo = 0xa89a11e07c1fe, .ex = -2, .sgn=0}, + {.hi = 0x995bdfca28b53a54, .lo = 0x49c4863de522b217, .ex = -2, .sgn=0}, + {.hi = 0x9c76dd866c689dcc, .lo = 0xe7bc08111d0bfca4, .ex = -2, .sgn=0}, + {.hi = 0x9f917abeda4498df, .lo = 0xf3ff913a4aadb85e, .ex = -2, .sgn=0}, + {.hi = 0xa2abb58949f2ced7, .lo = 0xa5dbee6084ee1260, .ex = -2, .sgn=0}, + {.hi = 0xa5c58bfbcfd4436a, .lo = 0x69fcb11e19f58619, .ex = -2, .sgn=0}, + {.hi = 0xa8defc2cbe2f8fcc, .lo = 0xcd12a1f6ab6b095, .ex = -2, .sgn=0}, + {.hi = 0xabf80432a65ef190, .lo = 0x8c95c4c91179176b, .ex = -2, .sgn=0}, + {.hi = 0xaf10a22459fe32a6, .lo = 0x3feef3bb58b1f10d, .ex = -2, .sgn=0}, + {.hi = 0xb228d418ec1869ad, .lo = 0x16031a34d4fc855d, .ex = -2, .sgn=0}, + {.hi = 0xb5409827b25591f0, .lo = 0xcd73fb5d8d45d302, .ex = -2, .sgn=0}, + {.hi = 0xb857ec684627fa4c, .lo = 0x187e26d290714d70, .ex = -2, .sgn=0}, + {.hi = 0xbb6ecef285f98a3a, .lo = 0xbddd8a0365d6b1d3, .ex = -2, .sgn=0}, + {.hi = 0xbe853dde9658dc60, .lo = 0xdfe1b074e22fc666, .ex = -2, .sgn=0}, + {.hi = 0xc19b3744e3262dcd, .lo = 0xad5a41de48f6b26f, .ex = -2, .sgn=0}, + {.hi = 0xc4b0b93e20c0213f, .lo = 0xdab4e426409b23a0, .ex = -2, .sgn=0}, + {.hi = 0xc7c5c1e34d3055b2, .lo = 0x5cc8c00e4fccd850, .ex = -2, .sgn=0}, + {.hi = 0xcada4f4db157cf77, .lo = 0xfa6171200ab2efc3, .ex = -2, .sgn=0}, + {.hi = 0xcdee5f96e21b332c, .lo = 0x65a3132adfb7dfd5, .ex = -2, .sgn=0}, + {.hi = 0xd101f0d8c18ed1c1, .lo = 0xaadb580a1eba209f, .ex = -2, .sgn=0}, + {.hi = 0xd415012d802284f0, .lo = 0xdf4005ef6a64aa02, .ex = -2, .sgn=0}, + {.hi = 0xd7278eaf9dcd5b55, .lo = 0x1779df36d1cc8912, .ex = -2, .sgn=0}, + {.hi = 0xda399779eb391377, .lo = 0xcbabaeb97af8e8aa, .ex = -2, .sgn=0}, + {.hi = 0xdd4b19a78aed6515, .lo = 0xece7f445cecf1e28, .ex = -2, .sgn=0}, + {.hi = 0xe05c1353f27b17e5, .lo = 0xebc61ade6ca83cd, .ex = -2, .sgn=0}, + {.hi = 0xe36c829aeba6e720, .lo = 0x26a0eecdb4f16266, .ex = -2, .sgn=0}, + {.hi = 0xe67c659895943123, .lo = 0x82b0aecadf808123, .ex = -2, .sgn=0}, + {.hi = 0xe98bba6965ef725f, .lo = 0xb91caf23416e7e80, .ex = -2, .sgn=0}, + {.hi = 0xec9a7f2a2a188aeb, .lo = 0x7244ee20f591983b, .ex = -2, .sgn=0}, + {.hi = 0xefa8b1f8084ccdfc, .lo = 0x1050cdf22f34182f, .ex = -2, .sgn=0}, + {.hi = 0xf2b650f080d0da8d, .lo = 0x587f3fa044e2d27d, .ex = -2, .sgn=0}, + {.hi = 0xf5c35a316f1a3c80, .lo = 0x643720de93ba81bd, .ex = -2, .sgn=0}, + {.hi = 0xf8cfcbd90af8d57a, .lo = 0x4221dc4ba772598d, .ex = -2, .sgn=0}, + {.hi = 0xfbdba405e9c00cca, .lo = 0xd24d3023da491920, .ex = -2, .sgn=0}, + {.hi = 0xfee6e0d6ff6fc5a4, .lo = 0x8b74fe2508ab8fc2, .ex = -2, .sgn=0}, + {.hi = 0x80f8c035cfee8d76, .lo = 0xfd958d68e8b49e6b, .ex = -1, .sgn=0}, + {.hi = 0x827dc071bfed6ffa, .lo = 0xfb4c92369f0cf008, .ex = -1, .sgn=0}, + {.hi = 0x8402702f5b30f2a9, .lo = 0xcb07b25a7b0372a7, .ex = -1, .sgn=0}, + {.hi = 0x8586ce7ededc809d, .lo = 0x9d3dc689006896f4, .ex = -1, .sgn=0}, + {.hi = 0x870ada70ba4e6d49, .lo = 0x9d52755ece3f70, .ex = -1, .sgn=0}, + {.hi = 0x888e93158fb3bb04, .lo = 0x984156f553344306, .ex = -1, .sgn=0}, + {.hi = 0x8a11f77e349bc245, .lo = 0xa66d1d936c38c329, .ex = -1, .sgn=0}, + {.hi = 0x8b9506bbb28bb922, .lo = 0x575f33366be0afef, .ex = -1, .sgn=0}, + {.hi = 0x8d17bfdf47921ac8, .lo = 0xcb590d74f64e77c9, .ex = -1, .sgn=0}, + {.hi = 0x8e9a21fa66d9ee8d, .lo = 0xf2be3ecae62789d4, .ex = -1, .sgn=0}, + {.hi = 0x901c2c1eb93dee39, .lo = 0x632b9cff5cfee724, .ex = -1, .sgn=0}, + {.hi = 0x919ddd5e1ddb8b33, .lo = 0x609c464b3dd676ec, .ex = -1, .sgn=0}, + {.hi = 0x931f34caaaa5d23a, .lo = 0x6a1ff8bfe6396e28, .ex = -1, .sgn=0}, + {.hi = 0x94a03176acf82d45, .lo = 0xae4ba773da6bf754, .ex = -1, .sgn=0}, + {.hi = 0x9620d274aa290339, .lo = 0xe06a955a5b8e301d, .ex = -1, .sgn=0}, + {.hi = 0x97a116d7601c3515, .lo = 0xfc8b7184b21f2d50, .ex = -1, .sgn=0}, + {.hi = 0x9920fdb1c5d5783d, .lo = 0x9dd1eedf18a2e4df, .ex = -1, .sgn=0}, + {.hi = 0x9aa086170c0a8d86, .lo = 0x9ffa0d23f3c26c62, .ex = -1, .sgn=0}, + {.hi = 0x9c1faf1a9db554af, .lo = 0xdab6b478577e7be5, .ex = -1, .sgn=0}, + {.hi = 0x9d9e77d020a5bbe6, .lo = 0xdb895384528d0d60, .ex = -1, .sgn=0}, + {.hi = 0x9f1cdf4b76138b02, .lo = 0x98dbd3555ebcdefe, .ex = -1, .sgn=0}, + {.hi = 0xa09ae4a0bb300a19, .lo = 0x2f895f44a303cc0b, .ex = -1, .sgn=0}, + {.hi = 0xa21886e449b78316, .lo = 0xd29d23a624acd00c, .ex = -1, .sgn=0}, + {.hi = 0xa395c52ab8829dfc, .lo = 0x2be036401ba87cc2, .ex = -1, .sgn=0}, + {.hi = 0xa5129e88dc17976a, .lo = 0x82d9495ead5be348, .ex = -1, .sgn=0}, + {.hi = 0xa68f1213c73b5124, .lo = 0x17218792857f4c5a, .ex = -1, .sgn=0}, + {.hi = 0xa80b1ee0cb823c27, .lo = 0x3269f4702b88324a, .ex = -1, .sgn=0}, + {.hi = 0xa986c40579e11c0a, .lo = 0x8e3bdf8085321556, .ex = -1, .sgn=0}, + {.hi = 0xab020097a33da341, .lo = 0xc1654b64a0081b46, .ex = -1, .sgn=0}, + {.hi = 0xac7cd3ad58fee7f0, .lo = 0x811f953984eff83e, .ex = -1, .sgn=0}, + {.hi = 0xadf73c5ced9db0f3, .lo = 0x9a5318ac6fe94e4d, .ex = -1, .sgn=0}, + {.hi = 0xaf7139bcf5349ac6, .lo = 0x9fe5f4ea48965e2c, .ex = -1, .sgn=0}, + {.hi = 0xb0eacae4461013ed, .lo = 0x63c66682bae74898, .ex = -1, .sgn=0}, + {.hi = 0xb263eee9f93e3088, .lo = 0x695a5332090bb09b, .ex = -1, .sgn=0}, + {.hi = 0xb3dca4e56b1e54bb, .lo = 0x992d96e5021e3c37, .ex = -1, .sgn=0}, + {.hi = 0xb554ebee3bf0b58e, .lo = 0x971f4da709ad4378, .ex = -1, .sgn=0}, + {.hi = 0xb6ccc31c5065afee, .lo = 0x35ebacd79f209137, .ex = -1, .sgn=0}, + {.hi = 0xb8442987d22cf576, .lo = 0x9cc3ef36746de3b8, .ex = -1, .sgn=0}, + {.hi = 0xb9bb1e4930848ead, .lo = 0xcdb0531c4e58484b, .ex = -1, .sgn=0}, + {.hi = 0xbb31a07920c7b256, .lo = 0x55b92083658bb897, .ex = -1, .sgn=0}, + {.hi = 0xbca7af309efd7182, .lo = 0xa4b0d21fc5036a5, .ex = -1, .sgn=0}, + {.hi = 0xbe1d4988ee67380c, .lo = 0xd1f90f79f46c7e01, .ex = -1, .sgn=0}, + {.hi = 0xbf926e9b9a0f2127, .lo = 0x91a1b5eb79658c67, .ex = -1, .sgn=0}, + {.hi = 0xc1071d8275561f9b, .lo = 0x721853f8e528a934, .ex = -1, .sgn=0}, + {.hi = 0xc27b55579c81f96d, .lo = 0xcdc2bd470675104d, .ex = -1, .sgn=0}, + {.hi = 0xc3ef1535754b168d, .lo = 0x3122c2a59efddc37, .ex = -1, .sgn=0}, + {.hi = 0xc5625c36af6a222f, .lo = 0xf4ff2895ab6ebe89, .ex = -1, .sgn=0}, + {.hi = 0xc6d5297645257e8d, .lo = 0x14d24739de27e2e9, .ex = -1, .sgn=0}, + {.hi = 0xc8477c0f7bde8a98, .lo = 0x4ce0246ad4fa74, .ex = -1, .sgn=0}, + {.hi = 0xc9b9531de49eb968, .lo = 0x4319e5ad5b0dcb84, .ex = -1, .sgn=0}, + {.hi = 0xcb2aadbd5ca47af5, .lo = 0xfaa3dfe675a65ee2, .ex = -1, .sgn=0}, + {.hi = 0xcc9b8b0a0deff5d4, .lo = 0x2e663b3c7555a6c3, .ex = -1, .sgn=0}, + {.hi = 0xce0bea206fcf9192, .lo = 0x3c540a9eec47af38, .ex = -1, .sgn=0}, + {.hi = 0xcf7bca1d476c516d, .lo = 0xa81290bdbaad62e4, .ex = -1, .sgn=0}, + {.hi = 0xd0eb2a1da855fefd, .lo = 0xb9302788604e88f1, .ex = -1, .sgn=0}, + {.hi = 0xd25a093ef50f2482, .lo = 0x721fc87ba1d42456, .ex = -1, .sgn=0}, + {.hi = 0xd3c8669edf98d680, .lo = 0x87967926fdcecec4, .ex = -1, .sgn=0}, + {.hi = 0xd536415b69fe4c54, .lo = 0x1df22346611c6b4b, .ex = -1, .sgn=0}, + {.hi = 0xd6a39892e6e04764, .lo = 0x3090d44db12c418c, .ex = -1, .sgn=0}, + {.hi = 0xd8106b63fa0048a0, .lo = 0xa573f2aa90434ba5, .ex = -1, .sgn=0}, + {.hi = 0xd97cb8ed98cb93f5, .lo = 0x2e349483e3fb2a6a, .ex = -1, .sgn=0}, + {.hi = 0xdae8804f0ae6015b, .lo = 0x362cb974182e3030, .ex = -1, .sgn=0}, + {.hi = 0xdc53c0a7eab49b35, .lo = 0x3ccca3982328ed8b, .ex = -1, .sgn=0}, + {.hi = 0xddbe791825e8099e, .lo = 0x1a5bd9269d408d7e, .ex = -1, .sgn=0}, + {.hi = 0xdf28a8bffe06ca56, .lo = 0xcce2634be2bf54df, .ex = -1, .sgn=0}, + {.hi = 0xe0924ec008f734fd, .lo = 0x8aa895d5bf3e84ea, .ex = -1, .sgn=0}, + {.hi = 0xe1fb6a3931894b38, .lo = 0xf7a1f9bd9ba13b6b, .ex = -1, .sgn=0}, + {.hi = 0xe363fa4cb8005482, .lo = 0x7b32c72e31824e51, .ex = -1, .sgn=0}, + {.hi = 0xe4cbfe1c329c453a, .lo = 0xd40e9e6b989f89e5, .ex = -1, .sgn=0}, + {.hi = 0xe63374c98e22f0b4, .lo = 0x2872ce1bfc7ad1cd, .ex = -1, .sgn=0}, + {.hi = 0xe79a5d770e6905dc, .lo = 0xf1b65cc5fd780262, .ex = -1, .sgn=0}, + {.hi = 0xe900b7474edad637, .lo = 0x431626c10485bdda, .ex = -1, .sgn=0}, + {.hi = 0xea66815d4304e6c8, .lo = 0xcc39cfcc29960b1, .ex = -1, .sgn=0}, + {.hi = 0xebcbbadc371c4aaa, .lo = 0x1d90f780ae951140, .ex = -1, .sgn=0}, + {.hi = 0xed3062e7d086c6f0, .lo = 0xc71debc372b6f9d4, .ex = -1, .sgn=0}, + {.hi = 0xee9478a40e62bf86, .lo = 0x2a24164daec85ccb, .ex = -1, .sgn=0}, + {.hi = 0xeff7fb354a0eecb1, .lo = 0x527233b40d3432bb, .ex = -1, .sgn=0}, + {.hi = 0xf15ae9c037b1d8f0, .lo = 0x6c48e9e3420b0f1e, .ex = -1, .sgn=0}, + {.hi = 0xf2bd4369e6c126d3, .lo = 0x7f232aee178c6323, .ex = -1, .sgn=0}, + {.hi = 0xf41f0757c2889e84, .lo = 0x3c7f10db458c337c, .ex = -1, .sgn=0}, + {.hi = 0xf58034af92b102a7, .lo = 0x93fa6107c4327527, .ex = -1, .sgn=0}, + {.hi = 0xf6e0ca977bc6ac45, .lo = 0xe1079824233fef46, .ex = -1, .sgn=0}, + {.hi = 0xf840c835ffbfed66, .lo = 0xa9a56012067c570c, .ex = -1, .sgn=0}, + {.hi = 0xf9a02cb1fe833a0d, .lo = 0x8da894471de1a18, .ex = -1, .sgn=0}, + {.hi = 0xfafef732b66d1742, .lo = 0x343fbf4a7d42af3, .ex = -1, .sgn=0}, + {.hi = 0xfc5d26dfc4d5cfda, .lo = 0x27c07c911290b8d1, .ex = -1, .sgn=0}, + {.hi = 0xfdbabae12696eea4, .lo = 0x2377c3799c052fa, .ex = -1, .sgn=0}, + {.hi = 0xff17b25f38907dad, .lo = 0xa9c6ba50490539f, .ex = -1, .sgn=0}, + {.hi = 0x803a06415c170525, .lo = 0x6f53873e2f1477ff, .ex = 0, .sgn=0}, + {.hi = 0x80e7e43a61f5b6cb, .lo = 0x5ca183dc973abc22, .ex = 0, .sgn=0}, + {.hi = 0x819572af6decac84, .lo = 0x9fba97fdf0c4d24c, .ex = 0, .sgn=0}, + {.hi = 0x8242b1357110d372, .lo = 0x6fb2123fedfa6e22, .ex = 0, .sgn=0}, + {.hi = 0x82ef9f618dc5b70e, .lo = 0x91a965931f1a200a, .ex = 0, .sgn=0}, + {.hi = 0x839c3cc917ff6cb4, .lo = 0xbfd79717f2880abf, .ex = 0, .sgn=0}, + {.hi = 0x8448890195846099, .lo = 0x246efcff30cb064a, .ex = 0, .sgn=0}, + {.hi = 0x84f483a0be2f0403, .lo = 0x51917cac857fd5f5, .ex = 0, .sgn=0}, + {.hi = 0x85a02c3c7c2f5ca5, .lo = 0x327888fe4b62687b, .ex = 0, .sgn=0}, + {.hi = 0x864b826aec4c74e5, .lo = 0x85043222c9bdd18d, .ex = 0, .sgn=0}, + {.hi = 0x86f685c25e25acf5, .lo = 0x7e0b9b07548471a2, .ex = 0, .sgn=0}, + {.hi = 0x87a135d95473ec89, .lo = 0x4e091160e2430712, .ex = 0, .sgn=0}, + {.hi = 0x884b9246854ab50b, .lo = 0x4f14c8afe4560291, .ex = 0, .sgn=0}, + {.hi = 0x88f59aa0da591421, .lo = 0xb892ca8361d8c84c, .ex = 0, .sgn=0}, + {.hi = 0x899f4e7f712a765e, .lo = 0xc88302a31afce54a, .ex = 0, .sgn=0}, + {.hi = 0x8a48ad799b6759f3, .lo = 0x660558a02136130a, .ex = 0, .sgn=0}, + {.hi = 0x8af1b726df15e13c, .lo = 0x545f7d79ead8fa19, .ex = 0, .sgn=0}, + {.hi = 0x8b9a6b1ef6da4502, .lo = 0x21a6675f51580bc4, .ex = 0, .sgn=0}, + {.hi = 0x8c42c8f9d2372644, .lo = 0x101a5adbcb9ffb43, .ex = 0, .sgn=0}, + {.hi = 0x8cead04f95cdbf66, .lo = 0x4d49cbaf15aecd80, .ex = 0, .sgn=0}, + {.hi = 0x8d9280b89b9df49b, .lo = 0xde2d43c6b67a7cbe, .ex = 0, .sgn=0}, + {.hi = 0x8e39d9cd73464364, .lo = 0xbba4cfecbff54867, .ex = 0, .sgn=0}, + {.hi = 0x8ee0db26e24390f8, .lo = 0xaf0e2345f3bd24b4, .ex = 0, .sgn=0}, + {.hi = 0x8f87845de430d777, .lo = 0x9311a82459aa0f72, .ex = 0, .sgn=0}, + {.hi = 0x902dd50bab06b1b7, .lo = 0xb144016c7a30b39a, .ex = 0, .sgn=0}, + {.hi = 0x90d3ccc99f5ac58b, .lo = 0x9d1072e09b72292, .ex = 0, .sgn=0}, + {.hi = 0x91796b31609f0c54, .lo = 0x6714fe6925b78cc4, .ex = 0, .sgn=0}, + {.hi = 0x921eafdcc560f9c5, .lo = 0x33d0a284a8c954ad, .ex = 0, .sgn=0}, + {.hi = 0x92c39a65db88809d, .lo = 0x1f8481e704e4a767, .ex = 0, .sgn=0}, + {.hi = 0x93682a66e896f544, .lo = 0xb17821911e71c16e, .ex = 0, .sgn=0}, + {.hi = 0x940c5f7a69e5ce1c, .lo = 0x1489a97671a42, .ex = 0, .sgn=0}, + {.hi = 0x94b0393b14e54156, .lo = 0xd6c7af02d5c16fd9, .ex = 0, .sgn=0}, + {.hi = 0x9553b743d75ac03f, .lo = 0xac0106650f4ef023, .ex = 0, .sgn=0}, + {.hi = 0x95f6d92fd79f4fba, .lo = 0xd9f8e1a446e973b9, .ex = 0, .sgn=0}, + {.hi = 0x96999e9a74ddbde3, .lo = 0xa7a7556c3b33abc1, .ex = 0, .sgn=0}, + {.hi = 0x973c071f4750b49c, .lo = 0xc0a03934f0cce19b, .ex = 0, .sgn=0}, + {.hi = 0x97de125a2080a8ed, .lo = 0xd243aa0843a2c144, .ex = 0, .sgn=0}, + {.hi = 0x987fbfe70b81a708, .lo = 0x19cec845ac87a5c6, .ex = 0, .sgn=0}, + {.hi = 0x99210f624d30facb, .lo = 0xc4b992a37fb9b9bd, .ex = 0, .sgn=0}, + {.hi = 0x99c200686472b4a8, .lo = 0x1ab42d43235757b6, .ex = 0, .sgn=0}, + {.hi = 0x9a6292960a6f0ab0, .lo = 0x7e92c655656e6b85, .ex = 0, .sgn=0}, + {.hi = 0x9b02c58832cf95c0, .lo = 0x698b94f50326a043, .ex = 0, .sgn=0}, + {.hi = 0x9ba298dc0bfc6a88, .lo = 0x9a5614e8ffbeac6f, .ex = 0, .sgn=0}, + {.hi = 0x9c420c2eff590e5f, .lo = 0xc7fd954194e6d8aa, .ex = 0, .sgn=0}, + {.hi = 0x9ce11f1eb18147b1, .lo = 0x3e93627de8fd5779, .ex = 0, .sgn=0}, + {.hi = 0x9d7fd1490285c9e3, .lo = 0xe25e39549638ae68, .ex = 0, .sgn=0}, + {.hi = 0x9e1e224c0e28bc94, .lo = 0x2cad377d5c9c35d8, .ex = 0, .sgn=0}, + {.hi = 0x9ebc11c62c1a1dfb, .lo = 0xcc141e10c6460c8b, .ex = 0, .sgn=0}, + {.hi = 0x9f599f55f0340061, .lo = 0xa88d5f46834bbf8d, .ex = 0, .sgn=0}, + {.hi = 0x9ff6ca9a2ab6a26d, .lo = 0x22cc118a0c118aa0, .ex = 0, .sgn=0}, + {.hi = 0xa0939331e8846237, .lo = 0x7cec6df5bea167cf, .ex = 0, .sgn=0}, + {.hi = 0xa12ff8bc735d8af6, .lo = 0x71acea2819360c35, .ex = 0, .sgn=0}, + {.hi = 0xa1cbfad9521bfd1b, .lo = 0x166c36e7bb3c402f, .ex = 0, .sgn=0}, + {.hi = 0xa267992848eeb0c0, .lo = 0x3b5167ee359a234e, .ex = 0, .sgn=0}, + {.hi = 0xa302d34959951243, .lo = 0x9443372e20d4377c, .ex = 0, .sgn=0}, + {.hi = 0xa39da8dcc39a38e5, .lo = 0xca9a8a720d4c69c, .ex = 0, .sgn=0}, + {.hi = 0xa4381983048ff747, .lo = 0xbf623cf5301a2dde, .ex = 0, .sgn=0}, + {.hi = 0xa4d224dcd849c5b0, .lo = 0x23d251cc8d7975cc, .ex = 0, .sgn=0}, + {.hi = 0xa56bca8b391785db, .lo = 0x189d39ffe11aaa2b, .ex = 0, .sgn=0}, + {.hi = 0xa6050a2f60002049, .lo = 0x8c33ebf3aa8501fb, .ex = 0, .sgn=0}, + {.hi = 0xa69de36ac4fbfadc, .lo = 0x9b3ad6e4022183d9, .ex = 0, .sgn=0}, + {.hi = 0xa73655df1f2f489e, .lo = 0x149f6e75993468a3, .ex = 0, .sgn=0}, + {.hi = 0xa7ce612e65243291, .lo = 0x6b2a39f856a69781, .ex = 0, .sgn=0}, + {.hi = 0xa86604facd04d969, .lo = 0x3463a2c2e6e9cc55, .ex = 0, .sgn=0}, + {.hi = 0xa8fd40e6ccd52ffd, .lo = 0x6cc14c4f53e2e82d, .ex = 0, .sgn=0}, + {.hi = 0xa99414951aacae5e, .lo = 0xd147625fda929af8, .ex = 0, .sgn=0}, + {.hi = 0xaa2a7fa8acefdd63, .lo = 0xb714ee81b53b4b9d, .ex = 0, .sgn=0}, + {.hi = 0xaac081c4ba89ba8a, .lo = 0xe1b3dfc4dbda9bfd, .ex = 0, .sgn=0}, + {.hi = 0xab561a8cbb24f410, .lo = 0xf17cee69b0d2ecde, .ex = 0, .sgn=0}, + {.hi = 0xabeb49a46764fd15, .lo = 0x1becda8089c1a94c, .ex = 0, .sgn=0}, + {.hi = 0xac800eafb91ef9a9, .lo = 0xf86ba0dde982fb59, .ex = 0, .sgn=0}, + {.hi = 0xad146952eb9282af, .lo = 0x44bf16268608db96, .ex = 0, .sgn=0}, + {.hi = 0xada859327ba24151, .lo = 0x9d30d4cfeb04f1fb, .ex = 0, .sgn=0}, + {.hi = 0xae3bddf3280c620d, .lo = 0x3d53817865422565, .ex = 0, .sgn=0}, + {.hi = 0xaecef739f1a2df10, .lo = 0xf74d099042e8f326, .ex = 0, .sgn=0}, + {.hi = 0xaf61a4ac1b83a1de, .lo = 0xa89a9b8f726b95bf, .ex = 0, .sgn=0}, + {.hi = 0xaff3e5ef2b507c06, .lo = 0x8c679e67fc462d51, .ex = 0, .sgn=0}, + {.hi = 0xb085baa8e966f6da, .lo = 0xe4cad00d5c94bcd2, .ex = 0, .sgn=0}, + {.hi = 0xb117227f6117f9f9, .lo = 0x8d8be132d576e614, .ex = 0, .sgn=0}, + {.hi = 0xb1a81d18e0df4889, .lo = 0x24784f32c3e3e5bd, .ex = 0, .sgn=0}, + {.hi = 0xb238aa1bfa9ad507, .lo = 0x8cc7d4bd05ffd5ae, .ex = 0, .sgn=0}, + {.hi = 0xb2c8c92f83c1eb87, .lo = 0xac9f7ebbc469ef59, .ex = 0, .sgn=0}, + {.hi = 0xb35879fa959c323c, .lo = 0x5d6635109164f740, .ex = 0, .sgn=0}, + {.hi = 0xb3e7bc248d78802e, .lo = 0xa156468ef6c18c60, .ex = 0, .sgn=0}, + {.hi = 0xb4768f550ce389fd, .lo = 0x4a85350f69018c55, .ex = 0, .sgn=0}, +}; + +/* Table containing 128-bit approximations of cos2pi(i/2^11) for 0 <= i < 256 + (to nearest). + Each entry is to be interpreted as (hi/2^64+lo/2^128)*2^ex*(-1)*sgn. + Generated with computeC() from sin.sage. */ +static const dint64_t C[256] = { + {.hi = 0x8000000000000000, .lo = 0x0, .ex = 1, .sgn=0}, + {.hi = 0xffffb10b10e80e95, .lo = 0x3031437d7eccb9df, .ex = 0, .sgn=0}, + {.hi = 0xfffec42c7454926b, .lo = 0x38e310779edfec68, .ex = 0, .sgn=0}, + {.hi = 0xfffd3964bc6275ba, .lo = 0x69fff9ae0dedb047, .ex = 0, .sgn=0}, + {.hi = 0xfffb10b4dc96dabb, .lo = 0xb47903f7a19f8ee2, .ex = 0, .sgn=0}, + {.hi = 0xfff84a1e29de8571, .lo = 0x8cc193c5d508e13f, .ex = 0, .sgn=0}, + {.hi = 0xfff4e5a25a8d095b, .lo = 0x43366df666fd54ff, .ex = 0, .sgn=0}, + {.hi = 0xfff0e343865bbb13, .lo = 0x5428ed0647c9e5d1, .ex = 0, .sgn=0}, + {.hi = 0xffec4304266865d9, .lo = 0x5657552366961732, .ex = 0, .sgn=0}, + {.hi = 0xffe704e71533c508, .lo = 0x53aa9423bb0adc21, .ex = 0, .sgn=0}, + {.hi = 0xffe128ef8e9fc17a, .lo = 0x7d209f32d42d864e, .ex = 0, .sgn=0}, + {.hi = 0xffdaaf212fed72db, .lo = 0x4fd8f038449ec436, .ex = 0, .sgn=0}, + {.hi = 0xffd3977ff7bae4e9, .lo = 0x664649b4d541b9c5, .ex = 0, .sgn=0}, + {.hi = 0xffcbe2104600a0a9, .lo = 0x5595ca3f421ae09c, .ex = 0, .sgn=0}, + {.hi = 0xffc38ed6dc0ef98b, .lo = 0x1c676208aa3be545, .ex = 0, .sgn=0}, + {.hi = 0xffba9dd8dc8b1e83, .lo = 0xccfed60a91097c48, .ex = 0, .sgn=0}, + {.hi = 0xffb10f1bcb6bef1d, .lo = 0x421e8edaaf59453e, .ex = 0, .sgn=0}, + {.hi = 0xffa6e2a58df6947d, .lo = 0xd2c665c2da3e7844, .ex = 0, .sgn=0}, + {.hi = 0xff9c187c6abade6a, .lo = 0x1e1862cca089938b, .ex = 0, .sgn=0}, + {.hi = 0xff90b0a7098f6443, .lo = 0x2dabd3195a05710f, .ex = 0, .sgn=0}, + {.hi = 0xff84ab2c738d6a03, .lo = 0x519c314973ccae6b, .ex = 0, .sgn=0}, + {.hi = 0xff780814130c893c, .lo = 0x3ea4f30adda3016f, .ex = 0, .sgn=0}, + {.hi = 0xff6ac765b39e1e19, .lo = 0x1b9d5851979f28fb, .ex = 0, .sgn=0}, + {.hi = 0xff5ce92982087867, .lo = 0x50a7bb6a6ee3b0f1, .ex = 0, .sgn=0}, + {.hi = 0xff4e6d680c41d0a9, .lo = 0xf668633f1ab858a, .ex = 0, .sgn=0}, + {.hi = 0xff3f542a416b0134, .lo = 0xb085c1828f69296a, .ex = 0, .sgn=0}, + {.hi = 0xff2f9d7971ca0364, .lo = 0x27e31939e2eec09c, .ex = 0, .sgn=0}, + {.hi = 0xff1f495f4ec430d7, .lo = 0xf5971326a3540ea9, .ex = 0, .sgn=0}, + {.hi = 0xff0e57e5ead848d1, .lo = 0x1f1901544271c3f8, .ex = 0, .sgn=0}, + {.hi = 0xfefcc917b99839a5, .lo = 0xe0abd3a9b64df725, .ex = 0, .sgn=0}, + {.hi = 0xfeea9cff8fa2ae54, .lo = 0xec34413e87ef2740, .ex = 0, .sgn=0}, + {.hi = 0xfed7d3a8a29c603b, .lo = 0x2f88b949a72ff96c, .ex = 0, .sgn=0}, + {.hi = 0xfec46d1e89292cf0, .lo = 0x41390efdc726e9ef, .ex = 0, .sgn=0}, + {.hi = 0xfeb0696d3ae4f04d, .lo = 0xb7b6cc53c3abc817, .ex = 0, .sgn=0}, + {.hi = 0xfe9bc8a1105c22a5, .lo = 0xd3af6ee4f2101c20, .ex = 0, .sgn=0}, + {.hi = 0xfe868ac6c3043b2e, .lo = 0xb4f70c910505e10, .ex = 0, .sgn=0}, + {.hi = 0xfe70afeb6d33d6a2, .lo = 0x2907cf2b3f6feac2, .ex = 0, .sgn=0}, + {.hi = 0xfe5a381c8a1aa224, .lo = 0xd54faa364b7da8f6, .ex = 0, .sgn=0}, + {.hi = 0xfe432367f5b90a62, .lo = 0x87b8875373a818a4, .ex = 0, .sgn=0}, + {.hi = 0xfe2b71dbecd7aefc, .lo = 0x8598c2c429caf7, .ex = 0, .sgn=0}, + {.hi = 0xfe1323870cfe9a3d, .lo = 0x90cd1d959db674ef, .ex = 0, .sgn=0}, + {.hi = 0xfdfa3878546c3d28, .lo = 0x9bfe5c51e91cbdcd, .ex = 0, .sgn=0}, + {.hi = 0xfde0b0bf220c2fd4, .lo = 0xe276d247626a23fd, .ex = 0, .sgn=0}, + {.hi = 0xfdc68c6b356db62f, .lo = 0x499ddb331d19539d, .ex = 0, .sgn=0}, + {.hi = 0xfdabcb8caeba091b, .lo = 0xfac7397cc07a6470, .ex = 0, .sgn=0}, + {.hi = 0xfd906e340eaa6401, .lo = 0xd6e270740a186977, .ex = 0, .sgn=0}, + {.hi = 0xfd747472367dd6c5, .lo = 0x61beb8cd2696fc78, .ex = 0, .sgn=0}, + {.hi = 0xfd57de5867eedc39, .lo = 0x6c696582f346fd91, .ex = 0, .sgn=0}, + {.hi = 0xfd3aabf84528b50b, .lo = 0xeae6bd951c1dabbe, .ex = 0, .sgn=0}, + {.hi = 0xfd1cdd63d0bc8735, .lo = 0x863b87258f11ad7e, .ex = 0, .sgn=0}, + {.hi = 0xfcfe72ad6d9641f2, .lo = 0xa06fab9f9d106709, .ex = 0, .sgn=0}, + {.hi = 0xfcdf6be7def1464c, .lo = 0xa4e064308f4999f4, .ex = 0, .sgn=0}, + {.hi = 0xfcbfc926484cd43a, .lo = 0xa3e22b4d38917e73, .ex = 0, .sgn=0}, + {.hi = 0xfc9f8a7c2d603c60, .lo = 0x5d582cac7cb4391c, .ex = 0, .sgn=0}, + {.hi = 0xfc7eaffd720ed673, .lo = 0x2880268f2e62955, .ex = 0, .sgn=0}, + {.hi = 0xfc5d39be5a5bbc4b, .lo = 0x1c0d254b6c8da4bd, .ex = 0, .sgn=0}, + {.hi = 0xfc3b27d38a5d49ab, .lo = 0x256778ffcb5c1769, .ex = 0, .sgn=0}, + {.hi = 0xfc187a52063060c2, .lo = 0x9433b49289417ea2, .ex = 0, .sgn=0}, + {.hi = 0xfbf5314f31eb7375, .lo = 0x25aafd7fdba12c5f, .ex = 0, .sgn=0}, + {.hi = 0xfbd14ce0d191516e, .lo = 0x7190c94899dff1b8, .ex = 0, .sgn=0}, + {.hi = 0xfbaccd1d0903bb09, .lo = 0xe63ae8632b84473c, .ex = 0, .sgn=0}, + {.hi = 0xfb87b21a5bf5b917, .lo = 0x75df66f0ec3dd459, .ex = 0, .sgn=0}, + {.hi = 0xfb61fbefadddb985, .lo = 0x61ce9d5ef5a81487, .ex = 0, .sgn=0}, + {.hi = 0xfb3baab441e770f7, .lo = 0xb4b54683879c9c17, .ex = 0, .sgn=0}, + {.hi = 0xfb14be7fbae58156, .lo = 0x2172a361fd2a722f, .ex = 0, .sgn=0}, + {.hi = 0xfaed376a1b42e559, .lo = 0x2079880c450348ac, .ex = 0, .sgn=0}, + {.hi = 0xfac5158bc4f4211f, .lo = 0x4a188aa367f90ab1, .ex = 0, .sgn=0}, + {.hi = 0xfa9c58fd796837d4, .lo = 0x10655ecd5cc771d8, .ex = 0, .sgn=0}, + {.hi = 0xfa7301d859796671, .lo = 0x1fe196a53fb5b237, .ex = 0, .sgn=0}, + {.hi = 0xfa491035e55da3a3, .lo = 0xd24377c77a591e24, .ex = 0, .sgn=0}, + {.hi = 0xfa1e842ffc96e4e0, .lo = 0x431c393c7f62da65, .ex = 0, .sgn=0}, + {.hi = 0xf9f35de0dde328ab, .lo = 0xba5dbf4510eddc8f, .ex = 0, .sgn=0}, + {.hi = 0xf9c79d63272c4628, .lo = 0x4504ae08d19b2980, .ex = 0, .sgn=0}, + {.hi = 0xf99b42d1d57781eb, .lo = 0x78685d850f80ecdc, .ex = 0, .sgn=0}, + {.hi = 0xf96e4e4844d4e82a, .lo = 0x80e8c17bf80e8f02, .ex = 0, .sgn=0}, + {.hi = 0xf940bfe2304e6c45, .lo = 0xc0e2a1352ed7f292, .ex = 0, .sgn=0}, + {.hi = 0xf91297bbb1d6cdbe, .lo = 0x68fc6e4d6a920bd2, .ex = 0, .sgn=0}, + {.hi = 0xf8e3d5f1423842a0, .lo = 0x9701914c7f8fbcd7, .ex = 0, .sgn=0}, + {.hi = 0xf8b47a9fb902e76c, .lo = 0xac9f07f54ff5bc14, .ex = 0, .sgn=0}, + {.hi = 0xf88485e44c7af48a, .lo = 0xb36a9dfaadafc1e1, .ex = 0, .sgn=0}, + {.hi = 0xf853f7dc9186b952, .lo = 0xc7adc6b4988891bb, .ex = 0, .sgn=0}, + {.hi = 0xf822d0a67b9c5cb5, .lo = 0xa776175bd284fe05, .ex = 0, .sgn=0}, + {.hi = 0xf7f110605caf6390, .lo = 0xa76f7efc19aed41c, .ex = 0, .sgn=0}, + {.hi = 0xf7beb728e51dfcb8, .lo = 0x730785813f78aa1e, .ex = 0, .sgn=0}, + {.hi = 0xf78bc51f239e12c6, .lo = 0x214cffcee9dd33ca, .ex = 0, .sgn=0}, + {.hi = 0xf7583a62852a23b2, .lo = 0x4becad887680c197, .ex = 0, .sgn=0}, + {.hi = 0xf7241712d4edde49, .lo = 0xf99107e50d631330, .ex = 0, .sgn=0}, + {.hi = 0xf6ef5b503c328589, .lo = 0x50ca117eb18beed7, .ex = 0, .sgn=0}, + {.hi = 0xf6ba073b424b19e8, .lo = 0x2c791f59cc1ffc23, .ex = 0, .sgn=0}, + {.hi = 0xf6841af4cc8048a4, .lo = 0xce8c455197cdf8a7, .ex = 0, .sgn=0}, + {.hi = 0xf64d969e1dfc2119, .lo = 0x119d358de0493956, .ex = 0, .sgn=0}, + {.hi = 0xf6167a58d7b59026, .lo = 0x9dc7e5954c5a8f24, .ex = 0, .sgn=0}, + {.hi = 0xf5dec646f85ba1c6, .lo = 0xc8c615e72768d6b5, .ex = 0, .sgn=0}, + {.hi = 0xf5a67a8adc4088ca, .lo = 0xed0dd4bf62edd13f, .ex = 0, .sgn=0}, + {.hi = 0xf56d97473d446cda, .lo = 0x275a2bbb2bab6c8a, .ex = 0, .sgn=0}, + {.hi = 0xf5341c9f32bffeb9, .lo = 0x8da64484aaa0febc, .ex = 0, .sgn=0}, + {.hi = 0xf4fa0ab6316ed2ec, .lo = 0x163c5c7f03b718c5, .ex = 0, .sgn=0}, + {.hi = 0xf4bf61b00b5982b7, .lo = 0x890ac4aafa6a37bf, .ex = 0, .sgn=0}, + {.hi = 0xf48421b0efbf939b, .lo = 0xf8f9d3b87d11fd52, .ex = 0, .sgn=0}, + {.hi = 0xf4484add6b01254b, .lo = 0x667e06866c07c369, .ex = 0, .sgn=0}, + {.hi = 0xf40bdd5a6688662f, .lo = 0x5019794a1f5896e5, .ex = 0, .sgn=0}, + {.hi = 0xf3ced94d28b2ce8a, .lo = 0x18ef535a7ffa7a3d, .ex = 0, .sgn=0}, + {.hi = 0xf3913edb54ba2242, .lo = 0x50f29b4b49f31c37, .ex = 0, .sgn=0}, + {.hi = 0xf3530e2aea9d3966, .lo = 0xd981acdcf6bc3e4, .ex = 0, .sgn=0}, + {.hi = 0xf314476247088f74, .lo = 0xa5486bdc455d56a2, .ex = 0, .sgn=0}, + {.hi = 0xf2d4eaa8233e997d, .lo = 0x431be53f92ece9e6, .ex = 0, .sgn=0}, + {.hi = 0xf294f82394ffe320, .lo = 0xebadcdbf915e8f6c, .ex = 0, .sgn=0}, + {.hi = 0xf2546ffc0e72f286, .lo = 0xaf0eed81e8c51e55, .ex = 0, .sgn=0}, + {.hi = 0xf21352595e0bf350, .lo = 0xe7112e89103cc0c7, .ex = 0, .sgn=0}, + {.hi = 0xf1d19f63ae7428a2, .lo = 0x844e6a35ddc2b713, .ex = 0, .sgn=0}, + {.hi = 0xf18f574386712643, .lo = 0x8f6bac72988088b0, .ex = 0, .sgn=0}, + {.hi = 0xf14c7a21c8cbd0f4, .lo = 0x2730081c758fb42b, .ex = 0, .sgn=0}, + {.hi = 0xf1090827b43725fd, .lo = 0x67127db35b287316, .ex = 0, .sgn=0}, + {.hi = 0xf0c5017ee336ca0f, .lo = 0xc4e557b119ef3185, .ex = 0, .sgn=0}, + {.hi = 0xf08066514c055f7e, .lo = 0x973ea9903ed5125f, .ex = 0, .sgn=0}, + {.hi = 0xf03b36c9407aa3e8, .lo = 0x992d39ec5c561d28, .ex = 0, .sgn=0}, + {.hi = 0xeff573116df1555d, .lo = 0x62aef7b55319d1d4, .ex = 0, .sgn=0}, + {.hi = 0xefaf1b54dd2cdf0f, .lo = 0xf03a18a5e16ab641, .ex = 0, .sgn=0}, + {.hi = 0xef682fbef23ecda6, .lo = 0x767c0e8ad33bc085, .ex = 0, .sgn=0}, + {.hi = 0xef20b07b6c6c0b37, .lo = 0xe2398bf0eeb28cde, .ex = 0, .sgn=0}, + {.hi = 0xeed89db66611e307, .lo = 0x86f8c20fb664b01b, .ex = 0, .sgn=0}, + {.hi = 0xee8ff79c548acd0f, .lo = 0xa1d2c3d018a9279f, .ex = 0, .sgn=0}, + {.hi = 0xee46be5a0813016b, .lo = 0x7872773830d368be, .ex = 0, .sgn=0}, + {.hi = 0xedfcf21cabacd3b1, .lo = 0xfee6a1eebfa13b4a, .ex = 0, .sgn=0}, + {.hi = 0xedb29311c504d652, .lo = 0x11815196b9fbf5df, .ex = 0, .sgn=0}, + {.hi = 0xed67a1673455c601, .lo = 0x7289102076a125e5, .ex = 0, .sgn=0}, + {.hi = 0xed1c1d4b344c3d4f, .lo = 0xddffe98c4f8aa031, .ex = 0, .sgn=0}, + {.hi = 0xecd006ec59ea306f, .lo = 0xa8392eb238578ab0, .ex = 0, .sgn=0}, + {.hi = 0xec835e79946a3145, .lo = 0x7e610231ac1d6181, .ex = 0, .sgn=0}, + {.hi = 0xec3624222d227bd1, .lo = 0x278047ae3dd0889, .ex = 0, .sgn=0}, + {.hi = 0xebe85815c767cb00, .lo = 0x1e99ccb9adc62ca6, .ex = 0, .sgn=0}, + {.hi = 0xeb99fa84606ff5ff, .lo = 0xdae311e656e0661, .ex = 0, .sgn=0}, + {.hi = 0xeb4b0b9e4f345617, .lo = 0x39e39c6c2ab3655d, .ex = 0, .sgn=0}, + {.hi = 0xeafb8b944453f52f, .lo = 0x3383bbb5156bf1d7, .ex = 0, .sgn=0}, + {.hi = 0xeaab7a9749f584fe, .lo = 0x24db98ad3a0647a1, .ex = 0, .sgn=0}, + {.hi = 0xea5ad8d8c3a91f05, .lo = 0x4a0ca5ea449b1c83, .ex = 0, .sgn=0}, + {.hi = 0xea09a68a6e49cd62, .lo = 0x15ad45b4a1b5e823, .ex = 0, .sgn=0}, + {.hi = 0xe9b7e3de5fdedc8b, .lo = 0xcd24d4bd1056c826, .ex = 0, .sgn=0}, + {.hi = 0xe9659107077cf60f, .lo = 0x89a92b199adfbafa, .ex = 0, .sgn=0}, + {.hi = 0xe912ae372d27045d, .lo = 0xacb1c26a06e5ae02, .ex = 0, .sgn=0}, + {.hi = 0xe8bf3ba1f1aedfbb, .lo = 0xf8972affb3d98e1f, .ex = 0, .sgn=0}, + {.hi = 0xe86b397ace95c46f, .lo = 0x9fec1e78c4376186, .ex = 0, .sgn=0}, + {.hi = 0xe816a7f595ec9232, .lo = 0xbfe8378abfb87b6f, .ex = 0, .sgn=0}, + {.hi = 0xe7c187467233d508, .lo = 0xdbfb0fe56c6f80fe, .ex = 0, .sgn=0}, + {.hi = 0xe76bd7a1e63b9786, .lo = 0x125129529d48a92f, .ex = 0, .sgn=0}, + {.hi = 0xe715993ccd02fe9c, .lo = 0xe2ba81b9ce96e02e, .ex = 0, .sgn=0}, + {.hi = 0xe6becc4c5997af06, .lo = 0x82fcedb4c6434d76, .ex = 0, .sgn=0}, + {.hi = 0xe667710616f4fc59, .lo = 0xdd2a3e32c3859960, .ex = 0, .sgn=0}, + {.hi = 0xe60f879fe7e2e1e5, .lo = 0x7613b68f6ab03130, .ex = 0, .sgn=0}, + {.hi = 0xe5b7105006d4c560, .lo = 0x9b695cd67c93bd79, .ex = 0, .sgn=0}, + {.hi = 0xe55e0b4d05c80388, .lo = 0x5a7c210a3a15e7ea, .ex = 0, .sgn=0}, + {.hi = 0xe50478cdce2246bc, .lo = 0xe1f5a58c80292554, .ex = 0, .sgn=0}, + {.hi = 0xe4aa5909a08fa7b4, .lo = 0x122785ae67f5515d, .ex = 0, .sgn=0}, + {.hi = 0xe44fac3814e09856, .lo = 0x20d63b5b9e3cd6ac, .ex = 0, .sgn=0}, + {.hi = 0xe3f4729119e798d9, .lo = 0x56992551ae074e99, .ex = 0, .sgn=0}, + {.hi = 0xe398ac4cf556b732, .lo = 0xd1197dc12c63176, .ex = 0, .sgn=0}, + {.hi = 0xe33c59a4439cd8ec, .lo = 0x36563e2ffad8351a, .ex = 0, .sgn=0}, + {.hi = 0xe2df7acff7c2cf83, .lo = 0xd6fe4dd22e60a4a2, .ex = 0, .sgn=0}, + {.hi = 0xe28210095b483751, .lo = 0xfd39138aa2d508ed, .ex = 0, .sgn=0}, + {.hi = 0xe224198a0e002123, .lo = 0xe0521df01a1be6f5, .ex = 0, .sgn=0}, + {.hi = 0xe1c5978c05ed8691, .lo = 0xf4e8a8372f8c5810, .ex = 0, .sgn=0}, + {.hi = 0xe1668a498f1f892c, .lo = 0xe2f9d4600f4d0325, .ex = 0, .sgn=0}, + {.hi = 0xe106f1fd4b8d7c96, .lo = 0x6ba8a9d9ba877899, .ex = 0, .sgn=0}, + {.hi = 0xe0a6cee232f2bb9c, .lo = 0x6d6c98fe79817946, .ex = 0, .sgn=0}, + {.hi = 0xe046213392aa486c, .lo = 0x55ff6038a5197367, .ex = 0, .sgn=0}, + {.hi = 0xdfe4e92d0d8a37f5, .lo = 0x720588ff6547d884, .ex = 0, .sgn=0}, + {.hi = 0xdf83270a9bbee890, .lo = 0xab01350f013d78dd, .ex = 0, .sgn=0}, + {.hi = 0xdf20db088aa60404, .lo = 0x64a58b2f103485dd, .ex = 0, .sgn=0}, + {.hi = 0xdebe05637ca94cfb, .lo = 0x4b19aa71fec3ae6d, .ex = 0, .sgn=0}, + {.hi = 0xde5aa65869193805, .lo = 0x4248f15548f69ca, .ex = 0, .sgn=0}, + {.hi = 0xddf6be249c075037, .lo = 0xd597b10a01676659, .ex = 0, .sgn=0}, + {.hi = 0xdd924d05b620678a, .lo = 0x739c45b982193b5e, .ex = 0, .sgn=0}, + {.hi = 0xdd2d5339ac8692fd, .lo = 0x49c6e0ea76cbcaac, .ex = 0, .sgn=0}, + {.hi = 0xdcc7d0fec8aaf2aa, .lo = 0xb2069fd0b482b4e8, .ex = 0, .sgn=0}, + {.hi = 0xdc61c693a82745d5, .lo = 0xaca8017e375b64e5, .ex = 0, .sgn=0}, + {.hi = 0xdbfb34373c974b0e, .lo = 0xccb7fd40d543f4a1, .ex = 0, .sgn=0}, + {.hi = 0xdb941a28cb71ec87, .lo = 0x2c19b63253da43fc, .ex = 0, .sgn=0}, + {.hi = 0xdb2c78a7ede238a9, .lo = 0x5a98479cbef2ecbc, .ex = 0, .sgn=0}, + {.hi = 0xdac44ff490a02710, .lo = 0x5b267c1bcff0ab62, .ex = 0, .sgn=0}, + {.hi = 0xda5ba04ef3c929f4, .lo = 0xe257bde73d83dc1a, .ex = 0, .sgn=0}, + {.hi = 0xd9f269f7aab88c29, .lo = 0x28e81dcb6dab91ac, .ex = 0, .sgn=0}, + {.hi = 0xd988ad2f9bdf9bbb, .lo = 0xc4e4dc69fc2fff6f, .ex = 0, .sgn=0}, + {.hi = 0xd91e6a38009da15a, .lo = 0x1bb35ad6d2e74b67, .ex = 0, .sgn=0}, + {.hi = 0xd8b3a1526517a48b, .lo = 0x1ed1a8ff78f1b632, .ex = 0, .sgn=0}, + {.hi = 0xd84852c0a80ffcdb, .lo = 0x24b9fe00663574a4, .ex = 0, .sgn=0}, + {.hi = 0xd7dc7ec4fabdb011, .lo = 0xced12d2899b803db, .ex = 0, .sgn=0}, + {.hi = 0xd77025a1e0a39d8b, .lo = 0xcb78e80e67ba1b8, .ex = 0, .sgn=0}, + {.hi = 0xd703479a2f6776cc, .lo = 0x6cb3bfd65b38562b, .ex = 0, .sgn=0}, + {.hi = 0xd695e4f10ea88570, .lo = 0x83f082b570611d7, .ex = 0, .sgn=0}, + {.hi = 0xd627fde9f7d63e7e, .lo = 0x7afbefc05e9f7d99, .ex = 0, .sgn=0}, + {.hi = 0xd5b992c8b606a351, .lo = 0x7190b755535d4f18, .ex = 0, .sgn=0}, + {.hi = 0xd54aa3d165cc7018, .lo = 0x7d00ae97abaa4096, .ex = 0, .sgn=0}, + {.hi = 0xd4db3148750d1819, .lo = 0xf630e8b6dac83e69, .ex = 0, .sgn=0}, + {.hi = 0xd46b3b72a2d68fc9, .lo = 0xdc4663a3168698d2, .ex = 0, .sgn=0}, + {.hi = 0xd3fac294ff34e4d0, .lo = 0xb77d4f6bd0ee8591, .ex = 0, .sgn=0}, + {.hi = 0xd389c6f4eb07a41c, .lo = 0xa8faac741a6394dc, .ex = 0, .sgn=0}, + {.hi = 0xd31848d817d70e16, .lo = 0xeeeaddb72f00e0dd, .ex = 0, .sgn=0}, + {.hi = 0xd2a6488487a91918, .lo = 0x4300fd1c1ce507e5, .ex = 0, .sgn=0}, + {.hi = 0xd233c6408cd64236, .lo = 0x981ba7e42537275f, .ex = 0, .sgn=0}, + {.hi = 0xd1c0c252c9de2c86, .lo = 0xda7485a5aeffeb4c, .ex = 0, .sgn=0}, + {.hi = 0xd14d3d02313c0eed, .lo = 0x744fea20e8abef92, .ex = 0, .sgn=0}, + {.hi = 0xd0d93696053af098, .lo = 0x77a18eb13d2ecde5, .ex = 0, .sgn=0}, + {.hi = 0xd064af55d7c9b43e, .lo = 0x6b8a685f6cb61c21, .ex = 0, .sgn=0}, + {.hi = 0xcfefa7898a4ef23c, .lo = 0xdaf200dd81212d10, .ex = 0, .sgn=0}, + {.hi = 0xcf7a1f794d7ca1b1, .lo = 0xdfcb60445c1bf973, .ex = 0, .sgn=0}, + {.hi = 0xcf04176da12390ac, .lo = 0x4d27090f10c454e, .ex = 0, .sgn=0}, + {.hi = 0xce8d8faf5406ab8b, .lo = 0xf5babff66def7892, .ex = 0, .sgn=0}, + {.hi = 0xce16888783ae13b3, .lo = 0x93e391861a034684, .ex = 0, .sgn=0}, + {.hi = 0xcd9f023f9c3a059e, .lo = 0x23af31db7179a4aa, .ex = 0, .sgn=0}, + {.hi = 0xcd26fd2158358e7d, .lo = 0x649474e36b8db9d3, .ex = 0, .sgn=0}, + {.hi = 0xccae7976c0691177, .lo = 0x83e907fbd7aaf0b0, .ex = 0, .sgn=0}, + {.hi = 0xcc35778a2bac9ca1, .lo = 0xf839ce18e08bfb50, .ex = 0, .sgn=0}, + {.hi = 0xcbbbf7a63eba0dd5, .lo = 0x70cbb7f3343451be, .ex = 0, .sgn=0}, + {.hi = 0xcb41fa15ebff0777, .lo = 0x2293661be51140ab, .ex = 0, .sgn=0}, + {.hi = 0xcac77f24736eb553, .lo = 0xd9944be1631846d8, .ex = 0, .sgn=0}, + {.hi = 0xca4c871d625361a9, .lo = 0x5328edeb3e6784de, .ex = 0, .sgn=0}, + {.hi = 0xc9d1124c931fda7a, .lo = 0x8335241be1693225, .ex = 0, .sgn=0}, + {.hi = 0xc95520fe2d40a74b, .lo = 0x83b0e96e1249c2b0, .ex = 0, .sgn=0}, + {.hi = 0xc8d8b37ea4ed0f62, .lo = 0xb562c00b34ee771, .ex = 0, .sgn=0}, + {.hi = 0xc85bca1abaf7f0a7, .lo = 0x65862939b83382e0, .ex = 0, .sgn=0}, + {.hi = 0xc7de651f7ca06749, .lo = 0x2b31bc86877fd2c, .ex = 0, .sgn=0}, + {.hi = 0xc76084da43624634, .lo = 0xd5c149509e9059f1, .ex = 0, .sgn=0}, + {.hi = 0xc6e22998b4c6608e, .lo = 0xcfe6c1b1a6b4e2a4, .ex = 0, .sgn=0}, + {.hi = 0xc66353a8c232a43c, .lo = 0xe993503baf5afb41, .ex = 0, .sgn=0}, + {.hi = 0xc5e40358a8ba05a7, .lo = 0x43da25d99267326b, .ex = 0, .sgn=0}, + {.hi = 0xc56438f6f0ec3cca, .lo = 0xab4906075507e74, .ex = 0, .sgn=0}, + {.hi = 0xc4e3f4d26ea553b6, .lo = 0xdd40950cf1ed92fa, .ex = 0, .sgn=0}, + {.hi = 0xc463373a40dd06a3, .lo = 0x9dd768f30ca8e85c, .ex = 0, .sgn=0}, + {.hi = 0xc3e2007dd175f5a4, .lo = 0xa87e78136665cdb2, .ex = 0, .sgn=0}, + {.hi = 0xc36050ecd50ca830, .lo = 0x8ac9e1386e4cbabb, .ex = 0, .sgn=0}, + {.hi = 0xc2de28d74ac6628b, .lo = 0x74c8f010d986a9e0, .ex = 0, .sgn=0}, + {.hi = 0xc25b888d7c1fcd38, .lo = 0xb7041e9bc8c18b0d, .ex = 0, .sgn=0}, + {.hi = 0xc1d8705ffcbb6e90, .lo = 0xbdf0715cb8b20bd7, .ex = 0, .sgn=0}, + {.hi = 0xc154e09faa2ff69a, .lo = 0x17858573216e0a22, .ex = 0, .sgn=0}, + {.hi = 0xc0d0d99dabd65d44, .lo = 0x2bda5328933c854a, .ex = 0, .sgn=0}, + {.hi = 0xc04c5bab7297d322, .lo = 0x6dd06968e0ed1957, .ex = 0, .sgn=0}, + {.hi = 0xbfc7671ab8bb84c6, .lo = 0xe4e62d86dd136e78, .ex = 0, .sgn=0}, + {.hi = 0xbf41fc3d81b430db, .lo = 0xd46655d6b012455, .ex = 0, .sgn=0}, + {.hi = 0xbebc1b6619ed9116, .lo = 0x2715ef03f8543355, .ex = 0, .sgn=0}, + {.hi = 0xbe35c4e716999630, .lo = 0x29d7f7b67d43b177, .ex = 0, .sgn=0}, + {.hi = 0xbdaef913557d76f0, .lo = 0xac85320f528d6d5d, .ex = 0, .sgn=0}, + {.hi = 0xbd27b83dfcbe9279, .lo = 0x2ea36923d5d8e213, .ex = 0, .sgn=0}, + {.hi = 0xbca002ba7aaf25ea, .lo = 0x4a48496734be336d, .ex = 0, .sgn=0}, + {.hi = 0xbc17d8dc859ad583, .lo = 0x727c405ffc73af56, .ex = 0, .sgn=0}, + {.hi = 0xbb8f3af81b93095c, .lo = 0xfce8d84068e825b6, .ex = 0, .sgn=0}, + {.hi = 0xbb062961823b1ddc, .lo = 0x5120e35e1c1a250c, .ex = 0, .sgn=0}, + {.hi = 0xba7ca46d46946802, .lo = 0x33201477347447d8, .ex = 0, .sgn=0}, + {.hi = 0xb9f2ac703cca0db3, .lo = 0x39db32d014440024, .ex = 0, .sgn=0}, + {.hi = 0xb96841bf7ffcb21a, .lo = 0x9de1e3b22b8bf4db, .ex = 0, .sgn=0}, + {.hi = 0xb8dd64b0720df647, .lo = 0xa726f4f0828585c9, .ex = 0, .sgn=0}, + {.hi = 0xb8521598bb6bce26, .lo = 0x1c041d1ea5fb3fdb, .ex = 0, .sgn=0}, + {.hi = 0xb7c654ce4adba9f2, .lo = 0x2e7a35723f3ed035, .ex = 0, .sgn=0}, + {.hi = 0xb73a22a755457448, .lo = 0x7f86f63bb23f496a, .ex = 0, .sgn=0}, + {.hi = 0xb6ad7f7a557e64f2, .lo = 0xeb2d28ef943dc88c, .ex = 0, .sgn=0}, + {.hi = 0xb6206b9e0c13a892, .lo = 0xea7c015f12b987f7, .ex = 0, .sgn=0}, + {.hi = 0xb592e7697f14dd4a, .lo = 0x737dd2824b608d13, .ex = 0, .sgn=0}, +}; + +/* The following is a degree-7 polynomial with odd coefficients + approximating sin2pi(x) for -2^-24 < x < 2^-11+2^-24 + with relative error 2^-77.306. + Generated with sin_fast.sollya. */ +static const double PSfast[] = { + 0x1.921fb54442d18p+2, 0x1.1a62645446203p-52, // degree 1 (h+l) + -0x1.4abbce625be53p5, // degree 3 + 0x1.466bc678d8d63p6, // degree 5 + -0x1.331554ca19669p6, // degree 7 +}; + +/* The following is a degree-6 polynomial with even coefficients + approximating cos2pi(x) for -2^-24 < x < 2^-11+2^-24 + with relative error 2^-75.188. + Generated with cos_fast.sollya. */ +static const double PCfast[] = { + 0x1p+0, -0x1.923015cp-77, // degree 0 + -0x1.3bd3cc9be45dep4, // degree 2 + 0x1.03c1f080ad892p6, // degree 4 + -0x1.55a5c590f9e6ap6, // degree 6 +}; + +/* The following is a degree-11 polynomial with odd coefficients + approximating sin2pi(x) for 0 <= x < 2^-11 with relative error 2^-127.75. + Generated with sin_accurate.sollya. */ +static const dint64_t PS[] = { + {.hi = 0xc90fdaa22168c234, .lo = 0xc4c6628b80dc1cd1, .ex = 3, .sgn=0}, // 1 + {.hi = 0xa55de7312df295f5, .lo = 0x5dc72f712aa57db4, .ex = 6, .sgn=1}, // 3 + {.hi = 0xa335e33bad570e92, .lo = 0x3f33be0021aa54d2, .ex = 7, .sgn=0}, // 5 + {.hi = 0x9969667315ec2d9d, .lo = 0xe59d6ab8509a2025, .ex = 7, .sgn=1}, // 7 + {.hi = 0xa83c1a43bf1c6485, .lo = 0x7d5f8f76fa7d74ed, .ex = 6, .sgn=0}, // 9 + {.hi = 0xf16ab2898eae62f9, .lo = 0xa7f0339113b8b3c5, .ex = 4, .sgn=1}, // 11 +}; + +/* The following is a degree-10 polynomial with even coefficients + approximating cos2pi(x) for 0 <= x < 2^-11 with relative error 2^-137.246. + Generated with cos_accurate.sollya. */ +static const dint64_t PC[] = { + {.hi = 0x8000000000000000, .lo = 0x0, .ex = 1, .sgn=0}, // degree 0 + {.hi = 0x9de9e64df22ef2d2, .lo = 0x56e26cd9808c1949, .ex = 5, .sgn=1}, // 2 + {.hi = 0x81e0f840dad61d9a, .lo = 0x9980f00630cb655e, .ex = 7, .sgn=0}, // 4 + {.hi = 0xaae9e3f1e5ffcfe2, .lo = 0xa508509534006249, .ex = 7, .sgn=1}, // 6 + {.hi = 0xf0fa83448dd1e094, .lo = 0xe0603ce7044eeba, .ex = 6, .sgn=0}, // 8 + {.hi = 0xd368f6f4207cfe49, .lo = 0xec63157807ebffa, .ex = 5, .sgn=1}, // 10 +}; + +/* Table generated with ./buildSC 15 using accompanying buildSC.c. + For each i, 0 <= i < 256, xi=i/2^11+SC[i][0], with + SC[i][1] and SC[i][2] approximating sin2pi(xi) and cos2pi(xi) + respectively, both with 53+15 bits of accuracy. */ +static const double SC[256][3] = { + {0x0p+0, 0x0p+0, 0x1p+0}, /* 0 */ + {-0x1.c0f6cp-35, 0x1.921f892b900fep-9, 0x1.ffff621623fap-1}, /* 1 */ + {-0x1.9c7935ep-35, 0x1.921f0ea27ce01p-8, 0x1.fffd8858eca2ep-1}, /* 2 */ + {-0x1.d14d1acp-34, 0x1.2d96af779b0bbp-7, 0x1.fffa72c986392p-1}, /* 3 */ + {-0x1.dba8f6a8p-33, 0x1.921d1ce2d0a1cp-7, 0x1.fff62169dddaap-1}, /* 4 */ + {0x1.a6b7cdfp-32, 0x1.f6a29bdb7377p-7, 0x1.fff0943c02419p-1}, /* 5 */ + {0x1.b49618dp-33, 0x1.2d936d1506f3dp-6, 0x1.ffe9cb44829cp-1}, /* 6 */ + {-0x1.398d6fcp-35, 0x1.5fd4d1e21de6dp-6, 0x1.ffe1c687174b1p-1}, /* 7 */ + {-0x1.e9e9a8c8p-31, 0x1.9215597791e0ap-6, 0x1.ffd886097afcfp-1}, /* 8 */ + {-0x1.34e844cp-32, 0x1.c454f2e9480c7p-6, 0x1.ffce09ce95933p-1}, /* 9 */ + {-0x1.989a8a4p-32, 0x1.f693709b94f92p-6, 0x1.ffc251dfbac0cp-1}, /* 10 */ + {0x1.04a9b99p-30, 0x1.146860e69a571p-5, 0x1.ffb55e40a5c43p-1}, /* 11 */ + {-0x1.56947cp-36, 0x1.2d865748774adp-5, 0x1.ffa72efff95d1p-1}, /* 12 */ + {-0x1.c348768p-35, 0x1.46a396d34121ap-5, 0x1.ff97c420a8451p-1}, /* 13 */ + {0x1.9e80552p-32, 0x1.5fc00e6e4c65cp-5, 0x1.ff871dacd8761p-1}, /* 14 */ + {0x1.3f11d74p-34, 0x1.78dbaa97099ebp-5, 0x1.ff753bb18af95p-1}, /* 15 */ + {0x1.c039af4p-33, 0x1.91f65fc0abc0ap-5, 0x1.ff621e370ca7ap-1}, /* 16 */ + {0x1.53e1f8p-35, 0x1.ab101bf74ac2ep-5, 0x1.ff4dc54b00181p-1}, /* 17 */ + {0x1.114a649p-29, 0x1.c428d7de920e9p-5, 0x1.ff3830f2e9043p-1}, /* 18 */ + {0x1.adf0ef4p-31, 0x1.dd40723a3cdfbp-5, 0x1.ff21614b9d9adp-1}, /* 19 */ + {-0x1.d21f5918p-30, 0x1.f656e1e9e59cdp-5, 0x1.ff09565e83d77p-1}, /* 20 */ + {-0x1.4f54d708p-30, 0x1.07b612d6be078p-4, 0x1.fef0102c634e3p-1}, /* 21 */ + {-0x1.1efec9ap-30, 0x1.1440118ba7bdp-4, 0x1.fed58ecf342dap-1}, /* 22 */ + {0x1.cc17ba88p-29, 0x1.20c96cf0a7eedp-4, 0x1.feb9d24646fa6p-1}, /* 23 */ + {0x1.121dbe4p-33, 0x1.2d5209628edfp-4, 0x1.fe9cdacf99cffp-1}, /* 24 */ + {-0x1.9ecf61p-34, 0x1.39d9f103bf7f7p-4, 0x1.fe7ea854e6b08p-1}, /* 25 */ + {-0x1.04ede8ep-31, 0x1.466116c629e5cp-4, 0x1.fe5f3af4ee201p-1}, /* 26 */ + {-0x1.1821cecp-31, 0x1.52e773c9920c7p-4, 0x1.fe3e92c0e4108p-1}, /* 27 */ + {0x1.cdec726p-31, 0x1.5f6d02131f0b2p-4, 0x1.fe1cafc7f1a24p-1}, /* 28 */ + {-0x1.edece4dp-31, 0x1.6bf1b2653648cp-4, 0x1.fdf99233c230cp-1}, /* 29 */ + {-0x1.2aa4d1cp-31, 0x1.787585bc45f0fp-4, 0x1.fdd53a01d11d9p-1}, /* 30 */ + {0x1.d461592p-32, 0x1.84f871e32cf68p-4, 0x1.fdafa74f16482p-1}, /* 31 */ + {0x1.f0cbd728p-29, 0x1.917a71d3d2956p-4, 0x1.fd88da29f302ep-1}, /* 32 */ + {-0x1.583247p-30, 0x1.9dfb6c9865b06p-4, 0x1.fd60d2e14a6b1p-1}, /* 33 */ + {-0x1.2e81bf4p-30, 0x1.aa7b706bfdbbap-4, 0x1.fd3791484ff5p-1}, /* 34 */ + {-0x1.13941418p-28, 0x1.b6fa680a05c27p-4, 0x1.fd0d15a4b8471p-1}, /* 35 */ + {0x1.71098ffp-30, 0x1.c3785eba12b42p-4, 0x1.fce15fceddccfp-1}, /* 36 */ + {-0x1.c3519e8p-32, 0x1.cff53302f059p-4, 0x1.fcb4703b969e1p-1}, /* 37 */ + {0x1.2f522a5p-27, 0x1.dc70fb84af16ep-4, 0x1.fc8646987fc1dp-1}, /* 38 */ + {-0x1.ae9bed8p-33, 0x1.e8eb7f8a589e2p-4, 0x1.fc56e3b91ca3ap-1}, /* 39 */ + {0x1.f8868b2p-30, 0x1.f564e87d2330fp-4, 0x1.fc264701f9a09p-1}, /* 40 */ + {-0x1.b07985f8p-29, 0x1.00ee8835051f4p-3, 0x1.fbf47105f7439p-1}, /* 41 */ + {0x1.cbdaa94p-30, 0x1.072a05e1d4d8ep-3, 0x1.fbc16172a9e36p-1}, /* 42 */ + {0x1.37c5b908p-28, 0x1.0d64df9619f0dp-3, 0x1.fb8d18b635327p-1}, /* 43 */ + {-0x1.068b5fc8p-28, 0x1.139f09bc617f5p-3, 0x1.fb5797351da85p-1}, /* 44 */ + {-0x1.8ea66818p-29, 0x1.19d8919fa4ec8p-3, 0x1.fb20dc7da8affp-1}, /* 45 */ + {0x1.6278ceb8p-28, 0x1.2011719d50b87p-3, 0x1.fae8e8bd4427fp-1}, /* 46 */ + {-0x1.096df84p-29, 0x1.264993433763ap-3, 0x1.faafbcbfca356p-1}, /* 47 */ + {0x1.9b2534fp-29, 0x1.2c810967bbf7p-3, 0x1.fa7557d8d987ep-1}, /* 48 */ + {0x1.215b4ep-34, 0x1.32b7bfa25c91bp-3, 0x1.fa39bac71954bp-1}, /* 49 */ + {-0x1.94db891p-30, 0x1.38edb9d29b39dp-3, 0x1.f9fce56700a6dp-1}, /* 50 */ + {0x1.7727f7b8p-29, 0x1.3f22f7c3cce3ap-3, 0x1.f9bed7b8c8d8cp-1}, /* 51 */ + {-0x1.0cb33038p-29, 0x1.45576971dd53p-3, 0x1.f97f925d53c83p-1}, /* 52 */ + {-0x1.9071106p-31, 0x1.4b8b175c71e22p-3, 0x1.f93f14feb8022p-1}, /* 53 */ + {0x1.62741e78p-29, 0x1.51bdfa7ea30d5p-3, 0x1.f8fd5fe3efac8p-1}, /* 54 */ + {0x1.f8e16d0cp-28, 0x1.57f00e80e6e12p-3, 0x1.f8ba733a1ceb1p-1}, /* 55 */ + {-0x1.76acbcap-31, 0x1.5e2143b7bc1c2p-3, 0x1.f8764fad5e9bfp-1}, /* 56 */ + {-0x1.0a0f73ap-30, 0x1.6451a76411746p-3, 0x1.f830f4ad232d8p-1}, /* 57 */ + {0x1.ca11d1bcp-28, 0x1.6a8135d7bd143p-3, 0x1.f7ea625eb5af7p-1}, /* 58 */ + {-0x1.02f23628p-29, 0x1.70afd74071191p-3, 0x1.f7a299d3f182ap-1}, /* 59 */ + {0x1.b34dcb8p-29, 0x1.76dda08544b5cp-3, 0x1.f7599a1ac7ecdp-1}, /* 60 */ + {0x1.161ff4p-32, 0x1.7d0a7bf2d4abap-3, 0x1.f70f64322da74p-1}, /* 61 */ + {-0x1.c49b8b4p-31, 0x1.83366ddb3de23p-3, 0x1.f6c3f7e7c2707p-1}, /* 62 */ + {0x1.21da851p-29, 0x1.8961743b1429p-3, 0x1.f6775552a6ba2p-1}, /* 63 */ + {0x1.ac63edap-30, 0x1.8f8b851098588p-3, 0x1.f6297cef0cdd6p-1}, /* 64 */ + {0x1.27ef489cp-27, 0x1.95b4a5b9f2cebp-3, 0x1.f5da6e7820551p-1}, /* 65 */ + {0x1.ae8937p-30, 0x1.9bdcc07900146p-3, 0x1.f58a2b0689c82p-1}, /* 66 */ + {0x1.eb48c7ep-29, 0x1.a203e4a4f950ep-3, 0x1.f538b1d392049p-1}, /* 67 */ + {-0x1.bfd282fp-29, 0x1.a829ffaad0d79p-3, 0x1.f4e603d51f1aap-1}, /* 68 */ + {0x1.7ccf638p-29, 0x1.ae4f1fa80e1b5p-3, 0x1.f492204c5ef9ep-1}, /* 69 */ + {-0x1.2435c578p-28, 0x1.b4732b72ebc86p-3, 0x1.f43d0890e1e72p-1}, /* 70 */ + {0x1.0293fecp-30, 0x1.ba9634155f866p-3, 0x1.f3e6bbb6c2ea4p-1}, /* 71 */ + {-0x1.7bb1f92p-29, 0x1.c0b82461f65ep-3, 0x1.f38f3ae6f9afcp-1}, /* 72 */ + {0x1.27aaebcp-29, 0x1.c6d906faacf65p-3, 0x1.f3368589e17a2p-1}, /* 73 */ + {-0x1.2e2bcd5p-27, 0x1.ccf8c3f74a6c9p-3, 0x1.f2dc9cfb5fa74p-1}, /* 74 */ + {-0x1.6f070acp-30, 0x1.d31773ba218a8p-3, 0x1.f2817fd4d045bp-1}, /* 75 */ + {0x1.469adfcp-29, 0x1.d935004779e57p-3, 0x1.f2252f59c122dp-1}, /* 76 */ + {0x1.4f51c18p-32, 0x1.df5164301377ap-3, 0x1.f1c7abdeaa3efp-1}, /* 77 */ + {0x1.78e44dap-29, 0x1.e56ca4202807cp-3, 0x1.f168f51c5d5d5p-1}, /* 78 */ + {0x1.49bb5f8p-32, 0x1.eb86b4a1b7e9bp-3, 0x1.f1090bc4b68p-1}, /* 79 */ + {-0x1.67ba541p-28, 0x1.f19f9369d5e93p-3, 0x1.f0a7effdc937fp-1}, /* 80 */ + {0x1.c0cab95p-29, 0x1.f7b74ab7219d2p-3, 0x1.f045a1219e594p-1}, /* 81 */ + {-0x1.2b77e32p-30, 0x1.fdcdc0ca3288dp-3, 0x1.efe220cf5c751p-1}, /* 82 */ + {-0x1.e0d8cbp-33, 0x1.01f18054c8362p-2, 0x1.ef7d6e54c347dp-1}, /* 83 */ + {-0x1.ecd5b9cp-29, 0x1.04fb7f6d35d68p-2, 0x1.ef178a6f9a987p-1}, /* 84 */ + {0x1.eb24de5p-29, 0x1.0804e1d369ff2p-2, 0x1.eeb074934fdfp-1}, /* 85 */ + {0x1.4a897c4p-30, 0x1.0b0d9d7b0d042p-2, 0x1.ee482e14bcdep-1}, /* 86 */ + {0x1.336c376p-30, 0x1.0e15b555e7becp-2, 0x1.eddeb6908ca8cp-1}, /* 87 */ + {-0x1.3952d9p-31, 0x1.111d25efd48b8p-2, 0x1.ed740e7eb8dd6p-1}, /* 88 */ + {0x1.fc2a5d4p-31, 0x1.1423ef5c7e1bdp-2, 0x1.ed0835dc24e89p-1}, /* 89 */ + {0x1.a88ed37p-29, 0x1.172a0eb8361dap-2, 0x1.ec9b2d0ec8288p-1}, /* 90 */ + {-0x1.8ca4cb94p-27, 0x1.1a2f7b10b6d7p-2, 0x1.ec2cf55d6117cp-1}, /* 91 */ + {0x1.0144524p-27, 0x1.1d3446fd0cd3fp-2, 0x1.ebbd8c1d62f96p-1}, /* 92 */ + {-0x1.abf810cp-28, 0x1.203855b85f89ap-2, 0x1.eb4cf57454132p-1}, /* 93 */ + {0x1.5d4c5d58p-28, 0x1.233bbcca40561p-2, 0x1.eadb2e40746cap-1}, /* 94 */ + {-0x1.a1b0c58p-29, 0x1.263e685b1d714p-2, 0x1.ea68396d87754p-1}, /* 95 */ + {-0x1.77c8dacp-29, 0x1.294061d2eb611p-2, 0x1.e9f41597393c8p-1}, /* 96 */ + {0x1.915540ep-30, 0x1.2c41a580014cfp-2, 0x1.e97ec348fb87fp-1}, /* 97 */ + {-0x1.abb6d9bp-28, 0x1.2f422b2d0990cp-2, 0x1.e90843c55b996p-1}, /* 98 */ + {-0x1.b8ee5d58p-28, 0x1.3241f8cea2836p-2, 0x1.e890962268c49p-1}, /* 99 */ + {-0x1.1cd29828p-28, 0x1.35410a8396266p-2, 0x1.e817baf85c094p-1}, /* 100 */ + {-0x1.e216afp-32, 0x1.383f5e08283e2p-2, 0x1.e79db2a188b0ap-1}, /* 101 */ + {-0x1.24afc3p-31, 0x1.3b3cef6993c0bp-2, 0x1.e7227dbf82004p-1}, /* 102 */ + {-0x1.aa1657cp-31, 0x1.3e39be4767224p-2, 0x1.e6a61c62d5274p-1}, /* 103 */ + {-0x1.c5b65fap-30, 0x1.4135c898485bbp-2, 0x1.e6288ee07fea5p-1}, /* 104 */ + {0x1.23e8978p-32, 0x1.44310de3c284bp-2, 0x1.e5a9d54bbd26cp-1}, /* 105 */ + {-0x1.2b1d77ap-29, 0x1.472b8976d498dp-2, 0x1.e529f06cb187dp-1}, /* 106 */ + {-0x1.daaa348p-31, 0x1.4a253cb97efd1p-2, 0x1.e4a8e007231a2p-1}, /* 107 */ + {-0x1.322f5708p-28, 0x1.4d1e2260c3422p-2, 0x1.e426a500f6e33p-1}, /* 108 */ + {0x1.64758e8p-29, 0x1.50163eca0b337p-2, 0x1.e3a33e996b722p-1}, /* 109 */ + {0x1.12486278p-28, 0x1.530d89a17e007p-2, 0x1.e31eae3fb917bp-1}, /* 110 */ + {-0x1.6c3416ccp-27, 0x1.5603fcf8cd8a3p-2, 0x1.e298f502a579bp-1}, /* 111 */ + {0x1.ab481ffp-29, 0x1.58f9a896aa209p-2, 0x1.e2121016e14fcp-1}, /* 112 */ + {-0x1.6eb838bp-29, 0x1.5bee77aaf890bp-2, 0x1.e18a032eb4df5p-1}, /* 113 */ + {-0x1.d159b8p-32, 0x1.5ee2734efeef5p-2, 0x1.e100ccaa6bd78p-1}, /* 114 */ + {-0x1.a42e4ap-34, 0x1.61d595bedeabcp-2, 0x1.e0766d944915ep-1}, /* 115 */ + {-0x1.43d0dcp-30, 0x1.64c7dd5cc0cd1p-2, 0x1.dfeae63903034p-1}, /* 116 */ + {-0x1.8c7bdb7p-27, 0x1.67b9453ca2122p-2, 0x1.df5e378482eaep-1}, /* 117 */ + {0x1.1c0ead6p-30, 0x1.6aa9d844c980ap-2, 0x1.ded05f6a23a52p-1}, /* 118 */ + {0x1.7d526p-31, 0x1.6d99867e90d92p-2, 0x1.de4160e97b2e2p-1}, /* 119 */ + {0x1.924e0368p-28, 0x1.7088555d3c816p-2, 0x1.ddb13afb14e37p-1}, /* 120 */ + {-0x1.74b7c3ep-30, 0x1.73763c09fba09p-2, 0x1.dd1fef5335416p-1}, /* 121 */ + {-0x1.7943adp-30, 0x1.766340685c982p-2, 0x1.dc8d7ccf2567ap-1}, /* 122 */ + {0x1.79dd614p-29, 0x1.794f5f7522b88p-2, 0x1.dbf9e402aa5c3p-1}, /* 123 */ + {0x1.7b64f32p-30, 0x1.7c3a939c32d81p-2, 0x1.db652607e0db1p-1}, /* 124 */ + {-0x1.2bea5ce8p-28, 0x1.7f24db825141cp-2, 0x1.dacf43268b5bp-1}, /* 125 */ + {0x1.733c024p-30, 0x1.820e3b8bf15ap-2, 0x1.da383a7aed887p-1}, /* 126 */ + {-0x1.eac0fc94p-27, 0x1.84f6a51d077b3p-2, 0x1.d9a00efd84537p-1}, /* 127 */ + {0x1.aca37338p-27, 0x1.87de2f4704f98p-2, 0x1.d906bbf17f4dap-1}, /* 128 */ + {-0x1.910c4fp-30, 0x1.8ac4b7dc0d986p-2, 0x1.d86c4862b5d6ep-1}, /* 129 */ + {-0x1.33bb86p-31, 0x1.8daa52b4dc041p-2, 0x1.d7d0b0374a559p-1}, /* 130 */ + {-0x1.69e1507p-27, 0x1.908ef408ad22p-2, 0x1.d733f5e71c3bcp-1}, /* 131 */ + {0x1.cffacf08p-27, 0x1.9372ab7784d36p-2, 0x1.d696161d786c9p-1}, /* 132 */ + {-0x1.8629d9fp-26, 0x1.965552b0849abp-2, 0x1.d5f7190eeae23p-1}, /* 133 */ + {0x1.415p-30, 0x1.99371687c64f3p-2, 0x1.d556f5155d9ddp-1}, /* 134 */ + {-0x1.bd37aad8p-27, 0x1.9c17cf40715cbp-2, 0x1.d4b5b2caf8386p-1}, /* 135 */ + {0x1.d02cde7p-26, 0x1.9ef79ea4d995dp-2, 0x1.d4134ac5eb246p-1}, /* 136 */ + {-0x1.10547acp-30, 0x1.a1d653d9adf5ep-2, 0x1.d36fc7d291602p-1}, /* 137 */ + {-0x1.01a1a228p-27, 0x1.a4b40f9c0120bp-2, 0x1.d2cb22b45236bp-1}, /* 138 */ + {0x1.3ce2bacp-29, 0x1.a790ce2056b9ap-2, 0x1.d2255c3ae11a5p-1}, /* 139 */ + {-0x1.ccb4a6p-32, 0x1.aa6c828db4ea8p-2, 0x1.d17e774d4e3e2p-1}, /* 140 */ + {0x1.5db4bp-29, 0x1.ad47321f29847p-2, 0x1.d0d672bc0b122p-1}, /* 141 */ + {0x1.32f6a6ep-29, 0x1.b020d7a285e23p-2, 0x1.d02d4fb84d334p-1}, /* 142 */ + {0x1.cf8e39bcp-26, 0x1.b2f97c27f7494p-2, 0x1.cf830c2248c5ep-1}, /* 143 */ + {0x1.8927bbp-30, 0x1.b5d10129a750ap-2, 0x1.ced7af22cb105p-1}, /* 144 */ + {-0x1.3dec3c1p-28, 0x1.b8a77f8d0bbc5p-2, 0x1.ce2b32e50d6cdp-1}, /* 145 */ + {-0x1.26ba536p-28, 0x1.bb7cf08f0290dp-2, 0x1.cd7d98fcf3b1ep-1}, /* 146 */ + {0x1.23c568ep-29, 0x1.be51524e3aa53p-2, 0x1.cccee1da3d56ep-1}, /* 147 */ + {-0x1.f3b3afp-29, 0x1.c1249c1f5f2f6p-2, 0x1.cc1f0f95e1e24p-1}, /* 148 */ + {-0x1.1286a47p-28, 0x1.c3f6d2ef7054bp-2, 0x1.cb6e20ff37e81p-1}, /* 149 */ + {0x1.641214ep-29, 0x1.c6c7f594003d9p-2, 0x1.cabc165bf1b6p-1}, /* 150 */ + {0x1.0cda7c9p-27, 0x1.c997ff2bffccbp-2, 0x1.ca08f0dee434cp-1}, /* 151 */ + {-0x1.5557ac9p-28, 0x1.cc66e7b42e8f1p-2, 0x1.c954b28bca62ep-1}, /* 152 */ + {0x1.555eb62p-28, 0x1.cf34bccc567a1p-2, 0x1.c89f57f6e20f3p-1}, /* 153 */ + {-0x1.4e0e361p-28, 0x1.d2016cbb5e39ap-2, 0x1.c7e8e59999e1fp-1}, /* 154 */ + {0x1.446da1ep-29, 0x1.d4cd039d0ed05p-2, 0x1.c731585f970ebp-1}, /* 155 */ + {0x1.103d328p-29, 0x1.d797767638decp-2, 0x1.c678b3174afe1p-1}, /* 156 */ + {0x1.5814d6p-28, 0x1.da60c7ae9dc22p-2, 0x1.c5bef522be6fbp-1}, /* 157 */ + {-0x1.5e2321ep-29, 0x1.dd28f054cbb3fp-2, 0x1.c5042052c8c42p-1}, /* 158 */ + {-0x1.a259ffep-29, 0x1.dfeff54854631p-2, 0x1.c44833611bc7dp-1}, /* 159 */ + {-0x1.4f28d8p-31, 0x1.e2b5d34665b35p-2, 0x1.c38b2f278ea7ep-1}, /* 160 */ + {-0x1.de571p-36, 0x1.e57a86d137f2p-2, 0x1.c2cd1493d05c2p-1}, /* 161 */ + {0x1.e0d8d14p-29, 0x1.e83e0ffb7bfb4p-2, 0x1.c20de3a08ea07p-1}, /* 162 */ + {-0x1.12a858ep-28, 0x1.eb0067e48baf4p-2, 0x1.c14d9e2bd511ep-1}, /* 163 */ + {0x1.9a17403p-27, 0x1.edc19997a4431p-2, 0x1.c08c413089b2ep-1}, /* 164 */ + {0x1.68c8636p-29, 0x1.f0819163d1bcp-2, 0x1.bfc9d21568f32p-1}, /* 165 */ + {0x1.4cc5eb8p-29, 0x1.f3405a482e11dp-2, 0x1.bf064dd580fc9p-1}, /* 166 */ + {-0x1.fce7cd8p-27, 0x1.f5fde8f3f11d4p-2, 0x1.be41b798f6b97p-1}, /* 167 */ + {-0x1.af8169p-29, 0x1.f8ba4c98a9816p-2, 0x1.bd7c0b1a7f14bp-1}, /* 168 */ + {0x1.6e39e2p-33, 0x1.fb7575d1ea75p-2, 0x1.bcb54cac5dde5p-1}, /* 169 */ + {0x1.30f9256p-28, 0x1.fe2f665dcd168p-2, 0x1.bbed7bd1e17bp-1}, /* 170 */ + {0x1.626de2p-31, 0x1.00740ca0d5fbbp-1, 0x1.bb2499f9fe7a3p-1}, /* 171 */ + {0x1.5cc703p-30, 0x1.01cfc8afeea0ep-1, 0x1.ba5aa650dd495p-1}, /* 172 */ + {-0x1.6191e6p-32, 0x1.032ae54fe4057p-1, 0x1.b98fa2065a5e6p-1}, /* 173 */ + {-0x1.6b1485p-31, 0x1.0485624c328c8p-1, 0x1.b8c38d39737bcp-1}, /* 174 */ + {-0x1.11fbc3ap-29, 0x1.05df3e66a716dp-1, 0x1.b7f668a580fdp-1}, /* 175 */ + {-0x1.0eca7fp-27, 0x1.07387825589ecp-1, 0x1.b728352c44517p-1}, /* 176 */ + {-0x1.8073bc9ep-25, 0x1.089109ef1284dp-1, 0x1.b658f630112edp-1}, /* 177 */ + {-0x1.9dcf0adp-27, 0x1.09e9051603e29p-1, 0x1.b588a13ab750fp-1}, /* 178 */ + {-0x1.06ea9fp-29, 0x1.0b405820e78e7p-1, 0x1.b4b740d3cc07bp-1}, /* 179 */ + {-0x1.36a8d0cp-30, 0x1.0c9704a1ea4e5p-1, 0x1.b3e4d40f5524dp-1}, /* 180 */ + {0x1.63d1f3p-30, 0x1.0ded0bc01a533p-1, 0x1.b3115a3a628afp-1}, /* 181 */ + {0x1.f3181f14p-26, 0x1.0f4270e4787bfp-1, 0x1.b23cd1314c779p-1}, /* 182 */ + {-0x1.f269b78p-29, 0x1.109723e75c5cfp-1, 0x1.b167430cfebdbp-1}, /* 183 */ + {0x1.1d84dc08p-27, 0x1.11eb36bc9db52p-1, 0x1.b090a4915ee88p-1}, /* 184 */ + {-0x1.08e60068p-27, 0x1.133e9ba0061d8p-1, 0x1.afb8fe69a6527p-1}, /* 185 */ + {0x1.cda72abp-27, 0x1.14915d557a7c9p-1, 0x1.aee049bc0aeep-1}, /* 186 */ + {-0x1.f32f95p-30, 0x1.15e36dfb6bb55p-1, 0x1.ae068f6991699p-1}, /* 187 */ + {0x1.138092dp-28, 0x1.1734d6f34d7fp-1, 0x1.ad2bc96c1e1f5p-1}, /* 188 */ + {0x1.6b382dd4p-26, 0x1.188595ae376a5p-1, 0x1.ac4ff962bdb6dp-1}, /* 189 */ + {-0x1.f12fafap-28, 0x1.19d59f592a587p-1, 0x1.ab7326685eb57p-1}, /* 190 */ + {-0x1.2909e5ap-28, 0x1.1b2500aed7ac6p-1, 0x1.aa954823cf815p-1}, /* 191 */ + {-0x1.d66a8978p-25, 0x1.1c73aa0150cf9p-1, 0x1.a9b668fb0503fp-1}, /* 192 */ + {0x1.311ea86p-27, 0x1.1dc1b7db74db1p-1, 0x1.a8d675d9c6cc8p-1}, /* 193 */ + {-0x1.41c02b8p-31, 0x1.1f0f08a1a06a4p-1, 0x1.a7f5853bb4309p-1}, /* 194 */ + {-0x1.ca1f4edp-26, 0x1.205ba57211271p-1, 0x1.a71391146958fp-1}, /* 195 */ + {-0x1.910ce77p-28, 0x1.21a7988f8326bp-1, 0x1.a63092626202fp-1}, /* 196 */ + {0x1.2bfadbeep-25, 0x1.22f2dc71afab6p-1, 0x1.a54c8cd9fd0d9p-1}, /* 197 */ + {-0x1.5f1c02a8p-27, 0x1.243d5df4afb93p-1, 0x1.a4678dbbe5e73p-1}, /* 198 */ + {-0x1.db12b9p-30, 0x1.2587347f493a4p-1, 0x1.a38184db0df23p-1}, /* 199 */ + {-0x1.7b29ep-30, 0x1.26d05490f2f61p-1, 0x1.a29a7a2f40b49p-1}, /* 200 */ + {-0x1.b3ddca4p-29, 0x1.2818be6930629p-1, 0x1.a1b26d8f070d7p-1}, /* 201 */ + {0x1.e112744p-29, 0x1.2960730ff2bcdp-1, 0x1.a0c95e3df5e0ep-1}, /* 202 */ + {-0x1.5269766p-28, 0x1.2aa76dafcbbf4p-1, 0x1.9fdf4fae1df6fp-1}, /* 203 */ + {-0x1.09777e1p-28, 0x1.2bedb1b6b4e15p-1, 0x1.9ef43f6cbe162p-1}, /* 204 */ + {0x1.ae2051fp-28, 0x1.2d333e4617f25p-1, 0x1.9e082e148680ep-1}, /* 205 */ + {-0x1.36f6ced8p-27, 0x1.2e780cb47180ep-1, 0x1.9d1b207f383c3p-1}, /* 206 */ + {-0x1.23fdc6bp-28, 0x1.2fbc23fba2f44p-1, 0x1.9c2d1197130a7p-1}, /* 207 */ + {0x1.bc540ep-33, 0x1.30ff7fd6d967dp-1, 0x1.9b3e0478b961bp-1}, /* 208 */ + {-0x1.cfb4ed7p-28, 0x1.32421da0bf0e9p-1, 0x1.9a4dfb1c89326p-1}, /* 209 */ + {0x1.55802aecp-26, 0x1.3384042a92b1dp-1, 0x1.995cf06920d11p-1}, /* 210 */ + {0x1.60719e4p-28, 0x1.34c52608e3a92p-1, 0x1.986aee6d6837ep-1}, /* 211 */ + {-0x1.cbf2e48p-30, 0x1.36058ac8863b6p-1, 0x1.9777ef832c986p-1}, /* 212 */ + {0x1.9061c32p-27, 0x1.374533ab707dp-1, 0x1.9683f2ad7e2ecp-1}, /* 213 */ + {-0x1.da84dfep-27, 0x1.3884160f9488fp-1, 0x1.958f000fdd50ap-1}, /* 214 */ + {0x1.92e8a74p-29, 0x1.39c23eba6b22ap-1, 0x1.94990dd9cee51p-1}, /* 215 */ + {-0x1.bff5d9ap-29, 0x1.3affa20756bddp-1, 0x1.93a225056084ap-1}, /* 216 */ + {0x1.4c462p-36, 0x1.3c3c4498e98ebp-1, 0x1.92aa41fbb951cp-1}, /* 217 */ + {-0x1.e4613e9p-28, 0x1.3d782261dff62p-1, 0x1.91b167e92d706p-1}, /* 218 */ + {0x1.0eb2964p-30, 0x1.3eb33ed579bbep-1, 0x1.90b794146043cp-1}, /* 219 */ + {-0x1.60abec2p-29, 0x1.3fed94c834d8ap-1, 0x1.8fbcca9583479p-1}, /* 220 */ + {0x1.6954977p-27, 0x1.4127281ddac03p-1, 0x1.8ec1085083553p-1}, /* 221 */ + {0x1.a16fec2p-29, 0x1.425ff1f841235p-1, 0x1.8dc452ca328d3p-1}, /* 222 */ + {-0x1.27bcdd3p-27, 0x1.4397f44aa44f2p-1, 0x1.8cc6a8771e165p-1}, /* 223 */ + {-0x1.60dded4p-28, 0x1.44cf317a563dbp-1, 0x1.8bc8076122736p-1}, /* 224 */ + {-0x1.9a8f405cp-26, 0x1.4605a2b02d705p-1, 0x1.8ac875232f3efp-1}, /* 225 */ + {0x1.32777dcp-27, 0x1.473b532bc5a67p-1, 0x1.89c7e8713120cp-1}, /* 226 */ + {-0x1.1418a7bp-26, 0x1.4870306ca20e2p-1, 0x1.88c670a0ea774p-1}, /* 227 */ + {-0x1.fed182ep-28, 0x1.49a44886b534p-1, 0x1.87c401fdf05e5p-1}, /* 228 */ + {0x1.86144d8p-27, 0x1.4ad796ea1410cp-1, 0x1.86c0a04dbacc5p-1}, /* 229 */ + {0x1.1bc2e6p-33, 0x1.4c0a14640d2afp-1, 0x1.85bc51aa114c2p-1}, /* 230 */ + {-0x1.f53d2fep-28, 0x1.4d3bc5aaa8cd5p-1, 0x1.84b7121b30a13p-1}, /* 231 */ + {-0x1.2e100ap-30, 0x1.4e6cab91556bep-1, 0x1.83b0e0e6b6cccp-1}, /* 232 */ + {-0x1.fa58c62p-29, 0x1.4f9cc1c69fddep-1, 0x1.82a9c1c1ab463p-1}, /* 233 */ + {0x1.bb491ep-33, 0x1.50cc09fdcbd92p-1, 0x1.81a1b3342f858p-1}, /* 234 */ + {0x1.a11541p-28, 0x1.51fa82c3aa029p-1, 0x1.8098b67ea8509p-1}, /* 235 */ + {0x1.ab0a5d3p-27, 0x1.53282b20b96b6p-1, 0x1.7f8ecc791953p-1}, /* 236 */ + {-0x1.cba0438p-28, 0x1.5454fe43a7d7cp-1, 0x1.7e83f96af78ap-1}, /* 237 */ + {-0x1.0dd83a4p-29, 0x1.5581033a81573p-1, 0x1.7d783712e20ecp-1}, /* 238 */ + {-0x1.e9a8299p-28, 0x1.56ac33fbb8253p-1, 0x1.7c6b8acf90fa6p-1}, /* 239 */ + {0x1.225c4aap-29, 0x1.57d6939d4b513p-1, 0x1.7b5df1da18065p-1}, /* 240 */ + {-0x1.82e66ep-27, 0x1.59001b9e64d79p-1, 0x1.7a4f72157cfdfp-1}, /* 241 */ + {0x1.51a6a354p-26, 0x1.5a28d5b36d597p-1, 0x1.794002a7c9023p-1}, /* 242 */ + {0x1.13917f4p-26, 0x1.5b50b4e10bec1p-1, 0x1.782faf6dc7ba2p-1}, /* 243 */ + {0x1.49310ccp-30, 0x1.5c77bc15ab4efp-1, 0x1.771e75c43942ep-1}, /* 244 */ + {0x1.24d493cp-30, 0x1.5d9dee9de49dbp-1, 0x1.760c529bc17bp-1}, /* 245 */ + {-0x1.04638f7p-26, 0x1.5ec347044e0f4p-1, 0x1.74f94b0af972p-1}, /* 246 */ + {-0x1.3f41b28p-29, 0x1.5fe7cb834600cp-1, 0x1.73e55936a516p-1}, /* 247 */ + {-0x1.a5f6f5cp-30, 0x1.610b7515d1562p-1, 0x1.72d083b8214ebp-1}, /* 248 */ + {0x1.19fb2ep-28, 0x1.622e459eafbc1p-1, 0x1.71bac8c7b0592p-1}, /* 249 */ + {-0x1.56d2c2bp-28, 0x1.6350396fe4e62p-1, 0x1.70a42bec51665p-1}, /* 250 */ + {-0x1.3c156c2p-28, 0x1.64715385bed93p-1, 0x1.6f8caa4969708p-1}, /* 251 */ + {-0x1.f23e576p-29, 0x1.659191d2fd57fp-1, 0x1.6e7445d74f711p-1}, /* 252 */ + {0x1.1e4be38p-30, 0x1.66b0f41d484c4p-1, 0x1.6d5afecd4938dp-1}, /* 253 */ + {-0x1.397cc8d8p-27, 0x1.67cf76eac73dfp-1, 0x1.6c40d89625f63p-1}, /* 254 */ + {-0x1.202f686p-28, 0x1.68ed1e0990551p-1, 0x1.6b25cf728c35p-1}, /* 255 */ +}; + +// Multiply exactly a and b, such that *hi + *lo = a * b. +static inline void a_mul(double *hi, double *lo, double a, double b) { + *hi = a * b; + *lo = __builtin_fma (a, b, -*hi); +} + +/* Multiply a double with a double double : a * (bh + bl) + with error bounded by ulp(lo) */ +static inline void s_mul (double *hi, double *lo, double a, double bh, + double bl) { + a_mul (hi, lo, a, bh); /* exact */ + *lo = __builtin_fma (a, bl, *lo); + /* the error is bounded by ulp(lo), where |lo| < |a*bl| + ulp(hi) */ +} + +// Returns (ah + al) * (bh + bl) - (al * bl) +// We can ignore al * bl when assuming al <= ulp(ah) and bl <= ulp(bh) +static inline void d_mul(double *hi, double *lo, double ah, double al, + double bh, double bl) { + double s, t; + + a_mul(hi, &s, ah, bh); + t = __builtin_fma(al, bh, s); + *lo = __builtin_fma(ah, bl, t); +} + +static inline void +fast_two_sum(double *hi, double *lo, double a, double b) +{ + double e; + + *hi = a + b; + e = *hi - a; /* exact */ + *lo = b - e; /* exact */ +} + +/* Put in h+l an approximation of sin2pi(xh+xl), + for 2^-24 <= xh+xl < 2^-11 + 2^-24, + and |xl| < 2^-52.36, with absolute error < 2^-77.09 + (see evalPSfast() in sin.sage). + Assume uh + ul approximates (xh+xl)^2. */ +static void +evalPSfast (double *h, double *l, double xh, double xl, double uh, double ul) +{ + double t; + *h = PSfast[4]; // degree 7 + *h = __builtin_fma (*h, uh, PSfast[3]); // degree 5 + *h = __builtin_fma (*h, uh, PSfast[2]); // degree 3 + s_mul (h, l, *h, uh, ul); + fast_two_sum (h, &t, PSfast[0], *h); + *l += PSfast[1] + t; + // multiply by xh+xl + d_mul (h, l, *h, *l, xh, xl); +} + +/* Put in h+l an approximation of cos2pi(xh+xl), + for 2^-24 <= xh+xl < 2^-11 + 2^-24, + and |xl| < 2^-52.36, with relative error < 2^-69.96 + (see evalPCfast() in sin.sage). + Assume uh + ul approximates (xh+xl)^2. */ +static void +evalPCfast (double *h, double *l, double uh, double ul) +{ + double t; + *h = PCfast[4]; // degree 6 + *h = __builtin_fma (*h, uh, PCfast[3]); // degree 4 + *h = __builtin_fma (*h, uh, PCfast[2]); // degree 2 + s_mul (h, l, *h, uh, ul); + fast_two_sum (h, &t, PCfast[0], *h); + *l += PCfast[1] + t; +} + +/* Put in Y an approximation of sin2pi(X), for 0 <= X < 2^-11, + where X2 approximates X^2. + Absolute error bounded by 2^-132.999 with 0 <= Y < 0.003068 + (see evalPS() in sin.sage), and relative error bounded by + 2^-124.648 (see evalPSrel(K=8) in sin.sage). */ +static void +evalPS (dint64_t *Y, dint64_t *X, dint64_t *X2) +{ + mul_dint_21 (Y, X2, PS+5); // degree 11 + add_dint (Y, Y, PS+4); // degree 9 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PS+3); // degree 7 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PS+2); // degree 5 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PS+1); // degree 3 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PS+0); // degree 1 + mul_dint (Y, Y, X); // multiply by X +} + +/* Put in Y an approximation of cos2pi(X), for 0 <= X < 2^-11, + where X2 approximates X^2. + Absolute/relative error bounded by 2^-125.999 with 0.999995 < Y <= 1 + (see evalPC() in sin.sage). */ +static void +evalPC (dint64_t *Y, dint64_t *X2) +{ + mul_dint_21 (Y, X2, PC+5); // degree 10 + add_dint (Y, Y, PC+4); // degree 8 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PC+3); // degree 6 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PC+2); // degree 4 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PC+1); // degree 2 + mul_dint (Y, Y, X2); + add_dint (Y, Y, PC+0); // degree 0 +} + +// normalize X such that X->hi has its most significant bit set (if X <> 0) +static void +normalize (dint64_t *X) +{ + int cnt; + if (X->hi != 0) + { + cnt = __builtin_clzll (X->hi); + if (cnt) + { + X->hi = (X->hi << cnt) | (X->lo >> (64 - cnt)); + X->lo = X->lo << cnt; + } + X->ex -= cnt; + } + else if (X->lo != 0) + { + cnt = __builtin_clzll (X->lo); + X->hi = X->lo << cnt; + X->lo = 0; + X->ex -= 64 + cnt; + } +} + +/* Approximate X/(2pi) mod 1. If Xin is the input value, and Xout the + output value, we have: + |Xout - (Xin/(2pi) mod 1)| < 2^-126.67*|Xout| + Assert X is normalized at input, and normalize X at output. +*/ +static void +reduce (dint64_t *X) +{ + int e = X->ex; + u128 u; + + if (e <= 1) // |X| < 2 + { + /* multiply by T[0]/2^64 + T[1]/2^128, where + |T[0]/2^64 + T[1]/2^128 - 1/(2pi)| < 2^-130.22 */ + u = (u128) X->hi * (u128) T[1]; + uint64_t tiny = u; + X->lo = u >> 64; + u = (u128) X->hi * (u128) T[0]; + X->lo += u; + X->hi = (u >> 64) + (X->lo < (uint64_t) u); + /* hi + lo/2^64 + tiny/2^128 = hi_in * (T[0]/2^64 + T[1]/2^128) thus + |hi + lo/2^64 + tiny/2^128 - hi_in/(2*pi)| < hi_in * 2^-130.22 + Since X is normalized at input, hi_in >= 2^63, and since T[0] >= 2^61, + we have hi >= 2^(63+61-64) = 2^60, thus the normalize() below + perform a left shift by at most 3 bits */ + e = X->ex; + normalize (X); + e = e - X->ex; + // put the upper e bits of tiny into X->lo + if (e) + X->lo |= tiny >> (64 - e); + /* The error is bounded by 2^-130.22 (relative) + ulp(lo) (absolute). + Since now X->hi >= 2^63, the absolute error of ulp(lo) converts into + a relative error of less than 2^-127. + This yields a maximal relative error of: + (1 + 2^-130.22) * (1 + 2^-127) - 1 < 2^-126.852. + */ + return; + } + + // now 2 <= e <= 1024 + + /* The upper 64-bit word X->hi corresponds to hi/2^64*2^e, if multiplied by + T[i]/2^((i+1)*64) it yields hi*T[i]/2^128 * 2^(e-i*64). + If e-64i <= -128, it contributes to less than 2^-128; + if e-64i >= 128, it yields an integer, which is 0 modulo 1. + We thus only consider the values of i such that -127 <= e-64i <= 127, + i.e., (-127+e)/64 <= i <= (127+e)/64. + Up to 4 consecutive values of T[i] can contribute (only 3 when e is a + multiple of 64). */ + int i = (e < 127) ? 0 : (e - 127 + 64 - 1) / 64; // ceil((e-127)/64) + // 0 <= i <= 15 + uint64_t c[5]; + u = (u128) X->hi * (u128) T[i+3]; // i+3 <= 18 + c[0] = u; + c[1] = u >> 64; + u = (u128) X->hi * (u128) T[i+2]; + c[1] += u; + c[2] = (u >> 64) + (c[1] < (uint64_t) u); + u = (u128) X->hi * (u128) T[i+1]; + c[2] += u; + c[3] = (u >> 64) + (c[2] < (uint64_t) u); + u = (u128) X->hi * (u128) T[i]; + c[3] += u; + c[4] = (u >> 64) + (c[3] < (uint64_t) u); + + /* up to here, the ignored part hi*(T[i+4]+T[i+5]+...) can contribute by + less than 2^64 in c[0], thus less than 1 in c[1] */ + + int f = e - 64 * i; // hi*T[i]/2^128 is multiplied by 2^f + /* {c, 5} = hi*(T[i]+T[i+1]/2^64+T[i+2]/2^128+T[i+3]/2^192) */ + /* now shift c[0..4] by f bits to the left */ + uint64_t tiny; + if (f < 64) + { + X->hi = (c[4] << f) | (c[3] >> (64 - f)); + X->lo = (c[3] << f) | (c[2] >> (64 - f)); + tiny = (c[2] << f) | (c[1] >> (64 - f)); + /* the ignored part was less than 1 in c[1], + thus less than 2^(f-64) <= 1/2 in tiny */ + } + else if (f == 64) + { + X->hi = c[3]; + X->lo = c[2]; + tiny = c[1]; + /* the ignored part was less than 1 in c[1], + thus less than 1 in tiny */ + } + else /* 65 <= f <= 127: this case can only occur when e >= 65 */ + { + int g = f - 64; /* 1 <= g <= 63 */ + /* we compute an extra term */ + u = (u128) X->hi * (u128) T[i+4]; // i+4 <= 19 + u = u >> 64; + c[0] += u; + c[1] += (c[0] < u); + c[2] += (c[0] < u) && c[1] == 0; + c[3] += (c[0] < u) && c[1] == 0 && c[2] == 0; + c[4] += (c[0] < u) && c[1] == 0 && c[2] == 0 && c[3] == 0; + X->hi = (c[3] << g) | (c[2] >> (64 - g)); + X->lo = (c[2] << g) | (c[1] >> (64 - g)); + tiny = (c[1] << g) | (c[0] >> (64 - g)); + /* the ignored part was less than 1 in c[0], + thus less than 1/2 in tiny */ + } + /* The approximation error between X/in(2pi) mod 1 and + X->hi/2^64 + X->lo/2^128 + tiny/2^192 is: + (a) the ignored part in tiny, which is less than ulp(tiny), + thus less than 1/2^192; + (b) the ignored terms hi*T[i+4] + ... or hi*T[i+5] + ..., + which accumulate to less than ulp(tiny) too, thus + less than 1/2^192. + Thus the approximation error is less than 2^-191 (absolute). + */ + X->ex = 0; + normalize (X); + /* the worst case (for 2^25 <= x < 2^1024) is X->ex = -61, attained + for |x| = 0x1.6ac5b262ca1ffp+851 */ + if (X->ex < 0) // put the upper -ex bits of tiny into low bits of lo + X->lo |= tiny >> (64 + X->ex); + /* Since X->ex >= -61, it means X >= 2^-62 before the normalization, + thus the maximal absolute error of 2^-191 yields a relative error + bounded by 2^-191/2^-62 = 2^-129. + There is an additional truncation error (for tiny) of at most 1 ulp + of X->lo, thus at most 2^-127. + The relative error is thus bounded by 2^-126.67. */ +} + +/* Given Xin:=X with 0 <= Xin < 1, return i and modify X such that + Xin = i/2^11 + Xout, with 0 <= Xout < 2^-11. + This operation is exact. */ +static int +reduce2 (dint64_t *X) +{ + if (X->ex <= -11) + return 0; + int sh = 64 - 11 - X->ex; + int i = X->hi >> sh; + X->hi = X->hi & ((1ull << sh) - 1); + normalize (X); + return i; +} + +/* h+l <- c1/2^64 + c0/2^128 */ +static void +set_dd (double *h, double *l, uint64_t c1, uint64_t c0) +{ + uint64_t e, f, g; + b64u64_u t; + if (c1) + { + e = __builtin_clzll (c1); + if (e) + { + c1 = (c1 << e) | (c0 >> (64 - e)); + c0 = c0 << e; + } + f = 0x3fe - e; + t.u = (f << 52) | ((c1 << 1) >> 12); + *h = t.f; + c0 = (c1 << 53) | (c0 >> 11); + if (c0) + { + g = __builtin_clzll (c0); + if (g) + c0 = c0 << g; + t.u = ((f - 53 - g) << 52) | ((c0 << 1) >> 12); + *l = t.f; + } + else + *l = 0; + } + else if (c0) + { + e = __builtin_clzll (c0); + f = 0x3fe - 64 - e; + c0 = c0 << (e+1); // most significant bit shifted out + /* put the upper 52 bits of c0 into h */ + t.u = (f << 52) | (c0 >> 12); + *h = t.f; + /* put the lower 12 bits of c0 into l */ + c0 = c0 << 52; + if (c0) + { + g = __builtin_clzll (c0); + c0 = c0 << (g+1); + t.u = ((f - 64 - g) << 52) | (c0 >> 12); + *l = t.f; + } + else + *l = 0; + } + else + *h = *l = 0; + /* Since we truncate from two 64-bit words to a double-double, + we have another truncation error of less than 2^-106, thus + the absolute error is bounded as follows: + | h + l - frac(x/(2pi)) | < 2^-75.999 + 2^-106 < 2^-75.998 */ +} + +/* Assuming 0x1.6a09e667f3bccp-27 < x < +Inf, + return i and set h,l such that i/2^11+h+l approximates frac(x/(2pi)). + If x <= 0x1.921fb54442d18p+2: + | i/2^11 + h + l - frac(x/(2pi)) | < 2^-104.116 * |i/2^11 + h + l| + with |h| < 2^-11 and |l| < 2^-52.36. + + Otherwise only the absolute error is bounded: + | i/2^11 + h + l - frac(x/(2pi)) | < 2^-75.998 + with 0 <= h < 2^-11 and |l| < 2^-53. + + In both cases we have |l| < 2^-51.64*|i/2^11 + h|. + + Put in err1 a bound for the absolute error: + | i/2^11 + h + l - frac(x/(2pi)) |. +*/ +static int +reduce_fast (double *h, double *l, double x, double *err1) +{ + if (__builtin_expect(x <= 0x1.921fb54442d17p+2, 1)) // x < 2*pi + { + /* | CH+CL - 1/(2pi) | < 2^-110.523 */ +#define CH 0x1.45f306dc9c883p-3 +#define CL -0x1.6b01ec5417056p-57 + a_mul (h, l, CH, x); // exact + *l = __builtin_fma (CL, x, *l); + /* The error in the above fma() is at most ulp(l), + where |l| <= CL*|x|+|l_in|. + Assume 2^(e-1) <= x < 2^e. + Then |h| < 2^(e-2) and |l_in| <= 1/2 ulp(2^(e-2)) = 2^(e-55), + where l_in is the value of l after a_mul. + Then |l| <= CL*x + 2^(e-55) <= 2^e*(CL+2-55) < 2^e * 2^-55.6. + The rounding error of the fma() is bounded by + ulp(l) <= 2^e * ulp(2^-55.6) = 2^(e-108). + The error due to the approximation of 1/(2pi) + is bounded by 2^-110.523*x <= 2^(e-110.523). + Adding both errors yields: + |h + l - x/(2pi)| < 2^e * (2^-108 + 2^-110.523) < 2^e * 2^-107.768. + Since |x/(2pi)| > 2^(e-1)/(2pi), the relative error is bounded by: + 2^e * 2^-107.768 / (2^(e-1)/(2pi)) = 4pi * 2^-107.768 < 2^-104.116. + + Bound on l: since |h| < 1, we have after |l| <= ulp(h) <= 2^-53 + after a_mul(), and then |l| <= |CL|*0x1.921fb54442d17p+2 + 2^-53 + < 2^-52.36. + + Bound on l relative to h: after a_mul() we have |l| <= ulp(h) + <= 2^-52*h. After fma() we have |l| <= CL*x + 2^-52*h + <= 2^-53.84*CH*x + 2^-52*h <= (2^-53.84+2^-52)*h < 2^-51.64*h. + */ + *err1 = 0x1.d9p-105 * *h; // error < 2^-104.116 * h + } + else // x > 0x1.921fb54442d17p+2 + { + b64u64_u t = {.f = x}; + int e = (t.u >> 52) & 0x7ff; /* 1025 <= e <= 2046 */ + /* We have 2^(e-1023) <= x < 2^(e-1022), thus + ulp(x) is a multiple of 2^(e-1075), for example + if x is just above 2*pi, e=1025, 2^2 <= x < 2^e, + and ulp(x) is a multiple of 2^-50. + On the other side 1/(2pi) ~ T[0]/2^64 + T[1]/2^128 + T[2]/2^192 + ... + Let i be the smallest integer such that 2^(e-1075)/2^(64*(i+1)) + is not an integer, i.e., e - 1139 - 64i < 0, i.e., + i >= (e-1138)/64. */ + uint64_t m = (1ull << 52) | (t.u & 0xfffffffffffffull); + uint64_t c[3]; + u128 u; + // x = m/2^53 * 2^(e-1022) + if (e <= 1074) // 1025 <= e <= 1074: 2^2 <= x < 2^52 + { + /* In that case the contribution of x*T[2]/2^192 is less than + 2^(52+64-192) <= 2^-76. */ + u = (u128) m * (u128) T[1]; + c[0] = u; + c[1] = u >> 64; + u = (u128) m * (u128) T[0]; + c[1] += u; + c[2] = (u >> 64) + (c[1] < (uint64_t) u); + /* | c[2]*2^128+c[1]*2^64+c[0] - m/(2pi)*2^128 | < m*T[2]/2^64 < 2^53 + thus: + | (c[2]*2^128+c[1]*2^64+c[0])*2^(e-1203) - x/(2pi) | < 2^(e-1150) + The low 1075-e bits of c[2] contribute to frac(x/(2pi)). + */ + e = 1075 - e; // 1 <= e <= 50 + // e is the number of low bits of C[2] contributing to frac(x/(2pi)) + } + else // 1075 <= e <= 2046, 2^52 <= x < 2^1024 + { + int i = (e - 1138 + 63) / 64; // i = ceil((e-1138)/64), 0 <= i <= 15 + /* m*T[i] contributes to f = 1139 + 64*i - e bits to frac(x/(2pi)) + with 1 <= f <= 64 + m*T[i+1] contributes a multiple of 2^(-f-64), + and at most to 2^(53-f) + m*T[i+2] contributes a multiple of 2^(-f-128), + and at most to 2^(-11-f) + m*T[i+3] contributes a multiple of 2^(-f-192), + and at most to 2^(-75-f) <= 2^-76 + */ + u = (u128) m * (u128) T[i+2]; + c[0] = u; + c[1] = u >> 64; + u = (u128) m * (u128) T[i+1]; + c[1] += u; + c[2] = (u >> 64) + (c[1] < (uint64_t) u); + u = (u128) m * (u128) T[i]; + c[2] += u; + e = 1139 + (i<<6) - e; // 1 <= e <= 64 + // e is the number of low bits of C[2] contributing to frac(x/(2pi)) + } + if (e == 64) + { + c[0] = c[1]; + c[1] = c[2]; + } + else + { + c[0] = (c[1] << (64 - e)) | c[0] >> e; + c[1] = (c[2] << (64 - e)) | c[1] >> e; + } + /* In all cases the ignored contribution from x*T[2] or x*T[i+3] + is less than 2^-76, + and the truncated part from the above shift is less than 2^-128 thus: + | c[1]/2^64 + c[0]/2^128 - frac(x/(2pi)) | < 2^-76+2^-128 < 2^-75.999 + */ + set_dd (h, l, c[1], c[0]); + /* set_dd() ensures |h| < 1 and |l| < ulp(h) <= 2^-53 */ + *err1 = 0x1.01p-76; + } + + double i = __builtin_floor (*h * 0x1p11); + *h = __builtin_fma (i, -0x1p-11, *h); + return i; +} + +/* Assume x is a regular number and x > 0x1.6a09e667f3bccp-27, + return a bound on the maximal absolute error err: + | h + l - cos(x) | < err */ +static double +cos_fast (double *h, double *l, double x) +{ + int neg = 0, is_cos = 1; + + double err1; + int i = reduce_fast (h, l, x, &err1); + /* err1 is an absolute bound for | i/2^11 + h + l - frac(x/(2pi)) |: + | i/2^11 + h + l - frac(x/(2pi)) | < err1 */ + + // if i >= 2^10: 1/2 <= frac(x/(2pi)) < 1 thus pi <= x <= 2pi + // we use cos(pi+x) = -cos(x) + neg = neg ^ (i >> 10); + i = i & 0x3ff; + // | i/2^11 + h + l - frac(x/(2pi)) | mod 1/2 < err1 + + // now i < 2^10 + // if i >= 2^9: 1/4 <= frac(x/(2pi)) < 1/2 thus pi/2 <= x <= pi + // we use cos(pi/2+x) = -sin(x) + is_cos = is_cos ^ (i >> 9); + neg = neg ^ (i >> 9); + i = i & 0x1ff; + // | i/2^11 + h + l - frac(x/(2pi)) | mod 1/4 < err1 + + // now 0 <= i < 2^9 + // if i >= 2^8: 1/8 <= frac(x/(2pi)) < 1/4 + // we use cos(pi/2-x) = sin(x) + if (i & 0x100) // case pi/4 <= x_red <= pi/2 + { + is_cos = !is_cos; + i = 0x1ff - i; + /* 0x1p-11 - h is exact below: indeed, reduce_fast first computes + a first value of h (say h0, with 0 <= h0 < 1), then i = floor(h0*2^11) + and h1 = h0 - 2^11*i with 0 <= h1 < 2^-11. + If i >= 2^8 here, this implies h0 >= 1/2^3, thus ulp(h0) >= 2^-55: + h0 and h1 are integer multiples of 2^-55. + Thus h1 = k*2^-55 with 0 <= k < 2^44 (since 0 <= h1 < 2^-11). + Then 0x1p-11 - h = (2^44-k)*2^-55 is exactly representable. + We can have a huge cancellation in 0x1p-11 - h, for example for + x = 0x1.61a3db8c8d129p+1023 where we have before this operation + h = 0x1.ffffffffff8p-12, and h = 0x1p-53 afterwards. But this + does not hurt since we bound the absolute error and not the + relative error at the end. */ + *h = 0x1p-11 - *h; + *l = -*l; + } + + /* Now 0 <= i < 256 and 0 <= h+l < 2^-11 + with | i/2^11 + h + l - frac(x/(2pi)) | cmod 1/4 < err1 + If is_cos=1, cos(x) = cos2pi(R + err1); + if is_cos=0, cos(x) = sin2pi (R + err1). + In both cases R = i/2^11 + h + l, 0 <= R < 1/4. + */ + double sh, sl, ch, cl; + /* since the SC[] table evaluates at i/2^11 + SC[i][0] and not at i/2^11, + we must subtract SC[i][0] from h+l */ + /* Here h = k*2^-55 with 0 <= k < 2^44, and SC[i][0] is an integer + multiple of 2^-62, with |SC[i][0]| < 2^-24, thus SC[i][0] = m*2^-62 + with |m| < 2^38. It follows h-SC[i][0] = (k*2^7 + m)*2^-62 with + 2^51 - 2^38 < k*2^7 + m < 2^51 + 2^38, thus h-SC[i][0] is exact. + Now |h| < 2^-11 + 2^-24. */ + *h -= SC[i][0]; + // now -2^-24 < h < 2^-11+2^-24 + // from reduce_fast() we have |l| < 2^-52.36 + double uh, ul; + a_mul (&uh, &ul, *h, *h); + ul = __builtin_fma (*h + *h, *l, ul); + // uh+ul approximates (h+l)^2 + evalPSfast (&sh, &sl, *h, *l, uh, ul); + /* the absolute error of evalPSfast() is less than 2^-77.09 from + routine evalPSfast() in sin.sage: + | sh + sh - sin(h+l) | < 2^-77.09 */ + evalPCfast (&ch, &cl, uh, ul); + /* the relative error of evalPCfast() is less than 2^-69.96 from + routine evalPCfast(rel=true) in sin.sage: + | ch + cl - cos(h+l) | < 2^-69.96 * |ch + cl| */ + double err; + if (!is_cos) + { + s_mul (&sh, &sl, SC[i][2], sh, sl); + s_mul (&ch, &cl, SC[i][1], ch, cl); + fast_two_sum (h, l, ch, sh); + *l += sl + cl; + /* absolute error bounded by 2^-68.588 + from global_error(is_sin=true,rel=false) in sin.sage: + | h + l - sin2pi (R) | < 2^-68.588 + thus: + | h + l - cos(x) | < 2^-68.588 + | sin2pi (R) - sin |x| | + < 2^-68.588 + err1 */ + err = 0x1.55p-69; // 2^-66.588 < 0x1.55p-69 + } + else + { + s_mul (&ch, &cl, SC[i][2], ch, cl); + s_mul (&sh, &sl, SC[i][1], sh, sl); + fast_two_sum (h, l, ch, -sh); + *l += cl - sl; + /* absolute error bounded by 2^-68.414 + from global_error(is_sin=false,rel=false) in sin.sage: + | h + l - cos2pi (R) | < 2^-68.414 + thus: + | h + l - cos(x) | < 2^-68.414 + | cos2pi (R) - sin |x| | + < 2^-68.414 * |h + l| + err1 */ + err = 0x1.81p-69; // 2^-68.414 < 0x1.81p-69 + } + static const double sgn[2] = {1.0, -1.0}; + *h *= sgn[neg]; + *l *= sgn[neg]; + return err + err1; +} + +/* Assume x is a regular number and x > 0x1.6a09e667f3bccp-27. */ +__attribute__((cold)) +static double +cos_accurate (double x) +{ + dint64_t X[1]; + dint_fromd (X, x); + + /* reduce argument */ + reduce (X); + + // now |X - x/(2pi) mod 1| < 2^-126.67*X, with 0 <= X < 1. + + int neg = 0, is_cos = 1; + + // Write X = i/2^11 + r with 0 <= r < 2^11. + int i = reduce2 (X); // exact + + if (i & 0x400) // pi <= x < 2*pi: cos(x) = -cos(x-pi) + { + neg = 1; + i = i & 0x3ff; + } + + // now i < 2^10 + + if (i & 0x200) // pi/2 <= x < pi: cos(x) = -sin(x-pi/2) + { + neg = !neg; + is_cos = 0; + i = i & 0x1ff; + } + + // now 0 <= i < 2^9 + + if (i & 0x100) + // pi/4 <= x < pi/2: cos(x) = sin(pi/2-x), sin(x) = cos(pi/2-x) + { + is_cos = !is_cos; + X->sgn = 1; // negate X + add_dint (X, &MAGIC, X); // X -> 2^-11 - X + // here: 256 <= i <= 511 + i = 0x1ff - i; + // now 0 <= i < 256 + } + + // now 0 <= i < 256 and 0 <= X < 2^-11 + + /* If is_cos=1, cos |x| = cos2pi (R * (1 + eps)) + (cases 0 <= x < pi/4 and 3pi/4 <= x < pi) + if is_cos=0, cos |x| = sin2pi (R * (1 + eps)) + (case pi/4 <= x < 3pi/4) + In both cases R = i/2^11 + X, 0 <= R < 1/4, and |eps| < 2^-126.67. + */ + + dint64_t U[1], V[1], X2[1]; + mul_dint (X2, X, X); // X2 approximates X^2 + evalPC (U, X2); // cos2pi(X) + /* since 0 <= X < 2^-11, we have 0.999 < U <= 1 */ + evalPS (V, X, X2); // sin2pi(X) + /* since 0 <= X < 2^-11, we have 0 <= V < 0.0005 */ + if (!is_cos) + { + // sin2pi(R) ~ sin2pi(i/2^11)*cos2pi(X)+cos2pi(i/2^11)*sin2pi(X) + mul_dint (U, S+i, U); + /* since 0 <= S[i] < 0.705 and 0.999 < Uin <= 1, we have + 0 <= U < 0.705 */ + mul_dint (V, C+i, V); + /* For the error analysis, we distinguish the case i=0. + For i=0, we have S[i]=0 and C[1]=1, thus V is the value computed + by evalPS() above, with relative error < 2^-124.648. + + For 1 <= i < 256, analyze_sin_case1(rel=true) from sin.sage gives a + relative error bound of -122.797 (obtained for i=1). + In all cases, the relative error for the computation of + sin2pi(i/2^11)*cos2pi(X)+cos2pi(i/2^11)*sin2pi(X) is bounded by -122.797 + not taking into account the approximation error in R: + |U - sin2pi(R)| < |U| * 2^-122.797, with U the value computed + after add_dint (U, U, V) below. + + For the approximation error in R, we have: + cos(x) = sin2pi (R * (1 + eps)) + R = i/2^11 + X, 0 <= R < 1/4, and |eps| < 2^-126.67. + Thus cos(x) = sin2pi(R+R*eps) + = sin2pi(R)+R*eps*2*pi*cos2pi(theta), theta in [R,R+R*eps] + Since 2*pi*R/sin(2*pi*R) < pi/2 for R < 1/4, it follows: + | cos(x) - sin2pi(R) | < pi/2*R*|sin(2*pi*R)| + | cos(x) - sin2pi(R) | < 2^-126.018 * |sin2pi(R)|. + + Adding both errors we get: + | cos(x) - U | < |U| * 2^-122.797 + 2^-126.018 * |sin2pi(R)| + < |U| * 2^-122.797 + 2^-126.018 * |U| * (1 + 2^-122.797) + < |U| * 2^-122.650. + */ + } + else + { + // cos2pi(R) ~ cos2pi(i/2^11)*cos2pi(X)-sin2pi(i/2^11)*sin2pi(X) + mul_dint (U, C+i, U); + mul_dint (V, S+i, V); + V->sgn = 1 - V->sgn; // negate V + /* For 0 <= i < 256, analyze_sin_case2(rel=true) from sin.sage gives a + relative error bound of -123.540 (obtained for i=0): + |U - cos2pi(R)| < |U| * 2^-123.540, with U the value computed + after add_dint (U, U, V) below. + + For the approximation error in R, we have: + cos(x) = cos2pi (R * (1 + eps)) + R = i/2^11 + X, 0 <= R < 1/4, and |eps| < 2^-126.67. + Thus cos(x) = cos2pi(R+R*eps) + = cos2pi(R)-R*eps*2*pi*sin2pi(theta), theta in [R,R+R*eps] + Since we have R < 1/4, we have cos2pi(R) >= sqrt(2)/2, + and it follows: + | cos(x)/cos2pi(R) - 1 | < 2*pi*R*eps/(sqrt(2)/2) + < pi/2*eps/sqrt(2) [since R < 1/4] + < 2^-126.518. + Adding both errors we get: + | cos(x) - U | < |U| * 2^-123.540 + 2^-126.518 * |cos2pi(R)| + < |U| * 2^-123.540 + 2^-126.518 * |U| * (1 + 2^-123.540) + < |U| * 2^-123.367. + */ + } + add_dint (U, U, V); + /* If is_cos=0: + | cos(x) - U | < |U| * 2^-122.650 + If is_cos=1: + | cos(x) - U | < |U| * 2^-123.367. + In all cases the total error is bounded by |U| * 2^-122.650. + The term |U| * 2^-122.650 contributes to at most 2^(128-122.650) < 41 ulps + relatively to U->lo. + */ + uint64_t err = 41; + uint64_t hi0, hi1, lo0, lo1; + lo0 = U->lo - err; + hi0 = U->hi - (lo0 > U->lo); + lo1 = U->lo + err; + hi1 = U->hi + (lo1 < U->lo); + /* check the upper 54 bits are equal */ + if ((hi0 >> 10) != (hi1 >> 10)) + { + static const double exceptions[][3] = { + {0x1.8000000000009p-23, 0x1.fffffffffff7p-1, 0x1.b56666666666cp-143}, + {0x1.8000000000024p-22, 0x1.ffffffffffdcp-1, 0x1.b56666666667ep-137}, + {0x1.800000000009p-21, 0x1.ffffffffff7p-1, 0x1.b5666666666c4p-131}, + {0x1.20000000000f3p-20, 0x1.fffffffffebcp-1, 0x1.37642666666fdp-127}, + {0x1.800000000024p-20, 0x1.fffffffffdcp-1, 0x1.b5666666667ddp-125}, + }; + for (int k = 0; k < 5; k++) + { + if (__builtin_fabs (x) == exceptions[k][0]) + return exceptions[k][1] + exceptions[k][2]; + } + /* if we go here, we have a hard-to-round case, but since all hard-to-round + cases are known and pass all tests, we are ok */ + } + + if (neg) + U->sgn = 1 - U->sgn; + + double y = dint_tod (U); + + return y; +} + +double +cr_cos (double x) +{ + b64u64_u t = {.f = x}; + int e = (t.u >> 52) & 0x7ff; + + if (__builtin_expect (e == 0x7ff, 0)) /* NaN, +Inf and -Inf. */ + { +#ifdef CORE_MATH_SUPPORT_ERRNO + if ((t.u << 1) == 0x7ffull<<53) // Inf + errno = EDOM; +#endif + if ((t.u << 1) == 0x7ffull<<53) // Inf + return 0.0 / 0.0; // raise invalid flag + return x + x; // return qNaN + } + + /* now x is a regular number */ + + /* For |x| <= 0x1.6a09e667f3bccp-27, cos(x) rounds to x (to nearest): + we can assume x >= 0 without loss of generality since cos(-x) = cos(x), + we have 1 - x^2/2 < cos(x) < 1 for say 0 < x <= 1 thus + |cos(x) - 1| < x^2/2. + Assume 0 < x < 1, and write x = c*2^e with 1/2 <= c < 1. + For 0 < x < 1, 1/2 < cos(x) < 1, thus ulp(cos(x)) = 2^-53, + and x^2/2 = c^2/2*2^(2e), thus + x^2/2 < ulp(cos(x))/2 rewrites as c^2/2*2^(2e) < 2^-54, + or c^2*2^(2e+53) < 1 (1). + For e <= -27, since c^2 < 1, we have c^2*2^(2e+53) < 1/2 < 1. + For e=-26, (1) rewrites c^2*2 < 1 which yields c <= 0x1.6a09e667f3bccp-1. + */ + t.u &= 0x7fffffffffffffff; + if (__builtin_expect (t.u <= 0x3e46a09e667f3bcc, 0)) + // |x| <= 0x1.6a09e667f3bccp-27 + return __builtin_fma (t.f, -0x1p-28, 1.0); + + double h, l, err; + err = cos_fast (&h, &l, t.f); + double left = h + (l - err), right = h + (l + err); + /* With SC[] from ./buildSC 15 we get 1100 failures out of 50000000 + random tests, i.e., about 0.002%. */ + if (__builtin_expect (left == right, 1)) + return left; + + return cos_accurate (t.f); +} diff --git a/growlibm/accelerators/cosquot.c b/growlibm/accelerators/cosquot.c new file mode 100644 index 0000000000..c658429cba --- /dev/null +++ b/growlibm/accelerators/cosquot.c @@ -0,0 +1,794 @@ +#include +#include +#include +#include + +typedef struct { + double hi; + double lo; +} dd_t; + +static inline void sincos_wrapper(double x, double *s, double *c) { +#if defined(__APPLE__) + __sincos(x, s, c); +#else + sincos(x, s, c); +#endif +} + +static inline dd_t dd_make(double hi, double lo) { + double s = hi + lo; + double e = lo - (s - hi); + dd_t out = {s, e}; + return out; +} + +static inline dd_t dd_from_double(double x) { + dd_t out = {x, 0.0}; + return out; +} + +static inline void two_sum(double a, double b, double *s, double *e) { + *s = a + b; + { + double bb = *s - a; + *e = (a - (*s - bb)) + (b - bb); + } +} + +static inline void two_prod(double a, double b, double *p, double *e) { + *p = a * b; + *e = fma(a, b, -*p); +} + +static inline dd_t dd_add(dd_t a, dd_t b) { + double s, e, t; + two_sum(a.hi, b.hi, &s, &e); + t = e + a.lo + b.lo; + return dd_make(s, t); +} + +static inline dd_t dd_add_d(dd_t a, double b) { + double s, e; + two_sum(a.hi, b, &s, &e); + return dd_make(s, e + a.lo); +} + +static inline dd_t dd_sub(dd_t a, dd_t b) { + dd_t nb = {-b.hi, -b.lo}; + return dd_add(a, nb); +} + +static inline dd_t dd_mul_d(dd_t a, double b) { + double p, e; + two_prod(a.hi, b, &p, &e); + e += a.lo * b; + return dd_make(p, e); +} + +static inline dd_t dd_div_d(dd_t a, double b) { + double q1, q2, q3; + dd_t q, r; + + q1 = a.hi / b; + q = dd_from_double(q1); + + r = dd_sub(a, dd_mul_d(q, b)); + q2 = r.hi / b; + q = dd_add_d(q, q2); + + r = dd_sub(a, dd_mul_d(q, b)); + q3 = r.hi / b; + q = dd_add_d(q, q3); + + return q; +} + +/* 3.243F6A8885A3... in base 2^16 limbs. */ +static const uint16_t PI_LIMBS[] = { + 0x0003, + 0x243F, + 0x6A88, + 0x85A3, + 0x08D3, + 0x1319, + 0x8A2E, + 0x0370, + 0x7344, + 0xA409, + 0x3822, + 0x299F, + 0x31D0, + 0x082E, + 0xFA98, + 0xEC4E, + 0x6C89, + 0x4528, + 0x21E6, + 0x38D0, + 0x1377, + 0xBE54, + 0x66CF, + 0x34E9, + 0x0C6C, + 0xC0AC, + 0x29B7, + 0xC97C, + 0x50DD, + 0x3F84, + 0xD5B5, + 0xB547, + 0x0917, + 0x9216, + 0xD5D9, + 0x8979, + 0xFB1B, + 0xD131, + 0x0BA6, + 0x98DF, + 0xB5AC, + 0x2FFD, + 0x72DB, + 0xD01A, + 0xDFB7, + 0xB8E1, + 0xAFED, + 0x6A26, + 0x7E96, + 0xBA7C, + 0x9045, + 0xF12C, + 0x7F99, + 0x24A1, + 0x9947, + 0xB391, + 0x6CF7, + 0x0801, + 0xF2E2, + 0x858E, + 0xFC16, + 0x6369, + 0x20D8, + 0x7157, + 0x4E69, + 0xA458, + 0xFEA3, + 0xF493, + 0x3D7E, + 0x0D95, + 0x748F, + 0x728E, + 0xB658, + 0x718B, + 0xCD58, + 0x8215, + 0x4AEE, + 0x7B54, + 0xA41D, + 0xC25A, + 0x59B5, + 0x9C30, + 0xD539, + 0x2AF2, + 0x6013, + 0xC5D1, + 0xB023, + 0x2860, + 0x85F0, + 0xCA41, + 0x7918, + 0xB8DB, + 0x38EF, + 0x8E79, + 0xDCB0, + 0x603A, + 0x180E, + 0x6C9E, + 0x0E8B, + 0xB01E, + 0x8A3E, + 0xD715, + 0x77C1, + 0xBD31, + 0x4B27, + 0x78AF, + 0x2FDA, + 0x5560, + 0x5C60, + 0xE655, + 0x25F3, + 0xAA55, + 0xAB94, + 0x5748, + 0x9862, + 0x63E8, + 0x1440, + 0x55CA, + 0x396A, + 0x2AAB, + 0x10B6, + 0xB4CC, + 0x5C34, + 0x1141, + 0xE8CE, + 0xA154, + 0x86AF, + 0x7C72, + 0xE993, + 0xB3EE, + 0x1411, + 0x636F, + 0xBC2A, + 0x2BA9, + 0xC55D, + 0x7418, + 0x31F6, + 0xCE5C, + 0x3E16, + 0x9B87, + 0x931E, + 0xAFD6, + 0xBA33, + 0x6C24, + 0xCF5C, + 0x7A32, + 0x5381, + 0x2895, + 0x8677, + 0x3B8F, + 0x4898, + 0x6B4B, + 0xB9AF, + 0xC4BF, + 0xE81B, + 0x6628, + 0x2193, + 0x61D8, + 0x09CC, + 0xFB21, + 0xA991, + 0x487C, + 0xAC60, + 0x5DEC, + 0x8032, + 0xEF84, + 0x5D5D, + 0xE985, + 0x75B1, + 0xDC26}; + +/* 2/pi = 0.A2F9836E4E44... in base 2^16 limbs. */ +static const uint16_t TWO_OVER_PI_LIMBS[] = { + 0xA2F9, + 0x836E, + 0x4E44, + 0x1529, + 0xFC27, + 0x57D1, + 0xF534, + 0xDDC0, + 0xDB62, + 0x9599, + 0x3C43, + 0x9041, + 0xFE51, + 0x63AB, + 0xDEBB, + 0xC561, + 0xB724, + 0x6E3A, + 0x424D, + 0xD2E0, + 0x0649, + 0x2EEA, + 0x09D1, + 0x921C, + 0xFE1D, + 0xEB1C, + 0xB129, + 0xA73E, + 0xE882, + 0x35F5, + 0x2EBB, + 0x4484, + 0xE99C, + 0x7026, + 0xB45F, + 0x7E41, + 0x3991, + 0xD639, + 0x8353, + 0x39F4, + 0x9C84, + 0x5F8B, + 0xBDF9, + 0x283B, + 0x1FF8, + 0x97FF, + 0xDE05, + 0x980F, + 0xEF2F, + 0x118B, + 0x5A0A, + 0x6D1F, + 0x6D36, + 0x7ECF, + 0x27CB, + 0x09B7, + 0x4F46, + 0x3F66, + 0x9E5F, + 0xEA2D, + 0x7527, + 0xBAC7, + 0xEBE5, + 0xF17B, + 0x3D07, + 0x39F7, + 0x8A52, + 0x92EA, + 0x6BFB, + 0x5FB1, + 0x1F8D, + 0x5D08, + 0x5603, + 0x3046, + 0xFC7B, + 0x6BAB, + 0xF0CF, + 0xBC20, + 0x9AF4, + 0x361D, + 0xA9E3, + 0x9161, + 0x5EE6, + 0x1B08, + 0x6599, + 0x855F, + 0x14A0, + 0x6840, + 0x8DFF, + 0xD880, + 0x4D73, + 0x2731, + 0x0606, + 0x1556, + 0xCA73, + 0xA8C9, + 0x60E2, + 0x7BC0, + 0x8C6B, + 0x47C4, + 0x19C3, + 0x67CD, + 0xDCE8, + 0x092A, + 0x8359, + 0xC476, + 0x8B96, + 0x1CA6, + 0xDDAF, + 0x44D1, + 0x5719, + 0x053E, + 0xA5FF, + 0x0705, + 0x3F7E, + 0x33E8, + 0x32C2, + 0xDE4F, + 0x9832, + 0x7DBB, + 0xC33D, + 0x26EF, + 0x6B1E, + 0x5EF8, + 0x9F3A, + 0x1F35, + 0xCAF2, + 0x7F1D, + 0x87F1, + 0x2190, + 0x7C7C, + 0x246A, + 0xFA6E, + 0xD577, + 0x2D30, + 0x433B, + 0x15C6, + 0x14B5, + 0x9D19, + 0xC3C2, + 0xC4AD, + 0x414D, + 0x2C5D, + 0x000C, + 0x467D, + 0x862D, + 0x71E3, + 0x9AC6, + 0x9B00, + 0x6233, + 0x7CD2, + 0xB497, + 0xA7B4, + 0xD555, + 0x37F6, + 0x3ED7, + 0x1810, + 0xA3FC, + 0x764D, + 0x2A9D, + 0x64AB, + 0xD770, + 0xF87C, + 0x6357, + 0xB07A, + 0xE715, + 0x1756, + 0x49C0, + 0xD9D6, + 0x3B38}; +enum { N_PI_LIMBS = (int)(sizeof(PI_LIMBS) / sizeof(PI_LIMBS[0])) }; + +typedef struct { + double y_hi; + double y_lo; +} ypi_stream_t; + +#define EXP_CAP 1024 + +/* + * Split a into hi + lo with <= 32 mantissa bits in hi and <= 21 in lo. + * This keeps y_part * limb (limb < 2^16) exact in double. + */ +static void split_32(double a, double *hi, double *lo) { + if (!isfinite(a) || a == 0.0) { + *hi = a; + *lo = 0.0; + return; + } + + { + int exp2; + double m = frexp(a, &exp2); + double sigd = ldexp(fabs(m), 53); + uint64_t sig = (uint64_t)nearbyint(sigd); + uint64_t hi_sig; + double hi_m; + + if (sig == (1ULL << 53)) { + sig >>= 1; + exp2 += 1; + } + + hi_sig = sig & ~((1ULL << 21) - 1ULL); + hi_m = ldexp((double)hi_sig, -53); + if (m < 0.0) hi_m = -hi_m; + + *hi = ldexp(hi_m, exp2); + *lo = a - *hi; + } +} + +static void build_y_pi_stream(double y, ypi_stream_t *stream) { + split_32(y, &stream->y_hi, &stream->y_lo); +} + +/* Shewchuk-style expansion grow: exact add of one scalar into an expansion. */ +static int grow_expansion_zeroelim(int elen, const double *e, double b, double *h) { + double Q = b; + int hlen = 0; + int i; + + for (i = 0; i < elen; ++i) { + double sum, hh; + two_sum(Q, e[i], &sum, &hh); + if (hh != 0.0) { + if (hlen < EXP_CAP) h[hlen++] = hh; + } + Q = sum; + } + + if (Q != 0.0 || hlen == 0) { + if (hlen < EXP_CAP) { + h[hlen++] = Q; + } else { + h[EXP_CAP - 1] = Q; + hlen = EXP_CAP; + } + } + + return hlen; +} + +static int expansion_add_terms_signed(int len, + double *exp, + int nterms, + const double *terms, + double sign, + double *scratch) { + double *cur = exp; + double *next = scratch; + int i; + + for (i = 0; i < nterms; ++i) { + double *tmp; + len = grow_expansion_zeroelim(len, cur, sign * terms[i], next); + tmp = cur; + cur = next; + next = tmp; + } + + if (cur != exp) { + memcpy(exp, cur, (size_t)len * sizeof(double)); + } + + return len; +} + +static int expansion_sign(int len, const double *exp) { + int i; + for (i = len - 1; i >= 0; --i) { + if (exp[i] > 0.0) return 1; + if (exp[i] < 0.0) return -1; + } + return 0; +} + +static int expansion_is_finite(int len, const double *exp) { + int i; + for (i = 0; i < len; ++i) { + if (!isfinite(exp[i])) return 0; + } + return 1; +} + +static dd_t expansion_to_dd(int len, const double *exp) { + dd_t acc = dd_from_double(0.0); + int i; + for (i = len - 1; i >= 0; --i) { + acc = dd_add_d(acc, exp[i]); + } + return acc; +} + +/* + * Build y*pi*2^shift as an expansion by alternating hi/lo streams from + * smallest to largest term. + */ +static int build_candidate_expansion(const ypi_stream_t *stream, + int shift, + double *cand, + double *scratch) { + double *cur = cand; + double *next = scratch; + int len = 1; + int n = N_PI_LIMBS; + int i; + cur[0] = 0.0; + + for (i = n - 1; i >= 0; --i) { + int e = shift - 16 * i; + double limb = (double)PI_LIMBS[i]; + double t_hi = ldexp(stream->y_hi, e) * limb; + double t_lo = ldexp(stream->y_lo, e) * limb; + double *tmp; + + len = grow_expansion_zeroelim(len, cur, t_hi, next); + tmp = cur; + cur = next; + next = tmp; + + len = grow_expansion_zeroelim(len, cur, t_lo, next); + tmp = cur; + cur = next; + next = tmp; + } + + if (cur != cand) { + memcpy(cand, cur, (size_t)len * sizeof(double)); + } + + return len; +} + +typedef struct { + dd_t remainder; + int quotient_mod2; +} reduce_out_t; + +static reduce_out_t hp_reduce_x_mod_y_pi(double ax, const ypi_stream_t *stream) { + reduce_out_t out; + double rem[EXP_CAP], cand[EXP_CAP], diff[EXP_CAP], mod[EXP_CAP], scratch[EXP_CAP]; + int rem_len = 1; + int mod_len; + dd_t mod_dd; + int shift; + int i; + + out.remainder = dd_from_double(NAN); + out.quotient_mod2 = 0; + + rem[0] = ax; + mod_len = build_candidate_expansion(stream, 0, mod, scratch); + if (!expansion_is_finite(mod_len, mod)) return out; + + mod_dd = expansion_to_dd(mod_len, mod); + if (!(mod_dd.hi > 0.0) || !isfinite(mod_dd.hi)) return out; + + /* + * Since ax/mod_dd.hi differs from the exact quotient by less than a factor + * of two, the exponent gap is already a safe upper bound on the top quotient + * bit. That is enough to seed the binary subtraction loop. + */ + shift = ilogb(ax) - ilogb(mod_dd.hi); + if (shift < 0) shift = 0; + + while (shift > 0) { + int probe_len = build_candidate_expansion(stream, shift, cand, scratch); + if (expansion_is_finite(probe_len, cand)) break; + --shift; + } + + for (i = shift; i >= 0; --i) { + int cand_len = build_candidate_expansion(stream, i, cand, scratch); + int diff_len; + + if (!expansion_is_finite(cand_len, cand)) continue; + + memcpy(diff, rem, (size_t)rem_len * sizeof(double)); + diff_len = rem_len; + diff_len = expansion_add_terms_signed(diff_len, diff, cand_len, cand, -1.0, scratch); + + if (expansion_sign(diff_len, diff) >= 0) { + rem_len = diff_len; + memcpy(rem, diff, (size_t)rem_len * sizeof(double)); + if (i == 0) out.quotient_mod2 ^= 1; + } + } + + for (;;) { + int diff_len; + memcpy(diff, rem, (size_t)rem_len * sizeof(double)); + diff_len = rem_len; + diff_len = expansion_add_terms_signed(diff_len, diff, mod_len, mod, -1.0, scratch); + if (expansion_sign(diff_len, diff) < 0) break; + rem_len = diff_len; + memcpy(rem, diff, (size_t)rem_len * sizeof(double)); + out.quotient_mod2 ^= 1; + } + + if (expansion_sign(rem_len, rem) < 0) { + rem_len = expansion_add_terms_signed(rem_len, rem, mod_len, mod, 1.0, scratch); + out.quotient_mod2 ^= 1; + } + + out.remainder = expansion_to_dd(rem_len, rem); + return out; +} + +/* + * Public reduction helper for future sin/tan variants. + * Returns 0 on success. + */ +int reduce_x_mod_y_pi(double x, double y, double *r_hi, double *r_lo, int *quotient_mod2) { + const double pi_hi = 3.14159265358979323846264338327950288; + double ax, ay; + ypi_stream_t stream; + reduce_out_t red; + + if (r_hi == 0 || r_lo == 0 || quotient_mod2 == 0) return -1; + if (!isfinite(x) || !isfinite(y) || y == 0.0) return -1; + + ax = fabs(x); + ay = fabs(y); + + if (ax == 0.0) { + *r_hi = 0.0; + *r_lo = 0.0; + *quotient_mod2 = 0; + return 0; + } + + if (isinf(ay)) { + *r_hi = 0.0; + *r_lo = 0.0; + *quotient_mod2 = 0; + return 0; + } + + /* If y*pi is guaranteed above all finite x, quotient is zero. */ + if (ay > DBL_MAX / pi_hi) { + *r_hi = ax; + *r_lo = 0.0; + *quotient_mod2 = 0; + return 0; + } + + build_y_pi_stream(ay, &stream); + red = hp_reduce_x_mod_y_pi(ax, &stream); + + if (!isfinite(red.remainder.hi)) return -1; + + *r_hi = red.remainder.hi; + *r_lo = red.remainder.lo; + *quotient_mod2 = red.quotient_mod2 & 1; + return 0; +} + +/* Optional helper: directly return (x/y) mod pi in double-double chunks. */ +int reduce_x_over_y_mod_pi(double x, double y, double *z_hi, double *z_lo, int *quotient_mod2) { + double r_hi, r_lo; + dd_t z; + + if (z_hi == 0 || z_lo == 0 || quotient_mod2 == 0) return -1; + if (reduce_x_mod_y_pi(x, y, &r_hi, &r_lo, quotient_mod2) != 0) return -1; + + z = dd_div_d(dd_make(r_hi, r_lo), fabs(y)); + *z_hi = z.hi; + *z_lo = z.lo; + return 0; +} + +static double cos_dd(dd_t z) { + double sh, ch, sl, cl; + sincos_wrapper(z.hi, &sh, &ch); + sincos_wrapper(z.lo, &sl, &cl); + return fma(-sh, sl, ch * cl); +} + +static double sin_dd(dd_t z) { + double sh, ch, sl, cl; + sincos_wrapper(z.hi, &sh, &ch); + sincos_wrapper(z.lo, &sl, &cl); + return fma(sh, cl, ch * sl); +} + +/* + * Compute sin(x/y) using x mod (y*pi) reduction, then divide by y in dd. + */ +double sinquot(double x, double y) { + double z_hi, z_lo; + int qmod2; + int neg; + dd_t z; + double out; + + if (isnan(x) || isnan(y)) return NAN; + if (y == 0.0) return NAN; + if (isinf(x)) return NAN; + if (x == 0.0 || isinf(y)) return x / y; + + if (reduce_x_over_y_mod_pi(x, y, &z_hi, &z_lo, &qmod2) != 0) return NAN; + + z = dd_make(z_hi, z_lo); + out = sin_dd(z); + neg = signbit(x) ^ signbit(y); + if (qmod2) out = -out; + if (neg) out = -out; + return out; +} + +/* + * Compute cos(x/y) using x mod (y*pi) reduction, then divide by y in dd. + */ +double cosquot(double x, double y) { + double z_hi, z_lo; + int qmod2; + dd_t z; + double out; + + if (isnan(x) || isnan(y)) return NAN; + if (y == 0.0) return NAN; + if (isinf(x)) return NAN; + if (isinf(y)) return 1.0; + if (x == 0.0) return 1.0; + + if (reduce_x_over_y_mod_pi(x, y, &z_hi, &z_lo, &qmod2) != 0) return NAN; + + z = dd_make(z_hi, z_lo); + out = cos_dd(z); + if (qmod2) out = -out; + return out; +} diff --git a/growlibm/accelerators/e_rem_pio2.c b/growlibm/accelerators/e_rem_pio2.c new file mode 100644 index 0000000000..7242bb232b --- /dev/null +++ b/growlibm/accelerators/e_rem_pio2.c @@ -0,0 +1,175 @@ + +/* @(#)e_rem_pio2.c 1.4 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ + +/* __ieee754_rem_pio2(x,y) + * + * return the remainder of x rem pi/2 in y[0]+y[1] + * use __kernel_rem_pio2() + */ + +#include "fdlibm.h" + +/* + * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi + */ +#ifdef __STDC__ +static const int two_over_pi[] = { +#else +static int two_over_pi[] = { +#endif +0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, +0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, +0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, +0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, +0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, +0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, +0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, +0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, +0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, +0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, +0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, +}; + +#ifdef __STDC__ +static const int npio2_hw[] = { +#else +static int npio2_hw[] = { +#endif +0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C, +0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C, +0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A, +0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C, +0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB, +0x404858EB, 0x404921FB, +}; + +/* + * invpio2: 53 bits of 2/pi + * pio2_1: first 33 bit of pi/2 + * pio2_1t: pi/2 - pio2_1 + * pio2_2: second 33 bit of pi/2 + * pio2_2t: pi/2 - (pio2_1+pio2_2) + * pio2_3: third 33 bit of pi/2 + * pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3) + */ + +#ifdef __STDC__ +static const double +#else +static double +#endif +zero = 0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */ +half = 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */ +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ +pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ +pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ +pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */ +pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */ +pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */ +pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */ + +#ifdef __STDC__ + int __ieee754_rem_pio2(double x, double *y) +#else + int __ieee754_rem_pio2(x,y) + double x,y[]; +#endif +{ + double z,w,t,r,fn; + double tx[3]; + int e0,i,j,nx,n,ix,hx; + + hx = __HI(x); /* high word of x */ + ix = hx&0x7fffffff; + if(ix<=0x3fe921fb) /* |x| ~<= pi/4 , no need for reduction */ + {y[0] = x; y[1] = 0; return 0;} + if(ix<0x4002d97c) { /* |x| < 3pi/4, special case with n=+-1 */ + if(hx>0) { + z = x - pio2_1; + if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ + y[0] = z - pio2_1t; + y[1] = (z-y[0])-pio2_1t; + } else { /* near pi/2, use 33+33+53 bit pi */ + z -= pio2_2; + y[0] = z - pio2_2t; + y[1] = (z-y[0])-pio2_2t; + } + return 1; + } else { /* negative x */ + z = x + pio2_1; + if(ix!=0x3ff921fb) { /* 33+53 bit pi is good enough */ + y[0] = z + pio2_1t; + y[1] = (z-y[0])+pio2_1t; + } else { /* near pi/2, use 33+33+53 bit pi */ + z += pio2_2; + y[0] = z + pio2_2t; + y[1] = (z-y[0])+pio2_2t; + } + return -1; + } + } + if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */ + t = fabs(x); + n = (int) (t*invpio2+half); + fn = (double)n; + r = t-fn*pio2_1; + w = fn*pio2_1t; /* 1st round good to 85 bit */ + if(n<32&&ix!=npio2_hw[n-1]) { + y[0] = r-w; /* quick check no cancellation */ + } else { + j = ix>>20; + y[0] = r-w; + i = j-(((__HI(y[0]))>>20)&0x7ff); + if(i>16) { /* 2nd iteration needed, good to 118 */ + t = r; + w = fn*pio2_2; + r = t-w; + w = fn*pio2_2t-((t-r)-w); + y[0] = r-w; + i = j-(((__HI(y[0]))>>20)&0x7ff); + if(i>49) { /* 3rd iteration need, 151 bits acc */ + t = r; /* will cover all possible cases */ + w = fn*pio2_3; + r = t-w; + w = fn*pio2_3t-((t-r)-w); + y[0] = r-w; + } + } + } + y[1] = (r-y[0])-w; + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + else return n; + } + /* + * all other (large) arguments + */ + if(ix>=0x7ff00000) { /* x is inf or NaN */ + y[0]=y[1]=x-x; return 0; + } + /* set z = scalbn(|x|,ilogb(x)-23) */ + __LO(z) = __LO(x); + e0 = (ix>>20)-1046; /* e0 = ilogb(z)-23; */ + __HI(z) = ix - (e0<<20); + for(i=0;i<2;i++) { + tx[i] = (double)((int)(z)); + z = (z-tx[i])*two24; + } + tx[2] = z; + nx = 3; + while(tx[nx-1]==zero) nx--; /* skip zero term */ + n = __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi); + if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;} + return n; +} diff --git a/growlibm/accelerators/fdlibm.h b/growlibm/accelerators/fdlibm.h new file mode 100644 index 0000000000..3fbb8e6eeb --- /dev/null +++ b/growlibm/accelerators/fdlibm.h @@ -0,0 +1,223 @@ +#include +/* @(#)fdlibm.h 1.5 04/04/22 */ +/* + * ==================================================== + * Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved. + * + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* Sometimes it's necessary to define __LITTLE_ENDIAN explicitly + but these catch some common cases. */ + +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define __LITTLE_ENDIAN +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define __BIG_ENDIAN +#elif defined(i386) || defined(i486) || \ + defined(intel) || defined(x86) || defined(i86pc) || \ + defined(__alpha) || defined(__osf__) || \ + defined(__aarch64__) || defined(__arm__) || defined(__ARMEL__) +#define __LITTLE_ENDIAN +#endif + +#ifdef __LITTLE_ENDIAN +#define __HI(x) *(1+(int*)&x) +#define __LO(x) *(int*)&x +#define __HIp(x) *(1+(int*)x) +#define __LOp(x) *(int*)x +#else +#define __HI(x) *(int*)&x +#define __LO(x) *(1+(int*)&x) +#define __HIp(x) *(int*)x +#define __LOp(x) *(1+(int*)x) +#endif + +// #ifdef __STDC__ +// #define __P(p) p +// #else +// #define __P(p) () +// #endif + +/* + * ANSI/POSIX + */ + +extern int signgam; + +// #define MAXFLOAT ((float)3.40282346638528860e+38) + +enum fdversion {fdlibm_ieee = -1, fdlibm_svid, fdlibm_xopen, fdlibm_posix}; + +#define _LIB_VERSION_TYPE enum fdversion +#define _LIB_VERSION _fdlib_version + +/* if global variable _LIB_VERSION is not desirable, one may + * change the following to be a constant by: + * #define _LIB_VERSION_TYPE const enum version + * In that case, after one initializes the value _LIB_VERSION (see + * s_lib_version.c) during compile time, it cannot be modified + * in the middle of a program + */ +extern _LIB_VERSION_TYPE _LIB_VERSION; + +#define _IEEE_ fdlibm_ieee +#define _SVID_ fdlibm_svid +#define _XOPEN_ fdlibm_xopen +#define _POSIX_ fdlibm_posix + +struct fdl_exception { + int type; + char *name; + double arg1; + double arg2; + double retval; +}; + +#define HUGE MAXFLOAT + +/* + * set X_TLOSS = pi*2**52, which is possibly defined in + * (one may replace the following line by "#include ") + */ + +#define X_TLOSS 1.41484755040568800000e+16 + +#define DOMAIN 1 +#define SING 2 +#define OVERFLOW 3 +#define UNDERFLOW 4 +#define TLOSS 5 +#define PLOSS 6 + +/* + * ANSI/POSIX + */ +extern double acos __P((double)); +extern double asin __P((double)); +extern double atan __P((double)); +extern double atan2 __P((double, double)); +extern double cos __P((double)); +extern double sin __P((double)); +extern double tan __P((double)); + +extern double cosh __P((double)); +extern double sinh __P((double)); +extern double tanh __P((double)); + +extern double exp __P((double)); +extern double frexp __P((double, int *)); +extern double ldexp __P((double, int)); +extern double log __P((double)); +extern double log10 __P((double)); +extern double modf __P((double, double *)); + +extern double pow __P((double, double)); +extern double sqrt __P((double)); + +extern double ceil __P((double)); +extern double fabs __P((double)); +extern double floor __P((double)); +extern double fmod __P((double, double)); + +extern double erf __P((double)); +extern double erfc __P((double)); +extern double gamma __P((double)); +extern double hypot __P((double, double)); +extern int isnan __P((double)); +extern int finite __P((double)); +extern double j0 __P((double)); +extern double j1 __P((double)); +extern double jn __P((int, double)); +extern double lgamma __P((double)); +extern double y0 __P((double)); +extern double y1 __P((double)); +extern double yn __P((int, double)); + +extern double acosh __P((double)); +extern double asinh __P((double)); +extern double atanh __P((double)); +extern double cbrt __P((double)); +extern double logb __P((double)); +extern double nextafter __P((double, double)); +extern double remainder __P((double, double)); +#ifdef _SCALB_INT +extern double scalb __P((double, int)); +#else +extern double scalb __P((double, double)); +#endif + +extern int matherr __P((struct fdl_exception *)); + +/* + * IEEE Test Vector + */ +extern double significand __P((double)); + +/* + * Functions callable from C, intended to support IEEE arithmetic. + */ +extern double copysign __P((double, double)); +extern int ilogb __P((double)); +extern double rint __P((double)); +extern double scalbn __P((double, int)); + +/* + * BSD math library entry points + */ +extern double expm1 __P((double)); +extern double log1p __P((double)); + +/* + * Reentrant version of gamma & lgamma; passes signgam back by reference + * as the second argument; user must allocate space for signgam. + */ +#ifdef _REENTRANT +extern double gamma_r __P((double, int *)); +extern double lgamma_r __P((double, int *)); +#endif /* _REENTRANT */ + +/* ieee style elementary functions */ +extern double __ieee754_sqrt __P((double)); +extern double __ieee754_acos __P((double)); +extern double __ieee754_acosh __P((double)); +extern double __ieee754_log __P((double)); +extern double __ieee754_atanh __P((double)); +extern double __ieee754_asin __P((double)); +extern double __ieee754_atan2 __P((double,double)); +extern double __ieee754_exp __P((double)); +extern double __ieee754_cosh __P((double)); +extern double __ieee754_fmod __P((double,double)); +extern double __ieee754_pow __P((double,double)); +extern double __ieee754_lgamma_r __P((double,int *)); +extern double __ieee754_gamma_r __P((double,int *)); +extern double __ieee754_lgamma __P((double)); +extern double __ieee754_gamma __P((double)); +extern double __ieee754_log10 __P((double)); +extern double __ieee754_sinh __P((double)); +extern double __ieee754_hypot __P((double,double)); +extern double __ieee754_j0 __P((double)); +extern double __ieee754_j1 __P((double)); +extern double __ieee754_y0 __P((double)); +extern double __ieee754_y1 __P((double)); +extern double __ieee754_jn __P((int,double)); +extern double __ieee754_yn __P((int,double)); +extern double __ieee754_remainder __P((double,double)); +extern int __ieee754_rem_pio2 __P((double,double*)); +#ifdef _SCALB_INT +extern double __ieee754_scalb __P((double,int)); +#else +extern double __ieee754_scalb __P((double,double)); +#endif + +/* fdlibm kernel function */ +extern double __kernel_standard __P((double,double,int)); +extern double __kernel_sin __P((double,double,int)); +extern double __kernel_cos __P((double,double)); +extern double __kernel_tan __P((double,double,int)); +extern int __kernel_rem_pio2 __P((double*,double*,int,int,int,const int*)); diff --git a/growlibm/accelerators/invgud.c b/growlibm/accelerators/invgud.c new file mode 100644 index 0000000000..5adde1d06a --- /dev/null +++ b/growlibm/accelerators/invgud.c @@ -0,0 +1,563 @@ + +/* @(#)k_rem_pio2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include +#include + +int __ieee754_rem_pio2(double x, double *y); + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) + * double x[],y[]; int e0,nx,prec; int ipio2[]; + * + * __kernel_rem_pio2 return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0] + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * ipio2[] + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The recommended value is 2,3,4, + * 6 for single, double, extended,and quad. + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ + + +static const int init_jk[] = {3,4,4,6}; /* initial value for jk */ + +static const double PIo2[] = { + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +static const double +zero = 0.0, +one = 1.0, +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */ + +int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int *ipio2) +{ + int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0;i<=jk;i++) { + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for(i=0,j=jz,z=q[jz];j>0;i++,j--) { + fw = (double)((int)(twon24* z)); + iq[i] = (int)(z-two24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int) z; + z -= (double)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(24-q0)); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if(q0==0) ih = iq[jz-1]>>23; + else if(z>=0.5) ih=2; + + if(ih>0) { /* q > 0.5 */ + n += 1; carry = 0; + for(i=0;i0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbn(one,q0); + } + } + + /* check if recomputation is needed */ + if(z==zero) { + j = 0; + for (i=jz-1;i>=jk;i--) j |= iq[i]; + if(j==0) { /* need recomputation */ + for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ + + for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double) ipio2[jv+i]; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if(z==0.0) { + jz -= 1; q0 -= 24; + while(iq[jz]==0) { jz--; q0-=24;} + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if(z>=two24) { + fw = (double)((int)(twon24*z)); + iq[jz] = (int)(z-two24*fw); + jz += 1; q0 += 24; + iq[jz] = (int) fw; + } else iq[jz] = (int) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(one,q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(double)iq[i]; fw*=twon24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz;i>=0;i--) { + for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1;i<=jz;i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz;i>0;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz;i>1;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; + if(ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} + +/* + * 2/pi table (24-bit chunks), enough for float32 Payne-Hanek reduction. + */ +static const int ipio2[] = { + 0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, + 0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, + 0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, + 0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, + 0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, + 0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, + 0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, + 0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, + 0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, + 0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, + 0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B +}; + +static const double igd_pio2 = 1.57079632679489661923132169163975144; +static const double igd_pio4 = 0.78539816339744830961566084581987572; +static const double igd_invpio2 = 6.36619772367581382433e-01; +static const double igd_pio2_1 = 1.57079631090164184570e+00; +static const double igd_pio2_1t = 1.58932547735281966916e-08; + +static int rem_pio2f_payne_hanek(float x, double *y) { + union { + float f; + uint32_t i; + } u = {x}; + + uint32_t ix = u.i & 0x7fffffff; + int sign = (int)(u.i >> 31); + + if (ix < 0x4dc90fdb) { + double fn = nearbyint((double)x * igd_invpio2); + int n = (int)fn; + *y = (double)x - fn * igd_pio2_1 - fn * igd_pio2_1t; + + if (*y < -igd_pio4) { + fn -= 1.0; + n -= 1; + *y = (double)x - fn * igd_pio2_1 - fn * igd_pio2_1t; + } else if (*y > igd_pio4) { + fn += 1.0; + n += 1; + *y = (double)x - fn * igd_pio2_1 - fn * igd_pio2_1t; + } + return n; + } + + if (ix >= 0x7f800000) { + *y = x - x; + return 0; + } + + { + double tx[1], ty[1]; + int e0 = (int)(ix >> 23) - (0x7f + 23); + int n; + + u.i = ix - ((uint32_t)e0 << 23); + tx[0] = u.f; + n = __kernel_rem_pio2(tx, ty, e0, 1, 0, ipio2); + + if (sign) { + *y = -ty[0]; + return -n; + } + + *y = ty[0]; + return n; + } +} + +/* + * Approximation on r in [-pi/4, 0]: + * log(tan(r/2 + pi/4)) ~= r * P(r^2) + */ +static double igd_eval_right(double r) { + const double c1 = 9.99999999046208917167e-01; + const double c3 = 1.66666738775469084934e-01; + const double c5 = 4.16650801733863162889e-02; + const double c7 = 1.21187678887473179101e-02; + const double c9 = 3.73616485125713268182e-03; + const double c11 = 1.49750210889144601862e-03; + const double c13 = 6.71644977424151817339e-05; + const double c15 = 4.33110262370356813073e-04; + + double z = r * r; + double p = c15; + p = c13 + z * p; + p = c11 + z * p; + p = c9 + z * p; + p = c7 + z * p; + p = c5 + z * p; + p = c3 + z * p; + p = c1 + z * p; + return r * p; +} + +/* + * Approximation on r in [-pi/2, -pi/4]: + * delta = r + pi/2 in [0, pi/4] + * log(tan(delta/2)) = log(delta/2) + log(tan(delta/2)/(delta/2)) + */ +static double igd_eval_left(double r) { + const double d2 = 8.33333333244799216319e-02; + const double d4 = 4.86111138783593955541e-03; + const double d6 = 3.41707883128417487808e-04; + const double d8 = 2.62620338971920276310e-05; + const double d10 = 2.10090737912994710151e-06; + const double d12 = 2.17969221163014923668e-07; + + double delta = r + igd_pio2; + if (delta <= 0.0) return -INFINITY; + + { + double z = delta * delta; + double corr = d12; + corr = d10 + z * corr; + corr = d8 + z * corr; + corr = d6 + z * corr; + corr = d4 + z * corr; + corr = d2 + z * corr; + corr *= z; + return log(0.5 * delta) + corr; + } +} + +static double igd_eval_reduced(double r) { + if (r >= -igd_pio4) return igd_eval_right(r); + return igd_eval_left(r); +} + +/* + * Sollya scripts used for double-polynomial generation: + * g = ((log(tan(sqrt(x)/2 + pi/4))/sqrt(x)) - 1) / x; + * p = remez(g, 14, [0x1p-40; (pi*pi)/16]); + * print(round(coeff(p, i), D, RN)) for i in 0..14 + * + * f = log(tan(x)/x); + * p = remez(f, [|0,2,4,6,8,10,12,14,16|], [0; pi/8]); + * print(round(coeff(p, i), D, RN)) for i in 0..16 + */ +static double igd_eval_right_double(double r) { + const double c0 = 0x1.5555555555555p-3; + const double c1 = 0x1.555555555553fp-5; + const double c2 = 0x1.8c98c98c9b702p-7; + const double c3 = 0x1.f442d26418619p-9; + const double c4 = 0x1.4bc8d7d1762acp-10; + const double c5 = 0x1.c71f291afca44p-12; + const double c6 = 0x1.3fba17ed4455p-13; + const double c7 = 0x1.c92a18755783bp-15; + const double c8 = 0x1.4d3d2d18d3aa9p-16; + const double c9 = 0x1.d1fe4c71a04a2p-18; + const double c10 = 0x1.c8114f156fa39p-19; + const double c11 = -0x1.7c8baaee5272cp-23; + const double c12 = 0x1.c4f602f717b86p-20; + const double c13 = -0x1.9ede0881edd8dp-21; + const double c14 = 0x1.989fd5ab5c45cp-22; + + double z = r * r; + double p = c14; + p = fma(z, p, c13); + p = fma(z, p, c12); + p = fma(z, p, c11); + p = fma(z, p, c10); + p = fma(z, p, c9); + p = fma(z, p, c8); + p = fma(z, p, c7); + p = fma(z, p, c6); + p = fma(z, p, c5); + p = fma(z, p, c4); + p = fma(z, p, c3); + p = fma(z, p, c2); + p = fma(z, p, c1); + p = fma(z, p, c0); + return fma(r * z, p, r); +} + +static double igd_eval_left_double_delta(double delta) { + const double c0 = 0x1.2f97659f4a315p-56; + const double c2 = 0x1.555555555542p-2; + const double c4 = 0x1.3e93e93ec7d3bp-4; + const double c6 = 0x1.664f484d25225p-6; + const double c8 = 0x1.b85fe5f19eee8p-8; + const double c10 = 0x1.1e5a1678cbd17p-9; + const double c12 = 0x1.83d2f58019c9p-11; + const double c14 = 0x1.048d82dd4f1fbp-12; + const double c16 = 0x1.ed1d2fa3a1167p-14; + + if (delta <= 0.0) return -INFINITY; + + { + double t = 0.5 * delta; + double z = t * t; + double corr = c16; + corr = fma(z, corr, c14); + corr = fma(z, corr, c12); + corr = fma(z, corr, c10); + corr = fma(z, corr, c8); + corr = fma(z, corr, c6); + corr = fma(z, corr, c4); + corr = fma(z, corr, c2); + corr = fma(z, corr, c0); + return log(t) + corr; + } +} + +double invgud(double x) { + double y[2]; + double ysum, ay, r, out, sgn; + int n, k; + + if (!isfinite(x)) return x + x; + if (x == 0.0) return x; + + n = __ieee754_rem_pio2(x, y); + k = (n + 1) & 7; + + sgn = (k & 2) ? -1.0 : 1.0; + ysum = y[0] + y[1]; + ay = fabs(ysum); + + if (k & 1) { + r = -ay; + if (ysum > 0.0) sgn = -sgn; + out = sgn * igd_eval_right_double(r); + } else { + if (ay >= igd_pio4) { + r = ay - igd_pio2; + out = sgn * igd_eval_right_double(r); + } else { + out = sgn * igd_eval_left_double_delta(ay); + } + } + return out; +} + +float invgudf(float x) { + union { + float f; + uint32_t i; + } ux = {x}; + + uint32_t ix = ux.i & 0x7fffffff; + double y; + int n, k; + double sgn, ay, r, out; + + if (ix >= 0x7f800000) return x - x; + if (ix == 0) return x; + + n = rem_pio2f_payne_hanek(x, &y); + k = (n + 1) & 7; + + sgn = (k & 2) ? -1.0 : 1.0; + ay = fabs(y); + + if (k & 1) { + r = -ay; + if (y > 0.0) sgn = -sgn; + } else { + r = ay - igd_pio2; + } + + out = sgn * igd_eval_reduced(r); + return (float)out; +} diff --git a/growlibm/accelerators/k_rem_pio2.c b/growlibm/accelerators/k_rem_pio2.c new file mode 100644 index 0000000000..ec473ac0d3 --- /dev/null +++ b/growlibm/accelerators/k_rem_pio2.c @@ -0,0 +1,316 @@ + +/* @(#)k_rem_pio2.c 1.3 95/01/18 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) + * double x[],y[]; int e0,nx,prec; int ipio2[]; + * + * __kernel_rem_pio2 return the last three digits of N with + * y = x - N*pi/2 + * so that |y| < pi/2. + * + * The method is to compute the integer (mod 8) and fraction parts of + * (2/pi)*x without doing the full multiplication. In general we + * skip the part of the product that are known to be a huge integer ( + * more accurately, = 0 mod 8 ). Thus the number of operations are + * independent of the exponent of the input. + * + * (2/pi) is represented by an array of 24-bit integers in ipio2[]. + * + * Input parameters: + * x[] The input value (must be positive) is broken into nx + * pieces of 24-bit integers in double precision format. + * x[i] will be the i-th 24 bit of x. The scaled exponent + * of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 + * match x's up to 24 bits. + * + * Example of breaking a double positive z into x[0]+x[1]+x[2]: + * e0 = ilogb(z)-23 + * z = scalbn(z,-e0) + * for i = 0,1,2 + * x[i] = floor(z) + * z = (z-x[i])*2**24 + * + * + * y[] ouput result in an array of double precision numbers. + * The dimension of y[] is: + * 24-bit precision 1 + * 53-bit precision 2 + * 64-bit precision 2 + * 113-bit precision 3 + * The actual value is the sum of them. Thus for 113-bit + * precison, one may have to do something like: + * + * long double t,w,r_head, r_tail; + * t = (long double)y[2] + (long double)y[1]; + * w = (long double)y[0]; + * r_head = t+w; + * r_tail = w - (r_head - t); + * + * e0 The exponent of x[0] + * + * nx dimension of x[] + * + * prec an integer indicating the precision: + * 0 24 bits (single) + * 1 53 bits (double) + * 2 64 bits (extended) + * 3 113 bits (quad) + * + * ipio2[] + * integer array, contains the (24*i)-th to (24*i+23)-th + * bit of 2/pi after binary point. The corresponding + * floating value is + * + * ipio2[i] * 2^(-24(i+1)). + * + * External function: + * double scalbn(), floor(); + * + * + * Here is the description of some local variables: + * + * jk jk+1 is the initial number of terms of ipio2[] needed + * in the computation. The recommended value is 2,3,4, + * 6 for single, double, extended,and quad. + * + * jz local integer variable indicating the number of + * terms of ipio2[] used. + * + * jx nx - 1 + * + * jv index for pointing to the suitable ipio2[] for the + * computation. In general, we want + * ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8 + * is an integer. Thus + * e0-3-24*jv >= 0 or (e0-3)/24 >= jv + * Hence jv = max(0,(e0-3)/24). + * + * jp jp+1 is the number of terms in PIo2[] needed, jp = jk. + * + * q[] double array with integral value, representing the + * 24-bits chunk of the product of x and 2/pi. + * + * q0 the corresponding exponent of q[0]. Note that the + * exponent for q[i] would be q0-24*i. + * + * PIo2[] double precision array, obtained by cutting pi/2 + * into 24 bits chunks. + * + * f[] ipio2[] in floating point + * + * iq[] integer array by breaking up q[] in 24-bits chunk. + * + * fq[] final product of x*(2/pi) in fq[0],..,fq[jk] + * + * ih integer. If >0 it indicates q[] is >= 0.5, hence + * it also indicates the *sign* of the result. + * + */ + + +/* + * Constants: + * The hexadecimal values are the intended ones for the following + * constants. The decimal values may be used, provided that the + * compiler will convert from decimal to binary accurately enough + * to produce the hexadecimal values shown. + */ + +#include "fdlibm.h" + +#ifdef __STDC__ +static const int init_jk[] = {2,3,4,6}; /* initial value for jk */ +#else +static int init_jk[] = {2,3,4,6}; +#endif + +#ifdef __STDC__ +static const double PIo2[] = { +#else +static double PIo2[] = { +#endif + 1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */ + 7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */ + 5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */ + 3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */ + 1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */ + 1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */ + 2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */ + 2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */ +}; + +#ifdef __STDC__ +static const double +#else +static double +#endif +zero = 0.0, +one = 1.0, +two24 = 1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */ +twon24 = 5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */ + +#ifdef __STDC__ + int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int *ipio2) +#else + int __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) + double x[], y[]; int e0,nx,prec; int ipio2[]; +#endif +{ + int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; + double z,fw,f[20],fq[20],q[20]; + + /* initialize jk*/ + jk = init_jk[prec]; + jp = jk; + + /* determine jx,jv,q0, note that 3>q0 */ + jx = nx-1; + jv = (e0-3)/24; if(jv<0) jv=0; + q0 = e0-24*(jv+1); + + /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ + j = jv-jx; m = jx+jk; + for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j]; + + /* compute q[0],q[1],...q[jk] */ + for (i=0;i<=jk;i++) { + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; + } + + jz = jk; +recompute: + /* distill q[] into iq[] reversingly */ + for(i=0,j=jz,z=q[jz];j>0;i++,j--) { + fw = (double)((int)(twon24* z)); + iq[i] = (int)(z-two24*fw); + z = q[j-1]+fw; + } + + /* compute n */ + z = scalbn(z,q0); /* actual value of z */ + z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */ + n = (int) z; + z -= (double)n; + ih = 0; + if(q0>0) { /* need iq[jz-1] to determine n */ + i = (iq[jz-1]>>(24-q0)); n += i; + iq[jz-1] -= i<<(24-q0); + ih = iq[jz-1]>>(23-q0); + } + else if(q0==0) ih = iq[jz-1]>>23; + else if(z>=0.5) ih=2; + + if(ih>0) { /* q > 0.5 */ + n += 1; carry = 0; + for(i=0;i0) { /* rare case: chance is 1 in 12 */ + switch(q0) { + case 1: + iq[jz-1] &= 0x7fffff; break; + case 2: + iq[jz-1] &= 0x3fffff; break; + } + } + if(ih==2) { + z = one - z; + if(carry!=0) z -= scalbn(one,q0); + } + } + + /* check if recomputation is needed */ + if(z==zero) { + j = 0; + for (i=jz-1;i>=jk;i--) j |= iq[i]; + if(j==0) { /* need recomputation */ + for(k=1;iq[jk-k]==0;k++); /* k = no. of terms needed */ + + for(i=jz+1;i<=jz+k;i++) { /* add q[jz+1] to q[jz+k] */ + f[jx+i] = (double) ipio2[jv+i]; + for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; + q[i] = fw; + } + jz += k; + goto recompute; + } + } + + /* chop off zero terms */ + if(z==0.0) { + jz -= 1; q0 -= 24; + while(iq[jz]==0) { jz--; q0-=24;} + } else { /* break z into 24-bit if necessary */ + z = scalbn(z,-q0); + if(z>=two24) { + fw = (double)((int)(twon24*z)); + iq[jz] = (int)(z-two24*fw); + jz += 1; q0 += 24; + iq[jz] = (int) fw; + } else iq[jz] = (int) z ; + } + + /* convert integer "bit" chunk to floating-point value */ + fw = scalbn(one,q0); + for(i=jz;i>=0;i--) { + q[i] = fw*(double)iq[i]; fw*=twon24; + } + + /* compute PIo2[0,...,jp]*q[jz,...,0] */ + for(i=jz;i>=0;i--) { + for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k]; + fq[jz-i] = fw; + } + + /* compress fq[] into y[] */ + switch(prec) { + case 0: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + break; + case 1: + case 2: + fw = 0.0; + for (i=jz;i>=0;i--) fw += fq[i]; + y[0] = (ih==0)? fw: -fw; + fw = fq[0]-fw; + for (i=1;i<=jz;i++) fw += fq[i]; + y[1] = (ih==0)? fw: -fw; + break; + case 3: /* painful */ + for (i=jz;i>0;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (i=jz;i>1;i--) { + fw = fq[i-1]+fq[i]; + fq[i] += fq[i-1]-fw; + fq[i-1] = fw; + } + for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; + if(ih==0) { + y[0] = fq[0]; y[1] = fq[1]; y[2] = fw; + } else { + y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw; + } + } + return n&7; +} diff --git a/growlibm/accelerators/powcos.c b/growlibm/accelerators/powcos.c new file mode 100644 index 0000000000..5d4945ab73 --- /dev/null +++ b/growlibm/accelerators/powcos.c @@ -0,0 +1,569 @@ +#include +#include +#include "accelerators.h" + +int __ieee754_rem_pio2(double x, double *y); + +#if (defined(__clang__) && __clang_major__ >= 14) || \ + (defined(__GNUC__) && __GNUC__ >= 14 && __BITINT_MAXWIDTH__ && __BITINT_MAXWIDTH__ >= 128) +typedef unsigned _BitInt(128) u128; +#else +typedef unsigned __int128 u128; +#endif + +typedef union { + double f; + uint64_t u; +} b64u64_u; + +/* 1/(2*pi) approximated downward in 64-bit limbs, copied from cos.c. */ +static const uint64_t T[20] = { + 0x28be60db9391054a, 0x7f09d5f47d4d3770, 0x36d8a5664f10e410, + 0x7f9458eaf7aef158, 0x6dc91b8e909374b8, 0x01924bba82746487, + 0x3f877ac72c4a69cf, 0xba208d7d4baed121, 0x3a671c09ad17df90, + 0x4e64758e60d4ce7d, 0x272117e2ef7e4a0e, 0xc7fe25fff7816603, + 0xfbcbc462d6829b47, 0xdb4d9fb3c9f2c26d, 0xd3d18fd9a797fa8b, + 0x5d49eeb1faf97c5e, 0xcf41ce7de294a4ba, 0x9afed7ec47e35742, + 0x1580cc11bf1edaea, 0xfc33ef0826bd0d87, +}; + +static inline void a_mul(double *hi, double *lo, double a, double b) { + *hi = a * b; + *lo = fma(a, b, -*hi); +} + +/* h+l <- c1/2^64 + c0/2^128 */ +static void set_dd(double *h, double *l, uint64_t c1, uint64_t c0) { + uint64_t e, f, g; + b64u64_u t; + + if (c1) { + e = __builtin_clzll(c1); + if (e) { + c1 = (c1 << e) | (c0 >> (64 - e)); + c0 = c0 << e; + } + f = 0x3fe - e; + t.u = (f << 52) | ((c1 << 1) >> 12); + *h = t.f; + c0 = (c1 << 53) | (c0 >> 11); + if (c0) { + g = __builtin_clzll(c0); + if (g) c0 = c0 << g; + t.u = ((f - 53 - g) << 52) | ((c0 << 1) >> 12); + *l = t.f; + } else { + *l = 0.0; + } + } else if (c0) { + e = __builtin_clzll(c0); + f = 0x3fe - 64 - e; + c0 = c0 << (e + 1); // most significant bit shifted out + t.u = (f << 52) | (c0 >> 12); + *h = t.f; + c0 = c0 << 52; + if (c0) { + g = __builtin_clzll(c0); + c0 = c0 << (g + 1); + t.u = ((f - 64 - g) << 52) | (c0 >> 12); + *l = t.f; + } else { + *l = 0.0; + } + } else { + *h = *l = 0.0; + } +} + +/* Fast reduction copied/adapted from cos.c::reduce_fast. */ +static int fast_reduce(double *h, double *l, double x, double *err1) { + if (__builtin_expect(x <= 0x1.921fb54442d17p+2, 1)) { // x < 2*pi +#define CH 0x1.45f306dc9c883p-3 +#define CL -0x1.6b01ec5417056p-57 + a_mul(h, l, CH, x); + *l = fma(CL, x, *l); + *err1 = 0x1.d9p-105 * *h; +#undef CH +#undef CL + } else { + b64u64_u t = {.f = x}; + int e = (t.u >> 52) & 0x7ff; + uint64_t m = (1ull << 52) | (t.u & 0xfffffffffffffull); + uint64_t c[3]; + u128 u; + + if (e <= 1074) { + u = (u128)m * (u128)T[1]; + c[0] = (uint64_t)u; + c[1] = (uint64_t)(u >> 64); + u = (u128)m * (u128)T[0]; + c[1] += (uint64_t)u; + c[2] = (uint64_t)(u >> 64) + (c[1] < (uint64_t)u); + e = 1075 - e; + } else { + int i = (e - 1138 + 63) / 64; + u = (u128)m * (u128)T[i + 2]; + c[0] = (uint64_t)u; + c[1] = (uint64_t)(u >> 64); + u = (u128)m * (u128)T[i + 1]; + c[1] += (uint64_t)u; + c[2] = (uint64_t)(u >> 64) + (c[1] < (uint64_t)u); + u = (u128)m * (u128)T[i]; + c[2] += (uint64_t)u; + e = 1139 + (i << 6) - e; + } + + if (e == 64) { + c[0] = c[1]; + c[1] = c[2]; + } else { + c[0] = (c[1] << (64 - e)) | (c[0] >> e); + c[1] = (c[2] << (64 - e)) | (c[1] >> e); + } + + set_dd(h, l, c[1], c[0]); + *err1 = 0x1.01p-76; + } + + double i = floor(*h * 0x1p11); + *h = fma(i, -0x1p-11, *h); + return (int)i; +} + +/* + * Sollya scripts used for the polynomial generation: + * + * display = hexadecimal!; + * hi = (pi/4)^2; + * lo = 0x1p-40; + * + * p2 = remez(cos(sqrt(x))^2, 10, [0;hi]); + * q2 = remez((sin(sqrt(x))/sqrt(x))^2, 7, [lo;hi]); + * + * p4 = remez(cos(sqrt(x))^4, 10, [0;hi]); + * q4 = remez((sin(sqrt(x))/sqrt(x))^4, 8, [lo;hi]); + * + * p6 = remez(cos(sqrt(x))^6, 11, [0;hi]); + * q6 = remez((sin(sqrt(x))/sqrt(x))^6, 9, [lo;hi]); + * + * lcos = remez(log(cos(sqrt(x))), 12, [0;hi]); + * lsinc = remez(log(sin(sqrt(x))/sqrt(x)), 12, [lo;hi]); + * + * print(round(coeff(p, i), D, RN)) + */ + +static inline double powcos_clamp01(double x) { + if (x < 0.0) return 0.0; + if (x > 1.0) return 1.0; + return x; +} + +static inline int powcos_reduce_full_slow(double x, double *r, double *z) { + double y[2]; + int n = __ieee754_rem_pio2(x, y); + double zz = fma(y[0], y[0], fma(2.0 * y[0], y[1], y[1] * y[1])); + + if (zz < 0.0) zz = 0.0; + *r = y[0] + y[1]; + *z = zz; + return n; +} + +static inline int powcos_reduce_full(double x, double *r, double *z) { + const long double two_pi = 0x1.921fb54442d18469898cc51701b8p+2L; + const double min_fast = 0x1.6a09e667f3bccp-27; + double ax = fabs(x); + + if (ax <= min_fast) { + *r = x; + *z = x * x; + return 0; + } + + double h, l, err1; + int i = fast_reduce(&h, &l, ax, &err1); + long double frac = (long double)i * 0x1p-11L + (long double)h + (long double)l; + long double s = 4.0L * frac; + int n_abs = (int)floorl(s + 0.5L); + long double dist = fabsl(s - (long double)n_abs); + long double tol = fmaxl(4.0L * (long double)err1 + 0x1p-68L, 0x1p-60L); + + if (dist <= tol) { + return powcos_reduce_full_slow(x, r, z); + } + + long double delta = (long double)(i - (n_abs << 9)) * 0x1p-11L + (long double)h + (long double)l; + /* Slow fallback is only needed very close to cos-zero crossings. */ + if ((n_abs & 1) && fabsl(delta) < 0x1p-12L) { + return powcos_reduce_full_slow(x, r, z); + } + long double rr = delta * two_pi; + int n = n_abs; + + if (x < 0.0) { + rr = -rr; + n = -n_abs; + } + + *r = (double)rr; + *z = (double)(rr * rr); + if (*z < 0.0) *z = 0.0; + return n; +} + +static inline void powcos_reduce(double x, int *odd_quadrant, double *z) { + const long double two_pi = 0x1.921fb54442d18469898cc51701b8p+2L; + const double min_fast = 0x1.6a09e667f3bccp-27; + double ax = fabs(x); + + if (ax <= min_fast) { + *odd_quadrant = 0; + *z = x * x; + return; + } + + double h, l, err1; + int i = fast_reduce(&h, &l, ax, &err1); + long double frac = (long double)i * 0x1p-11L + (long double)h + (long double)l; + long double s = 4.0L * frac; + int n_abs = (int)floorl(s + 0.5L); + long double dist = fabsl(s - (long double)n_abs); + long double tol = fmaxl(4.0L * (long double)err1 + 0x1p-68L, 0x1p-60L); + + if (dist <= tol) { + double r_slow; + *odd_quadrant = powcos_reduce_full_slow(x, &r_slow, z) & 1; + return; + } + + long double delta = (long double)(i - (n_abs << 9)) * 0x1p-11L + (long double)h + (long double)l; + if ((n_abs & 1) && fabsl(delta) < 0x1p-12L) { + double r_slow; + *odd_quadrant = powcos_reduce_full_slow(x, &r_slow, z) & 1; + return; + } + + long double rr = fabsl(delta) * two_pi; + *odd_quadrant = n_abs & 1; + *z = (double)(rr * rr); + if (*z < 0.0) *z = 0.0; +} + +static inline double powcos_logcos_even(double z) { + const double c0 = -0x1.dff88a50f5f76p-53; + const double c1 = -0x1.ffffffffff821p-2; + const double c2 = -0x1.5555555604894p-4; + const double c3 = -0x1.6c16c10c71537p-6; + const double c4 = -0x1.ba1bbcce3c31fp-8; + const double c5 = -0x1.1ea38d4844306p-9; + const double c6 = -0x1.837c25a39f34dp-11; + const double c7 = -0x1.0acedb5665233p-12; + const double c8 = -0x1.9966d194fdbc9p-14; + const double c9 = -0x1.3cc234c60e236p-16; + const double c10 = -0x1.05705e8b74741p-15; + const double c11 = 0x1.8e8eab6384f26p-17; + const double c12 = -0x1.23482b5eb1f1ap-17; + double p = c12; + + if (z == 0.0) return 0.0; + p = fma(z, p, c11); + p = fma(z, p, c10); + p = fma(z, p, c9); + p = fma(z, p, c8); + p = fma(z, p, c7); + p = fma(z, p, c6); + p = fma(z, p, c5); + p = fma(z, p, c4); + p = fma(z, p, c3); + p = fma(z, p, c2); + p = fma(z, p, c1); + return fma(z, p, c0); +} + +static inline double powcos_logsin_ratio(double z) { + const double c0 = -0x1.ddc88ce92f353p-81; + const double c1 = -0x1.5555555555555p-3; + const double c2 = -0x1.6c16c16c16c17p-8; + const double c3 = -0x1.71de3a556c71bp-12; + const double c4 = -0x1.bbd7793350bbcp-16; + const double c5 = -0x1.1eed8efef055cp-19; + const double c6 = -0x1.8355d22007d4ep-23; + const double c7 = -0x1.0d0f7ce5d465p-26; + const double c8 = -0x1.7da6e9f40418ep-30; + const double c9 = -0x1.12d5a8461fb08p-33; + const double c10 = -0x1.947704deca229p-37; + const double c11 = -0x1.0f279d85ef3f6p-40; + const double c12 = -0x1.42999227657dfp-43; + double p = c12; + + if (z == 0.0) return 0.0; + p = fma(z, p, c11); + p = fma(z, p, c10); + p = fma(z, p, c9); + p = fma(z, p, c8); + p = fma(z, p, c7); + p = fma(z, p, c6); + p = fma(z, p, c5); + p = fma(z, p, c4); + p = fma(z, p, c3); + p = fma(z, p, c2); + p = fma(z, p, c1); + return fma(z, p, c0); +} + +static inline int powcos_logcos_positive(int k, double r, double z, double *logcos_out) { + double ar = fabs(r); + + switch (k & 3) { + case 0: + if (z < 0x1p-8) { + double sh = sin(0.5 * r); + *logcos_out = log1p(-2.0 * sh * sh); + } else { + *logcos_out = powcos_logcos_even(z); + } + return 1; + case 1: + if (r < 0.0) { + if (ar == 0.0) return 0; + *logcos_out = log(ar) + powcos_logsin_ratio(z); + return 1; + } + return 0; + case 2: + return 0; + default: + if (r > 0.0) { + if (ar == 0.0) return 0; + *logcos_out = log(ar) + powcos_logsin_ratio(z); + return 1; + } + return 0; + } +} + +static inline double powcos_reduced_cos(int k, double r) { + double ar = fabs(r); + double m = (k & 1) ? sin(ar) : cos(ar); + + switch (k & 3) { + case 0: + return m; + case 1: + if (r < 0.0 || (r == 0.0 && signbit(r))) return m; + return -m; + case 2: + return -m; + default: + if (r > 0.0 || (r == 0.0 && !signbit(r))) return m; + return -m; + } +} + +static inline double powcos2_even(double z) { + const double c0 = 0x1p0; + const double c1 = -0x1p0; + const double c2 = 0x1.5555555555555p-2; + const double c3 = -0x1.6c16c16c16c16p-5; + const double c4 = 0x1.a01a01a019fc8p-9; + const double c5 = -0x1.27e4fb778788p-13; + const double c6 = 0x1.1eed8efe1ebaap-18; + const double c7 = -0x1.93974976073cap-24; + const double c8 = 0x1.ae7eb70bd5813p-30; + const double c9 = -0x1.67fe89745f754p-36; + const double c10 = 0x1.d73498c8bd4a1p-43; + + double z2 = z * z; + double z4 = z2 * z2; + double a0 = fma(c1, z, c0); + double a1 = fma(c3, z, c2); + double a2 = fma(c5, z, c4); + double a3 = fma(c7, z, c6); + double a4 = fma(c9, z, c8); + double b0 = fma(a1, z2, a0); + double b1 = fma(a3, z2, a2); + double b2 = fma(c10, z2, a4); + + return fma(z4, fma(z4, b2, b1), b0); +} + +static inline double powcos2_odd(double z) { + const double c0 = 0x1p0; + const double c1 = -0x1.5555555555526p-2; + const double c2 = 0x1.6c16c16c1396cp-5; + const double c3 = -0x1.a01a019d88418p-9; + const double c4 = 0x1.27e4fa71665d5p-13; + const double c5 = -0x1.1eed1d7abc2e1p-18; + const double c6 = 0x1.9360c51731d53p-24; + const double c7 = -0x1.a0d3a53bb2a66p-30; + + double z2 = z * z; + double z4 = z2 * z2; + double a0 = fma(c1, z, c0); + double a1 = fma(c3, z, c2); + double a2 = fma(c5, z, c4); + double a3 = fma(c7, z, c6); + double b0 = fma(a1, z2, a0); + double b1 = fma(a3, z2, a2); + + return z * fma(b1, z4, b0); +} + +static inline double powcos4_even(double z) { + const double c0 = 0x1p0; + const double c1 = -0x1.ffffffffffff9p0; + const double c2 = 0x1.aaaaaaaaaa8d1p0; + const double c3 = -0x1.82d82d82d250dp-1; + const double c4 = 0x1.a69a69a569afap-3; + const double c5 = -0x1.290ce04ee58dap-5; + const double c6 = 0x1.1f35450cc75ffp-8; + const double c7 = -0x1.93af80479dc8ap-12; + const double c8 = 0x1.ae6633e30ed9fp-16; + const double c9 = -0x1.65bcf671d6a5bp-20; + const double c10 = 0x1.af57cb5a3478fp-25; + + double z2 = z * z; + double z4 = z2 * z2; + double a0 = fma(c1, z, c0); + double a1 = fma(c3, z, c2); + double a2 = fma(c5, z, c4); + double a3 = fma(c7, z, c6); + double a4 = fma(c9, z, c8); + double b0 = fma(a1, z2, a0); + double b1 = fma(a3, z2, a2); + double b2 = fma(c10, z2, a4); + + return fma(z4, fma(z4, b2, b1), b0); +} + +static inline double powcos4_odd(double z) { + const double c0 = 0x1.ffffffffffffep-1; + const double c1 = -0x1.55555555553b3p-1; + const double c2 = 0x1.9999999987e71p-3; + const double c3 = -0x1.26bd1677757cdp-5; + const double c4 = 0x1.1ea5d26743b09p-8; + const double c5 = -0x1.937db673fc21cp-12; + const double c6 = 0x1.ae68da502d504p-16; + const double c7 = -0x1.6690ee1152ba5p-20; + const double c8 = 0x1.b8c14729bedbbp-25; + + double z2 = z * z; + double z4 = z2 * z2; + double a0 = fma(c1, z, c0); + double a1 = fma(c3, z, c2); + double a2 = fma(c5, z, c4); + double a3 = fma(c7, z, c6); + double b0 = fma(a1, z2, a0); + double b1 = fma(a3, z2, a2); + double p = fma(z4, c8, b1); + + return z2 * fma(p, z4, b0); +} + +static inline double powcos6_even(double z) { + const double c0 = 0x1p0; + const double c1 = -0x1.7ffffffffffb7p1; + const double c2 = 0x1.fffffffffe9fp1; + const double c3 = -0x1.91111110e7345p1; + const double c4 = 0x1.9c09c096e854fp0; + const double c5 = -0x1.2669ddb654337p-1; + const double c6 = 0x1.304ce86f325c6p-3; + const double c7 = -0x1.d5b0e0678c10ep-6; + const double c8 = 0x1.169eda0ecc00bp-8; + const double c9 = -0x1.045db550df2a2p-11; + const double c10 = 0x1.805ebd95d229p-15; + const double c11 = -0x1.81bda2f54204ep-19; + + double p = c11; + + p = fma(z, p, c10); + p = fma(z, p, c9); + p = fma(z, p, c8); + p = fma(z, p, c7); + p = fma(z, p, c6); + p = fma(z, p, c5); + p = fma(z, p, c4); + p = fma(z, p, c3); + p = fma(z, p, c2); + p = fma(z, p, c1); + return fma(z, p, c0); +} + +static inline double powcos6_odd(double z) { + const double c0 = 0x1p0; + const double c1 = -0x1.ffffffffffe0bp-1; + const double c2 = 0x1.ddddddddd0bd2p-2; + const double c3 = -0x1.1566abbdeeaedp-3; + const double c4 = 0x1.c2c6d66365e44p-6; + const double c5 = -0x1.119e38d182a31p-8; + const double c6 = 0x1.02d58db1900b4p-11; + const double c7 = -0x1.88f3c7c8d3f8cp-15; + const double c8 = 0x1.e45c04a52b0cbp-19; + const double c9 = -0x1.afd99d3e80f2bp-23; + + double p = c9; + double z2 = z * z; + + p = fma(z, p, c8); + p = fma(z, p, c7); + p = fma(z, p, c6); + p = fma(z, p, c5); + p = fma(z, p, c4); + p = fma(z, p, c3); + p = fma(z, p, c2); + p = fma(z, p, c1); + p = fma(z, p, c0); + return z2 * z * p; +} + +double powcos2(double x) { + int odd_quadrant; + double z, out; + + if (!isfinite(x)) return x - x; + + powcos_reduce(x, &odd_quadrant, &z); + out = odd_quadrant ? powcos2_odd(z) : powcos2_even(z); + return powcos_clamp01(out); +} + +double powcos4(double x) { + int odd_quadrant; + double z, out; + + if (!isfinite(x)) return x - x; + + powcos_reduce(x, &odd_quadrant, &z); + out = odd_quadrant ? powcos4_odd(z) : powcos4_even(z); + return powcos_clamp01(out); +} + +double powcos6(double x) { + int odd_quadrant; + double z, out; + + if (!isfinite(x)) return x - x; + + powcos_reduce(x, &odd_quadrant, &z); + out = odd_quadrant ? powcos6_odd(z) : powcos6_even(z); + return powcos_clamp01(out); +} + +double powcos(double x, double y) { + double r, z; + int n, k; + + if (!isfinite(x) || !isfinite(y)) return pow(cos(x), y); + + n = powcos_reduce_full(x, &r, &z); + k = n & 3; + + double logc; + if (__builtin_expect(powcos_logcos_positive(k, r, z, &logc), 1)) { + return exp(y * logc); + } + + double c = powcos_reduced_cos(k, r); + if (c > 0.0) return exp(y * log(c)); + return pow(c, y); +} diff --git a/growlibm/eval/accelerator_utils.py b/growlibm/eval/accelerator_utils.py new file mode 100644 index 0000000000..026cfa5c18 --- /dev/null +++ b/growlibm/eval/accelerator_utils.py @@ -0,0 +1,58 @@ +import re +from pathlib import Path + + +def default_platform_path(platform): + return Path(__file__).resolve().parents[1] / "platforms" / f"{platform.lower()}.rkt" + + +def load_accelerator_names(platform_path): + text = platform_path.read_text(encoding="utf-8") + matches = re.findall(r"from-accelerators\s+'([A-Za-z0-9_]+)", text) + seen = set() + names = [] + for name in matches: + if name not in seen: + seen.add(name) + names.append(name) + return names + + +def alternative_exprs(test): + seen = set() + exprs = [] + + def add_expr(expr): + if expr in (None, "", "()", False): + return + expr_text = str(expr) + if expr_text in seen: + return + seen.add(expr_text) + exprs.append(expr_text) + + add_expr(test.get("output")) + + raw = test.get("cost-accuracy") + if isinstance(raw, list) and len(raw) >= 2: + best = raw[1] + if isinstance(best, list) and len(best) >= 3: + add_expr(best[2]) + + rest = raw[2] if len(raw) > 2 else [] + if isinstance(rest, list): + for point in rest: + if isinstance(point, list) and len(point) >= 3: + add_expr(point[2]) + + return exprs + + +def accelerator_hits(test, accelerator_names): + exprs = alternative_exprs(test) + found = [] + for name in accelerator_names: + pattern = rf"(?" +PAGE_END = "" + + +def warn(message): + print(f"warning: {message}", file=sys.stderr) + + +def load_json(path): + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def benchmark_key(test): + identifier = test.get("identifier") + if identifier not in (None, "", "#f"): + return str(identifier) + return str(test.get("name") or test.get("link")) + + +def load_tests(results_path): + if not results_path.exists(): + warn(f"missing {results_path}") + return {} + + data = load_json(results_path) + tests = {} + for test in data.get("tests", []): + tests[benchmark_key(test)] = test + return tests + + +def parse_cost_accuracy(test): + raw = test.get("cost-accuracy") + if not isinstance(raw, list) or len(raw) < 2: + return (None, []) + + initial = parse_point(raw[0]) + points = [] + + best = parse_point(raw[1]) + if best is not None: + points.append(best) + + if len(raw) > 2 and isinstance(raw[2], list): + for point in raw[2]: + parsed = parse_point(point) + if parsed is not None: + points.append(parsed) + + return (initial, points) + + +def parse_point(raw): + if not isinstance(raw, list) or len(raw) < 2: + return None + + try: + return (float(raw[0]), float(raw[1])) + except (TypeError, ValueError): + return None + + +def pareto_frontier(points): + frontier = [] + best_error = float("inf") + for cost, error in sorted(points, key=lambda point: (point[0], point[1])): + if error < best_error: + frontier.append((cost, error)) + best_error = error + return list(reversed(frontier)) + + +def sanitize_filename(name): + return re.sub(r"[^A-Za-z0-9._-]+", "_", name).strip("._") or "benchmark" + + +def format_accelerator_summary(accelerators): + if accelerators: + return f"Accelerators: yes ({', '.join(accelerators)})" + return "Accelerators: no" + + +def plot_benchmark(series, image_path, title, accelerator_summary): + try: + import matplotlib + from matplotlib.ticker import FuncFormatter + except ImportError as err: + raise SystemExit( + "matplotlib is required for growlibm/evaluate-benchmark-frontiers.py; " + "install it with `python3 -m pip install matplotlib`." + ) from err + + matplotlib.use("Agg") + import matplotlib.pyplot as plt + + fig, ax = plt.subplots(figsize=(8, 4.8)) + have_points = False + + for entry in series: + initial, points = parse_cost_accuracy(entry["test"]) + bits = entry["bits"] + if initial is None or initial[0] == 0 or bits <= 0: + continue + + frontier = pareto_frontier(points) + if frontier: + have_points = True + ax.plot( + [initial[0] / point[0] for point in frontier if point[0]], + [1 - (point[1] / bits) for point in frontier if point[0]], + color=entry["color"], + linewidth=1.5, + alpha=0.4, + ) + ax.scatter( + [initial[0] / point[0] for point in frontier if point[0]], + [1 - (point[1] / bits) for point in frontier if point[0]], + s=30, + color=entry["color"], + alpha=0.85, + label=entry["label"], + ) + + have_points = True + ax.scatter( + [1.0], + [1 - (initial[1] / bits)], + s=64, + marker="s", + facecolors="white", + edgecolors=entry["color"], + linewidths=1.8, + ) + + if not have_points: + ax.text(0.5, 0.5, "No frontier data found", ha="center", va="center", transform=ax.transAxes) + + ax.set_title( + "Per-Benchmark Speed/Accuracy Frontier: " + f"{title}\n{textwrap.fill(accelerator_summary, width=70)}" + ) + ax.set_xlabel("Speedup (x)") + ax.set_ylabel("Accuracy") + ax.set_ylim(0.0, 1.0) + ax.xaxis.set_major_formatter(FuncFormatter(lambda value, _: f"{value:.2g}x")) + ax.yaxis.set_major_formatter(FuncFormatter(lambda value, _: f"{100 * value:.0f}%")) + ax.grid(True, linewidth=0.5, alpha=0.2) + if have_points: + ax.legend(loc="lower right") + + fig.tight_layout() + fig.savefig(image_path, dpi=180) + plt.close(fig) + + +def benchmark_section(benchmark): + title = html.escape(benchmark["title"]) + grow_link = html.escape(benchmark["growlibm_link"]) + vanilla_link = html.escape(benchmark["vanilla_link"]) + image = html.escape(benchmark["image"]) + accelerators = benchmark["accelerators"] + summary = format_accelerator_summary(accelerators).replace("Accelerators:", "Uses accelerators:") + + return ( + '
\n' + f"

{title}

\n" + f"

{html.escape(summary)}

\n" + '

growlibm_base | vanilla_base

\n' + f'

Pareto frontier for {title}

\n' + "
\n" + ) + + +def write_page(page_path, platform, benchmarks): + sections = "".join(benchmark_section(benchmark) for benchmark in benchmarks) + html_text = f""" + + + + {html.escape(platform)} benchmark frontiers + + + +

{html.escape(platform)} per-benchmark frontiers

+

Comparing growlibm_base against vanilla_base.

+ {sections} + + +""" + page_path.write_text(html_text, encoding="utf-8") + + +def inject_page_link(index_path, page_name): + if not index_path.exists(): + warn(f"missing {index_path}, skipping html injection") + return + + block = ( + f"\n{PAGE_START}\n" + '
\n' + "

Per-Benchmark Frontiers

\n" + f'

Open per-benchmark Pareto curve comparisons

\n' + "
\n" + f"{PAGE_END}\n" + ) + + html_text = index_path.read_text(encoding="utf-8") + if PAGE_START in html_text and PAGE_END in html_text: + before, rest = html_text.split(PAGE_START, 1) + _, after = rest.split(PAGE_END, 1) + updated = before + block + after + elif "" in html_text: + updated = html_text.replace("", f"{block}", 1) + else: + updated = html_text + block + + if updated != html_text: + index_path.write_text(updated, encoding="utf-8") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("reports_path", help="Path containing growlibm_base and vanilla_base") + parser.add_argument("platform", help="Platform label for generated html") + parser.add_argument( + "--platform-file", + default="growlibm/platforms/growlibm.rkt", + help="Platform file used to discover accelerator names", + ) + parser.add_argument( + "--page", + default="benchmark-frontiers.html", + help="Output page filename written in reports_path", + ) + parser.add_argument( + "--image-dir", + default="benchmark-frontiers", + help="Directory for generated benchmark frontier images", + ) + args = parser.parse_args() + + reports_path = Path(args.reports_path) + image_dir = reports_path / args.image_dir + image_dir.mkdir(parents=True, exist_ok=True) + + accelerator_names = load_accelerator_names(Path(args.platform_file)) + grow_tests = load_tests(reports_path / "growlibm_base" / "results.json") + vanilla_tests = load_tests(reports_path / "vanilla_base" / "results.json") + + shared_keys = [key for key in grow_tests if key in vanilla_tests] + missing_keys = sorted(set(grow_tests) ^ set(vanilla_tests)) + for key in missing_keys: + warn(f"benchmark present in only one report: {key}") + + benchmarks = [] + for key in shared_keys: + grow_test = grow_tests[key] + vanilla_test = vanilla_tests[key] + title = str(grow_test.get("name") or key) + image_name = f"{sanitize_filename(str(grow_test.get('link') or key))}.png" + benchmark_accelerators = accelerator_hits(grow_test, accelerator_names) + + plot_benchmark( + [ + { + "label": "vanilla_base", + "test": vanilla_test, + "bits": float(vanilla_test.get("bits", 0)), + "color": "#ff7f0e", + }, + { + "label": "growlibm_base", + "test": grow_test, + "bits": float(grow_test.get("bits", 0)), + "color": "#2ca02c", + }, + ], + image_dir / image_name, + title, + format_accelerator_summary(benchmark_accelerators), + ) + + benchmarks.append( + { + "title": title, + "image": f"{args.image_dir}/{image_name}", + "growlibm_link": f"growlibm_base/{grow_test.get('link')}/graph.html", + "vanilla_link": f"vanilla_base/{vanilla_test.get('link')}/graph.html", + "accelerators": benchmark_accelerators, + } + ) + + write_page(reports_path / args.page, args.platform, benchmarks) + inject_page_link(reports_path / "index.html", args.page) + + +if __name__ == "__main__": + main() diff --git a/growlibm/eval/evaluate-best-alt-bars.py b/growlibm/eval/evaluate-best-alt-bars.py new file mode 100644 index 0000000000..b13c00d424 --- /dev/null +++ b/growlibm/eval/evaluate-best-alt-bars.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python3 + +import argparse +import json +import re +import sys +from pathlib import Path + +from accelerator_utils import accelerator_hits, load_accelerator_names + +def warn(message): + print(f"warning: {message}", file=sys.stderr) + + +def load_json(path): + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def benchmark_key(test): + identifier = test.get("identifier") + if identifier not in (None, "", "#f"): + return str(identifier) + return str(test.get("name") or test.get("link")) + + +def parse_point(raw): + if not isinstance(raw, list) or len(raw) < 2: + return None + try: + return (float(raw[0]), float(raw[1])) + except (TypeError, ValueError): + return None + + +def most_accurate_alt(test): + raw = test.get("cost-accuracy") + if not isinstance(raw, list) or len(raw) < 2: + return None + + initial = parse_point(raw[0]) + best = parse_point(raw[1]) + bits = float(test.get("bits", 0)) + if initial is None or best is None or initial[0] == 0 or bits <= 0: + return None + + return { + "error": 100.0 * (best[1] / bits), + "speedup": initial[0] / best[0] if best[0] else 0.0, + } + + +def collect_benchmarks(reports_path, accelerator_names): + grow_data = load_json(reports_path / "growlibm_base" / "results.json") + vanilla_data = load_json(reports_path / "vanilla_base" / "results.json") + vanilla_tests = {benchmark_key(test): test for test in vanilla_data.get("tests", [])} + + benchmarks = [] + for grow_test in grow_data.get("tests", []): + accelerators = accelerator_hits(grow_test, accelerator_names) + if not accelerators: + continue + + key = benchmark_key(grow_test) + vanilla_test = vanilla_tests.get(key) + if vanilla_test is None: + warn(f"missing vanilla benchmark for {key}") + continue + + grow_alt = most_accurate_alt(grow_test) + vanilla_alt = most_accurate_alt(vanilla_test) + if grow_alt is None or vanilla_alt is None: + continue + + benchmarks.append( + { + "name": str(grow_test.get("name") or key), + "accelerators": accelerators, + "grow_error": grow_alt["error"], + "vanilla_error": vanilla_alt["error"], + "grow_speedup": grow_alt["speedup"], + "vanilla_speedup": vanilla_alt["speedup"], + } + ) + + return benchmarks + + +def plot_grouped_bars( + benchmarks, image_path, title, grow_key, vanilla_key, ylabel, square=False +): + import matplotlib + + + matplotlib.use("Agg") + import matplotlib.pyplot as plt + + if not benchmarks: + raise SystemExit("no shared benchmarks with most-accurate alternatives found") + + labels = [format_label(benchmark["name"]) for benchmark in benchmarks] + grow_values = [benchmark[grow_key] for benchmark in benchmarks] + vanilla_values = [benchmark[vanilla_key] for benchmark in benchmarks] + max_value = max([*grow_values, *vanilla_values], default=0.0) + + if square: + side = max(8.0, 0.7 * len(benchmarks) + 3.0) + fig, ax = plt.subplots(figsize=(side, side)) + else: + fig_width = max(13.0, 0.6 * len(benchmarks) + 3.0) + fig, ax = plt.subplots(figsize=(fig_width, 6.5)) + xs = list(range(len(benchmarks))) + bar_width = 0.38 + + ax.bar( + [x - bar_width / 2 for x in xs], + vanilla_values, + width=bar_width, + color="#ff7f0e", + label="vanilla", + ) + ax.bar( + [x + bar_width / 2 for x in xs], + grow_values, + width=bar_width, + color="#2ca02c", + label="growlibm", + ) + + label_offset = max(0.02 * max_value, 0.15) + top_limit = max(1.0, max_value + label_offset + 0.4) + ax.set_ylim(0, top_limit) + + def add_bar_labels(values, x_offset): + for x, value in zip(xs, values): + ax.text( + x + x_offset, + value + label_offset, + f"{value:.1f}%", + ha="center", + va="bottom", + fontsize=11, + ) + + add_bar_labels(vanilla_values, -bar_width / 2) + add_bar_labels(grow_values, bar_width / 2) + + ax.set_xticks(xs) + ax.set_xticklabels( + labels, + rotation=90, + fontsize=16, + ) + ax.set_ylabel(ylabel, fontsize=20) + ax.set_title(title, fontsize=20) + ax.grid(True, axis="y", linewidth=0.5, alpha=0.2) + ax.legend(loc="best") + + fig.tight_layout() + fig.savefig(image_path, dpi=180) + plt.close(fig) + + +def format_label(name): + if len(name) <= 10: + return name + + split_points = [match.end() for match in re.finditer(r"[-_/]", name[:-1])] + if not split_points: + return name + + midpoint = len(name) / 2 + split_point = min(split_points, key=lambda point: abs(point - midpoint)) + return f"{name[:split_point]}\n{name[split_point:]}" + + +def split_benchmarks(benchmarks, split_at): + if not split_at: + return [(benchmarks, None, None)] + + split_index = next( + (index for index, benchmark in enumerate(benchmarks) if benchmark["name"] == split_at), + None, + ) + if split_index is None: + warn(f"split benchmark {split_at!r} not found; plotting a single chart") + return [(benchmarks, None, None)] + + if split_index == 0: + warn(f"split benchmark {split_at!r} is first; plotting a single chart") + return [(benchmarks, None, None)] + + return [ + (benchmarks[:split_index], f"before {split_at}", None), + (benchmarks[split_index:], f"from {split_at} onward", f"from-{split_at}"), + ] + + +def figure_path(base_path, label_suffix): + if label_suffix is None: + return base_path + + extension = base_path.suffix or ".png" + label = re.sub(r"[^A-Za-z0-9._-]+", "_", label_suffix).strip("._") or "split" + return base_path.with_name(f"{base_path.stem}-{label}{extension}") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("reports_path", help="Path containing growlibm_base and vanilla_base") + parser.add_argument("platform", help="Platform label for generated plots") + parser.add_argument( + "--platform-file", + default="growlibm/platforms/growlibm.rkt", + help="Platform file used to discover accelerator names", + ) + args = parser.parse_args() + + reports_path = Path(args.reports_path) + accelerator_names = load_accelerator_names(Path(args.platform_file)) + benchmarks = collect_benchmarks(reports_path, accelerator_names) + benchmarks.sort(key=lambda benchmark: benchmark["vanilla_error"], reverse=True) + + platform_key = args.platform.lower() + split_at = "forward-y" if platform_key == "proj" else None + square = platform_key in {"basilisk", "coolprop"} + base_image_path = reports_path / f"{platform_key}_best-alt-bars.png" + + for section_benchmarks, split_label, suffix in split_benchmarks(benchmarks, split_at): + image_path = figure_path(base_image_path, suffix) + title = args.platform + plot_grouped_bars( + section_benchmarks, + image_path, + title, + "grow_error", + "vanilla_error", + "Error (%)", + square=square, + ) + +if __name__ == "__main__": + main() diff --git a/growlibm/eval/evaluate-frontier.py b/growlibm/eval/evaluate-frontier.py new file mode 100644 index 0000000000..1286c483b2 --- /dev/null +++ b/growlibm/eval/evaluate-frontier.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python3 + +import argparse +import json +import sys +from pathlib import Path + +from accelerator_utils import accelerator_hits, default_platform_path, load_accelerator_names + +def warn(message): + print(f"warning: {message}", file=sys.stderr) + +def load_json(path): + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + +def parse_point(raw): + if not isinstance(raw, list) or len(raw) < 2: + return None + + x_value, y_value = raw[0], raw[1] + if x_value == "N/A": + return None + + try: + return (float(x_value), float(y_value)) + except (TypeError, ValueError): + return None + +def benchmark_key(test): + identifier = test.get("identifier") + if identifier not in (None, "", "#f"): + return str(identifier) + return str(test.get("name") or test.get("link")) + +def parse_cost_accuracy(test): + raw = test.get("cost-accuracy") + if not isinstance(raw, list) or len(raw) < 2: + return None + + initial = parse_point(raw[0]) + if initial is None or initial[0] == 0: + return None + + points = [] + best = parse_point(raw[1]) + if best is not None: + points.append(best) + + if len(raw) > 2 and isinstance(raw[2], list): + for point in raw[2]: + parsed = parse_point(point) + if parsed is not None: + points.append(parsed) + + return (initial, points) + + +def pareto_compare(point1, point2): + cost1, error1 = point1 + cost2, error2 = point2 + if cost1 == cost2 and error1 == error2: + return "=" + if cost1 <= cost2 and error1 <= error2: + return "<" + if cost1 >= cost2 and error1 >= error2: + return ">" + return "<>" + +def pareto_union(curve1, curve2): + result = [] + left = list(curve1) + right = list(curve2) + while left and right: + point1 = left[0] + point2 = right[0] + relation = pareto_compare(point1, point2) + if relation == "<": + right.pop(0) + elif relation == ">": + left.pop(0) + elif relation == "=": + result.append(point1) + left.pop(0) + right.pop(0) + elif point1[1] < point2[1]: + result.append(point1) + left.pop(0) + else: + result.append(point2) + right.pop(0) + result.extend(left) + result.extend(right) + return result + + +def pareto_minimize(points): + minimized = [] + for point in sorted(points, key=lambda current: current[0]): + minimized = pareto_union([point], minimized) + return minimized + + +def pareto_shift(point0, frontier): + return [(point0[0] + point[0], point0[1] + point[1]) for point in frontier] + + +def pareto_convex(points): + prefix = [] + working = list(points) + while len(working) >= 3: + point0, point1, point2 = working[:3] + slope01 = (point1[1] - point0[1]) / (point1[0] - point0[0]) + slope12 = (point2[1] - point1[1]) / (point2[0] - point1[0]) + if slope12 > slope01: + if prefix: + working = [prefix.pop(), point0, point2, *working[3:]] + else: + working = [point0, point2, *working[3:]] + else: + prefix.append(point0) + working = [point1, point2, *working[3:]] + return prefix + working + + +def pareto_combine(frontiers, convex=False): + def finalize(frontier): + return pareto_convex(frontier) if convex else frontier + + combined = [] + for frontier in [pareto_minimize(frontier) for frontier in frontiers]: + if not combined: + combined = finalize(frontier) + continue + + combined_next = [] + for point in combined: + shifted = pareto_minimize(pareto_shift(point, frontier)) + combined_next = pareto_union(shifted, combined_next) + combined = finalize(combined_next) + return combined + + +def aggregate_frontier(data, benchmark_keys=None): + tests = data.get("tests", []) + if benchmark_keys is not None: + tests = [test for test in tests if benchmark_key(test) in benchmark_keys] + + if not tests: + return [] + + maximum_accuracy = sum(float(test.get("bits", 0)) for test in tests) + if maximum_accuracy <= 0: + return [] + + parsed = [] + for test in tests: + cost_accuracy = parse_cost_accuracy(test) + if cost_accuracy is None: + continue + + initial, points = cost_accuracy + rescaled = [(point[0] / initial[0], point[1]) for point in [initial, *points]] + parsed.append(rescaled) + + if not parsed: + return [] + + return sorted( + [ + (len(tests) / cost, 1.0 - (error / maximum_accuracy)) + for cost, error in pareto_combine(parsed, convex=True) + if cost != 0 + ], + key=lambda point: point[0], + ) + + +def parse_frontier(results_path, benchmark_keys=None): + if not results_path.exists(): + warn(f"missing {results_path}") + return [] + + data = load_json(results_path) + if benchmark_keys is not None: + return aggregate_frontier(data, benchmark_keys) + + merged = data.get("merged-cost-accuracy") + if not isinstance(merged, list) or len(merged) < 2: + warn(f"missing merged-cost-accuracy in {results_path}") + return [] + + frontier = [] + if isinstance(merged[1], list): + for raw_point in merged[1]: + point = parse_point(raw_point) + if point is not None: + frontier.append(point) + + return sorted(frontier, key=lambda point: point[0]) + + +def build_accuracy_reference(frontier): + reference = [] + best_speedup = 0.0 + for speedup, accuracy in sorted((point for point in frontier if point[0] > 0), key=lambda point: (-point[1], -point[0])): + best_speedup = max(best_speedup, speedup) + if reference and accuracy == reference[-1][0]: + reference[-1] = (accuracy, best_speedup) + else: + reference.append((accuracy, best_speedup)) + return reference + + +def vanilla_speedup_at_accuracy(reference, accuracy): + best_speedup = None + for candidate_accuracy, speedup in reference: + if candidate_accuracy < accuracy: + break + best_speedup = speedup + return best_speedup + + +def transform_point(point, vanilla_reference): + if point is None or point[0] <= 0: + return None + + vanilla_speedup = vanilla_speedup_at_accuracy(vanilla_reference, point[1]) + if vanilla_speedup is None or vanilla_speedup <= 0: + return None + + return (point[1], point[0] / vanilla_speedup) + + +def transform_frontier(frontier, vanilla_reference, max_relative_speedup=None): + transformed = [] + for point in frontier: + transformed_point = transform_point(point, vanilla_reference) + if transformed_point is None: + continue + + accuracy, relative_speedup = transformed_point + if max_relative_speedup is not None: + relative_speedup = min(relative_speedup, max_relative_speedup) + transformed.append((accuracy, relative_speedup)) + + return sorted(transformed, key=lambda point: point[0]) + + +def plot_frontier(series, image_path, platform, max_relative_speedup=None): + import matplotlib + from matplotlib.ticker import FuncFormatter + + matplotlib.use("Agg") + import matplotlib.pyplot as plt + + fig, ax = plt.subplots(figsize=(8, 6)) + have_points = False + minimum_accuracy_point = None + parsed_series = [] + vanilla_reference = None + + for one_series in series: + frontier = parse_frontier( + one_series["results_path"], + one_series.get("benchmark_keys"), + ) + parsed_series.append({**one_series, "frontier": frontier}) + if one_series.get("baseline"): + vanilla_reference = build_accuracy_reference(frontier) + + if vanilla_reference is None: + raise SystemExit("a baseline series is required to plot speedup over vanilla") + + for one_series in parsed_series: + transformed_frontier = transform_frontier( + one_series["frontier"], vanilla_reference, max_relative_speedup + ) + + if transformed_frontier: + have_points = True + xs = [point[0] for point in transformed_frontier] + ys = [point[1] for point in transformed_frontier] + candidate = min(transformed_frontier, key=lambda point: (point[0], point[1])) + if minimum_accuracy_point is None or (candidate[0], candidate[1]) < ( + minimum_accuracy_point[0], + minimum_accuracy_point[1], + ): + minimum_accuracy_point = candidate + ax.scatter(xs, ys, s=26, color=one_series["color"], label=one_series["label"]) + ax.plot(xs, ys, color=one_series["color"], linewidth=1.4, alpha=0.35) + + if not have_points: + ax.text(0.5, 0.5, "No frontier data found", ha="center", va="center", transform=ax.transAxes) + + title = f"{platform}" + ax.set_title(title, fontsize=20) + ax.set_xlabel("Accuracy", fontsize=18) + ax.set_ylabel("Speedup over vanilla", fontsize=18) + if minimum_accuracy_point is not None: + ax.set_xlim(minimum_accuracy_point[0], 1.0) + else: + ax.set_xlim(0.4, 1.0) + if max_relative_speedup is not None: + ax.set_ylim(0.9, max_relative_speedup) + else: + ax.set_ylim(bottom=0.9) + ax.axhline(1.0, color="black", linewidth=1.0, zorder=0) + ax.xaxis.set_major_formatter(FuncFormatter(lambda value, _: f"{100 * value:.0f}%")) + ax.yaxis.set_major_formatter(FuncFormatter(lambda value, _: f"{value:.2g}x")) + ax.grid(True, linewidth=0.5, alpha=0.2) + if have_points: + ax.legend(loc="upper left", fontsize=16) + ax.tick_params(axis="both", labelsize=14) + + fig.tight_layout() + fig.savefig(image_path, dpi=180) + plt.close(fig) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("reports_path", help="Path containing evaluate.sh report folders") + parser.add_argument("platform", help="Name of growlibm platform under test") + parser.add_argument( + "--accelerators-only", + action="store_true", + help="Aggregate only benchmarks where growlibm uses an accelerator", + ) + parser.add_argument( + "--max-relative-speedup", + type=float, + help="Cap plotted speedup-over-vanilla values on the vertical axis", + ) + parser.add_argument( + "--platform-file", + help="Platform file used to discover accelerator names", + ) + args = parser.parse_args() + + reports_path = Path(args.reports_path) + image_path = reports_path / f"{args.platform.lower()}_frontier.png" + benchmark_keys = None + + if args.accelerators_only: + platform_path = Path(args.platform_file) if args.platform_file else default_platform_path(args.platform) + accelerator_names = load_accelerator_names(platform_path) + growlibm_results = load_json(reports_path / "growlibm_base" / "results.json") + benchmark_keys = { + benchmark_key(test) + for test in growlibm_results.get("tests", []) + if accelerator_hits(test, accelerator_names) + } + if not benchmark_keys: + warn("no benchmarks used accelerators; filtered frontier will be empty") + + series = [ + { + "label": "vanilla", + "results_path": reports_path / "vanilla_base" / "results.json", + "color": "#ff7f0e", + "baseline": True, + "benchmark_keys": benchmark_keys, + }, + { + "label": "growlibm", + "results_path": reports_path / "growlibm_base" / "results.json", + "color": "#2ca02c", + "benchmark_keys": benchmark_keys, + }, + ] + + plot_frontier(series, image_path, args.platform, args.max_relative_speedup) + +if __name__ == "__main__": + main() diff --git a/growlibm/eval/evaluate-histograms.py b/growlibm/eval/evaluate-histograms.py new file mode 100644 index 0000000000..18fd62e929 --- /dev/null +++ b/growlibm/eval/evaluate-histograms.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python3 + +import argparse +import json +import math +import os +import sys +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[2] +DEFAULT_RESULTS = REPO_ROOT / "reports" / "histo" / "results.json" +DEFAULT_COSTS = REPO_ROOT / "reports" / "histo" / "costs.json" +DEFAULT_COUNTS = REPO_ROOT / "reports" / "histo" / "counts.json" +PLOT_CACHE_DIR = Path("/tmp/herbie-plot-cache") +PLOT_CACHE_DIR.mkdir(parents=True, exist_ok=True) +os.environ.setdefault("MPLCONFIGDIR", str(PLOT_CACHE_DIR / "matplotlib")) +os.environ.setdefault("XDG_CACHE_HOME", str(PLOT_CACHE_DIR / "xdg-cache")) + +import matplotlib + +matplotlib.use("Agg") +import matplotlib.pyplot as plt + + +def warn(message): + print(f"warning: {message}", file=sys.stderr) + + +def load_json(path): + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def load_results(path): + data = load_json(path) + tests = data.get("tests") + if not isinstance(tests, list): + raise SystemExit(f"{path} is missing a tests list") + return data + + +def benchmark_names(results): + names = [] + for test in results.get("tests", []): + name = test.get("name") or test.get("input") or test.get("link") + if name is not None: + names.append(str(name)) + return names + + +def numeric_mapping_values(mapping, keys, label): + if not isinstance(mapping, dict): + raise SystemExit(f"{label} file must contain a JSON object") + + values = [] + missing = [] + for key in keys: + raw_value = mapping.get(key) + if raw_value is None: + missing.append(key) + continue + + try: + values.append(float(raw_value)) + except (TypeError, ValueError): + warn(f"skipping non-numeric {label} value for {key}") + + if missing: + warn(f"{label} file is missing {len(missing)} candidates") + + extras = set(mapping) - set(keys) + if extras: + warn(f"{label} file has {len(extras)} extra candidates") + + if not values: + raise SystemExit(f"no numeric {label} values found") + + return values + + +def end_urgencies(results): + values = [] + for test in results.get("tests", []): + raw_error = test.get("end") + raw_bits = test.get("bits") + if raw_error is None or raw_bits is None: + continue + + try: + error_bits = float(raw_error) + bits = float(raw_bits) + except (TypeError, ValueError): + warn(f"skipping malformed end/bits values for {test.get('name', '')}") + continue + + if bits <= 0: + warn(f"skipping non-positive bit width for {test.get('name', '')}") + continue + + values.append(100.0 * (error_bits / bits)) + + if not values: + raise SystemExit("no end values found in results.json") + + return values + + +def maybe_drop_low_urgency(values, enabled): + if not enabled: + return values + + filtered = [value for value in values if value > 1] + if not filtered: + raise SystemExit("all urgency values were 0.1 or lower after filtering") + return filtered + + +def linear_bins(values, bin_count): + low = min(values) + high = max(values) + if low == high: + padding = 1.0 if low == 0 else abs(low) * 0.05 + return [low - padding, high + padding] + step = (high - low) / bin_count + return [low + index * step for index in range(bin_count + 1)] + + +def log_bins(values, bin_count): + positive_values = [value for value in values if value > 0] + if not positive_values: + raise SystemExit("log-scaled histogram requires positive values") + + low = min(positive_values) + high = max(positive_values) + if low == high: + low *= 0.95 + high *= 1.05 + return [low, high] + + log_low = math.log10(low) + log_high = math.log10(high) + step = (log_high - log_low) / bin_count + return [10 ** (log_low + index * step) for index in range(bin_count + 1)] + + +def plot_histogram(values, output_path, title, xlabel, color, bins, log_x=False): + fig, ax = plt.subplots(figsize=(8, 6)) + ax.hist(values, bins=bins, color=color, edgecolor="white", linewidth=0.8) + ax.set_title(title) + ax.set_xlabel(xlabel) + ax.set_ylabel("Candidates") + ax.grid(axis="y", alpha=0.25, linewidth=0.6) + ax.set_axisbelow(True) + if log_x: + ax.set_xscale("log") + + fig.tight_layout() + fig.savefig(output_path, dpi=180) + plt.close(fig) + + +def main(): + parser = argparse.ArgumentParser( + description="Plot separate histograms for candidate costs, counts, and end urgency." + ) + parser.add_argument("--results", type=Path, default=DEFAULT_RESULTS) + parser.add_argument("--costs", type=Path, default=DEFAULT_COSTS) + parser.add_argument("--counts", type=Path, default=DEFAULT_COUNTS) + parser.add_argument("--output-dir", type=Path) + parser.add_argument("--bins", type=int, default=30) + parser.add_argument( + "--drop-low-urgency", + action="store_true", + help="Discard candidates whose urgency is 0.1 or lower before plotting the urgency histogram", + ) + parser.add_argument( + "--drop-zero-urgency", + action="store_true", + help=argparse.SUPPRESS, + ) + args = parser.parse_args() + + if args.bins < 1: + raise SystemExit("--bins must be at least 1") + + results = load_results(args.results) + names = benchmark_names(results) + costs = numeric_mapping_values(load_json(args.costs), names, "cost") + counts = numeric_mapping_values(load_json(args.counts), names, "count") + urgencies = maybe_drop_low_urgency( + end_urgencies(results), + args.drop_low_urgency or args.drop_zero_urgency, + ) + + output_dir = args.output_dir or args.results.parent + output_dir.mkdir(parents=True, exist_ok=True) + + plot_histogram( + costs, + output_dir / "costs-histogram.png", + "Size Distribution", + "Size", + "#4c78a8", + log_bins(costs, args.bins), + log_x=True, + ) + plot_histogram( + counts, + output_dir / "counts-histogram.png", + "Frequency Distribution", + "Frequency", + "#f58518", + log_bins(counts, args.bins), + log_x=True, + ) + plot_histogram( + urgencies, + output_dir / "urgency-histogram.png", + "Urgency Distribution", + "Urgency (%)", + "#54a24b", + linear_bins(urgencies, args.bins), + ) + + +if __name__ == "__main__": + main() diff --git a/growlibm/eval/evaluate-report.py b/growlibm/eval/evaluate-report.py new file mode 100644 index 0000000000..d7c3a48f54 --- /dev/null +++ b/growlibm/eval/evaluate-report.py @@ -0,0 +1,113 @@ +import json, os, sys + +class report: + def __init__(self, accelerators, path) -> None: + self.accelerators = accelerators + self.path = path + +reports_path = sys.argv[1] +platform = sys.argv[2] +platforms = ["vanilla", "growlibm"] +options = ["base"] +if platform == "proj": + accelerators = ["sinprod", "cosprod", "sinquot", "cosquot", "log1pmd", "invgud", "hypot", "verdcos"] +elif platform == "basilisk": + accelerators = ["powcos", "powcos2", "powcos4", "powcos6", "ncos1p"] +elif platform == "coolprop": + accelerators = ["pow1ms", "pown2o3", "pow2o5", "pow3o5", "pow5o3", "pown16o5"] +else: + accelerators = [] + +output_path = reports_path + "/index.html" +reports = [] + +for p in platforms: + for o in options: + r = report(p == "growlibm" or p == "herbie20plus", p + "_" + o) + reports.append(r) +reports.append(report(True, "growlibmbest_base")) + +def calculate_end_accuracy(data): + total_end = 0 + max_accuracy = 0 + for test in data.get("tests", []): + total_end += test.get("end", 0) + max_accuracy += test.get("bits", 0) + if max_accuracy == 0: + return 0.0 + return 100 - (100 * (total_end / max_accuracy)) + +def load_report(path): + with open(path, 'r') as f: + return json.load(f) + +def get_accuracy_str(path): + if not os.path.exists(path): + return "n/a" + report = load_report(path) + percent = calculate_end_accuracy(report) + return f"{percent:.1f}%" + +def format_accelerator_rows(accelerators, counts): + rows = [] + for acc in accelerators: + count = counts.get(acc, 0) + rows.append(f'{acc}{count}') + return "".join(rows) + +def read_text(path): + with open(path, 'r') as f: + return f.read() + +def get_counts(path): + if not os.path.exists(path): + return {acc_name: 0 for acc_name in accelerators} + return {acc_name: read_text(path).count((acc_name + '.')) for acc_name in accelerators} + +accuracy_rows = [] +accelerator_rows = [] +for r in reports: + results_path = f"{reports_path}/{r.path}/results.json" + accuracy_rows.append(f"
  • {r.path}: {get_accuracy_str(results_path)}
  • ") + if r.accelerators: + accelerator_rows.append(f'{r.path}') + accelerator_rows.append( + format_accelerator_rows( + accelerators, + get_counts(f"{reports_path}/{r.path}/results.json"), + ) + ) + +accuracy_html = "".join(accuracy_rows) +accelerator_html = "".join(accelerator_rows) + +html_content = f""" + + + + + {platform} + + +

    {platform}

    +

    Evaluation

    +
      + {accuracy_html} +
    + +

    Accelerators

    + + + + + + {accelerator_html} +
    NameUses
    + + + + +""" + +with open(output_path, 'w') as f: + f.write(html_content) diff --git a/growlibm/eval/evaluate-timeline.py b/growlibm/eval/evaluate-timeline.py new file mode 100644 index 0000000000..87ec81a308 --- /dev/null +++ b/growlibm/eval/evaluate-timeline.py @@ -0,0 +1,585 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import html +import json +import re +import subprocess +import sys +import textwrap +from dataclasses import asdict, dataclass +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] +DEFAULT_TIMELINE_PATH = REPO_ROOT / "reports" / "timeline.json" +DEFAULT_LOG_PATH = REPO_ROOT / "reports" / "log.txt" +DEFAULT_OUTPUT_NAME = "timeline.png" + +CHECKPOINT_RE = re.compile( + r"^(start|after_[A-Za-z0-9_]+)\t([^\t]+)\t([0-9]+(?:\.[0-9]+)?)$" +) +SCRIPT_START_RE = re.compile(r"^\+ SCRIPT_START_ISO=(\S+)$") +LOG_TIME_RE = re.compile(r"^\+ log_time ([A-Za-z0-9_]+)$") +ISO_TIME_RE = re.compile(r"^\+ iso_time=(\S+)$") +ELAPSED_RE = re.compile(r"^\+ elapsed=([0-9]+(?:\.[0-9]+)?)$") +RUN_LABEL_RE = re.compile(r"^Running branch ([^ ]+) on repo ([^ ]+)$") +RUN_HERBIE_CANDIDATES_RE = re.compile(r"after_run_herbie_candidates_iter_(\d+)") +ADD_TO_PLATFORM_RE = re.compile(r"after_add_to_platform_iter_(\d+)") +HARDCODED_STAGE_DURATIONS = { + "after_initial_compilation": 4.1 * 60, + "after_final_compilation": 18.7 * 60, +} + + +@dataclass(frozen=True) +class Checkpoint: + phase: str + timestamp: str + elapsed_seconds: float + + +@dataclass(frozen=True) +class Stage: + label: str + start_phase: str + end_phase: str + start_timestamp: str + end_timestamp: str + elapsed_start_seconds: float + duration_seconds: float + elapsed_end_seconds: float + percent_of_total: float + + +@dataclass(frozen=True) +class IterationSpan: + label: str + elapsed_start_seconds: float + elapsed_end_seconds: float + + +def warn(message: str) -> None: + print(f"warning: {message}", file=sys.stderr) + + +def format_duration(seconds: float) -> str: + total_seconds = round(seconds) + hours, remainder = divmod(total_seconds, 3600) + minutes, secs = divmod(remainder, 60) + pieces = [] + if hours: + pieces.append(f"{hours}h") + if minutes or hours: + pieces.append(f"{minutes}m") + pieces.append(f"{secs}s") + return " ".join(pieces) + + +def humanize_phase(phase: str) -> str: + if phase == "start": + return "start" + + named_phases = { + "after_initial_compilation": "initial compilation", + "after_generate": "candidate generation", + "after_final_compilation": "final compilation", + } + if phase in named_phases: + return named_phases[phase] + + iter_match = RUN_HERBIE_CANDIDATES_RE.fullmatch(phase) + if iter_match: + return "urgency ranking" + + iter_match = ADD_TO_PLATFORM_RE.fullmatch(phase) + if iter_match: + return "implication pass" + + if phase.startswith("after_"): + phase = phase[len("after_") :] + return phase.replace("_", " ") + + +def stage_label(start_phase: str, end_phase: str) -> str: + if start_phase == "start": + return humanize_phase(end_phase) + return humanize_phase(end_phase) + + +def parse_runs_from_checkpoint_rows(lines: list[str]) -> list[list[Checkpoint]]: + runs = [] + current = [] + + for line in lines: + match = CHECKPOINT_RE.match(line) + if not match: + continue + + checkpoint = Checkpoint( + phase=match.group(1), + timestamp=match.group(2), + elapsed_seconds=float(match.group(3)), + ) + + if checkpoint.phase == "start" and current: + runs.append(current) + current = [checkpoint] + else: + current.append(checkpoint) + + if current: + runs.append(current) + + return runs + + +def parse_runs_from_xtrace(lines: list[str]) -> list[list[Checkpoint]]: + runs = [] + current = [] + pending_phase = None + pending_timestamp = None + pending_elapsed = None + + for line in lines: + start_match = SCRIPT_START_RE.match(line) + if start_match: + if current: + runs.append(current) + current = [Checkpoint("start", start_match.group(1), 0.0)] + pending_phase = None + pending_timestamp = None + pending_elapsed = None + continue + + log_time_match = LOG_TIME_RE.match(line) + if log_time_match: + pending_phase = log_time_match.group(1) + pending_timestamp = None + pending_elapsed = None + continue + + if pending_phase: + iso_time_match = ISO_TIME_RE.match(line) + if iso_time_match: + pending_timestamp = iso_time_match.group(1) + continue + + elapsed_match = ELAPSED_RE.match(line) + if elapsed_match: + pending_elapsed = float(elapsed_match.group(1)) + + if pending_timestamp is not None and pending_elapsed is not None: + if not current: + current = [Checkpoint("start", pending_timestamp, 0.0)] + current.append(Checkpoint(pending_phase, pending_timestamp, pending_elapsed)) + pending_phase = None + pending_timestamp = None + pending_elapsed = None + + if current: + runs.append(current) + + return runs + + +def checkpoint_from_json(payload: object) -> Checkpoint: + if not isinstance(payload, dict): + raise SystemExit("timeline JSON checkpoints must be objects") + + return Checkpoint( + phase=str(payload["phase"]), + timestamp=str(payload["timestamp"]), + elapsed_seconds=float(payload["elapsed_seconds"]), + ) + + +def extract_run_labels(lines: list[str]) -> list[str]: + labels = [] + for line in lines: + match = RUN_LABEL_RE.match(line) + if match: + labels.append(f"{match.group(1)} on {match.group(2)}") + return labels + + +def normalize_run(run: list[Checkpoint]) -> list[Checkpoint]: + deduped = [] + seen = set() + for checkpoint in run: + key = (checkpoint.phase, checkpoint.timestamp, checkpoint.elapsed_seconds) + if key in seen: + continue + seen.add(key) + deduped.append(checkpoint) + return sorted(deduped, key=lambda checkpoint: checkpoint.elapsed_seconds) + + +def load_runs_from_json(timeline_path: Path) -> tuple[list[list[Checkpoint]], list[str]]: + payload = json.loads(timeline_path.read_text(encoding="utf-8")) + + if isinstance(payload, dict): + if "runs" in payload: + run_payloads = payload["runs"] + else: + run_payloads = [payload["checkpoints"]] + labels = [str(label) for label in payload.get("run_labels", [])] + elif isinstance(payload, list): + if payload and isinstance(payload[0], list): + run_payloads = payload + else: + run_payloads = [payload] + labels = [] + else: + raise SystemExit("timeline JSON must be a checkpoint list or a runs object") + + runs = [ + normalize_run([checkpoint_from_json(checkpoint) for checkpoint in run_payload]) + for run_payload in run_payloads + ] + return [run for run in runs if run], labels + + +def load_runs(input_path: Path) -> tuple[list[list[Checkpoint]], list[str]]: + if input_path.suffix.lower() == ".json": + return load_runs_from_json(input_path) + + lines = input_path.read_text(encoding="utf-8", errors="replace").splitlines() + labels = extract_run_labels(lines) + + runs = [normalize_run(run) for run in parse_runs_from_checkpoint_rows(lines)] + runs = [run for run in runs if run] + if runs: + return runs, labels + + runs = [normalize_run(run) for run in parse_runs_from_xtrace(lines)] + runs = [run for run in runs if run] + return runs, labels + + +def select_run(runs: list[list[Checkpoint]], run_index: int) -> list[Checkpoint]: + if not runs: + raise SystemExit("no timeline checkpoints found in input") + + try: + run = runs[run_index] + except IndexError as err: + raise SystemExit( + f"requested run index {run_index} but only found {len(runs)} run(s)" + ) from err + + if len(run) < 2: + raise SystemExit("need at least two checkpoints to build a stage timeline") + + return run + + +def build_stages(checkpoints: list[Checkpoint]) -> list[Stage]: + stages = [] + elapsed_start_seconds = 0.0 + + for start, end in zip(checkpoints, checkpoints[1:]): + actual_duration = end.elapsed_seconds - start.elapsed_seconds + if actual_duration < 0: + raise SystemExit( + f"checkpoint {end.phase} is earlier than {start.phase}; log order is inconsistent" + ) + duration = HARDCODED_STAGE_DURATIONS.get(end.phase, actual_duration) + elapsed_end_seconds = elapsed_start_seconds + duration + + stages.append( + Stage( + label=stage_label(start.phase, end.phase), + start_phase=start.phase, + end_phase=end.phase, + start_timestamp=start.timestamp, + end_timestamp=end.timestamp, + elapsed_start_seconds=elapsed_start_seconds, + duration_seconds=duration, + elapsed_end_seconds=elapsed_end_seconds, + percent_of_total=0.0, + ) + ) + elapsed_start_seconds = elapsed_end_seconds + + total_elapsed = elapsed_start_seconds + if total_elapsed <= 0: + raise SystemExit("final checkpoint has non-positive elapsed time") + + return [ + Stage( + label=stage.label, + start_phase=stage.start_phase, + end_phase=stage.end_phase, + start_timestamp=stage.start_timestamp, + end_timestamp=stage.end_timestamp, + elapsed_start_seconds=stage.elapsed_start_seconds, + duration_seconds=stage.duration_seconds, + elapsed_end_seconds=stage.elapsed_end_seconds, + percent_of_total=(100.0 * stage.duration_seconds / total_elapsed), + ) + for stage in stages + ] + + +def stage_color(index: int) -> str: + palette = [ + "#4c78a8", + "#f58518", + "#54a24b", + "#e45756", + "#72b7b2", + "#b279a2", + "#ff9da6", + "#9d755d", + "#bab0ab", + "#8cd17d", + ] + return palette[index % len(palette)] + + +def iteration_index_for_phase(phase: str) -> int | None: + for pattern in (RUN_HERBIE_CANDIDATES_RE, ADD_TO_PLATFORM_RE): + match = pattern.fullmatch(phase) + if match: + return int(match.group(1)) + return None + + +def build_iteration_spans(stages: list[Stage]) -> list[IterationSpan]: + spans = [] + current_iteration = None + current_start = None + current_end = None + + for stage in stages: + iteration = iteration_index_for_phase(stage.end_phase) + if iteration is None: + if current_iteration is not None: + spans.append( + IterationSpan( + label=f"Filter Iteration {current_iteration + 1}", + elapsed_start_seconds=current_start, + elapsed_end_seconds=current_end, + ) + ) + current_iteration = None + current_start = None + current_end = None + continue + + if iteration != current_iteration: + if current_iteration is not None: + spans.append( + IterationSpan( + label=f"Filter Iteration {current_iteration + 1}", + elapsed_start_seconds=current_start, + elapsed_end_seconds=current_end, + ) + ) + current_iteration = iteration + current_start = stage.elapsed_start_seconds + current_end = stage.elapsed_end_seconds + else: + current_end = stage.elapsed_end_seconds + + if current_iteration is not None: + spans.append( + IterationSpan( + label=f"Filter Iteration {current_iteration + 1}", + elapsed_start_seconds=current_start, + elapsed_end_seconds=current_end, + ) + ) + + return spans + + +def render_svg(checkpoints: list[Checkpoint], stages: list[Stage]) -> str: + total_elapsed = stages[-1].elapsed_end_seconds + iteration_spans = build_iteration_spans(stages) + width = 1400 + left_margin = 110 + right_margin = 60 + top_margin = 46 + iteration_bar_top = 60 + iteration_bar_height = 18 + bar_top = 90 + bar_height = 42 + label_top = 180 + label_row_gap = 74 + label_line_height = 18 + bottom_margin = 44 + plot_width = width - left_margin - right_margin + height = label_top + label_row_gap + (3 * label_line_height) + bottom_margin + subtitle = f"Total time: {format_duration(total_elapsed)}" + + parts = [ + f'', + "growlibm timeline", + f"{html.escape(subtitle)}", + """ + +""".strip(), + f'', + f'{html.escape(subtitle)}', + f'', + ] + + for span in iteration_spans: + x_pos = left_margin + (plot_width * span.elapsed_start_seconds / total_elapsed) + bar_width = plot_width * ( + (span.elapsed_end_seconds - span.elapsed_start_seconds) / total_elapsed + ) + center_x = x_pos + (bar_width / 2.0) + parts.append( + f'' + ) + parts.append( + f'{html.escape(span.label)}' + ) + + for index, stage in enumerate(stages): + color = stage_color(index) + x_pos = left_margin + (plot_width * stage.elapsed_start_seconds / total_elapsed) + bar_width = max(2.0, plot_width * stage.duration_seconds / total_elapsed) + center_x = x_pos + (bar_width / 2.0) + label_x = center_x + label_y = label_top + ((index % 2) * label_row_gap) + wrapped = textwrap.wrap(stage.label, width=18) or [stage.label] + + parts.append( + f'' + ) + parts.append( + f'' + ) + parts.append( + f'{html.escape(wrapped[0])}' + ) + + for line_index, line in enumerate(wrapped[1:2], start=1): + parts.append( + f'{html.escape(line)}' + ) + + duration_y = label_y + min(len(wrapped), 2) * label_line_height + parts.append( + f'{html.escape(format_duration(stage.duration_seconds))}' + ) + + parts.append("") + return "\n".join(parts) + + +def write_output(svg_text: str, output_path: Path) -> Path: + suffix = output_path.suffix.lower() + if suffix == "": + output_path = output_path.with_suffix(".png") + suffix = ".png" + + output_path.parent.mkdir(parents=True, exist_ok=True) + + if suffix == ".svg": + output_path.write_text(svg_text, encoding="utf-8") + return output_path + + if suffix == ".png": + try: + subprocess.run( + ["rsvg-convert", "--format=png", "--output", str(output_path)], + input=svg_text, + text=True, + check=True, + ) + except FileNotFoundError as err: + raise SystemExit("rsvg-convert is required to export PNG output") from err + return output_path + + raise SystemExit("--output must end in .png or .svg") + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Generate a stage timeline plot from growlibm timeline JSON or a legacy log file." + ) + parser.add_argument( + "input_path", + nargs="?", + type=Path, + help="Path to timeline JSON or a growlibm log file (default: reports/timeline.json if present, otherwise reports/log.txt)", + ) + parser.add_argument( + "-o", + "--output", + type=Path, + help="Plot output path (default: alongside the input as timeline.png)", + ) + parser.add_argument( + "--json-output", + type=Path, + help="Optional JSON output path for the extracted checkpoints and stages", + ) + parser.add_argument( + "--run-index", + type=int, + default=-1, + help="Which run to render when the log contains multiple runs (default: -1, the last run)", + ) + args = parser.parse_args() + + input_path = args.input_path + if input_path is None: + if DEFAULT_TIMELINE_PATH.exists(): + input_path = DEFAULT_TIMELINE_PATH + else: + input_path = DEFAULT_LOG_PATH + if not input_path.exists(): + raise SystemExit(f"timeline input not found: {input_path}") + + output_path = args.output or input_path.with_name(DEFAULT_OUTPUT_NAME) + + runs, labels = load_runs(input_path) + checkpoints = select_run(runs, args.run_index) + stages = build_stages(checkpoints) + + if len(runs) > 1: + warn(f"found {len(runs)} runs in {input_path}; rendering run index {args.run_index}") + + selected_run_number = args.run_index + if selected_run_number < 0: + selected_run_number = len(runs) + selected_run_number + + run_label = f"run {selected_run_number + 1}" + if 0 <= selected_run_number < len(labels): + run_label = labels[selected_run_number] + + svg_text = render_svg(checkpoints=checkpoints, stages=stages) + output_path = write_output(svg_text, output_path) + + if args.json_output is not None: + args.json_output.parent.mkdir(parents=True, exist_ok=True) + payload = { + "input_path": str(input_path), + "run_index": args.run_index, + "run_count": len(runs), + "run_label": run_label, + "checkpoints": [asdict(checkpoint) for checkpoint in checkpoints], + "stages": [asdict(stage) for stage in stages], + } + args.json_output.write_text(json.dumps(payload, indent=2), encoding="utf-8") + + print(output_path) + + +if __name__ == "__main__": + main() diff --git a/growlibm/eval/generate-table.rkt b/growlibm/eval/generate-table.rkt new file mode 100644 index 0000000000..7420bb5ded --- /dev/null +++ b/growlibm/eval/generate-table.rkt @@ -0,0 +1,269 @@ +#lang racket + +(require racket/format + racket/file + racket/list + racket/runtime-path + racket/set + racket/string + "../../src/core/points.rkt" + "../../src/core/sampling.rkt" + "../../src/syntax/batch.rkt" + "../../src/syntax/load-platform.rkt" + "../../src/syntax/platform.rkt" + "../../src/syntax/sugar.rkt" + "../../src/syntax/types.rkt" + "../../src/utils/common.rkt") + +(define-runtime-path default-output-path "accelerator-table.tex") +(define-runtime-path default-reports-path "../../reports") + +(struct accelerator (impl-name name vars spec cost) #:transparent) + +;; Fill this in manually as needed. +(define accelerator->origin + (hash + 'sinprod "PROJ" + 'cosprod "PROJ" + 'cosquot "RPOJ" + 'sinquot "PROJ" + 'log1pmd "PROJ" + 'logfabs1p "PROJ" + 'invgud "PROJ" + 'hypot "PROJ" + 'verdcos "PROJ" + 'powcos2 "BASILISK" + 'powcos4 "BASILISK" + 'powcos6 "BASILISK" + 'powcos "BASILISK" + 'cosn1 "BASILISK" + 'pow1ms "BASILISK" + 'pow1ms "COOLPROP" + 'powquot2 "COOLPROP" + 'pown2o3 "COOLPROP" + 'pow2o5 "COOLPROP" + 'pow3o5 "COOLPROP" + 'pow5o3 "COOLPROP" + 'pown16o5 "COOLPROP")) + +(define (impl-fpcore-name impl-name) + (match (impl-info impl-name 'fpcore) + [`(! ,_props ... (,name ,_args ...)) name] + [`(,name ,_args ...) name] + [(? symbol? name) name] + [_ impl-name])) + +(define (growlibm-only-impls) + (activate-platform! "vanilla") + (define vanilla-impls (list->seteq (platform-impls (*active-platform*)))) + (activate-platform! "growlibm") + (filter (lambda (impl) (not (set-member? vanilla-impls impl))) + (platform-impls (*active-platform*)))) + +(define (collect-accelerators) + (sort + (for/list ([impl-name (in-list (growlibm-only-impls))]) + (accelerator impl-name + (impl-fpcore-name impl-name) + (impl-info impl-name 'vars) + (impl-info impl-name 'spec) + (impl-info impl-name 'cost))) + symbolaccuracy score repr) + (~r score #:precision '(= 3))) + +(define (format-cost cost) + (if (real? cost) + (~r cost #:precision '(= 3)) + (~a cost))) + +(define (make-pcontext spec-prog ctx) + (define-values (batch brfs) (progs->batch (list (prog->spec spec-prog)))) + (apply mk-pcontext (sample-points '(TRUE) batch brfs (list ctx)))) + +;; Return average error in bits for an expression over a given pcontext. +(define (get-error expr pcontext ctx) + (errors-score (errors expr pcontext ctx))) + +(define (compute-row acc) + (define repr (get-representation 'binary64)) + (define ctx (context (accelerator-vars acc) + repr + (make-list (length (accelerator-vars acc)) repr))) + (define spec-prog (fpcore->prog (accelerator-spec acc) ctx)) + (define accelerator-prog (cons (accelerator-impl-name acc) (accelerator-vars acc))) + (define cost-proc (platform-cost-proc (*active-platform*))) + (with-handlers ([exn:fail? + (lambda (exn) + (eprintf "Warning: failed to compute metrics for ~a: ~a\n" + (accelerator-name acc) + (exn-message exn)) + (hash 'name (symbol->string (accelerator-name acc)) + 'origin (hash-ref accelerator->origin (accelerator-name acc) "") + 'report-uses 0 + 'spec (~s (accelerator-spec acc)) + 'cost (format-cost (accelerator-cost acc)) + 'accuracy "n/a" + 'spec-cost "n/a" + 'spec-accuracy "n/a"))]) + (define pcontext (make-pcontext spec-prog ctx)) + (define accelerator-error (get-error accelerator-prog pcontext ctx)) + (define spec-error (get-error spec-prog pcontext ctx)) + (hash 'name (symbol->string (accelerator-name acc)) + 'origin (hash-ref accelerator->origin (accelerator-name acc) "") + 'report-uses 0 + 'spec (~s (accelerator-spec acc)) + 'cost (format-cost (accelerator-cost acc)) + 'accuracy (score->accuracy accelerator-error repr) + 'spec-cost (format-cost (cost-proc spec-prog repr)) + 'spec-accuracy (score->accuracy spec-error repr)))) + +(define (accumulate-accelerator-calls! expr accelerator-names counts) + (cond + [(list? expr) + (when (and (pair? expr) + (symbol? (first expr)) + (set-member? accelerator-names (first expr))) + (hash-update! counts (first expr) add1 0)) + (for ([subexpr (in-list expr)]) + (accumulate-accelerator-calls! subexpr accelerator-names counts))] + [(vector? expr) + (for ([subexpr (in-vector expr)]) + (accumulate-accelerator-calls! subexpr accelerator-names counts))] + [else (void)])) + +(define (collect-report-usage-counts accelerator-names [reports-path default-reports-path]) + (define counts (make-hasheq)) + (for ([name (in-set accelerator-names)]) + (hash-set! counts name 0)) + (if (directory-exists? reports-path) + (for ([path (in-directory reports-path)] + #:when (equal? (path->string (file-name-from-path path)) "final-alts.txt")) + (with-handlers ([exn:fail? + (lambda (exn) + (eprintf "Warning: failed to read ~a: ~a\n" + (path->string path) + (exn-message exn)))]) + (call-with-input-file path + (lambda (in) + (let loop () + (define expr (read in)) + (unless (eof-object? expr) + (accumulate-accelerator-calls! expr accelerator-names counts) + (loop))))))) + (eprintf "Warning: reports directory ~a does not exist; usage counts will be zero.\n" + (path->string reports-path))) + counts) + +(define (attach-report-usage row usage-counts) + (hash-set row + 'report-uses + (hash-ref usage-counts + (string->symbol (hash-ref row 'name)) + 0))) + +(define (render-rows rows) + (string-join + (for/list ([row (in-list rows)]) + (format + "~a & ~a & ~a & ~a & ~a & ~a & ~a \\\\" + (escape-latex (hash-ref row 'name)) + (escape-latex (hash-ref row 'spec)) + (escape-latex (hash-ref row 'spec-cost)) + (escape-latex (hash-ref row 'spec-accuracy)) + (escape-latex (hash-ref row 'cost)) + (escape-latex (hash-ref row 'accuracy)) + (hash-ref row 'report-uses) + + )) + "\n")) + +(define (render-latex rows) + (format + (string-append + "\\documentclass{article}\n" + "\\usepackage[T1]{fontenc}\n" + "\\usepackage[margin=1in]{geometry}\n" + "\\begin{document}\n" + "\\section*{growlibm accelerators}\n" + "\\begin{tabular}{llllllll}\n" + "\\hline\n" + "name & spec & naive cost & naive error & expert cost & expert error & uses\\\\\n" + "\\hline\n" + "~a\n" + "\\hline\n" + "\\end{tabular}\n" + "\\end{document}\n") + (render-rows rows))) + +(define output-path (make-parameter (path->string default-output-path))) +(define seed (make-parameter 1)) + +(command-line + #:program "generate-table.rkt" + #:once-each + [("--seed") n "Random seed for sampling points." + (define parsed (string->number n)) + (unless (and parsed (exact-integer? parsed)) + (error 'generate-table.rkt "Invalid --seed value: ~a" n)) + (seed parsed)] + [("--output") path "Output LaTeX path." + (output-path path)]) + +(define accelerators + (with-handlers ([exn:fail? + (lambda (exn) + (error 'generate-table.rkt + (string-append + "Failed to activate vanilla/growlibm platform. " + "Run `make compile-accelerators` first.\n" + (exn-message exn))))]) + (collect-accelerators))) + +(set-seed! (seed)) + +(define accelerator-usage-counts + (collect-report-usage-counts + (for/seteq ([acc (in-list accelerators)]) + (accelerator-name acc)))) + +(define (rownumber (vector-ref (current-command-line-arguments) 1))) +(define implication-seed (string->number (vector-ref (current-command-line-arguments) 2))) +(disable-flag! 'generate 'taylor) +(disable-flag! 'generate 'proofs) + +;;; ------------------------- HELPERS --------------------------------- +(define (register-op! platform fpcore name) + (parameterize ([*active-platform* platform]) + (define impl (fpcore->prog fpcore (get-ctx fpcore))) + (define spec (prog->spec impl)) + (define ctx (get-ctx spec)) + (define name* (string->symbol name)) + (register-fpcore-operator! name* ctx impl impl) + (void))) + +(define (run-herbie-expr expr + platform + #:seed [seed #f] + #:name [name "scratch"] + #:precision [precision (*default-precision*)]) + (define test (expr->test expr #:name name #:precision precision)) + (define result + (parameterize ([*active-platform* platform]) + (run-herbie 'improve test #:seed seed))) + (match (job-result-status result) + ['success + (define backend (job-result-backend result)) + (define end (improve-result-end backend)) + (define end-best (first end)) + (define final-error (errors-score (alt-analysis-errors end-best))) + final-error] + [_ (raise-arguments-error 'run-herbie-expr "Herbie run failed" "expr" expr)])) + +(define (add-accelerator cand) + (define name (candidate-name cand)) + (define spec (candidate-spec cand)) + (define cost (candidate-cost cand)) + (define fake-cost (floor (/ cost 5))) + + (define ctx + (context (free-variables spec) + (get-representation 'binary64) + (make-list (length (free-variables spec)) (get-representation 'binary64)))) + + (define prog (fpcore->prog spec ctx)) + (define spec* (prog->spec prog)) + (define free-vars (free-variables spec*)) + + (define (render-var-f64 var) + (format "[~a ]" var)) + (define (render-var-f32 var) + (format "[~a ]" var)) + + (define operator-strf64 + (format + "(define-operation (~a.f64 ~a) #:spec ~a #:impl (from-rival) #:fpcore (! :precision binary64 (~a ~a)) #:cost ~a)" + name + (string-join (map render-var-f64 free-vars)) + spec* + name + (string-join (map symbol->string free-vars)) + fake-cost)) + + (define operator-strf32 + (format + "(define-operation (~a.f32 ~a) #:spec ~a #:impl (from-rival) #:fpcore (! :precision binary32 (~a ~a)) #:cost ~a)" + name + (string-join (map render-var-f32 free-vars)) + spec* + name + (string-join (map symbol->string free-vars)) + fake-cost)) + + (with-output-to-file grow-platform-path + (lambda () + (displayln operator-strf64) + (displayln operator-strf32)) + #:exists 'append) + + (displayln (format "adding accelerator ~a, with spec: ~a" name spec))) + +(define (can-reach? start-name target-name implied-by) + (let loop ([curr start-name] + [visited (set)]) + (cond + [(equal? curr target-name) #t] + [(set-member? visited curr) #f] + [else + (for/or ([neighbor (hash-ref implied-by curr (set))]) + (loop neighbor (set-add visited curr)))]))) + +(define binary64-total-bits (representation-total-bits (get-representation 'binary64))) + +(define (error->accuracy err) + (- 100.0 (* 100.0 (/ err binary64-total-bits)))) + +(define (implied-by-accuracy? err) + (> (error->accuracy err) implication-threshold)) + +(define (format-accuracy percent) + (~r percent #:precision '(= 1))) + +;;; ------------------------- MAIN PIPELINE --------------------------------- +(define filename (vector-ref (current-command-line-arguments) 0)) +(define count-list (call-with-input-file "reports/counts.rkt" read)) +(define cost-list (call-with-input-file "reports/costs.rkt" read)) + +(define json (string->jsexpr (first (file->lines filename)))) +(define tests (hash-ref json 'tests)) +(define scored-pairs + (for/list ([t tests]) + (define input-str (hash-ref t 'input)) + (define name (hash-ref t 'link)) + (define end-val (hash-ref t 'end)) + (define spec (with-input-from-string input-str read)) + + (define found-count (assoc spec count-list)) + (define found-cost (assoc spec cost-list)) + + (define count + (if found-count + (cdr found-count) + (begin + (displayln (format "~a not found" input-str)) + 0))) + + (define cost + (if found-cost + (cdr found-cost) + (begin + (displayln (format "~a not found" input-str)) + 0))) + + (define score + (if (number? end-val) + (/ (* end-val count) cost) + 0)) + (candidate name spec score cost end-val))) + +(define sorted-cands (sort scored-pairs > #:key candidate-score)) + +(define existing-accelerators + (if (file-exists? accelerators-path) + (let ([data (call-with-input-file accelerators-path read-json)]) + (cond + [(vector? data) (vector->list data)] + [(list? data) data] + [else '()])) + '())) + +(define existing-name-set (make-hash)) +(for ([entry (in-list existing-accelerators)]) + (define entry-name (hash-ref entry 'name #f)) + (when entry-name + (hash-set! existing-name-set entry-name #t))) + +(define filtered-cands + (filter (lambda (cand) (not (hash-has-key? existing-name-set (candidate-name cand)))) sorted-cands)) + +(when (null? filtered-cands) + (displayln "No accelerators discovered in this iteration.") + (exit 0)) + +(define top-cands (take filtered-cands (min (length filtered-cands) top-k))) + +(define base-platform (platform-copy (*active-platform*))) +(define implied-by (make-hash)) + +(for-each (lambda (cand) (displayln (format "~a: ~a" (candidate-name cand) (candidate-spec cand)))) + top-cands) + +(when (> (length top-cands) 1) + (for ([cand-a (in-list top-cands)]) + (displayln "") + (displayln + (format "considering implication from ~a: ~a" (candidate-name cand-a) (candidate-spec cand-a))) + (define platform-a (platform-copy base-platform)) + (define name-a (candidate-name cand-a)) + (define spec-a (candidate-spec cand-a)) + (parameterize ([*active-platform* platform-a] + [*platform-extensions* '()]) + (register-op! platform-a spec-a (candidate-name cand-a)) + (for ([cand-b (in-list top-cands)] + #:unless (equal? (candidate-name cand-b) name-a)) + + (define err (run-herbie-expr (candidate-spec cand-b) platform-a #:seed implication-seed)) + (define baseline-err (candidate-error cand-b)) + (define accuracy (error->accuracy err)) + (define baseline-accuracy (error->accuracy baseline-err)) + (displayln (format " ~a: ~a, post-run ~a bits (~a%%), baseline ~a bits (~a%%)" + (candidate-name cand-b) + (candidate-spec cand-b) + err + (format-accuracy accuracy) + baseline-err + (format-accuracy baseline-accuracy))) + (when (implied-by-accuracy? err) + (displayln + (format " -> IMPLICATION DETECTED: ~a implies ~a" name-a (candidate-name cand-b))) + (define name-b (candidate-name cand-b)) + (hash-set! implied-by name-b (set-add (hash-ref implied-by name-b (set)) name-a))))))) + +(define (get-final-candidate-structs top-cands implied-by) + (define name->struct (make-hash (map (lambda (c) (cons (candidate-name c) c)) top-cands))) + (define all-names (hash-keys name->struct)) + (define reaches? (lambda (u v) (can-reach? v u implied-by))) + (define is-source? + (lambda (name) + (for/and ([other all-names]) + (if (and (reaches? other name) (not (reaches? name other))) #f #t)))) + + (define source-names (filter is-source? all-names)) + + (define sorted-source-names + (sort source-names + (lambda (a b) + (> ((lambda (x) (candidate-score x)) (hash-ref name->struct a)) + ((lambda (x) (candidate-score x)) (hash-ref name->struct b)))))) + + (define unique-names (remove-duplicates sorted-source-names (lambda (a b) (reaches? a b)))) + (map (lambda (name) (hash-ref name->struct name)) unique-names)) + +(define to-add (get-final-candidate-structs top-cands implied-by)) + +(define new-json-entries + (for/list ([cand (in-list to-add)]) + (add-accelerator cand) + (hash 'name (candidate-name cand) 'spec (format "~a" (candidate-spec cand))))) + +(define current-file-content + (if (file-exists? accelerators-path) + (let ([data (call-with-input-file accelerators-path read-json)]) + (cond + [(vector? data) (vector->list data)] + [(list? data) data] + [else '()])) + '())) + +(define final-list (append current-file-content new-json-entries)) + +(call-with-output-file accelerators-path + (lambda (out) (write-json final-list out)) + #:exists 'truncate) diff --git a/growlibm/generate-candidates-old.rkt b/growlibm/generate-candidates-old.rkt new file mode 100644 index 0000000000..9480c66ef3 --- /dev/null +++ b/growlibm/generate-candidates-old.rkt @@ -0,0 +1,267 @@ +#lang racket + +(require + "../src/api/sandbox.rkt" + "../src/core/points.rkt" + "../src/core/batch.rkt" + "../src/core/egg-herbie.rkt" + "../src/syntax/load-platform.rkt" + "../src/core/points.rkt" + "../src/core/batch.rkt" + "../src/core/egg-herbie.rkt" + "../src/syntax/load-platform.rkt" + "../src/syntax/sugar.rkt" + "../src/core/programs.rkt" + "../src/syntax/syntax.rkt" + "../src/utils/common.rkt" + "../src/syntax/platform.rkt" + "../src/syntax/types.rkt") + +(activate-platform! "no-accelerators") +(*node-limit* 50000) +(define (all-subexpressions* expr) + (define comparison-bases '(<.f64 <=.f64 >.f64 >=.f64 ==.f64 !=.f64 <.f32 <=.f32 >.f32 >=.f32 ==.f32 !=.f32)) + (define (comparison-op? op) + (and (symbol? op) + (member op comparison-bases))) + (define subexprs + (reap [sow] + (let loop ([expr expr]) + (match expr + [(or `(if ,test ,t ,f) + `(if.f32 ,test ,t ,f) + `(if.f64 ,test ,t ,f)) + (loop test) + (loop t) + (loop f)] + [(approx _ impl) + (loop impl)] + [(list (? comparison-op?) lhs rhs) + (loop lhs) + (loop rhs)] + [_ + (sow expr) + (match expr + [(? number?) (void)] + [(? literal?) (void)] + [(? symbol?) (void)] + [(list _ args ...) + (for ([arg args]) + (loop arg))] + [_ (void)])])))) + (remove-duplicates subexprs)) + +(define (get-subexpressions expr) + (define comparison-bases '(<.f64 <=.f64 >.f64 >=.f64 ==.f64 !=.f64 <.f32 <=.f32 >.f32 >=.f32 ==.f32 !=.f32)) + (define (comparison-op? op) + (and (symbol? op) + (member op comparison-bases))) + (define subexprs + (reap [sow] + (let loop ([expr expr]) + (match expr + [(or `(if ,test ,t ,f) + `(if.f32 ,test ,t ,f) + `(if.f64 ,test ,t ,f)) + (loop test) + (loop t) + (loop f)] + [(approx _ impl) + (loop impl)] + [(list (? comparison-op?) lhs rhs) + (loop lhs) + (loop rhs)] + [_ + (sow expr) + (match expr + [(? number?) (void)] + [(? literal?) (void)] + [(? symbol?) (void)] + [(list _ args ...) + (for ([arg args]) + (loop arg))] + [_ (void)])])))) + subexprs) + +(define (get-subexpressions2 expr) + (define comparison-bases '(<.f64 <=.f64 >.f64 >=.f64 ==.f64 !=.f64 <.f32 <=.f32 >.f32 >=.f32 ==.f32 !=.f32)) + (define (comparison-op? op) + (and (symbol? op) + (member op comparison-bases))) + + (define subexprs + (reap [sow] + (let loop ([expr expr]) + (match expr + [(or `(if ,test ,t ,f) + `(if.f32 ,test ,t ,f) + `(if.f64 ,test ,t ,f)) + (loop test) + (loop t) + (loop f)] + [(approx _ impl) + (loop impl)] + [(list (? comparison-op?) lhs rhs) + (loop lhs) + (loop rhs)] + [_ + (sow expr) + (match expr + [(? number?) (void)] + [(? literal?) (void)] + [(? symbol?) (void)] + [(list op args ...) + ;; --- UPDATED LOGIC FOR ALL COMBINATIONS --- + + ;; 1. Get a list of indices: (0 1 2 ...) + (define idxs (range (length args))) + + ;; 2. Get all subsets of indices to replace (excluding empty set) + (define subsets (combinations idxs)) + + (for ([subset subsets]) + (unless (null? subset) ;; Skip the case where nothing is replaced + (define new-args + (for/list ([arg args] + [i (in-naturals)]) + (if (member i subset) + ;; If this index is in the subset, replace with hole + (string->symbol (format "hole~a" i)) + ;; Otherwise keep the original arg + arg))) + (sow (cons op new-args)))) + + ;; ------------------------------------------- + + (for ([arg args]) + (loop arg))] + [_ (void)])])))) + subexprs) + +(define (remove-approxes expr) + (match expr + [(approx _ impl) (remove-approxes impl)] + [(list op args ...) (cons op (map remove-approxes args))] + [_ expr])) + +;;; (define (get-error expr) +;;; (with-handlers ([exn? (lambda (exn) 0)]) +;;; (define ctx (get-ctx expr)) +;;; (define spec (prog->spec expr)) +;;; (*num-points* 8000) +;;; (*context* ctx) +;;; (define pcon (get-spec-sample spec)) +;;; (define error (errors expr pcon ctx)) +;;; (define err-score (errors-score error)) +;;; err-score)) + +(define (best-exprs exprs ctxs) + (*context* (max-ctx ctxs)) + + ; egg schedule (3-phases for mathematical rewrites and implementation selection) + (define schedule '(lift rewrite lower)) + + ; run egg + (define-values (batch brfs) + (progs->batch exprs)) + + (define runner (make-egraph batch brfs (map context-repr ctxs) schedule (max-ctx ctxs))) + ; batchrefss is a (listof (listof batchref)) + (define batchrefss (egraph-best runner batch)) + batchrefss) + +(define (rename-vars impl) + (define free-vars (sort (free-variables impl) symbolsymbol (format "z~a" i))))) + (define impl* (replace-vars varDict impl)) + impl*) + +(define (count-frequencies xs) + (define ht (make-hash)) + (for ([x xs]) + (hash-update! ht x add1 0)) + ht) + +(define (max-ctx ctxs) + (foldl (lambda (a b) (if (> (length (context-vars a)) (length (context-vars b))) a b)) + (context (list) (get-representation 'binary64) (list)) + ctxs)) + +(define (get-ctx expr) + (define free-vars (free-variables expr)) + (context free-vars (get-representation 'binary64) + (make-list (length free-vars) (get-representation 'binary64)))) + +(define (deduplicate pairs) + (define exprs (map car pairs)) + (define counts (map cdr pairs)) + (define ctxs (map get-ctx exprs)) + (define ht (make-hash)) + (define best (best-exprs exprs ctxs)) + (for ([b best] + [c counts]) + (hash-update! ht (batch-pull (first b)) (lambda (n) (+ n c)) 0)) + ht) + +(define (to-fpcore-str pair) + (define expr (car pair)) + (define vars (sort (free-variables expr) symbolfpcore expr ctx))) + +(define (to-count-print p) + (define expr (car p)) + (define count (cdr p)) + (define ctx (get-ctx expr)) + (cons (prog->fpcore expr ctx) count)) + +(define report-dir (vector-ref (current-command-line-arguments) 0)) + +(define lines (file->list (string-append report-dir "/expr_dump.txt"))) +(define unflattened-subexprs (map all-subexpressions* (map remove-approxes lines))) + +(define subexprs (apply append unflattened-subexprs)) + +(define filtered-subexprs + (filter (lambda (n) + (not (or (symbol? n) + (literal? n) + (number? n)))) + subexprs)) + +(define filtered-again (filter (lambda (n) + (and (> (length (free-variables n)) 0) + (< (length (free-variables n)) 4))) filtered-subexprs)) + +(define renamed-subexprs (map rename-vars filtered-again)) +(define pairs (hash->list (count-frequencies renamed-subexprs))) + +(define deduplicated-pairs (hash->list (deduplicate pairs))) + +(define sorted-pairs (sort deduplicated-pairs (lambda (p1 p2) (> (cdr p1) (cdr p2))))) +(define first-2000 (take sorted-pairs (min (length sorted-pairs) 2000))) + +;;; (define filtered (filter (lambda (p) (< 0.1 (get-error (car p)))) first-2000)) + +;;; (define filtered first-2000) + +(define first-500 (take first-2000 (min (length first-2000) 500))) +(define fpcores-out (map to-fpcore-str first-500)) +(define counts-out (map to-count-print first-500)) + +(with-output-to-file (string-append report-dir "/counts.rkt") + (lambda () + (display counts-out)) + #:exists 'replace) + +(with-output-to-file (string-append report-dir "/candidates.txt") + (lambda () + (for-each displayln fpcores-out)) + #:exists 'replace) + +(module+ test + (require rackunit) + (check-equal? (rename-vars '(+ x y)) '(+ z0 z1))) diff --git a/growlibm/generate-candidates.rkt b/growlibm/generate-candidates.rkt new file mode 100644 index 0000000000..cd575baced --- /dev/null +++ b/growlibm/generate-candidates.rkt @@ -0,0 +1,322 @@ +#lang racket + +(require "../src/syntax/load-platform.rkt" + "../src/syntax/sugar.rkt" + "../src/core/programs.rkt" + "../src/syntax/syntax.rkt" + "growlibm-common.rkt" + "../src/api/sandbox.rkt" + "../src/core/egg-herbie.rkt" + "../src/syntax/platform.rkt" + "../src/utils/common.rkt" + "../src/utils/errors.rkt") + +;;; ------------------------- SETUP --------------------------------- +(activate-platform! "grow") +(*node-limit* 50000) +(define report-dir (vector-ref (current-command-line-arguments) 0)) +(define candidate-num (string->number (vector-ref (current-command-line-arguments) 1))) +(define err-threshold 0.1) +(define cut-hole 'cut_hole) +(define egg-batch-size 5000) +(define interesting-ops + '(fabs.f32 sin.f32 + cos.f32 + tan.f32 + sinh.f32 + cosh.f32 + tanh.f32 + asin.f32 + acos.f32 + atan.f32 + asinh.f32 + atanh.f32 + acosh.f32 + atan2.f32 + exp.f32 + exp2.f32 + log.f32 + log10.f32 + log2.f32 + logb.f32 + ceil.f32 + floor.f32 + sqrt.f32 + cbrt.f32 + pow.f32 + fmax.f32 + fmin.f32 + fmod.f32 + fabs.f64 + sin.f64 + cos.f64 + tan.f64 + sinh.f64 + cosh.f64 + tanh.f64 + asin.f64 + acos.f64 + atan.f64 + asinh.f64 + atanh.f64 + acosh.f64 + atan2.f64 + exp.f64 + exp2.f64 + log.f64 + log10.f64 + log2.f64 + logb.f64 + ceil.f64 + floor.f64 + sqrt.f64 + cbrt.f64 + pow.f64 + fmax.f64 + fmin.f64 + fmod.f64)) +(define max-vars 3) +(struct candidate (spec cost count ctx)) +;;; ------------------------- HELPERS --------------------------------- +(define cost-proc (platform-cost-proc (*active-platform*))) + +(define (operator-expr? e) + (match e + [(list _ _ ...) #t] + [_ #f])) + +(define (replace-child expr target replacement) + (match expr + [(list op args ...) + (cons op + (for/list ([arg (in-list args)] + [i (in-naturals)]) + (if (= i target) replacement arg)))])) + +(define (direct-cuts expr) + (match expr + [(list _ args ...) + (for/list ([arg (in-list args)] + [i (in-naturals)] + #:when (operator-expr? arg)) + (replace-child expr i cut-hole))] + [_ '()])) + +(define (get-subexpressions expr) + (reap [sow] + (let loop ([expr expr]) + (match expr + [(or (? number?) (? literal?) (? symbol?)) (void)] + [(list _ args ...) + (sow expr) + (for ([arg (in-list args)] + [i (in-naturals)]) + (when (operator-expr? arg) + (for ([cut (in-list (direct-cuts arg))]) + (sow (replace-child expr i cut)))) + (loop arg))] + [_ (void)])))) + +(define (eliminate-ifs expr) + (define comparison-bases + '(<.f64 <=.f64 >.f64 >=.f64 ==.f64 !=.f64 <.f32 <=.f32 >.f32 >=.f32 ==.f32 !=.f32)) + (define (comparison-op? op) + (member op comparison-bases)) + + (define (pure-math? e) + (let check ([e e]) + (match e + [(or `(if.f32 ,_ ,_ ,_) `(if.f64 ,_ ,_ ,_)) #f] + [(list (? comparison-op?) _ _) #f] + [(list _ args ...) (andmap check args)] + [_ #t]))) + + (reap [sow] + (let loop ([expr expr]) + (match expr + [(or `(if ,test ,t ,f) `(if.f32 ,test ,t ,f) `(if.f64 ,test ,t ,f)) + (loop test) + (loop t) + (loop f)] + + [(list (? comparison-op?) lhs rhs) + (loop lhs) + (loop rhs)] + + [(list op args ...) + (if (pure-math? expr) + (sow expr) + (for ([arg args]) + (loop arg)))] + + [_ (void)])))) + +(define (get-error expr) + (with-handlers ([exn:fail:user:herbie:sampling? + (lambda (exn) + (displayln (format "Error getting error for expr ~a: ~a" expr exn)) + 0)]) + (*num-points* 100) + (define test (expr->test expr #:precision 'binary64)) + (match-define (job-result 'sample _ 'success _ _ _ _ pcon) (run-herbie 'sample test)) + (match-define (job-result 'errors _ 'success _ _ _ _ point-errors) + (run-herbie 'errors test #:pcontext pcon)) + (/ (for/sum ([entry (in-list point-errors)]) (cdr entry)) (length point-errors)))) + +(define (run-egg exprs) + (define ctxs (map get-ctx exprs)) + (deduplicate-exprs exprs ctxs)) + +(define (run-egg-batched batch-size old-hash new-hash) + (for ([batch (in-slice batch-size (in-hash-pairs old-hash))]) + (define canonical-exprs (run-egg (map car batch))) + (for ([canonical-expr (in-list canonical-exprs)] + [pair (in-list batch)]) + (define expr* (alpha-rename canonical-expr)) + (define count (cdr pair)) + (hash-update! new-hash expr* (lambda (old) (+ old count)) 0)))) + +(define (alpha-rename impl) + (define free-vars (free-variables impl)) + (define varDict + (for/hash ([v free-vars] + [i (in-naturals)]) + (values v (string->symbol (format "z~a" i))))) + (define impl* (replace-vars varDict impl)) + impl*) + +(define (alpha-rename-all impl) + (define free-vars (free-variables impl)) + (define n (length free-vars)) + + (define new-vars + (for/list ([i (in-range n)]) + (string->symbol (format "z~a" i)))) + + (define perms (permutations new-vars)) + (for/list ([perm (in-list perms)]) + (define varDict + (for/hash ([v (in-list free-vars)] + [z (in-list perm)]) + (values v z))) + (replace-vars varDict impl))) + +(define (to-fpcore-str cand) + (define expr (candidate-spec cand)) + (define (binary64-impl expr) + (define spec (prog->spec expr)) + (fpcore->prog spec (get-ctx spec))) + (define impl (binary64-impl expr)) + (format "(FPCore ~a ~a)" (free-variables impl) (prog->fpcore impl (get-ctx impl)))) +(define (candidate-expr? expr) + (and (not (or (symbol? expr) (literal? expr) (number? expr))) + (has-some-free-vars? expr) + (has-not-too-many-free-vars? expr))) + +(define (has-some-free-vars? expr) + (> (length (free-variables expr)) 0)) + +(define (has-not-too-many-free-vars? expr) + (<= (length (free-variables expr)) max-vars)) + +(define (contains-interesting-op? expr) + (let loop ([expr expr]) + (match expr + [(list op args ...) (or (member op interesting-ops) (ormap loop args))] + [_ #f]))) + +(define (log-info name number report-dir) + (with-output-to-file (string-append report-dir "/info.txt") + (lambda () (display (format "~a, ~a\n" name number))) + #:exists 'append)) + +;;; ------------------------- MAIN PIPELINE --------------------------------- +(define root-hash (make-hash)) +(define canonical-root-hash (make-hash)) +(define candidate-hash (make-hash)) +(define canonical-candidate-hash (make-hash)) + +(define dump-dir "dump-intermediates") +(define dump-files + (sort (for/list ([name (in-list (directory-list dump-dir))] + #:when (regexp-match? #rx"[.]rktd$" (path->string name))) + (build-path dump-dir name)) + stringstring)) +(define roots + (for*/list ([dump-file (in-list dump-files)] + [root (in-list (file->list dump-file))]) + root)) + +(for* ([root (in-list roots)] + [expr (in-list (eliminate-ifs root))]) + (hash-update! root-hash (alpha-rename expr) add1 0)) + +(run-egg-batched egg-batch-size root-hash canonical-root-hash) + +(for* ([(root-expr root-count) (in-hash canonical-root-hash)] + [subexpr (in-list (get-subexpressions root-expr))] + #:when (candidate-expr? subexpr)) + (define renamed-subexpr (alpha-rename subexpr)) + (hash-update! candidate-hash renamed-subexpr (lambda (old) (+ old root-count)) 0)) + +(run-egg-batched egg-batch-size candidate-hash canonical-candidate-hash) + +(define pairs-raw (hash->list canonical-candidate-hash)) +(define candidates + (map (lambda (p) (candidate (car p) (cost-proc (car p)) (cdr p) (get-ctx (car p)))) pairs-raw)) + +(define filtered-candidates + (filter (lambda (c) + (and (> (candidate-count c) 1) + (contains-interesting-op? (candidate-spec c)) + (candidate-expr? (candidate-spec c)))) + candidates)) + +(define sorted-candidates + (sort filtered-candidates + (lambda (c1 c2) + (> (/ (candidate-count c1) (candidate-cost c1)) + (/ (candidate-count c2) (candidate-cost c2)))))) + +(define top-candidates (take sorted-candidates (min (length sorted-candidates) (* 2 candidate-num)))) +(define final-candidates + (filter (lambda (x) (> (get-error (candidate-spec x)) err-threshold)) top-candidates)) + +;; Output +(log-info "roots" (length roots) report-dir) +(log-info "canonical roots" (hash-count canonical-root-hash) report-dir) +(log-info "candidates" (hash-count candidate-hash) report-dir) +(log-info "canonical candidates" (hash-count canonical-candidate-hash) report-dir) +(log-info "filtered candidates" (length filtered-candidates) report-dir) + +(define final-output (take final-candidates (min (length final-candidates) candidate-num))) +(define fpcores-out (map to-fpcore-str final-output)) +(define counts-out + (map (lambda (c) (cons (prog->fpcore (candidate-spec c) (candidate-ctx c)) (candidate-count c))) + final-output)) + +(define costs-out + (map (lambda (c) (cons (prog->fpcore (candidate-spec c) (candidate-ctx c)) (candidate-cost c))) + final-output)) + +(define full-cands-out + (map (lambda (c) + (format "~a, ~a\n" (prog->fpcore (candidate-spec c) (candidate-ctx c)) (candidate-count c))) + sorted-candidates)) + +(with-output-to-file (string-append report-dir "/full-candidates.txt") + (lambda () (for-each display full-cands-out)) + #:exists 'replace) + +(with-output-to-file (string-append report-dir "/counts.rkt") + (lambda () (display counts-out)) + #:exists 'replace) + +(with-output-to-file (string-append report-dir "/costs.rkt") + (lambda () (display costs-out)) + #:exists 'replace) + +(with-output-to-file (string-append report-dir "/candidates.txt") + (lambda () (for-each displayln fpcores-out)) + #:exists 'replace) diff --git a/growlibm/generate-compare-html.py b/growlibm/generate-compare-html.py new file mode 100644 index 0000000000..42704eb971 --- /dev/null +++ b/growlibm/generate-compare-html.py @@ -0,0 +1,84 @@ +import json, html, sys + +REPORTS_PATH = sys.argv[1] +HERBIE20_REPORT_PATH = REPORTS_PATH + "/herbie20/results.json" +VANILLA_REPORT_PATH = REPORTS_PATH + "/no-accelerators/results.json" +GROW_REPORT_PATH = REPORTS_PATH + "/grow/results.json" +OUTPUT_PATH = REPORTS_PATH + "/index.html" +HERBIE20_FOLDER = "herbie20" +GROW_FOLDER = "grow" +VANILLA_FOLDER ="no-accelerators" +ACCELERATORS = ["sin-xy", "cos-xy", "cos-quotient-xy", "sin-quotient-xy"] + +def calculate_end_accuracy(data): + total_end = 0 + max_accuracy = 0 + for test in data.get("tests", []): + total_end += test.get("end", 0) + max_accuracy += test.get("bits", 0) + if max_accuracy == 0: + return 0.0 + return 100 - (100 * (total_end / max_accuracy)) + +def load_report(path): + with open(path, 'r') as f: + return json.load(f) + +def get_accuracy_str(path): + report = load_report(path) + percent = calculate_end_accuracy(report) + return f"{percent:.1f}%" + + +def format_accelerator_rows(accelerators, counts): + rows = [] + for acc in accelerators: + count = counts.get(acc, 0) + rows.append(f'{acc}{count}') + return "".join(rows) + +def read_text(path): + with open(path, 'r') as f: + return f.read() + +herbie20_accuracy_str = get_accuracy_str(HERBIE20_REPORT_PATH) +vanilla_accuracy_str = get_accuracy_str(VANILLA_REPORT_PATH) +grow_accuracy_str = get_accuracy_str(GROW_REPORT_PATH) + +counts = { + acc_name: read_text(GROW_REPORT_PATH).count(acc_name) + for acc_name in ACCELERATORS + if acc_name +} + +accelerator_rows = format_accelerator_rows(ACCELERATORS, counts) + +html_content = f""" + + + + + Comparing Platforms + + +

    Overall Summary

    +

    No Accelerators: {vanilla_accuracy_str} - Folder

    +

    Regular Herbie: {herbie20_accuracy_str} - Folder

    +

    Grow: {grow_accuracy_str} - Folder

    + +

    Accelerators

    + + + + + + {accelerator_rows} +
    NameUses
    + + + + +""" + +with open(OUTPUT_PATH, 'w') as f: + f.write(html_content) diff --git a/growlibm/generate-html.py b/growlibm/generate-html.py new file mode 100644 index 0000000000..b9890e40d7 --- /dev/null +++ b/growlibm/generate-html.py @@ -0,0 +1,118 @@ +import json, html, sys + +NUM_ITERATIONS = int(sys.argv[1]) +REPORTS_PATH = sys.argv[2] +START_REPORT_PATH = REPORTS_PATH + "/start/results.json" +END_REPORT_PATH = REPORTS_PATH + "/end/results.json" +ACCELERATORS_PATH = REPORTS_PATH + "/accelerators.json" +OUTPUT_PATH = REPORTS_PATH + "/index.html" +START_FOLDER = "start" +END_FOLDER = "end" + +def calculate_end_accuracy(data): + total_end = 0 + max_accuracy = 0 + for test in data.get("tests", []): + total_end += test.get("end", 0) + max_accuracy += test.get("bits", 0) + if max_accuracy == 0: + return 0.0 + return 100 - (100 * (total_end / max_accuracy)) + +def load_report(path): + with open(path, 'r') as f: + return json.load(f) + +def get_accuracy_str(path): + report = load_report(path) + percent = calculate_end_accuracy(report) + return f"{percent:.1f}%" + +def load_accelerators(path): + with open(path, 'r') as f: + data = json.load(f) + if isinstance(data, dict): + return [data] + if isinstance(data, (list, tuple, set)): + return list(data) + return [] + +def format_accelerator_rows(accelerators, counts): + rows = [] + for acc in accelerators: + name = html.escape(str(acc.get("name", ""))) + spec = html.escape(str(acc.get("spec", ""))) + count = counts.get(acc.get("name"), 0) + if count < 2: + continue + rows.append(f'{name}{spec}{count}') + return "".join(rows) + +end_report = load_report(END_REPORT_PATH) + +start_accuracy_str = get_accuracy_str(START_REPORT_PATH) +end_accuracy_str = get_accuracy_str(END_REPORT_PATH) +accelerators = load_accelerators(ACCELERATORS_PATH) + +def read_text(path): + with open(path, 'r') as f: + return f.read() + +counts = { + acc_name: read_text(END_REPORT_PATH).count(acc_name) + for acc_name in [str(acc.get("name", "")) for acc in accelerators] + if acc_name +} + +accelerator_rows = format_accelerator_rows(accelerators, counts) + +table_rows = "".join([ + f'iter{i}{get_accuracy_str(f"reports/iter{i}/results.json")}' + for i in range(NUM_ITERATIONS) +]) + +html_content = f""" + + + + + Growlibm Report + + +

    GrowLibm Report

    +

    Herbie Dumps

    +

    All Candidates

    +

    Top 500 Candidates

    +

    Candidate Counts

    +

    Candidate Costs

    +

    More info

    +

    Accelerators

    + +

    Overall Summary

    +

    Start: {start_accuracy_str} - Folder

    +

    End: {end_accuracy_str} - Folder

    + +

    Accelerators

    + + + + + + + {accelerator_rows} +
    NameSpecUses
    + +

    Grow Platform Iterations

    + + + + + + {table_rows} +
    IterationAccuracy
    + + +""" + +with open(OUTPUT_PATH, 'w') as f: + f.write(html_content) diff --git a/growlibm/generate.sh b/growlibm/generate.sh new file mode 100644 index 0000000000..a0b2b4a832 --- /dev/null +++ b/growlibm/generate.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# exit immediately upon first error, log every command executed +set -e -x + +# Ensure egglog is in the path +export PATH="$HOME/.cargo/bin/:$PATH" + +# Seed is fixed for the whole day; this way two branches run the same seed +SEED=$(date "+%Y%j") +REPORTDIR="reports" +TIMELINE_FILE="$REPORTDIR/timeline.json" + +log_time() { + python3 growlibm/timeline.py add "$TIMELINE_FILE" "$1" +} + +rustup update +make install +BENCHDIR="bench/graphics/pbrt.fpcore" +NUM_ITERS=2 +NUM_CANDIDATES=625 +NUM_ADD=25 + +# BENCHDIR="bench/numerics/kahan.fpcore" +# NUM_ITERS=1 +# NUM_CANDIDATES=100 +# NUM_ADD=5 + +cp growlibm/grow-template.rkt growlibm/grow.rkt + +mkdir -p "$REPORTDIR" +rm -rf "reports"/* || echo "nothing to delete" +python3 growlibm/timeline.py init "$TIMELINE_FILE" + +# run initial herbie +racket -y "src/main.rkt" report \ + --seed "$SEED" \ + --platform "grow" \ + --enable "dump:intermediates" \ + --disable "generate:taylor" \ + --disable "generate:evaluate" \ + "$BENCHDIR" \ + "$REPORTDIR/start" +log_time "after_initial_compilation" + +# generate accelerator candidates +racket -y growlibm/generate-candidates.rkt "$REPORTDIR" $NUM_CANDIDATES + +racket -y growlibm/to-json.rkt counts +racket -y growlibm/to-json.rkt costs +log_time "after_generate" + +# extend platform loop +for ((i = 0; i < $NUM_ITERS; i++)) do + racket -y "src/main.rkt" report \ + --seed "$SEED" \ + --platform "grow" \ + --threads 4 \ + --disable "generate:taylor" \ + --disable "reduce:regimes" \ + --disable "generate:evaluate" \ + "$REPORTDIR/candidates.txt" \ + "$REPORTDIR/iter$i" + log_time "after_run_herbie_candidates_iter_$i" + + racket -y "growlibm/extend-platform.rkt" "$REPORTDIR/iter$i/results.json" $NUM_ADD $SEED + log_time "after_add_to_platform_iter_$i" +done + +# run herbie again with expanded platform +racket -y "src/main.rkt" report \ + --seed "$SEED" \ + --platform "grow" \ + --threads 4 \ + --disable "generate:taylor" \ + --disable "generate:evaluate" \ + "$BENCHDIR" \ + "$REPORTDIR/end" +log_time "after_final_compilation" + +cat growlibm/grow.rkt + +# generate the html report page +python3 growlibm/generate-html.py $NUM_ITERS $REPORTDIR diff --git a/growlibm/grow-template.rkt b/growlibm/grow-template.rkt new file mode 100644 index 0000000000..240fce8397 --- /dev/null +++ b/growlibm/grow-template.rkt @@ -0,0 +1,214 @@ +#lang s-exp "../src/syntax/platform-language.rkt" + +;; C/C++ platform with a full libm + +(require math/flonum) + +(define-representation #:cost 1) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost 1] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 1]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 1] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost 1]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost 1) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 128] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 128] + [<.f32 #:spec (< x y) #:impl < #:cost 128] + [>.f32 #:spec (> x y) #:impl > #:cost 128] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 128] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 128]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 64) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 64] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 64] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 128] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 320]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 64] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 3200] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 3200] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 3200] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 3200] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 3200] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 3200] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 3200] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 3200] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 3200] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 3200] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 3200] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 3200] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 3200] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 3200] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 3200] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 3200] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 3200] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 3200] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 3200] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 3200] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 3200] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 3200] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 3200] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 3200] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 320] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 3200] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 3200] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 3200]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 3200] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 3200] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 3200] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 3200] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 3200] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 3200] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 3200] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 3200]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [erfc.f32 #:spec (- 1 (erf x)) #:impl (from-libm 'erfcf) #:fpcore (erfc x) #:cost 3200] + [expm1.f32 #:spec (- (exp x) 1) #:impl (from-libm 'expm1f) #:fpcore (expm1 x) #:cost 3200] + [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-libm 'log1pf) #:fpcore (log1p x) #:cost 3200]) + +(define-operation (hypot.f32 [x ] [y ]) + + #:spec (sqrt (+ (* x x) (* y y))) + #:impl (from-libm 'hypotf) + #:fpcore (! :precision binary32 (hypot x y)) + #:cost 3200) + +(define-operation (fma.f32 [x ] [y ] [z ]) + + #:spec (+ (* x y) z) + #:impl (from-libm 'fmaf) + #:fpcore (! :precision binary32 (fma x y z)) + #:cost 128) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 256] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 256] + [<.f64 #:spec (< x y) #:impl < #:cost 256] + [>.f64 #:spec (> x y) #:impl > #:cost 256] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 256] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 256]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 128) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 128] + [-.f64 #:spec (- x y) #:impl - #:cost 128] + [*.f64 #:spec (* x y) #:impl * #:cost 256] + [/.f64 #:spec (/ x y) #:impl / #:cost 640]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 128] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 6400] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 6400] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 6400] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 6400] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 6400] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 6400] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 6400] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 6400] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 6400] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 6400] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 6400] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 6400] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 6400] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 6400] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 6400] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 6400] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 6400] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 6400] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 6400] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 6400] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 6400] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 6400] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 6400] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 6400] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 640] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 6400] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 6400] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 6400]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 6400] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 6400] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 6400] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 6400] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 6400] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 6400] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 6400] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 6400]) diff --git a/growlibm/grow.rkt b/growlibm/grow.rkt new file mode 100644 index 0000000000..240fce8397 --- /dev/null +++ b/growlibm/grow.rkt @@ -0,0 +1,214 @@ +#lang s-exp "../src/syntax/platform-language.rkt" + +;; C/C++ platform with a full libm + +(require math/flonum) + +(define-representation #:cost 1) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost 1] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 1]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 1] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost 1]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost 1) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 128] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 128] + [<.f32 #:spec (< x y) #:impl < #:cost 128] + [>.f32 #:spec (> x y) #:impl > #:cost 128] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 128] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 128]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 64) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 64] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 64] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 128] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 320]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 64] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 3200] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 3200] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 3200] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 3200] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 3200] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 3200] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 3200] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 3200] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 3200] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 3200] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 3200] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 3200] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 3200] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 3200] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 3200] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 3200] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 3200] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 3200] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 3200] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 3200] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 3200] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 3200] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 3200] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 3200] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 320] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 3200] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 3200] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 3200]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 3200] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 3200] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 3200] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 3200] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 3200] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 3200] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 3200] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 3200]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [erfc.f32 #:spec (- 1 (erf x)) #:impl (from-libm 'erfcf) #:fpcore (erfc x) #:cost 3200] + [expm1.f32 #:spec (- (exp x) 1) #:impl (from-libm 'expm1f) #:fpcore (expm1 x) #:cost 3200] + [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-libm 'log1pf) #:fpcore (log1p x) #:cost 3200]) + +(define-operation (hypot.f32 [x ] [y ]) + + #:spec (sqrt (+ (* x x) (* y y))) + #:impl (from-libm 'hypotf) + #:fpcore (! :precision binary32 (hypot x y)) + #:cost 3200) + +(define-operation (fma.f32 [x ] [y ] [z ]) + + #:spec (+ (* x y) z) + #:impl (from-libm 'fmaf) + #:fpcore (! :precision binary32 (fma x y z)) + #:cost 128) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 256] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 256] + [<.f64 #:spec (< x y) #:impl < #:cost 256] + [>.f64 #:spec (> x y) #:impl > #:cost 256] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 256] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 256]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 128) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 128] + [-.f64 #:spec (- x y) #:impl - #:cost 128] + [*.f64 #:spec (* x y) #:impl * #:cost 256] + [/.f64 #:spec (/ x y) #:impl / #:cost 640]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 128] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 6400] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 6400] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 6400] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 6400] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 6400] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 6400] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 6400] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 6400] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 6400] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 6400] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 6400] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 6400] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 6400] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 6400] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 6400] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 6400] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 6400] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 6400] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 6400] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 6400] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 6400] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 6400] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 6400] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 6400] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 640] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 6400] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 6400] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 6400]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 6400] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 6400] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 6400] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 6400] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 6400] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 6400] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 6400] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 6400]) diff --git a/growlibm/growlibm-common.rkt b/growlibm/growlibm-common.rkt new file mode 100644 index 0000000000..7f3f98ea94 --- /dev/null +++ b/growlibm/growlibm-common.rkt @@ -0,0 +1,50 @@ +#lang racket + +(require + "../src/syntax/types.rkt" + "../src/syntax/types.rkt" + "../src/syntax/platform.rkt" + "../src/core/programs.rkt" + "../src/syntax/sugar.rkt" + "../src/syntax/read.rkt" + ) + +(provide get-ctx + expr->test) + +(define (get-ctx expr) + (define free-vars (sort (free-variables expr) symboltest expr + #:name [name "scratch"] + #:precision [precision 'binary64]) + (define vars (sort (free-variables expr) symbolprog expr default-ctx)] + [else (raise-arguments-error 'expr->test "not a Herbie expression" "expr" expr)])) + (define out-repr (repr-of impl-expr default-ctx)) + (define out-repr-name (representation-name out-repr)) + (define var-repr-names + (for/list ([var (in-list vars)]) + (cons var out-repr-name))) + (define spec (prog->spec impl-expr)) + (test name + #f + vars + impl-expr + '() + #t + spec + '(TRUE) + out-repr-name + var-repr-names)) diff --git a/growlibm/libaccelerators.dylib b/growlibm/libaccelerators.dylib new file mode 100755 index 0000000000..efd876125b Binary files /dev/null and b/growlibm/libaccelerators.dylib differ diff --git a/growlibm/platforms/basilisk.rkt b/growlibm/platforms/basilisk.rkt new file mode 100644 index 0000000000..c5bc2def7c --- /dev/null +++ b/growlibm/platforms/basilisk.rkt @@ -0,0 +1,292 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.2] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.177] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.167] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.169] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 1.728] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 1.689] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 1.812] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.718] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.500] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 1.213] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 1.528] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 2.575] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.442] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.506] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 1.674] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 1.510] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.198] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.610] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.244] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.214] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.160] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.710] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 1.307] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.926] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 1.512] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.564] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.068] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.170] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.167] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.347] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.489] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.165] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.649] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.069] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 1.199] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.177] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.086] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 2.190] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 2.557]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.2] + [-.f64 #:spec (- x y) #:impl - #:cost 0.177] + [*.f64 #:spec (* x y) #:impl * #:cost 0.167] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.169] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 1.728] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 1.689] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 1.812] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.718] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.500] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 1.213] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 1.528] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 2.575] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.442] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.506] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 1.674] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 1.510] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.198] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.610] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.244] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.214] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.160] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.710] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 1.307] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.926] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 1.512] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.564] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.068] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.170] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.167] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.347] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.489] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.165] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.649] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.069] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 1.199] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.177] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.086] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 2.190] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 2.557]) + + +;;; (define-operation (cosquot.f64 [x ] [y ]) +;;; +;;; #:spec (cos (/ x y)) +;;; #:impl (from-accelerators 'cosquot) +;;; #:fpcore (! :precision binary64 (cosquot x y)) +;;; #:cost 1918618) + +;;; (define-operation (sinquot.f64 [x ] [y ]) +;;; +;;; #:spec (sin (/ x y)) +;;; #:impl (from-accelerators 'sinquot) +;;; #:fpcore (! :precision binary64 (sinquot x y)) +;;; #:cost 1926771) + +;;; (define-operation (sinprod.f64 [x ] [y ]) +;;; +;;; #:spec (sin (* x y)) +;;; #:impl (from-accelerators 'sinprod) +;;; #:fpcore (! :precision binary64 (sinprod x y)) +;;; #:cost 4.086) + +;;; (define-operation (cosprod.f64 [x ] [y ]) +;;; +;;; #:spec (cos (* x y)) +;;; #:impl (from-accelerators 'cosprod) +;;; #:fpcore (! :precision binary64 (cosprod x y)) +;;; #:cost 4.086) + +;;; (define-operation (log1pmd.f64 [x ]) +;;; +;;; #:spec (log (/ (+ 1 x) (- 1 x))) +;;; #:impl (from-accelerators 'log1pmd) +;;; #:fpcore (! :precision binary64 (log1pmd x)) +;;; #:cost 1.093) + +;;; (define-operation (invgud.f64 [x ]) +;;; +;;; #:spec (log (tan (* (+ (+ x x) (PI)) 1/4))) +;;; #:impl (from-accelerators 'invgud) +;;; #:fpcore (! :precision binary64 (invgud x)) +;;; #:cost 9.955) + +;;; (define-operation (hypot.f64 [x ] [y ]) +;;; +;;; #:spec (sqrt (+ (* x x) (* y y))) +;;; #:impl (from-accelerators 'hypot) +;;; #:fpcore (! :precision binary64 (hypot x y)) +;;; #:cost 0.864) + +;;; (define-operation (verdcos.f64 [x ]) +;;; +;;; #:spec (- (cos (+ x x)) 1) +;;; #:impl (from-accelerators 'verdcos) +;;; #:fpcore (! :precision binary64 (verdcos x)) +;;; #:cost 2.562) + +(define-operation (powcos.f64 [x ] [y ]) + + #:spec (pow (cos x) y) + #:impl (from-accelerators 'powcos) + #:fpcore (! :precision binary64 (powcos x y)) + #:cost 8.155) + +(define-operation (powcos2.f64 [x ]) + + #:spec (pow (cos x) 2) + #:impl (from-accelerators 'powcos2) + #:fpcore (! :precision binary64 (powcos2 x)) + #:cost 4.056) + +(define-operation (powcos4.f64 [x ]) + + #:spec (pow (cos x) 4) + #:impl (from-accelerators 'powcos4) + #:fpcore (! :precision binary64 (powcos4 x)) + #:cost 3.461) + +(define-operation (powcos6.f64 [x ]) + + #:spec (pow (cos x) 6) + #:impl (from-accelerators 'powcos6) + #:fpcore (! :precision binary64 (powcos6 x)) + #:cost 3.884) + +;;; (define-operation (pow1ms.f64 [x ] [y ]) +;;; +;;; #:spec (pow (* (- 1 x) (- 1 x)) y) +;;; #:impl (from-accelerators 'pow1ms) +;;; #:fpcore (! :precision binary64 (pow1ms x y)) +;;; #:cost 2.855) diff --git a/growlibm/platforms/coolprop copy.rkt b/growlibm/platforms/coolprop copy.rkt new file mode 100644 index 0000000000..02263639a1 --- /dev/null +++ b/growlibm/platforms/coolprop copy.rkt @@ -0,0 +1,241 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; C/C++ platform with a full libm + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.125) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.200] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.200] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.250] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.350]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.125] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 4.250] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 4.250] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 4.750] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.750] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.250] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 0.500] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 0.850] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 0.500] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.125] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.100] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 0.500] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 2.000] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.250] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.125] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.375] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.175] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.250] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.250] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 0.750] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.175] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 0.875] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.375] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.300] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.875] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.250] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.000] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.625] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.275]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.000] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.000] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.200] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 0.750] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.250] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.250] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 1.750] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 1.000]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.125) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.200] + [-.f64 #:spec (- x y) #:impl - #:cost 0.200] + [*.f64 #:spec (* x y) #:impl * #:cost 0.250] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.350]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.125] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 4.200] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 4.200] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 4.650] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.750] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.650] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 0.500] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 0.850] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 0.500] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.125] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.100] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 0.450] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 2.000] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.250] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.125] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.375] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.175] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.300] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.250] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 0.750] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.175] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 0.850] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.350] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.300] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.850] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.250] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.000] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.625] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.250]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.000] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.000] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.200] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 0.750] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.250] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.250] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 1.750] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 1.000]) + +(define-operation (pow1ms.f64 [x ] [y ]) + + #:spec (pow (* (- 1 x) (- 1 x)) y) + #:impl (from-accelerators 'pow1ms) + #:fpcore (! :precision binary64 (pow1ms x y)) + #:cost 3.000) + +(define-operation (pown2o3.f64 [z0 ]) + + #:spec (pow z0 -2/3) + #:impl (from-accelerators 'pown2o3) + #:fpcore (! :precision binary64 (pown2o3 z0)) + #:cost 2.000) + +(define-operation (pow2o5.f64 [z0 ]) + + #:spec (pow z0 2/5) + #:impl (from-accelerators 'pow2o5) + #:fpcore (! :precision binary64 (pow2o5 z0)) + #:cost 11.946) + +(define-operation (pow3o5.f64 [z0 ]) + + #:spec (pow z0 3/5) + #:impl (from-accelerators 'pow3o5) + #:fpcore (! :precision binary64 (pow3o5 z0)) + #:cost 11.675) + +(define-operation (pow5o3.f64 [z0 ]) + + #:spec (pow z0 5/3) + #:impl (from-accelerators 'pow5o3) + #:fpcore (! :precision binary64 (pow5o3 z0)) + #:cost 2.044) + +(define-operation (pown16o5.f64 [z0 ]) + + #:spec (pow z0 -16/5) + #:impl (from-accelerators 'pown16o5) + #:fpcore (! :precision binary64 (pown16o5 z0)) + #:cost 28.021) diff --git a/growlibm/platforms/coolprop.rkt b/growlibm/platforms/coolprop.rkt new file mode 100644 index 0000000000..f15f32f93b --- /dev/null +++ b/growlibm/platforms/coolprop.rkt @@ -0,0 +1,292 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.2] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.177] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.167] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.169] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 1.728] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 1.689] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 1.812] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.718] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.500] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 1.213] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 1.528] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 2.575] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.442] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.506] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 1.674] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 1.510] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.198] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.610] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.244] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.214] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.160] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.710] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 1.307] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.926] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 1.512] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.564] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.068] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.170] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.167] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.347] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.489] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.165] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.649] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.069] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 1.199] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.177] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.086] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 2.190] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 2.557]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.2] + [-.f64 #:spec (- x y) #:impl - #:cost 0.177] + [*.f64 #:spec (* x y) #:impl * #:cost 0.167] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.169] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 1.728] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 1.689] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 1.812] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.718] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.500] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 1.213] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 1.528] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 2.575] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.442] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.506] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 1.674] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 1.510] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.198] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.610] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.244] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.214] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.160] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.710] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 1.307] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.926] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 1.512] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.564] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.068] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.170] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.167] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.347] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.489] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.165] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.649] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.069] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 1.199] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.177] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.086] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 2.190] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 2.557]) + + +;;; (define-operation (cosquot.f64 [x ] [y ]) +;;; +;;; #:spec (cos (/ x y)) +;;; #:impl (from-accelerators 'cosquot) +;;; #:fpcore (! :precision binary64 (cosquot x y)) +;;; #:cost 1918618) + +;;; (define-operation (sinquot.f64 [x ] [y ]) +;;; +;;; #:spec (sin (/ x y)) +;;; #:impl (from-accelerators 'sinquot) +;;; #:fpcore (! :precision binary64 (sinquot x y)) +;;; #:cost 1926771) + +;;; (define-operation (sinprod.f64 [x ] [y ]) +;;; +;;; #:spec (sin (* x y)) +;;; #:impl (from-accelerators 'sinprod) +;;; #:fpcore (! :precision binary64 (sinprod x y)) +;;; #:cost 4.086) + +;;; (define-operation (cosprod.f64 [x ] [y ]) +;;; +;;; #:spec (cos (* x y)) +;;; #:impl (from-accelerators 'cosprod) +;;; #:fpcore (! :precision binary64 (cosprod x y)) +;;; #:cost 4.086) + +;;; (define-operation (log1pmd.f64 [x ]) +;;; +;;; #:spec (log (/ (+ 1 x) (- 1 x))) +;;; #:impl (from-accelerators 'log1pmd) +;;; #:fpcore (! :precision binary64 (log1pmd x)) +;;; #:cost 1.093) + +;;; (define-operation (invgud.f64 [x ]) +;;; +;;; #:spec (log (tan (* (+ (+ x x) (PI)) 1/4))) +;;; #:impl (from-accelerators 'invgud) +;;; #:fpcore (! :precision binary64 (invgud x)) +;;; #:cost 9.955) + +;;; (define-operation (hypot.f64 [x ] [y ]) +;;; +;;; #:spec (sqrt (+ (* x x) (* y y))) +;;; #:impl (from-accelerators 'hypot) +;;; #:fpcore (! :precision binary64 (hypot x y)) +;;; #:cost 0.864) + +;;; (define-operation (verdcos.f64 [x ]) +;;; +;;; #:spec (- (cos (+ x x)) 1) +;;; #:impl (from-accelerators 'verdcos) +;;; #:fpcore (! :precision binary64 (verdcos x)) +;;; #:cost 2.562) + +;;; (define-operation (powcos.f64 [x ] [y ]) +;;; +;;; #:spec (pow (cos x) y) +;;; #:impl (from-accelerators 'powcos) +;;; #:fpcore (! :precision binary64 (powcos x y)) +;;; #:cost 8.155) + +;;; (define-operation (powcos2.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 2) +;;; #:impl (from-accelerators 'powcos2) +;;; #:fpcore (! :precision binary64 (powcos2 x)) +;;; #:cost 4.108) + +;;; (define-operation (powcos4.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 4) +;;; #:impl (from-accelerators 'powcos4) +;;; #:fpcore (! :precision binary64 (powcos4 x)) +;;; #:cost 4.037) + +;;; (define-operation (powcos6.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 6) +;;; #:impl (from-accelerators 'powcos6) +;;; #:fpcore (! :precision binary64 (powcos6 x)) +;;; #:cost 3.884) + +(define-operation (pow1ms.f64 [x ] [y ]) + + #:spec (pow (* (- 1 x) (- 1 x)) y) + #:impl (from-accelerators 'pow1ms) + #:fpcore (! :precision binary64 (pow1ms x y)) + #:cost 2.855) diff --git a/growlibm/platforms/growlibm.rkt b/growlibm/platforms/growlibm.rkt new file mode 100644 index 0000000000..f53c03196f --- /dev/null +++ b/growlibm/platforms/growlibm.rkt @@ -0,0 +1,292 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.2] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.177] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.167] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.169] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 1.728] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 1.689] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 1.812] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.718] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.500] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 1.213] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 1.528] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 2.575] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.442] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.506] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 1.674] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 1.510] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.198] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.610] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.244] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.214] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.160] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.710] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 1.307] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.926] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 1.512] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.564] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.068] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.170] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.167] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.347] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.489] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.165] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.649] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.069] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 1.199] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.177] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.086] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 2.190] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 2.557]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.2] + [-.f64 #:spec (- x y) #:impl - #:cost 0.177] + [*.f64 #:spec (* x y) #:impl * #:cost 0.167] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.169] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 1.728] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 1.689] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 1.812] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.718] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.500] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 1.213] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 1.528] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 2.575] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.442] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.506] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 1.674] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 1.510] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.198] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.610] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.244] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.214] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.160] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.710] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 1.307] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.926] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 1.512] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.564] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.068] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.170] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.167] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.347] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.489] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.165] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.649] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.069] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 1.199] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.177] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.086] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 2.190] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 2.557]) + + +(define-operation (cosquot.f64 [x ] [y ]) + + #:spec (cos (/ x y)) + #:impl (from-accelerators 'cosquot) + #:fpcore (! :precision binary64 (cosquot x y)) + #:cost 1918618) + +(define-operation (sinquot.f64 [x ] [y ]) + + #:spec (sin (/ x y)) + #:impl (from-accelerators 'sinquot) + #:fpcore (! :precision binary64 (sinquot x y)) + #:cost 1926771) + +(define-operation (sinprod.f64 [x ] [y ]) + + #:spec (sin (* x y)) + #:impl (from-accelerators 'sinprod) + #:fpcore (! :precision binary64 (sinprod x y)) + #:cost 4.086) + +(define-operation (cosprod.f64 [x ] [y ]) + + #:spec (cos (* x y)) + #:impl (from-accelerators 'cosprod) + #:fpcore (! :precision binary64 (cosprod x y)) + #:cost 4.086) + +(define-operation (log1pmd.f64 [x ]) + + #:spec (log (/ (+ 1 x) (- 1 x))) + #:impl (from-accelerators 'log1pmd) + #:fpcore (! :precision binary64 (log1pmd x)) + #:cost 1.093) + +(define-operation (invgud.f64 [x ]) + + #:spec (log (tan (* (+ (+ x x) (PI)) 1/4))) + #:impl (from-accelerators 'invgud) + #:fpcore (! :precision binary64 (invgud x)) + #:cost 9.955) + +(define-operation (hypot.f64 [x ] [y ]) + + #:spec (sqrt (+ (* x x) (* y y))) + #:impl (from-accelerators 'hypot) + #:fpcore (! :precision binary64 (hypot x y)) + #:cost 0.864) + +(define-operation (verdcos.f64 [x ]) + + #:spec (- (cos (+ x x)) 1) + #:impl (from-accelerators 'verdcos) + #:fpcore (! :precision binary64 (verdcos x)) + #:cost 2.562) + +(define-operation (powcos.f64 [x ] [y ]) + + #:spec (pow (cos x) y) + #:impl (from-accelerators 'powcos) + #:fpcore (! :precision binary64 (powcos x y)) + #:cost 6.616) + +(define-operation (powcos2.f64 [x ]) + + #:spec (pow (cos x) 2) + #:impl (from-accelerators 'powcos2) + #:fpcore (! :precision binary64 (powcos2 x)) + #:cost 4.056) + +(define-operation (powcos4.f64 [x ]) + + #:spec (pow (cos x) 4) + #:impl (from-accelerators 'powcos4) + #:fpcore (! :precision binary64 (powcos4 x)) + #:cost 3.461) + +(define-operation (powcos6.f64 [x ]) + + #:spec (pow (cos x) 6) + #:impl (from-accelerators 'powcos6) + #:fpcore (! :precision binary64 (powcos6 x)) + #:cost 3.884) + +(define-operation (pow1ms.f64 [x ] [y ]) + + #:spec (pow (* (- 1 x) (- 1 x)) y) + #:impl (from-accelerators 'pow1ms) + #:fpcore (! :precision binary64 (pow1ms x y)) + #:cost 2.855) diff --git a/growlibm/platforms/growlibmbest.rkt b/growlibm/platforms/growlibmbest.rkt new file mode 100644 index 0000000000..3e9cb2b499 --- /dev/null +++ b/growlibm/platforms/growlibmbest.rkt @@ -0,0 +1,211 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 1) + +(define-operations () + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost 1] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 1]) + +(define-operations ([x ] [y ]) + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 1] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost 1]) + +(define-operation (not [x ]) + #:spec (not x) #:impl not #:cost 1) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32) + +(define-operation (if.f32 [c ] [t ] [f ]) + #:spec (if c t f) #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + [==.f32 #:spec (== x y) #:impl = #:cost 128] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 128] + [<.f32 #:spec (< x y) #:impl < #:cost 128] + [>.f32 #:spec (> x y) #:impl > #:cost 128] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 128] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 128]) + +(define-operations () #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32]) + +(define-operation (neg.f32 [x ]) + #:spec (neg x) #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) #:cost 64) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 64] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 64] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 128] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 320]) + +(define-operations ([x ]) #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 64] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 3200] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 3200] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 3200] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 3200] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 3200] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 3200] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 3200] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 3200] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 3200] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 3200] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 3200] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 3200] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 3200] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 3200] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 3200] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 3200] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 3200] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 3200] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 3200] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 3200] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 3200] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 3200] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 3200] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 3200] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 320] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 3200] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 3200] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 3200]) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 3200] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 3200] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 3200] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 3200] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 3200] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 3200] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 3200] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 3200]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64) + +(define-operation (if.f64 [c ] [t ] [f ]) + #:spec (if c t f) #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + [==.f64 #:spec (== x y) #:impl = #:cost 256] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 256] + [<.f64 #:spec (< x y) #:impl < #:cost 256] + [>.f64 #:spec (> x y) #:impl > #:cost 256] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 256] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 256]) + +(define-operations () #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64]) + +(define-operation (neg.f64 [x ]) + #:spec (neg x) #:impl - + #:fpcore (! :precision binary64 (- x)) #:cost 128) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 128] + [-.f64 #:spec (- x y) #:impl - #:cost 128] + [*.f64 #:spec (* x y) #:impl * #:cost 256] + [/.f64 #:spec (/ x y) #:impl / #:cost 640]) + +(define-operations ([x ]) #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 128] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 6400] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 6400] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 6400] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 6400] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 6400] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 6400] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 6400] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 6400] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 6400] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 6400] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 6400] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 6400] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 6400] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 6400] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 6400] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 6400] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 6400] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 6400] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 6400] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 6400] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 6400] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 6400] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 6400] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 6400] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 640] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 6400] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 6400] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 6400]) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 6400] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 6400] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 6400] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 6400] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 6400] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 6400] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 6400] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 6400]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CASTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-operation (binary64->binary32 [x ]) + #:spec x #:fpcore (! :precision binary32 (cast x)) #:impl flsingle #:cost 64) + +(define-operation (binary32->binary64 [x ]) + #:spec x #:fpcore (! :precision binary64 (cast x)) #:impl identity #:cost 64) + + +(define-operation (sin_xy.f64 [x ] [y ]) + + #:spec (sin (* x y)) + #:impl (from-rival) + #:fpcore (! :precision binary64 (sin_xy x y)) + #:cost 1000) + +(define-operation (cos_xy.f64 [x ] [y ]) + + #:spec (cos (* x y)) + #:impl (from-rival) + #:fpcore (! :precision binary64 (cos_xy x y)) + #:cost 1000) + +(define-operation (sin_quotient_xy.f64 [x ] [y ]) + + #:spec (sin (/ x y)) + #:impl (from-rival) + #:fpcore (! :precision binary64 (sin_quotient_xy x y)) + #:cost 1000) + +(define-operation (cos_quotient_xy.f64 [x ] [y ]) + + #:spec (cos (/ x y)) + #:impl (from-rival) + #:fpcore (! :precision binary64 (cos_quotient_xy x y)) + #:cost 1000) + +(define-operation (log1pmd.f64 [x ]) + + #:spec (log (/ (+ 1 x) (- 1 x))) + #:impl (from-accelerators 'log1pmd) + #:fpcore (! :precision binary64 (log1pmd x)) + #:cost 1000) \ No newline at end of file diff --git a/growlibm/platforms/herbie20plus.rkt b/growlibm/platforms/herbie20plus.rkt new file mode 100644 index 0000000000..12ba8c9f31 --- /dev/null +++ b/growlibm/platforms/herbie20plus.rkt @@ -0,0 +1,237 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 1) + +(define-operations () + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost 1] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost 1]) + +(define-operations ([x ] [y ]) + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost 1] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost 1]) + +(define-operation (not [x ]) + #:spec (not x) #:impl not #:cost 1) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32) + +(define-operation (if.f32 [c ] [t ] [f ]) + #:spec (if c t f) #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + [==.f32 #:spec (== x y) #:impl = #:cost 128] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 128] + [<.f32 #:spec (< x y) #:impl < #:cost 128] + [>.f32 #:spec (> x y) #:impl > #:cost 128] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 128] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 128]) + +(define-operations () #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32]) + +(define-operation (neg.f32 [x ]) + #:spec (neg x) #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) #:cost 64) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 64] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 64] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 128] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 320]) + +(define-operations ([x ]) #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 64] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 3200] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 3200] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 3200] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 3200] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 3200] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 3200] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 3200] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 3200] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 3200] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 3200] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 3200] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 3200] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 3200] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 3200] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 3200] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 3200] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 3200] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 3200] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 3200] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 3200] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 3200] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 3200] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 3200] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 3200] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 320] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 3200] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 3200] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 3200]) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 3200] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 3200] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 3200] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 3200] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 3200] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 3200] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 3200] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 3200]) + +(define-operations ([x ]) #:fpcore (! :precision binary32 _) + [erfc.f32 #:spec (- 1 (erf x)) #:impl (from-libm 'erfcf) #:fpcore (erfc x) #:cost 3200] + [expm1.f32 #:spec (- (exp x) 1) #:impl (from-libm 'expm1f) #:fpcore (expm1 x) #:cost 3200] + [log1p.f32 #:spec (log (+ 1 x)) #:impl (from-libm 'log1pf) #:fpcore (log1p x) #:cost 3200]) + +(define-operation (hypot.f32 [x ] [y ]) + #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypotf) + #:fpcore (! :precision binary32 (hypot x y)) #:cost 3200) + +(define-operation (fma.f32 [x ] [y ] [z ]) + #:spec (+ (* x y) z) #:impl (from-libm 'fmaf) + #:fpcore (! :precision binary32 (fma x y z)) #:cost 128) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64) + +(define-operation (if.f64 [c ] [t ] [f ]) + #:spec (if c t f) #:impl if-impl + #:cost (if-cost 1)) + +(define-operations ([x ] [y ]) + [==.f64 #:spec (== x y) #:impl = #:cost 256] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 256] + [<.f64 #:spec (< x y) #:impl < #:cost 256] + [>.f64 #:spec (> x y) #:impl > #:cost 256] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 256] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 256]) + +(define-operations () #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64]) + +(define-operation (neg.f64 [x ]) + #:spec (neg x) #:impl - + #:fpcore (! :precision binary64 (- x)) #:cost 128) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 128] + [-.f64 #:spec (- x y) #:impl - #:cost 128] + [*.f64 #:spec (* x y) #:impl * #:cost 256] + [/.f64 #:spec (/ x y) #:impl / #:cost 640]) + +(define-operations ([x ]) #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 128] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 6400] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 6400] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 6400] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 6400] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 6400] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 6400] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 6400] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 6400] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 6400] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 6400] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 6400] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 6400] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 6400] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 6400] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 6400] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 6400] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 6400] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 6400] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 6400] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 6400] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 6400] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 6400] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 6400] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 6400] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 640] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 6400] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 6400] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 6400]) + +(define-operations ([x ] [y ]) #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 6400] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 6400] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 6400] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 6400] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 6400] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 6400] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 6400] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 6400]) + +(define-operations ([x ]) #:fpcore (! :precision binary64 _) + [erfc.f64 #:spec (- 1 (erf x)) #:impl (from-libm 'erfc) #:fpcore (erfc x) #:cost 6400] + [expm1.f64 #:spec (- (exp x) 1) #:impl (from-libm 'expm1) #:fpcore (expm1 x) #:cost 6400] + [log1p.f64 #:spec (log (+ 1 x)) #:impl (from-libm 'log1p) #:fpcore (log1p x) #:cost 6400]) + +(define-operation (hypot.f64 [x ] [y ]) + #:spec (sqrt (+ (* x x) (* y y))) #:impl (from-libm 'hypot) + #:fpcore (! :precision binary64 (hypot x y)) #:cost 6400) + +(define-operation (fma.f64 [x ] [y ] [z ]) + #:spec (+ (* x y) z) #:impl (from-libm 'fma) + #:fpcore (! :precision binary64 (fma x y z)) #:cost 256) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CASTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; (define-operation (binary64->binary32 [x ]) +;;; #:spec x #:fpcore (! :precision binary32 (cast x)) #:impl flsingle #:cost 64) + +;;; (define-operation (binary32->binary64 [x ]) +;;; #:spec x #:fpcore (! :precision binary64 (cast x)) #:impl identity #:cost 64) + + +;;; (define-operation (sin_xy.f64 [x ] [y ]) +;;; +;;; #:spec (sin (* x y)) +;;; #:impl (from-accelerators 'sin_xy) +;;; #:fpcore (! :precision binary64 (sin_xy x y)) +;;; #:cost 12800) + +;;; (define-operation (cos_xy.f64 [x ] [y ]) +;;; +;;; #:spec (cos (* x y)) +;;; #:impl (from-accelerators 'cos_xy) +;;; #:fpcore (! :precision binary64 (cos_xy x y)) +;;; #:cost 12800) + +;;; (define-operation (sin-quotient_xy.f64 [x ] [y ]) +;;; +;;; #:spec (sin (/ x y)) +;;; #:impl (from-accelerators 'sin_quotient_xy) +;;; #:fpcore (! :precision binary64 (sin-quotient_xy x y)) +;;; #:cost 12800) + +;;; (define-operation (cos-quotient_xy.f64 [x ] [y ]) +;;; +;;; #:spec (cos (/ x y)) +;;; #:impl (from-accelerators 'cos_quotient_xy) +;;; #:fpcore (! :precision binary64 (cos-quotient_xy x y)) +;;; #:cost 12800) + +;;; (define-operation (log1pmd.f64 [x ]) +;;; +;;; #:spec (log (/ (+ 1 x) (- 1 x))) +;;; #:impl (from-accelerators 'log1pmd) +;;; #:fpcore (! :precision binary64 (log1pmd x)) +;;; #:cost 3200) \ No newline at end of file diff --git a/growlibm/platforms/proj copy.rkt b/growlibm/platforms/proj copy.rkt new file mode 100644 index 0000000000..f83aa211d1 --- /dev/null +++ b/growlibm/platforms/proj copy.rkt @@ -0,0 +1,291 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.125) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.200] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.200] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.250] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.350]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.125] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 4.250] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 4.250] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 4.750] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.750] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.250] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 0.500] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 0.850] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 0.500] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.125] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.100] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 0.500] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 2.000] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.250] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.125] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.375] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.175] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.250] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.250] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 0.750] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.175] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 0.875] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.375] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.300] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.875] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.250] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.000] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.625] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.275]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.000] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.000] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.200] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 0.750] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.250] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.250] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 1.750] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 1.000]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.125) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.200] + [-.f64 #:spec (- x y) #:impl - #:cost 0.200] + [*.f64 #:spec (* x y) #:impl * #:cost 0.250] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.350]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.125] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 4.200] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 4.200] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 4.650] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.750] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.650] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 0.500] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 0.850] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 0.500] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.125] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.100] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 0.450] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 2.000] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.250] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.125] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.375] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.175] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.300] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.250] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 0.750] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.175] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 0.850] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.350] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.300] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.850] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.250] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.000] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.625] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.250]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.000] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.000] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.200] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 0.750] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.250] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.250] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 1.750] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 1.000]) + +(define-operation (sinprod.f64 [x ] [y ]) + + #:spec (sin (* x y)) + #:impl (from-accelerators 'sinprod) + #:fpcore (! :precision binary64 (sinprod x y)) + #:cost 7.362) + +(define-operation (cosprod.f64 [x ] [y ]) + + #:spec (cos (* x y)) + #:impl (from-accelerators 'cosprod) + #:fpcore (! :precision binary64 (cosprod x y)) + #:cost 7.103) + +(define-operation (log1pmd.f64 [x ]) + + #:spec (log (/ (+ 1 x) (- 1 x))) + #:impl (from-accelerators 'log1pmd) + #:fpcore (! :precision binary64 (log1pmd x)) + #:cost 1.019) + +;;; (define-operation (invgudf.f32 [x ]) +;;; +;;; #:spec (log (tan (* (+ (+ x x) (PI)) 1/4))) +;;; #:impl (from-accelerators 'invgudf) +;;; #:fpcore (! :precision binary32 (invgudf x)) +;;; #:cost 0) + +(define-operation (invgud.f64 [x ]) + + #:spec (log (tan (* (+ (+ x x) (PI)) 1/4))) + #:impl (from-accelerators 'invgud) + #:fpcore (! :precision binary64 (invgud x)) + #:cost 20.453) + +;;; (define-operation (invgud.f64 [x ]) +;;; +;;; #:spec (log (tan (+ (* (PI) 1/4) (* x 1/2)))) +;;; #:impl (from-accelerators 'invgud) +;;; #:fpcore (! :precision binary64 (invgud x)) +;;; #:cost 25000) + +(define-operation (hypot.f64 [x ] [y ]) + + #:spec (sqrt (+ (* x x) (* y y))) + #:impl (from-accelerators 'hypot) + #:fpcore (! :precision binary64 (hypot x y)) + #:cost 1.232) + +(define-operation (verdcos.f64 [x ]) + + #:spec (- (cos (+ x x)) 1) + #:impl (from-accelerators 'verdcos) + #:fpcore (! :precision binary64 (verdcos x)) + #:cost 3.325) + +;;; (define-operation (ncos1p.f64 [x ]) +;;; +;;; #:spec (- 1 (cos x)) +;;; #:impl (from-accelerators 'ncos1p) +;;; #:fpcore (! :precision binary64 (ncos1p x)) +;;; #:cost 12800) + +;;; (define-operation (sindivpz.f64 [x ] [y ] [z ]) +;;; +;;; #:spec (sin (+ (/ x y) z)) +;;; #:impl (from-accelerators 'sindivpz) +;;; #:fpcore (! :precision binary64 (sindivpz x y z)) +;;; #:cost 0) + +;;; (define-operation (cosdivpz.f64 [x ] [y ] [z ]) +;;; +;;; #:spec (cos (+ (/ x y) z)) +;;; #:impl (from-accelerators 'cosdivpz) +;;; #:fpcore (! :precision binary64 (cosdivpz x y z)) +;;; #:cost 0) + +;;; (define-operation (sinquot.f64 [x ] [y ]) +;;; +;;; #:spec (sin (/ x y)) +;;; #:impl (from-accelerators 'sinquot) +;;; #:fpcore (! :precision binary64 (sinquot x y)) +;;; #:cost 0) + +;;; (define-operation (cosquot.f64 [x ] [y ]) +;;; +;;; #:spec (cos (/ x y)) +;;; #:impl (from-accelerators 'cosquot) +;;; #:fpcore (! :precision binary64 (cosquot x y)) +;;; #:cost 10000) diff --git a/growlibm/platforms/proj.rkt b/growlibm/platforms/proj.rkt new file mode 100644 index 0000000000..6054a6cfe8 --- /dev/null +++ b/growlibm/platforms/proj.rkt @@ -0,0 +1,292 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.2] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.177] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.167] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.169] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 1.728] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 1.689] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 1.812] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.718] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.500] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 1.213] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 1.528] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 2.575] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.442] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.506] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 1.674] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 1.510] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.198] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.610] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.244] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.214] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.160] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.710] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 1.307] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.926] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 1.512] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.564] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.068] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.170] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.167] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.347] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.489] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.165] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.649] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.069] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 1.199] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.177] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.086] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 2.190] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 2.557]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.2] + [-.f64 #:spec (- x y) #:impl - #:cost 0.177] + [*.f64 #:spec (* x y) #:impl * #:cost 0.167] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.169] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 1.728] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 1.689] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 1.812] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.718] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.500] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 1.213] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 1.528] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 2.575] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.442] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.506] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 1.674] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 1.510] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.198] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.610] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.244] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.214] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.160] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.710] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 1.307] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.926] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 1.512] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.564] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.068] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.170] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.167] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.347] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.489] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.165] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.649] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.069] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 1.199] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.177] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.086] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 2.190] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 2.557]) + + +;;; (define-operation (cosquot.f64 [x ] [y ]) +;;; +;;; #:spec (cos (/ x y)) +;;; #:impl (from-accelerators 'cosquot) +;;; #:fpcore (! :precision binary64 (cosquot x y)) +;;; #:cost 1918618) + +;;; (define-operation (sinquot.f64 [x ] [y ]) +;;; +;;; #:spec (sin (/ x y)) +;;; #:impl (from-accelerators 'sinquot) +;;; #:fpcore (! :precision binary64 (sinquot x y)) +;;; #:cost 1926771) + +(define-operation (sinprod.f64 [x ] [y ]) + + #:spec (sin (* x y)) + #:impl (from-accelerators 'sinprod) + #:fpcore (! :precision binary64 (sinprod x y)) + #:cost 4.086) + +(define-operation (cosprod.f64 [x ] [y ]) + + #:spec (cos (* x y)) + #:impl (from-accelerators 'cosprod) + #:fpcore (! :precision binary64 (cosprod x y)) + #:cost 4.086) + +(define-operation (log1pmd.f64 [x ]) + + #:spec (log (/ (+ 1 x) (- 1 x))) + #:impl (from-accelerators 'log1pmd) + #:fpcore (! :precision binary64 (log1pmd x)) + #:cost 1.093) + +(define-operation (invgud.f64 [x ]) + + #:spec (log (tan (* (+ (+ x x) (PI)) 1/4))) + #:impl (from-accelerators 'invgud) + #:fpcore (! :precision binary64 (invgud x)) + #:cost 9.955) + +(define-operation (hypot.f64 [x ] [y ]) + + #:spec (sqrt (+ (* x x) (* y y))) + #:impl (from-accelerators 'hypot) + #:fpcore (! :precision binary64 (hypot x y)) + #:cost 0.864) + +(define-operation (verdcos.f64 [x ]) + + #:spec (- (cos (+ x x)) 1) + #:impl (from-accelerators 'verdcos) + #:fpcore (! :precision binary64 (verdcos x)) + #:cost 2.562) + +;;; (define-operation (powcos.f64 [x ] [y ]) +;;; +;;; #:spec (pow (cos x) y) +;;; #:impl (from-accelerators 'powcos) +;;; #:fpcore (! :precision binary64 (powcos x y)) +;;; #:cost 8.155) + +;;; (define-operation (powcos2.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 2) +;;; #:impl (from-accelerators 'powcos2) +;;; #:fpcore (! :precision binary64 (powcos2 x)) +;;; #:cost 4.815) + +;;; (define-operation (powcos4.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 4) +;;; #:impl (from-accelerators 'powcos4) +;;; #:fpcore (! :precision binary64 (powcos4 x)) +;;; #:cost 4.930) + +;;; (define-operation (powcos6.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 6) +;;; #:impl (from-accelerators 'powcos6) +;;; #:fpcore (! :precision binary64 (powcos6 x)) +;;; #:cost 4.798) + +;;; (define-operation (pow1ms.f64 [x ] [y ]) +;;; +;;; #:spec (pow (* (- 1 x) (- 1 x)) y) +;;; #:impl (from-accelerators 'pow1ms) +;;; #:fpcore (! :precision binary64 (pow1ms x y)) +;;; #:cost 4.020) diff --git a/growlibm/platforms/vanilla copy.rkt b/growlibm/platforms/vanilla copy.rkt new file mode 100644 index 0000000000..45f70561ae --- /dev/null +++ b/growlibm/platforms/vanilla copy.rkt @@ -0,0 +1,200 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.125) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.200] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.200] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.250] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.350]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.125] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 4.250] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 4.250] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 4.750] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.750] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.250] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 0.500] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 0.850] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 0.500] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.125] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.100] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 0.500] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 2.000] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.250] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.125] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.375] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.175] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.250] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.250] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 0.750] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.175] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 0.875] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.375] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.300] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.875] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.250] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.000] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.625] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.275]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.000] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.000] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.200] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 0.750] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.250] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.250] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 1.750] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 1.000]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.125) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.200] + [-.f64 #:spec (- x y) #:impl - #:cost 0.200] + [*.f64 #:spec (* x y) #:impl * #:cost 0.250] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.350]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.125] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 4.200] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 4.200] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 4.650] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.750] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.650] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 0.500] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 0.850] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 0.500] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.125] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.100] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 0.450] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 2.000] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.250] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.125] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.375] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.175] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.300] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.250] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 0.750] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.175] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 0.850] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.350] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.300] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.850] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.250] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.000] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.625] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.250]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.000] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.000] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.200] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 0.750] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.250] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.250] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 1.750] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 1.000]) \ No newline at end of file diff --git a/growlibm/platforms/vanilla.rkt b/growlibm/platforms/vanilla.rkt new file mode 100644 index 0000000000..573cd674e4 --- /dev/null +++ b/growlibm/platforms/vanilla.rkt @@ -0,0 +1,292 @@ +#lang s-exp "../../src/syntax/platform-language.rkt" + +;; Herbie 2.0 platform. Based on the C Windows platform, but with +;; every operation having heuristic costs from Herbie 2.0. + +(require math/flonum) + +(define 64bit-move-cost 0.125) +(define 32bit-move-cost 0.125) +(define boolean-move-cost 0.100) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BOOLEAN ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost boolean-move-cost) + +(define-operations () + + [TRUE #:spec (TRUE) #:impl (const true) #:fpcore TRUE #:cost boolean-move-cost] + [FALSE #:spec (FALSE) #:impl (const false) #:fpcore FALSE #:cost boolean-move-cost]) + +(define-operations ([x ] [y ]) + + [and #:spec (and x y) #:impl (lambda v (andmap values v)) #:cost boolean-move-cost] + [or #:spec (or x y) #:impl (lambda v (ormap values v)) #:cost boolean-move-cost]) + +(define-operation (not [x ]) #:spec (not x) #:impl not #:cost boolean-move-cost) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 32bit-move-cost) + +(define-operation (if.f32 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f32 #:spec (== x y) #:impl = #:cost 32bit-move-cost] + [!=.f32 #:spec (!= x y) #:impl (negate =) #:cost 32bit-move-cost] + [<.f32 #:spec (< x y) #:impl < #:cost 32bit-move-cost] + [>.f32 #:spec (> x y) #:impl > #:cost 32bit-move-cost] + [<=.f32 #:spec (<= x y) #:impl <= #:cost 32bit-move-cost] + [>=.f32 #:spec (>= x y) #:impl >= #:cost 32bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary32 _) + [PI.f32 #:spec (PI) #:impl (const (flsingle pi)) #:fpcore PI #:cost 32bit-move-cost] + [E.f32 #:spec (E) #:impl (const (flsingle (exp 1))) #:fpcore E #:cost 32bit-move-cost] + [INFINITY.f32 #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 32bit-move-cost] + [NAN.f32 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 32bit-move-cost]) + +(define-operation (neg.f32 [x ]) + + #:spec (neg x) + #:impl (compose flsingle -) + #:fpcore (! :precision binary32 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [+.f32 #:spec (+ x y) #:impl (compose flsingle +) #:cost 0.2] + [-.f32 #:spec (- x y) #:impl (compose flsingle -) #:cost 0.177] + [*.f32 #:spec (* x y) #:impl (compose flsingle *) #:cost 0.167] + [/.f32 #:spec (/ x y) #:impl (compose flsingle /) #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary32 _) + [fabs.f32 #:spec (fabs x) #:impl (from-libm 'fabsf) #:cost 0.169] + [sin.f32 #:spec (sin x) #:impl (from-libm 'sinf) #:cost 1.728] + [cos.f32 #:spec (cos x) #:impl (from-libm 'cosf) #:cost 1.689] + [tan.f32 #:spec (tan x) #:impl (from-libm 'tanf) #:cost 1.812] + [sinh.f32 #:spec (sinh x) #:impl (from-libm 'sinhf) #:cost 1.718] + [cosh.f32 #:spec (cosh x) #:impl (from-libm 'coshf) #:cost 1.500] + [acos.f32 #:spec (acos x) #:impl (from-libm 'acosf) #:cost 1.213] + [acosh.f32 #:spec (acosh x) #:impl (from-libm 'acoshf) #:cost 1.528] + [asin.f32 #:spec (asin x) #:impl (from-libm 'asinf) #:cost 2.575] + [asinh.f32 #:spec (asinh x) #:impl (from-libm 'asinhf) #:cost 1.442] + [atan.f32 #:spec (atan x) #:impl (from-libm 'atanf) #:cost 1.506] + [atanh.f32 #:spec (atanh x) #:impl (from-libm 'atanhf) #:cost 1.674] + [cbrt.f32 #:spec (cbrt x) #:impl (from-libm 'cbrtf) #:cost 1.510] + [ceil.f32 #:spec (ceil x) #:impl (from-libm 'ceilf) #:cost 0.198] + [erf.f32 #:spec (erf x) #:impl (from-libm 'erff) #:cost 1.610] + [exp.f32 #:spec (exp x) #:impl (from-libm 'expf) #:cost 1.244] + [exp2.f32 #:spec (exp2 x) #:impl (from-libm 'exp2f) #:cost 1.214] + [floor.f32 #:spec (floor x) #:impl (from-libm 'floorf) #:cost 0.160] + [lgamma.f32 #:spec (lgamma x) #:impl (from-libm 'lgammaf) #:cost 2.710] + [log.f32 #:spec (log x) #:impl (from-libm 'logf) #:cost 1.307] + [log10.f32 #:spec (log10 x) #:impl (from-libm 'log10f) #:cost 1.926] + [log2.f32 #:spec (log2 x) #:impl (from-libm 'log2f) #:cost 1.512] + [logb.f32 #:spec (logb x) #:impl (from-libm 'logbf) #:cost 0.564] + [rint.f32 #:spec (rint x) #:impl (from-libm 'rintf) #:cost 0.068] + [round.f32 #:spec (round x) #:impl (from-libm 'roundf) #:cost 0.170] + [sqrt.f32 #:spec (sqrt x) #:impl (from-libm 'sqrtf) #:cost 0.167] + [tanh.f32 #:spec (tanh x) #:impl (from-libm 'tanhf) #:cost 1.347] + [tgamma.f32 #:spec (tgamma x) #:impl (from-libm 'tgammaf) #:cost 2.489] + [trunc.f32 #:spec (trunc x) #:impl (from-libm 'truncf) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary32 _) + [pow.f32 #:spec (pow x y) #:impl (from-libm 'powf) #:cost 2.165] + [atan2.f32 #:spec (atan2 x y) #:impl (from-libm 'atan2f) #:cost 2.649] + [copysign.f32 #:spec (copysign x y) #:impl (from-libm 'copysignf) #:cost 0.069] + [fdim.f32 #:spec (fdim x y) #:impl (from-libm 'fdimf) #:cost 1.199] + [fmax.f32 #:spec (fmax x y) #:impl (from-libm 'fmaxf) #:cost 0.177] + [fmin.f32 #:spec (fmin x y) #:impl (from-libm 'fminf) #:cost 0.086] + [fmod.f32 #:spec (fmod x y) #:impl (from-libm 'fmodf) #:cost 2.190] + [remainder.f32 #:spec (remainder x y) #:impl (from-libm 'remainderf) #:cost 2.557]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINARY 64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-representation #:cost 64bit-move-cost) + +(define-operation (if.f64 [c ] [t ] [f ]) + + #:spec (if c t f) + #:impl if-impl + #:cost (if-cost boolean-move-cost)) + +(define-operations ([x ] [y ]) + + [==.f64 #:spec (== x y) #:impl = #:cost 64bit-move-cost] + [!=.f64 #:spec (!= x y) #:impl (negate =) #:cost 64bit-move-cost] + [<.f64 #:spec (< x y) #:impl < #:cost 64bit-move-cost] + [>.f64 #:spec (> x y) #:impl > #:cost 64bit-move-cost] + [<=.f64 #:spec (<= x y) #:impl <= #:cost 64bit-move-cost] + [>=.f64 #:spec (>= x y) #:impl >= #:cost 64bit-move-cost]) + +(define-operations () + + #:fpcore (! :precision binary64 _) + [PI.f64 #:spec (PI) #:impl (const pi) #:fpcore PI #:cost 64bit-move-cost] + [E.f64 #:spec (E) #:impl (const (exp 1)) #:fpcore E #:cost 64bit-move-cost] + [INFINITY #:spec (INFINITY) #:impl (const +inf.0) #:fpcore INFINITY #:cost 64bit-move-cost] + [NAN.f64 #:spec (NAN) #:impl (const +nan.0) #:fpcore NAN #:cost 64bit-move-cost]) + +(define-operation (neg.f64 [x ]) + + #:spec (neg x) + #:impl - + #:fpcore (! :precision binary64 (- x)) + #:cost 0.168) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [+.f64 #:spec (+ x y) #:impl + #:cost 0.2] + [-.f64 #:spec (- x y) #:impl - #:cost 0.177] + [*.f64 #:spec (* x y) #:impl * #:cost 0.167] + [/.f64 #:spec (/ x y) #:impl / #:cost 0.253]) + +(define-operations ([x ]) + + #:fpcore (! :precision binary64 _) + [fabs.f64 #:spec (fabs x) #:impl (from-libm 'fabs) #:cost 0.169] + [sin.f64 #:spec (sin x) #:impl (from-libm 'sin) #:cost 1.728] + [cos.f64 #:spec (cos x) #:impl (from-libm 'cos) #:cost 1.689] + [tan.f64 #:spec (tan x) #:impl (from-libm 'tan) #:cost 1.812] + [sinh.f64 #:spec (sinh x) #:impl (from-libm 'sinh) #:cost 1.718] + [cosh.f64 #:spec (cosh x) #:impl (from-libm 'cosh) #:cost 1.500] + [acos.f64 #:spec (acos x) #:impl (from-libm 'acos) #:cost 1.213] + [acosh.f64 #:spec (acosh x) #:impl (from-libm 'acosh) #:cost 1.528] + [asin.f64 #:spec (asin x) #:impl (from-libm 'asin) #:cost 2.575] + [asinh.f64 #:spec (asinh x) #:impl (from-libm 'asinh) #:cost 1.442] + [atan.f64 #:spec (atan x) #:impl (from-libm 'atan) #:cost 1.506] + [atanh.f64 #:spec (atanh x) #:impl (from-libm 'atanh) #:cost 1.674] + [cbrt.f64 #:spec (cbrt x) #:impl (from-libm 'cbrt) #:cost 1.510] + [ceil.f64 #:spec (ceil x) #:impl (from-libm 'ceil) #:cost 0.198] + [erf.f64 #:spec (erf x) #:impl (from-libm 'erf) #:cost 1.610] + [exp.f64 #:spec (exp x) #:impl (from-libm 'exp) #:cost 1.244] + [exp2.f64 #:spec (exp2 x) #:impl (from-libm 'exp2) #:cost 1.214] + [floor.f64 #:spec (floor x) #:impl (from-libm 'floor) #:cost 0.160] + [lgamma.f64 #:spec (lgamma x) #:impl (from-libm 'lgamma) #:cost 2.710] + [log.f64 #:spec (log x) #:impl (from-libm 'log) #:cost 1.307] + [log10.f64 #:spec (log10 x) #:impl (from-libm 'log10) #:cost 1.926] + [log2.f64 #:spec (log2 x) #:impl (from-libm 'log2) #:cost 1.512] + [logb.f64 #:spec (logb x) #:impl (from-libm 'logb) #:cost 0.564] + [rint.f64 #:spec (rint x) #:impl (from-libm 'rint) #:cost 0.068] + [round.f64 #:spec (round x) #:impl (from-libm 'round) #:cost 0.170] + [sqrt.f64 #:spec (sqrt x) #:impl (from-libm 'sqrt) #:cost 0.167] + [tanh.f64 #:spec (tanh x) #:impl (from-libm 'tanh) #:cost 1.347] + [tgamma.f64 #:spec (tgamma x) #:impl (from-libm 'tgamma) #:cost 2.489] + [trunc.f64 #:spec (trunc x) #:impl (from-libm 'trunc) #:cost 0.159]) + +(define-operations ([x ] [y ]) + + #:fpcore (! :precision binary64 _) + [pow.f64 #:spec (pow x y) #:impl (from-libm 'pow) #:cost 2.165] + [atan2.f64 #:spec (atan2 x y) #:impl (from-libm 'atan2) #:cost 2.649] + [copysign.f64 #:spec (copysign x y) #:impl (from-libm 'copysign) #:cost 0.069] + [fdim.f64 #:spec (fdim x y) #:impl (from-libm 'fdim) #:cost 1.199] + [fmax.f64 #:spec (fmax x y) #:impl (from-libm 'fmax) #:cost 0.177] + [fmin.f64 #:spec (fmin x y) #:impl (from-libm 'fmin) #:cost 0.086] + [fmod.f64 #:spec (fmod x y) #:impl (from-libm 'fmod) #:cost 2.190] + [remainder.f64 #:spec (remainder x y) #:impl (from-libm 'remainder) #:cost 2.557]) + + +;;; (define-operation (cosquot.f64 [x ] [y ]) +;;; +;;; #:spec (cos (/ x y)) +;;; #:impl (from-accelerators 'cosquot) +;;; #:fpcore (! :precision binary64 (cosquot x y)) +;;; #:cost 1918618) + +;;; (define-operation (sinquot.f64 [x ] [y ]) +;;; +;;; #:spec (sin (/ x y)) +;;; #:impl (from-accelerators 'sinquot) +;;; #:fpcore (! :precision binary64 (sinquot x y)) +;;; #:cost 1926771) + +;;; (define-operation (sinprod.f64 [x ] [y ]) +;;; +;;; #:spec (sin (* x y)) +;;; #:impl (from-accelerators 'sinprod) +;;; #:fpcore (! :precision binary64 (sinprod x y)) +;;; #:cost 4.086) + +;;; (define-operation (cosprod.f64 [x ] [y ]) +;;; +;;; #:spec (cos (* x y)) +;;; #:impl (from-accelerators 'cosprod) +;;; #:fpcore (! :precision binary64 (cosprod x y)) +;;; #:cost 4.086) + +;;; (define-operation (log1pmd.f64 [x ]) +;;; +;;; #:spec (log (/ (+ 1 x) (- 1 x))) +;;; #:impl (from-accelerators 'log1pmd) +;;; #:fpcore (! :precision binary64 (log1pmd x)) +;;; #:cost 1.093) + +;;; (define-operation (invgud.f64 [x ]) +;;; +;;; #:spec (log (tan (* (+ (+ x x) (PI)) 1/4))) +;;; #:impl (from-accelerators 'invgud) +;;; #:fpcore (! :precision binary64 (invgud x)) +;;; #:cost 9.955) + +;;; (define-operation (hypot.f64 [x ] [y ]) +;;; +;;; #:spec (sqrt (+ (* x x) (* y y))) +;;; #:impl (from-accelerators 'hypot) +;;; #:fpcore (! :precision binary64 (hypot x y)) +;;; #:cost 0.864) + +;;; (define-operation (verdcos.f64 [x ]) +;;; +;;; #:spec (- (cos (+ x x)) 1) +;;; #:impl (from-accelerators 'verdcos) +;;; #:fpcore (! :precision binary64 (verdcos x)) +;;; #:cost 2.562) + +;;; (define-operation (powcos.f64 [x ] [y ]) +;;; +;;; #:spec (pow (cos x) y) +;;; #:impl (from-accelerators 'powcos) +;;; #:fpcore (! :precision binary64 (powcos x y)) +;;; #:cost 8.155) + +;;; (define-operation (powcos2.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 2) +;;; #:impl (from-accelerators 'powcos2) +;;; #:fpcore (! :precision binary64 (powcos2 x)) +;;; #:cost 4.815) + +;;; (define-operation (powcos4.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 4) +;;; #:impl (from-accelerators 'powcos4) +;;; #:fpcore (! :precision binary64 (powcos4 x)) +;;; #:cost 4.930) + +;;; (define-operation (powcos6.f64 [x ]) +;;; +;;; #:spec (pow (cos x) 6) +;;; #:impl (from-accelerators 'powcos6) +;;; #:fpcore (! :precision binary64 (powcos6 x)) +;;; #:cost 4.798) + +;;; (define-operation (pow1ms.f64 [x ] [y ]) +;;; +;;; #:spec (pow (* (- 1 x) (- 1 x)) y) +;;; #:impl (from-accelerators 'pow1ms) +;;; #:fpcore (! :precision binary64 (pow1ms x y)) +;;; #:cost 4.020) diff --git a/growlibm/scratch.rkt b/growlibm/scratch.rkt new file mode 100644 index 0000000000..3f70a6ab2f --- /dev/null +++ b/growlibm/scratch.rkt @@ -0,0 +1,237 @@ +#lang racket + +(require + "../src/api/sandbox.rkt" + "../src/syntax/types.rkt" + "../src/core/points.rkt" + "../src/core/rules.rkt" + "../src/config.rkt" + "../src/syntax/batch.rkt" + "../src/core/egg-herbie.rkt" + "../src/syntax/read.rkt" + "../src/syntax/load-platform.rkt" + "../src/syntax/types.rkt" + "../src/core/points.rkt" + "../src/core/rules.rkt" + "../src/config.rkt" + "../src/core/egg-herbie.rkt" + "../src/syntax/read.rkt" + "../src/syntax/load-platform.rkt" + "../src/syntax/platform.rkt" + "../src/syntax/sugar.rkt" + "../src/core/programs.rkt" + "../src/syntax/syntax.rkt" + "../src/reports/common.rkt" + "../src/utils/common.rkt") + +(activate-platform! "no-accelerators") +(define cut-hole "cut_hole") +(define egg-batch-size 5000) +(define interesting-ops '(fabs.f32 sin.f32 cos.f32 tan.f32 sinh.f32 cosh.f32 tanh.f32 asin.f32 acos.f32 + atan.f32 asinh.f32 atanh.f32 acosh.f32 atan2.f32 exp.f32 exp2.f32 log.f32 log10.f32 + log2.f32 logb.f32 ceil.f32 floor.f32 sqrt.f32 cbrt.f32 pow.f32 fmax.f32 fmin.f32 fmod.f32 + fabs.f64 sin.f64 cos.f64 tan.f64 sinh.f64 cosh.f64 tanh.f64 asin.f64 acos.f64 + atan.f64 asinh.f64 atanh.f64 acosh.f64 atan2.f64 exp.f64 exp2.f64 log.f64 log10.f64 + log2.f64 logb.f64 ceil.f64 floor.f64 sqrt.f64 cbrt.f64 pow.f64 fmax.f64 fmin.f64 fmod.f64)) +(define max-vars 3) +(struct candidate (spec cost count ctx)) +;;; (define expr '(*.f64 (cos.f64 (*.f64 #s(literal -6.2831854820251465 binary64) z0)) (sqrt.f64 z1))) +;;; (define cost-proc (platform-cost-proc (*active-platform*))) +;;; (displayln (cost-proc expr (get-representation 'binary64))) +(define (get-ctx expr) + (define free-vars (sort (free-variables expr) symbolbatch exprs)) + + (define runner (make-egraph batch (map context-repr ctxs) schedule (second ctxs))) + ; batchrefss is a (listof (listof batchref)) + (define batchrefss (egraph-best runner batch)) + batchrefss) + +(define (operator-expr? e) + (match e + [(list _ _ ...) #t] + [_ #f])) + +(define (replace-child expr target replacement) + (match expr + [(list op args ...) + (cons op + (for/list ([arg (in-list args)] + [i (in-naturals)]) + (if (= i target) replacement arg)))])) + +(define (get-subexpressions expr) + (reap [sow] + (let loop ([expr expr]) + (match expr + [(or (? number?) (? literal?) (? symbol?)) (void)] + [(list _ args ...) + (sow expr) + (for ([arg (in-list args)] + [i (in-naturals)]) + (when (operator-expr? arg) + (sow (replace-child expr i cut-hole))) + (loop arg))] + [_ (void)])))) +;;; (define expr1 '(*.f64 z0 z0)) +;;; (define expr2 '(/.f64 z0 z1)) +;;; (define (get-ctx expr) +;;; (define free-vars (sort (free-variables expr) symboltest expr + #:name [name "scratch"] + #:precision [precision (*default-precision*)]) + (define vars (sort (free-variables expr) symbolprog expr default-ctx)] + [else (raise-arguments-error 'expr->test "not a Herbie expression" "expr" expr)])) + (define out-repr (repr-of impl-expr default-ctx)) + (define out-repr-name (representation-name out-repr)) + (define var-repr-names + (for/list ([var (in-list vars)]) + (cons var out-repr-name))) + (define spec impl-expr) + (test name + #f + vars + impl-expr + '() + #t + spec + '(TRUE) + out-repr-name + var-repr-names)) + +(define (run-herbie-expr expr platform + #:seed [seed #f] + #:name [name "scratch"] + #:precision [precision (*default-precision*)]) + (parameterize ([*active-platform* platform]) + (define test (expr->test expr #:name name #:precision precision)) + (define result (run-herbie 'improve test #:seed seed)) + (disable-flag! 'generate 'taylor) + (match (job-result-status result) + ['success + (define backend (job-result-backend result)) + (define end (improve-result-end backend)) + (define end-best (first end)) + (define final-error (errors-score (alt-analysis-errors end-best))) + final-error] + [_ + (raise-arguments-error 'run-herbie-expr "Herbie run failed" "expr" expr)]))) + +;;; (void (run-herbie-expr '(cbrt (/ (+ (sqrt (* (+ z2 z1) (- z1 z2))) z1) z0)))) + +;;; (define (register-op! platform fpcore name cost) +;;; (parameterize ([*active-platform* platform]) +;;; (define impl (fpcore->prog fpcore (get-ctx fpcore))) +;;; (define spec (prog->spec impl)) +;;; (define ctx (get-ctx spec)) +;;; (define vars (context-vars ctx)) +;;; (define name* (string->symbol name)) + +;;; (define op-impl +;;; (create-operator-impl! +;;; name* +;;; ctx +;;; #:spec spec +;;; #:impl (from-rival) +;;; #:fpcore `(! :precision binary64 (,name* ,@vars)) +;;; #:cost cost)) +;;; (platform-register-implementation! platform op-impl) +;;; (void))) + +(define base-platform (platform-copy (*active-platform*))) + +;;; (define (implies expr1 expr2) +;;; (define platform-a (platform-copy base-platform)) +;;; (register-op! platform-a expr1 "expr1" 0) +;;; (define before-err1 (run-herbie-expr expr2 base-platform)) +;;; (define after-err1 (run-herbie-expr expr2 platform-a)) + +;;; (define platform-b (platform-copy base-platform)) +;;; (register-op! platform-b expr2 "expr2" 0) +;;; (define before-err2 (run-herbie-expr expr1 base-platform)) +;;; (define after-err2 (run-herbie-expr expr1 platform-b)) + +;;; (displayln (format "~a, before: ~a, after: ~a" expr2 before-err1 after-err1)) +;;; (displayln (format "~a, before: ~a, after: ~a" expr1 before-err2 after-err2))) + +;;; (implies '(/ z0 (sqrt (+ (* z0 z0) (* z1 z1)))) '(* (/ z0 (sqrt (+ (* z0 z0) (* z1 z1)))) z2)) + +;;; (define expr1 '(if.f64 (or (>.f64 (fabs.f64 g) #s(literal 0 binary64)) (>.f64 (fabs.f64 (cos.f64 (+.f64 phi0 (/.f64 y esp)))) #s(literal 0 binary64))) (atan2.f64 g (cos.f64 (+.f64 phi0 (/.f64 y esp)))) #s(literal 0 binary64))) + +;;; (define (eliminate-ifs expr) +;;; (define comparison-bases +;;; '(<.f64 <=.f64 >.f64 >=.f64 ==.f64 !=.f64 +;;; <.f32 <=.f32 >.f32 >=.f32 ==.f32 !=.f32)) +;;; (define (comparison-op? op) (member op comparison-bases)) + +;;; (define (pure-math? e) +;;; (let check ([e e]) +;;; (match e +;;; [(or `(if.f32 ,_ ,_ ,_) +;;; `(if.f64 ,_ ,_ ,_)) #f] +;;; [(list (? comparison-op?) _ _) #f] +;;; [(list _ args ...) +;;; (andmap check args)] +;;; [_ #t]))) + +;;; (reap [sow] +;;; (let loop ([expr expr]) +;;; (match expr +;;; [(or `(if ,test ,t ,f) +;;; `(if.f32 ,test ,t ,f) +;;; `(if.f64 ,test ,t ,f)) +;;; (loop test) (loop t) (loop f)] + +;;; [(list (? comparison-op?) lhs rhs) +;;; (loop lhs) (loop rhs)] + +;;; [(list op args ...) +;;; (if (pure-math? expr) +;;; (sow expr) +;;; (for ([arg args]) +;;; (loop arg)))] + +;;; [_ (void)])))) + +;;; (displayln (eliminate-ifs expr1)) + + +(define expr1 '(pow (log (+ 1 (* x y))) 2)) +(displayln (get-subexpressions expr1)) \ No newline at end of file diff --git a/growlibm/scratch2.rkt b/growlibm/scratch2.rkt new file mode 100644 index 0000000000..5d0919ed70 --- /dev/null +++ b/growlibm/scratch2.rkt @@ -0,0 +1,57 @@ +#lang racket + +(require racket/list + "../src/api/sandbox.rkt" + "../src/core/points.rkt" + "../src/core/rules.rkt" + "../src/config.rkt" + "../src/core/batch.rkt" + "../src/core/egg-herbie.rkt" + "../src/syntax/load-platform.rkt" + "../src/syntax/sugar.rkt" + "../src/core/programs.rkt" + "../src/syntax/syntax.rkt" + "../src/utils/common.rkt") + +(activate-platform! "no-accelerators") + + +(define (all-subexpressions* expr) + (define comparison-bases '(<.f64 <=.f64 >.f64 >=.f64 ==.f64 !=.f64 <.f32 <=.f32 >.f32 >=.f32 ==.f32 !=.f32)) + (define (comparison-op? op) + (and (symbol? op) + (member op comparison-bases))) + (define subexprs + (reap [sow] + (let loop ([expr expr]) + (match expr + [(or `(if ,test ,t ,f) + `(if.f32 ,test ,t ,f) + `(if.f64 ,test ,t ,f)) + (loop test) + (loop t) + (loop f)] + [(approx _ impl) + (loop impl)] + [(list (? comparison-op?) lhs rhs) + (loop lhs) + (loop rhs)] + [_ + (sow expr) + (match expr + [(? number?) (void)] + [(? literal?) (void)] + [(? symbol?) (void)] + [(list _ args ...) + (for ([arg args]) + (loop arg))] + [_ (void)])])))) + (remove-duplicates subexprs)) + +(define (remove-approxes expr) + (match expr + [(approx _ impl) (remove-approxes impl)] + [(list op args ...) (cons op (map remove-approxes args))] + [_ expr])) + +(map displayln (all-subexpressions* '(if.f64 (<=.f64 (*.f64 v sinrot) #s(literal -99999999999999996863366107917975552 binary64)) (-.f64 #s(approx (* (- u u0) cosrot) (*.f64 cosrot u)) (*.f64 v sinrot)) (if.f64 (<=.f64 (*.f64 v sinrot) #s(literal 199999999999999995497619646912068059136 binary64)) #s(approx (- (* (- u u0) cosrot) (* v sinrot)) (*.f64 cosrot (-.f64 u u0))) (-.f64 #s(approx (* (- u u0) cosrot) (*.f64 cosrot u)) (*.f64 v sinrot)))))) diff --git a/growlibm/timeline.py b/growlibm/timeline.py new file mode 100644 index 0000000000..30bb2009d7 --- /dev/null +++ b/growlibm/timeline.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +import json +import sys +from datetime import datetime +from pathlib import Path + +command = sys.argv[1] +path = Path(sys.argv[2]) +now = datetime.now().astimezone() +timestamp = now.isoformat(timespec="microseconds") + +if command == "init": + checkpoints = [{"phase": "start", "timestamp": timestamp, "elapsed_seconds": 0}] +else: + checkpoints = json.loads(path.read_text(encoding="utf-8")) + start = datetime.fromisoformat(checkpoints[0]["timestamp"]) + checkpoints.append( + { + "phase": sys.argv[3], + "timestamp": timestamp, + "elapsed_seconds": round((now - start).total_seconds(), 6), + } + ) + +path.parent.mkdir(parents=True, exist_ok=True) +path.write_text(json.dumps(checkpoints, indent=2) + "\n", encoding="utf-8") diff --git a/growlibm/timing/compile.rkt b/growlibm/timing/compile.rkt new file mode 100644 index 0000000000..b16dedf954 --- /dev/null +++ b/growlibm/timing/compile.rkt @@ -0,0 +1,11 @@ +#lang racket + +(require "../../src/syntax/load-platform.rkt" + "../../src/syntax/load-platform.rkt" + "../../src/reports/common.rkt") + +(activate-platform! "growlibm") + +(define test (read (open-input-string (vector-ref (current-command-line-arguments) 0)))) + +(displayln (core->c test "foo")) \ No newline at end of file diff --git a/growlibm/timing/sample.rkt b/growlibm/timing/sample.rkt new file mode 100644 index 0000000000..07d649df10 --- /dev/null +++ b/growlibm/timing/sample.rkt @@ -0,0 +1,65 @@ +#lang racket + +(require "../../src/core/points.rkt" + "../../src/core/sampling.rkt" + "../../src/syntax/batch.rkt" + "../../src/syntax/load-platform.rkt" + "../../src/syntax/platform.rkt" + "../../src/syntax/sugar.rkt" + "../../src/syntax/types.rkt" + "../../src/utils/common.rkt") + +(activate-platform! "growlibm") + +(define args (current-command-line-arguments)) +(define core (read (open-input-string (vector-ref args 0)))) + +(when (> (vector-length args) 1) + (define seed (string->number (vector-ref args 1))) + (when seed + (set-seed! seed))) + +(define (parse-fpcore core) + (match core + [(list 'FPCore _ (list vars ...) props ... body) (values vars props body)] + [(list 'FPCore (list vars ...) props ... body) (values vars props body)] + [_ (error 'sample.rkt "invalid FPCore: ~a" core)])) + +(define (parse-context vars props) + (define prop-dict (props->dict props)) + (define default-prec (dict-ref prop-dict ':precision (*default-precision*))) + (define-values (var-names var-precs) + (for/lists (var-names var-precs) + ([var (in-list vars)]) + (match var + [(list '! var-props ... name) + (define var-prop-dict (props->dict var-props)) + (values name (dict-ref var-prop-dict ':precision default-prec))] + [(? symbol? name) (values name default-prec)] + [_ (error 'sample.rkt "invalid variable declaration: ~a" var)]))) + (define output-repr (get-representation default-prec)) + (define var-reprs (map get-representation var-precs)) + (values (context var-names output-repr var-reprs) prop-dict)) + +(define (fpcore-expr->spec expr ctx) + (prog->spec (fpcore->prog expr ctx))) + +(define (sample-core core) + (define-values (vars props body) (parse-fpcore core)) + (define-values (ctx prop-dict) (parse-context vars props)) + (*context* ctx) + + (define specification (fpcore-expr->spec (dict-ref prop-dict ':spec body) ctx)) + (define precondition (fpcore-expr->spec (dict-ref prop-dict ':pre 'TRUE) ctx)) + (define-values (batch brfs) (progs->batch (list specification))) + (define sample + (parameterize ([*num-points* (+ (*num-points*) (*reeval-pts*))]) + (sample-points precondition batch brfs (list ctx)))) + (pcontext-points (apply mk-pcontext sample))) + +(define points (sample-core core)) + +(for ([point (in-vector points)]) + (for ([value (in-vector point)]) + (display (format "~a " value))) + (displayln "")) diff --git a/growlibm/timing/time_ops.py b/growlibm/timing/time_ops.py new file mode 100644 index 0000000000..62ca0065ab --- /dev/null +++ b/growlibm/timing/time_ops.py @@ -0,0 +1,255 @@ +import argparse +import math +import subprocess +import sys + +DEFAULT_NUM_RUNS = 250 +BASE_DIR = "growlibm/timing" +unary_accelerators = ['log1pmd', 'invgud', 'verdcos', 'powcos2', 'powcos4', 'powcos6'] +binary_accelerators = ['sinprod', 'cosprod', 'hypot', 'powcos', 'pow1ms'] +unary_ops = ['neg', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cbrt', 'ceil', 'cos', 'cosh', 'erf', 'exp', 'exp2', 'fabs', 'floor', 'lgamma', 'log', 'log10', 'log2', 'logb', 'rint', 'round', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tgamma', 'trunc'] + unary_accelerators +binary_ops = ['+', '-', '*', '/', 'atan2', 'copysign', 'fdim', 'fmax', 'fmin', 'fmod', 'pow', 'remainder'] + binary_accelerators +all_ops = binary_ops + unary_ops +default_ops = all_ops +times = {} +costs = {} +plus_time = 0 + +class FPCore(object): + def __init__(self, core, arity) -> None: + self.arity = arity + self.core = core + +def double_to_c_str(f: float): + if math.isnan(f): + return 'NAN' + elif math.isinf(f): + return '-INFINITY' if f < 0 else 'INFINITY' + else: + return str(f) + +def format_fpcore(op : str, arity : int) -> FPCore: + op_ = '-' if op == 'neg' else op + vars = [f'z{i}' for i in range(arity)] + arg_str = ' '.join(vars) + app_str = ' '.join([op_] + vars) + core = f'(FPCore ({arg_str}) ({app_str}))' + return FPCore(core, arity) + +def generate_fpcore(op : str) -> FPCore: + core = FPCore("",0) + if op in unary_ops: + core = format_fpcore(op, 1) + elif op in binary_ops: + core = format_fpcore(op, 2) + return core + +def positive_int(value: str) -> int: + parsed = int(value) + if parsed <= 0: + raise argparse.ArgumentTypeError("value must be positive") + return parsed + +def parse_args(argv): + parser = argparse.ArgumentParser( + description="Time growlibm ops by sampling inputs, compiling a driver, and benchmarking it." + ) + parser.add_argument( + "--seed", + help="Seed passed to sample.rkt", + ) + parser.add_argument( + "--runs", + type=positive_int, + default=DEFAULT_NUM_RUNS, + help=f"Number of benchmark iterations per op (default: {DEFAULT_NUM_RUNS})", + ) + parser.add_argument( + "--sample-limit", + type=positive_int, + help="Limit the number of sampled inputs per op", + ) + parser.add_argument( + "--ops", + nargs="+", + default=default_ops, + help=f"Ops to benchmark (default: {' '.join(default_ops)})", + ) + parser.add_argument( + "--order", + choices=["both", "sorted", "unsorted"], + default="both", + help="Whether to benchmark sorted inputs, unsorted inputs, or both", + ) + parser.add_argument( + "legacy_seed", + nargs="?", + help="Backward-compatible positional seed", + ) + + args = parser.parse_args(argv) + if args.seed is not None and args.legacy_seed is not None: + parser.error("pass the seed either positionally or with --seed, not both") + + args.seed = args.seed if args.seed is not None else args.legacy_seed + + invalid_ops = [op for op in args.ops if op not in all_ops] + if invalid_ops: + parser.error(f"unknown ops: {', '.join(invalid_ops)}") + + return args + +def generate_driver(compiled, input_points, arity, filepath, runs): + with open(filepath, 'w') as f: + print('#include ', file=f) + print('#include ', file=f) + print('#include ', file=f) + print('#include ', file=f) + print('#include \"../../accelerators/accelerators.h\"', file=f) + print('#define TRUE 1', file=f) + print('#define FALSE 0', file=f) + print(f'#define NUM_RUNS {runs}', file=f) + + print(f'static inline {compiled}', file=f) + + for i, points in enumerate(input_points): + print(f"const double x{i}[{len(input_points[0])}] = {{", file=f) + print(',\n'.join(points), file=f) + print('};', file=f) + arg_str = ', '.join(map(lambda i: f'x{i}[i]', range(int(arity)))) + app_str = f'foo({arg_str})' + + print('int main() {', file=f) + print(f' struct timespec ts1, ts2;', file=f) + print(f' volatile double res;', file=f) + print(f' double total = 0;', file=f) + print(' // warmup loop', file=f) + print(f' for (long i = 0; i < {len(input_points[0])}; i++) {{', file=f) + print(f' res = {app_str};', file=f) + print(' }', file=f) + print(' // timing loop', file=f) + print(f' for(long run = 0; run < NUM_RUNS; run++) {{', file=f) + print(f' clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts1);', file=f) + print(f' for (long i = 0; i < {len(input_points[0])}; i++) {{', file=f) + print(f' res = {app_str};', file=f) + print(' }', file=f) + print(f' clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts2);', file=f) + print(f' double diff = (1000.0 * ts2.tv_sec + 1e-6 * ts2.tv_nsec) - (1000.0 * ts1.tv_sec + 1e-6 * ts1.tv_nsec);', file=f) + print(f' total += diff;', file=f) + print(' }', file=f) + print(f' printf("%.17g", total / NUM_RUNS);', file=f) + print(' return 0;', file=f) + print('}', file=f) + +def run_command(args, env=None): + try: + result = subprocess.run(args, capture_output=True, text=True, check=True, env=env) + return result.stdout + except subprocess.CalledProcessError as err: + if err.stdout: + print(err.stdout, file=sys.stderr, end="") + if err.stderr: + print(err.stderr, file=sys.stderr, end="") + raise + +def sample_points(fpcore, seed): + cmd = ['racket', f'{BASE_DIR}/sample.rkt', fpcore.core] + if seed is not None: + cmd.append(str(seed)) + result = run_command(cmd) + return [i.split() for i in result.splitlines()] + +def order_modes(order): + if order == "sorted": + return [("sorted", True)] + if order == "unsorted": + return [("unsorted", False)] + return [("unsorted", False), ("sorted", True)] + +def print_header(order): + print('--------------------------------------------------') + if order == "both": + print('|', 'op'.ljust(20), '|', 'unsorted'.ljust(10), '|', 'sorted'.ljust(10), '|') + else: + print('|', 'op'.ljust(20), '|', order.ljust(10), '|') + print('--------------------------------------------------') + +def print_result_row(op, timings, order): + if order == "both": + print('|', op.ljust(20), '|', f'{timings["unsorted"]:.5f} ms', '|', f'{timings["sorted"]:.5f} ms', '|') + else: + print('|', op.ljust(20), '|', f'{timings[order]:.5f} ms', '|') + +def time_op(op, sort_points, points, runs): + fpcore = generate_fpcore(op) + points = list(points) + if sort_points: + points.sort(key= lambda x: float(x[0])) + _points = [list(col) for col in zip(*points)] + + result = run_command(['racket', f'{BASE_DIR}/compile.rkt', fpcore.core]) + op_name = 'div' if op == '/' else op + order_name = "sorted" if sort_points else "unsorted" + driver_name = f"{order_name}_{op_name}.c" + generate_driver(result, _points, str(fpcore.arity), f'{BASE_DIR}/drivers/{driver_name}', runs) + + cmd = [ + 'clang', + '-O2', + '-I', + '..', + f'{BASE_DIR}/drivers/{driver_name}', + '-o', + 'benchmark', + '-Lgrowlibm/accelerators', + '-laccelerators', + '-lm' + ] + if sys.platform.startswith('linux'): + cmd.append('-Wl,-rpath,$ORIGIN/growlibm/accelerators') + + run_command(cmd) + + result = run_command(['./benchmark']) + return float(result) + +if __name__ == "__main__": + args = parse_args(sys.argv[1:]) + mode_list = order_modes(args.order) + + print_header(args.order) + + for op in args.ops: + points = sample_points(generate_fpcore(op), args.seed) + if args.sample_limit is not None: + points = points[:args.sample_limit] + + if not points: + raise RuntimeError(f"no sample points generated for {op}") + + print( + f"Timing {op} with {len(points)} sample points and {args.runs} runs...", + file=sys.stderr, + ) + + timings = {} + for label, sort_points in mode_list: + timings[label] = time_op(op, sort_points, points, args.runs) + + primary_label = "unsorted" if "unsorted" in timings else mode_list[0][0] + times[op] = timings[primary_label] + if op == "+": + plus_time = timings[primary_label] + + print_result_row(op, timings, args.order) + + print('--------------------------------------------------') + + if plus_time > 0: + for op, time in times.items(): + costs[op] = time / plus_time * .2 + + for op, cost in costs.items(): + print(op, cost) + else: + print("Skipping cost ratios because '+' was not benchmarked.", file=sys.stderr) diff --git a/growlibm/to-json.rkt b/growlibm/to-json.rkt new file mode 100644 index 0000000000..d153324e69 --- /dev/null +++ b/growlibm/to-json.rkt @@ -0,0 +1,15 @@ +#lang racket/base + +(require json) + +(define file-name (vector-ref (current-command-line-arguments) 0)) + +(define l + (call-with-input-file (string-append "reports/" file-name ".rkt") read)) + +(define test-list (map (lambda (p) (cons (string->symbol (format "~a"(car p))) (cdr p))) l)) +(define hash (make-hash test-list)) + +(call-with-output-file (string-append "reports/" file-name ".json") + (lambda (out) (write-json hash out)) + #:exists 'replace) \ No newline at end of file diff --git a/old_scripts/countsubexprs.py b/old_scripts/countsubexprs.py new file mode 100644 index 0000000000..29ff8f21d6 --- /dev/null +++ b/old_scripts/countsubexprs.py @@ -0,0 +1,68 @@ +import re +import math +import warnings + +import sys +maxLength = math.inf +numberToSelect = 1000 +fileName = sys.argv[1] + +def subExprs(s): + ret = [] + stack = [] + for i, c in enumerate(s): + if c == '(': + if len(stack) < maxLength: + stack.append(i) + elif c == ')': + if stack: + start = stack.pop() + subexpr = s[start:i+1] + ret.append(subexpr) + return ret + +def renameVars(s): + toReplace = list(re.findall(r" (?!binary32|binary64)[a-zA-Z_][\*.a-zA-Z0-9_-]*",s)) + toReplace = set(toReplace) + toReplace = [i.strip() for i in toReplace] + for i,oldVar in enumerate(toReplace): + s = re.sub(fr' {oldVar}\b',fr' z{i}',s) + return s + +def isImpl(s): + return ('approx' not in s) and ('.f64' in s or '.f32' in s) + +def isBasicFunction(s): + return re.match(r'(\(\S+\.(f64|f32) z0( z1)?\))|(\(\S+\.(f64|f32) z1 z0\))',s) + +lines = [] +final = {} +exprs = dict() + +with open(fileName) as f: + for i,line in enumerate(f): + # warnings.warn(i) + + for subExpr in subExprs(line): + if(not isImpl(subExpr)): + continue + if('if' in subExpr or '<' in subExpr or '=' in subExpr or '>' in subExpr): + continue + + renamed = renameVars(subExpr) + if(isBasicFunction(renamed)): + continue + + if('z0' not in renamed): + continue + + if(renamed not in exprs): + exprs[renamed] = 1 + else: + exprs[renamed] +=1 + +sortedExprs = [k for k, v in sorted(exprs.items(), key=lambda item: item[1])] +# print(exprs) + +for i in range(max(0,len(sortedExprs)-numberToSelect), len(sortedExprs)): + print(sortedExprs[i],',',exprs[sortedExprs[i]]) \ No newline at end of file diff --git a/old_scripts/get-errors.rkt b/old_scripts/get-errors.rkt new file mode 100644 index 0000000000..a7424475cb --- /dev/null +++ b/old_scripts/get-errors.rkt @@ -0,0 +1,45 @@ +#lang racket +(require + "./src/api/sandbox.rkt" + "./src/syntax/platform.rkt" + "src/syntax/syntax.rkt" + "src/syntax/types.rkt" + "src/core/points.rkt" + "src/core/programs.rkt" + "src/utils/errors.rkt" + "src/core/rules.rkt" + "src/config.rkt" + "src/core/batch.rkt" + "src/core/egg-herbie.rkt" + "src/core/sampling.rkt" + "src/syntax/read.rkt" + "src/syntax/sugar.rkt" + "src/syntax/load-platform.rkt") + +(activate-platform! "herbie20") + +(define (get-error-fpcore fpcore) + (define test (car (load-port (open-input-string fpcore)))) + (define ctx (test-context test)) + (*num-points* 8000) + (*context* ctx) + (define pcon (get-sample test)) + (define error (errors (test-spec test) pcon ctx)) + (define err-score (errors-score error)) + err-score) + +(define (get-errors file-path) + (with-input-from-file file-path + (lambda () + (for ([line (in-lines)]) + (define split-line (regexp-split #px"," line)) + (define fpcore (car split-line)) + + (define error (with-handlers ([exn? (λ (e) (printf "Skipping due to error: ~a\n" (exn-message e)))]) + + (define error (get-error-fpcore fpcore)) + error)) + + (printf "~a , ~a \n" (string-replace line "\n" "") error) + )))) +(get-errors (vector-ref (current-command-line-arguments) 0)) diff --git a/old_scripts/growlibm-falloff_hard.fpcore b/old_scripts/growlibm-falloff_hard.fpcore new file mode 100644 index 0000000000..78db64a1b9 --- /dev/null +++ b/old_scripts/growlibm-falloff_hard.fpcore @@ -0,0 +1,122 @@ +; Hard falloff benchmarks sourced from growlibm/Falloff.cpp. Troe, SRI, and Tsang falloff formulæ mix exponentials, logarithms, and guarded reciprocals, which create cancellation-prone transitions between low- and high-pressure limits. + +(FPCore (T m_a m_rt3 m_rt1 m_t2) + :name "falloff-troe-fcent" + :pre (and (> T 0) + (>= m_a 0) + (<= m_a 1) + (> m_rt3 0) + (> m_rt1 0)) + (let ((term3 (* (- 1 m_a) (exp (- (* T m_rt3)))))) + (let ((term1 (* m_a (exp (- (* T m_rt1)))))) + (let ((base (+ term3 term1))) + (if (< (fabs m_t2) 1e-12) + base + (+ base (exp (/ (- m_t2) T)))))))) + +(FPCore (T m_a m_rt3 m_rt1 m_t2 SmallNumber) + :name "falloff-troe-log-fcent" + :pre (and (> T 0) + (> SmallNumber 0) + (>= m_a 0) + (<= m_a 1) + (> m_rt3 0) + (> m_rt1 0)) + (let ((term3 (* (- 1 m_a) (exp (- (* T m_rt3)))))) + (let ((term1 (* m_a (exp (- (* T m_rt1)))))) + (let ((base (+ term3 term1))) + (let ((fcent (if (< (fabs m_t2) 1e-12) + base + (+ base (exp (/ (- m_t2) T)))))) + (let ((safe (if (> fcent SmallNumber) fcent SmallNumber))) + (/ (log safe) (log 10.0)))))))) + +(FPCore (pr work SmallNumber) + :name "falloff-troe-blend" + :pre (and (> SmallNumber 0) + (> pr 0) + (< (fabs work) 10)) + (let ((guard (if (> pr SmallNumber) pr SmallNumber))) + (let ((lpr (/ (log guard) (log 10.0)))) + (let ((cc (+ -0.4 (* -0.67 work)))) + (let ((nn (+ 0.75 (* -1.27 work)))) + (let ((lp (+ lpr cc))) + (let ((den (- nn (* 0.14 lp)))) + (let ((f1 (/ lp den))) + (let ((lgf (/ work (+ 1 (* f1 f1))))) + (pow 10.0 lgf)))))))))) + +(FPCore (T3 SmallNumber) + :name "falloff-troe-inverse-t3" + :pre (and (> SmallNumber 0)) + (let ((absT3 (fabs T3))) + (if (< absT3 SmallNumber) + (/ 1.0 SmallNumber) + (/ 1.0 T3)))) + +(FPCore (T1 SmallNumber) + :name "falloff-troe-inverse-t1" + :pre (and (> SmallNumber 0)) + (let ((absT1 (fabs T1))) + (if (< absT1 SmallNumber) + (/ 1.0 SmallNumber) + (/ 1.0 T1)))) + +(FPCore (T m_a m_b m_c) + :name "falloff-sri-work" + :pre (and (> T 0) + (>= m_a 0) + (>= m_c 0)) + (let ((base (* m_a (exp (/ (- m_b) T))))) + (if (< m_c 1e-12) + base + (+ base (exp (/ (- T) m_c)))))) + +(FPCore (pr work m_d m_e T SmallNumber) + :name "falloff-sri-factor" + :pre (and (> pr 0) + (> work 0) + (> T 0) + (> SmallNumber 0) + (>= m_d 0)) + (let ((guard (if (> pr SmallNumber) pr SmallNumber))) + (let ((lpr (/ (log guard) (log 10.0)))) + (let ((xx (/ 1.0 (+ 1.0 (* lpr lpr))))) + (let ((amp (* m_d (pow T m_e)))) + (* (pow work xx) amp)))))) + +(FPCore (pr work SmallNumber) + :name "falloff-troe-shape" + :pre (and (> SmallNumber 0) + (> pr 0) + (< (fabs work) 10)) + (let ((guard (if (> pr SmallNumber) pr SmallNumber))) + (let ((lpr (/ (log guard) (log 10.0)))) + (let ((cc (+ -0.4 (* -0.67 work)))) + (let ((nn (+ 0.75 (* -1.27 work)))) + (let ((lp (+ lpr cc))) + (let ((den (- nn (* 0.14 lp)))) + (/ lp den)))))))) + +(FPCore (T m_a m_b SmallNumber) + :name "falloff-tsang-work" + :pre (and (> T 0) + (> SmallNumber 0)) + (let ((fcent (+ m_a (* m_b T)))) + (let ((safe (if (> fcent SmallNumber) fcent SmallNumber))) + (/ (log safe) (log 10.0))))) + +(FPCore (pr work SmallNumber) + :name "falloff-tsang-factor" + :pre (and (> SmallNumber 0) + (> pr 0) + (< (fabs work) 10)) + (let ((guard (if (> pr SmallNumber) pr SmallNumber))) + (let ((lpr (/ (log guard) (log 10.0)))) + (let ((cc (+ -0.4 (* -0.67 work)))) + (let ((nn (+ 0.75 (* -1.27 work)))) + (let ((lp (+ lpr cc))) + (let ((den (- nn (* 0.14 lp)))) + (let ((f1 (/ lp den))) + (let ((lgf (/ work (+ 1 (* f1 f1))))) + (pow 10.0 lgf)))))))))) diff --git a/old_scripts/growlibm-helmholtz.fpcore b/old_scripts/growlibm-helmholtz.fpcore new file mode 100644 index 0000000000..898af945f0 --- /dev/null +++ b/old_scripts/growlibm-helmholtz.fpcore @@ -0,0 +1,98 @@ +; Benchmarks from growlibm/HelmholtzEOSMixtureBackend.cpp capturing cancellation near tau-delta coupling and saturation-property differences. + +(FPCore (R tau delta dar_dDelta d2ar_dDelta_dTau d2ar_dDelta2 d2ar_dTau2 d2a0_dTau2) + :pre (and (> R 0) + (> tau 0) + (!= (+ 1 (+ (* 2 (* delta dar_dDelta)) + (* (pow delta 2) d2ar_dDelta2))) + 0)) + (let ((mix (+ 1 (+ (* delta dar_dDelta) + (* -1 (* (* delta tau) d2ar_dDelta_dTau))))) + (den (+ 1 (+ (* 2 (* delta dar_dDelta)) + (* (pow delta 2) d2ar_dDelta2))))) + (* R (+ (* -1 (* (pow tau 2) (+ d2ar_dTau2 d2a0_dTau2))) + (/ (pow mix 2) den))))) + +(FPCore (R T mm tau delta dar_dDelta d2ar_dDelta_dTau d2ar_dDelta2 d2ar_dTau2 d2a0_dTau2) + :pre (and (> R 0) + (> T 0) + (> mm 0) + (> tau 0) + (!= (* (pow tau 2) (+ d2ar_dTau2 d2a0_dTau2)) 0) + (>= (- (+ 1 (+ (* 2 (* delta dar_dDelta)) + (* (pow delta 2) d2ar_dDelta2))) + (/ (pow (+ 1 (+ (* delta dar_dDelta) + (* -1 (* (* delta tau) d2ar_dDelta_dTau)))) + 2) + (* (pow tau 2) (+ d2ar_dTau2 d2a0_dTau2)))) + 0)) + (let ((mix (+ 1 (+ (* delta dar_dDelta) + (* -1 (* (* delta tau) d2ar_dDelta_dTau))))) + (den (+ 1 (+ (* 2 (* delta dar_dDelta)) + (* (pow delta 2) d2ar_dDelta2)))) + (heat (+ d2ar_dTau2 d2a0_dTau2))) + (let ((rad (- den (/ (pow mix 2) (* (pow tau 2) heat))))) + (sqrt (* (/ (* R T) mm) rad))))) + +(FPCore (R tau delta d2a0_dTau2 d2ar_dTau2 dar_dDelta d2ar_dDelta_dTau) + :pre (and (> R 0) + (> tau 0) + (>= delta 0)) + (let ((curv (+ d2a0_dTau2 d2ar_dTau2)) + (corr (+ 1 (+ (* delta dar_dDelta) + (* -1 (* (* tau delta) d2ar_dDelta_dTau))))) + (tau2 (pow tau 2))) + (* R (+ (* -1 (* tau2 curv)) + corr)))) + +(FPCore (T R rho tau delta d2ar_dDelta_dTau dar_dDelta d2ar_dDelta2) + :pre (and (> T 0) + (> R 0) + (!= rho 0) + (> tau 0) + (>= delta 0)) + (let ((term1 (* tau (* delta d2ar_dDelta_dTau))) + (term2 (* delta dar_dDelta)) + (term3 (* (pow delta 2) d2ar_dDelta2))) + (let ((sum (+ term1 (+ term2 term3)))) + (* (/ (* T R) rho) sum)))) + +(FPCore (delta_h T dDeltaV_dT deltaV dDeltaH_dT) + :pre (and (> T 0) + (!= (pow delta_h 2) 0)) + (/ (- (* delta_h (+ (* T dDeltaV_dT) deltaV)) + (* T (* deltaV dDeltaH_dT))) + (pow delta_h 2))) + +(FPCore (delta_h T dDeltaV_dp deltaV dDeltaH_dp) + :pre (and (> T 0) + (!= (pow delta_h 2) 0)) + (/ (- (* delta_h (* T dDeltaV_dp)) + (* T (* deltaV dDeltaH_dp))) + (pow delta_h 2))) + +(FPCore (denominator numerator dnumerator ddenominator) + :pre (!= (pow denominator 2) 0) + (/ (- (* denominator dnumerator) + (* numerator ddenominator)) + (pow denominator 2))) + +(FPCore (rho d2p_dT_drho dp_dT_drho d2p_drho2_T dp_drho_T) + :pre (and (> rho 0) + (!= dp_dT_drho 0) + (!= dp_drho_T 0)) + (- 2 + (* rho (- (/ d2p_dT_drho dp_dT_drho) + (/ d2p_drho2_T dp_drho_T))))) + +(FPCore (rho rhoV rhoL hV hL) + :pre (and (> rho 0) + (!= rhoV 0) + (!= rhoL 0) + (!= (- hV hL) 0)) + (let ((diff (- (/ 1 rhoV) + (/ 1 rhoL))) + (deltaH (- hV hL)) + (rho2 (pow rho 2))) + (let ((numer (* (* -1 rho2) diff))) + (/ numer deltaH)))) diff --git a/old_scripts/script.py b/old_scripts/script.py new file mode 100644 index 0000000000..29cef2e635 --- /dev/null +++ b/old_scripts/script.py @@ -0,0 +1,13 @@ +import subprocess + +name = "hamming" +benchmark_dir = "bench/hamming" +results_dir = f"{name}_results" + +subprocess.run(f"mkdir -p {results_dir}", shell=True, check=True) +subprocess.run(f"Racket -y src/main.rkt report --platform no-accelerators --seed 42 {benchmark_dir} {results_dir}/{name}out/ > {results_dir}/{name}_dump", shell=True, check=True) +subprocess.run(f"Python3 countsubexprs.py {results_dir}/{name}_dump > {results_dir}/{name}_top1k_subexprs", shell=True, check=True) +subprocess.run(f"Python3 toFpcore.py {results_dir}/{name}_top1k_subexprs > {results_dir}/{name}_subexr_fpcores", shell=True, check=True) +subprocess.run(f"Racket deduplicate.rkt {results_dir}/{name}_subexr_fpcores > {results_dir}/{name}_deduped", shell=True, check=True) +subprocess.run(f"Python3 toFpcore.py {results_dir}/{name}_deduped > {results_dir}/{name}_deduped_fpcores", shell=True, check=True) +subprocess.run(f"Racket get-errors.rkt {results_dir}/{name}_deduped_fpcores > {results_dir}/{name}_final", shell=True, check=True) \ No newline at end of file diff --git a/old_scripts/toFpcore.py b/old_scripts/toFpcore.py new file mode 100644 index 0000000000..adcce81b4b --- /dev/null +++ b/old_scripts/toFpcore.py @@ -0,0 +1,17 @@ +import sys +fileName = sys.argv[1] + +with open(file=fileName) as f: + lines = list(f) + +for i, line in enumerate(lines): + splitLine = line.split(',') + expr = splitLine[0].strip() + count = splitLine[1].strip() + expr = expr.replace(".f32","").replace(".f64","").replace("#s(literal","").replace("binary64)","").replace("binary32)","").replace("(PI)","PI") + print("(FPCore (",end="") + for j in range(100): + if("z"+str(j) in expr): + print("z"+str(j)+ " ",end="") + print(") ",end="") + print(expr.strip().replace("neg","-")+') ,'+count) \ No newline at end of file diff --git a/src/reports/resources/report-page.js b/src/reports/resources/report-page.js index dae32ef303..8c5df0f3f5 100644 --- a/src/reports/resources/report-page.js +++ b/src/reports/resources/report-page.js @@ -7,6 +7,8 @@ var compareAgainstURL = "" var diffAgainstFields = {} var otherJsonData = null var resultsJsonData = null +var countsJsonData = null +var costsJsonData = null function update() { const bodyNode = document.querySelector("body"); @@ -678,6 +680,9 @@ function buildBody(jsonData, otherJsonData) { buildTableHeader("name"), buildTableHeader("start"), buildTableHeader("end", resultHelpText), + buildTableHeader("score"), + buildTableHeader("cost"), + buildTableHeader("count"), buildTableHeader("target", targetHelpText), buildTableHeader("time"), ]), @@ -692,6 +697,10 @@ function compareTests(l, r) { let cmp; if (sortState.key == "name") { cmp = l.name.localeCompare(r.name); + } else if (sortState.key == "score") { + const lv = getScore(l); + const rv = getScore(r); + cmp = lv - rv; } else { if (l[sortState.key] === false) { cmp = 1; @@ -785,6 +794,9 @@ function buildDiffFooter(jsonData, otherJsonData) { Element("th", {}, ["Total"]), radioState == "startAcc" ? Element("td", { classList: color }, [text]) : Element("td", {}, []), radioState == "endAcc" ? Element("td", { classList: color }, [text]) : Element("td", {}, []), + + Element("td", {}, []), + radioState == "targetAcc" ? Element("td", { classList: color }, [text]) : Element("td", {}, []), radioState == "time" ? Element("td", { classList: color }, [text]) : Element("td", {}, []), Element("td", {}, []), @@ -805,7 +817,30 @@ function getMinimum(target) { }, Infinity); } -// Builds either a normal run row or a comparison row when `other` is present. +function getCountForTestName(name) { + if (!countsJsonData) return 0; + const raw = countsJsonData[name]; + const n = Number(raw); + return Number.isFinite(n) ? n : 0; +} + +function getCostForTestName(name) { + if (!costsJsonData) return 0; + const raw = costsJsonData[name]; + const n = Number(raw); + return Number.isFinite(n) ? n : 0; +} + +function getScore(test) { + const count = getCountForTestName(test.name); + const cost = getCostForTestName(test.name); + if (cost === 0) + return 0 + const endVal = (test && typeof test.end === "number") ? test.end : 0; + return ((endVal * count) / (cost / 1000)) * 1000; +} + +// HACK I kinda hate this split lambda function, Zane function buildRow(test, other) { var smallestTarget = getMinimum(test.target) @@ -826,6 +861,9 @@ function buildRow(test, other) { Element("td", {}, [test.name]), Element("td", {}, [startAccuracy]), Element("td", {}, [resultAccuracy]), + Element("td", {}, [String(Math.floor(getScore(test)))]), + Element("td", {}, [String(Math.floor(getCostForTestName(test.name)))]), + Element("td", {}, [String(Math.floor(getCountForTestName(test.name)))]), Element("td", {}, [targetAccuracy]), Element("td", {}, [formatTime(test.time)]), Element("td", {}, [ @@ -906,6 +944,9 @@ function buildRow(test, other) { Element("td", { title: testTitle }, [test.name]), tdStartAccuracy, tdResultAccuracy, + Element("td", {}, [String(Math.floor(getScore(test)))]), + Element("td", {}, [String(Math.floor(getCostForTestName(test.name)))]), + Element("td", {}, [String(Math.floor(getCountForTestName(test.name)))]), tdTargetAccuracy, tdTime, Element("td", {}, [ @@ -1198,4 +1239,51 @@ async function getResultsJson() { } } -getResultsJson() +async function getCountsJson() { + if (countsJsonData != null) return; + let response; + try { + response = await fetch("../counts.json", { + headers: { "content-type": "application/json" }, + }); + } catch (err) { + return showGetJsonError(err); + } + countsJsonData = await response.json(); + update(); +} + +async function getCostsJson() { + if (costsJsonData != null) return; + let response; + try { + response = await fetch("../costs.json", { + headers: { "content-type": "application/json" }, + }); + } catch (err) { + return showGetJsonError(err); + } + costsJsonData = await response.json(); + update(); +} + +function storeBenchmarks(tests) { + var tempDir = {} + var tempAllWarnings = {} + for (let test of tests) { + const linkComponents = test.link.split("/") + if (linkComponents.length > 1) { + tempDir[linkComponents[0]] = linkComponents[0] + } + for (let warning of test.warnings) { + tempAllWarnings[warning] = warning + } + } + allSuites = Object.keys(tempDir); + allWarnings = Object.keys(tempAllWarnings); + update(); +} + +getCountsJson(); +getCostsJson(); +getResultsJson(); diff --git a/src/syntax/generators.rkt b/src/syntax/generators.rkt index 46c7f4a013..974b1ee8d7 100644 --- a/src/syntax/generators.rkt +++ b/src/syntax/generators.rkt @@ -2,7 +2,8 @@ (require math/flonum math/bigfloat - ffi/unsafe) + ffi/unsafe + racket/runtime-path) (require "rival.rkt" "../config.rkt" @@ -12,6 +13,7 @@ (provide from-rival from-ffi from-libm + from-accelerators from-bigfloat define-generator (struct-out generator)) @@ -73,9 +75,22 @@ (error 'ffi-generator "Could not find FFI implementation of `~a ~a ~a`" otype name itypes)))) (define libm-lib (ffi-lib #f)) + +(define-runtime-path growlibm-dir "../../growlibm/accelerators") +(define accelerator-lib-path + (let ([suffix (bytes->string/utf-8 (system-type 'so-suffix))]) + (build-path growlibm-dir (string-append "libaccelerators" suffix)))) + +(define accelerators-lib + (with-handlers ([exn:fail? (lambda (_exn) #f)]) + (ffi-lib accelerator-lib-path #:fail (lambda () #f)))) + (define (from-libm name) (from-ffi libm-lib name)) +(define (from-accelerators name) + (from-ffi accelerators-lib name)) + ; ----------------------- BIGFLOAT GENERATOR ------------------------ (define (repr->bf x type) diff --git a/src/syntax/load-platform.rkt b/src/syntax/load-platform.rkt index 229bd2011a..4a557be62d 100644 --- a/src/syntax/load-platform.rkt +++ b/src/syntax/load-platform.rkt @@ -8,11 +8,18 @@ (define-runtime-module-path herbie10-platform "../platforms/herbie10.rkt") (define-runtime-module-path herbie20-platform "../platforms/herbie20.rkt") +(define-runtime-module-path grow-platform "../../growlibm/grow.rkt") (define-runtime-module-path c-platform "../platforms/c.rkt") (define-runtime-module-path c-windows-platform "../platforms/c-windows.rkt") (define-runtime-module-path racket-platform "../platforms/racket.rkt") (define-runtime-module-path math-platform "../platforms/math.rkt") (define-runtime-module-path rival-platform "../platforms/rival.rkt") +(define-runtime-module-path vanilla-platform "../../growlibm/platforms/vanilla.rkt") +(define-runtime-module-path herbie20plus-platform "../../growlibm/platforms/herbie20plus.rkt") +(define-runtime-module-path growlibmbest-platform "../../growlibm/platforms/growlibmbest.rkt") +(define-runtime-module-path proj-platform "../../growlibm/platforms/proj.rkt") +(define-runtime-module-path basilisk-platform "../../growlibm/platforms/basilisk.rkt") +(define-runtime-module-path coolprop-platform "../../growlibm/platforms/coolprop.rkt") (define default-platforms (hash "herbie10" @@ -28,7 +35,21 @@ "math" math-platform "rival" - rival-platform)) + rival-platform + "grow" + grow-platform + "vanilla" + vanilla-platform + "herbie20plus" + herbie20plus-platform + "growlibmbest" + growlibmbest-platform + "proj" + proj-platform + "basilisk" + basilisk-platform + "coolprop" + coolprop-platform)) (define platforms (make-hash))