are determined via underlying equivalence, opposed to lexically identical
expressions (CSE).
- Spare Conditional Constant Propagation:
- Simultaneously remove dead code and propagates constants. This is
- not the same as individual dead code elimination and constant propagation
- passes. This is multipass.
-
The following are optimizations that can be implemented before the
transformation into a binary (code generator).
- No virtuals / pure virtuals
- Essentially "C structs but with operators" :)
- Arrays:
- They're currently implemented, but support in the engine
- plus implicit bounds checks (and ability to turn the bounds
- checking off)
-
- Exceptions:
- I feel like all languages suck at implementing this. This would
- require support from the engine, but it would help catch bugs. We
- could make it fast using a neat method of "frame pointers".
-
Overloaded Functions:
Ability to make individual functions with the same name, but take
different amount of arguments or type of arguments.
become "default", otherwise if two arguments are specified then
the "default" string is overrode with what ever the user passes.
- Character Type:
- A char type would be nice to have. Essentially implemented as a
- string, we can both "get" and "set" indices inside strings with
- the help of builtin functions.
-
- {
- string foo = "test";
- foo[0] = 'r';
-
- print("it's time to ", foo);
- }
-
- Array Accessor With C-Semantics:
- Also the ability to use them as array accessors:
-
- {
- float hugearray['Z'];
-
- hugearray['a'] = 100.0f;
- }
-
- Keep existing "pointer-like" semantics as well. In C arrays
- simple work as pointers, a[1] -> *(a+1), or 1[a] -> *(1+a)
- so we should allow both forms of syntax. As well as operand
- reversal.
-
- {
- float h['Z'];
- *(h+'a') = 100;
- *('a'+h) = 'a'[h];
- }
-
- FTEQCC Inline Assembly:
- This is still up for debate, mainly because a) it's syntax is
- just utter crap. b) If we do an assembler, it should be nice.
- we could provide a -std=fteqcc for the assembler itself :P
- just like the compiler; although I think that's just insane.
-
- Please see Assembler below.
-
Namespaces:
There is already a ticket open on this. They'd work just like C++
identically even.
-Standalone QCVM:
- The following are QCVM additions:
-
- Proper ASM disassembly:
- Proper disassembly of compiled .dat files. Annotated if possible
- when -g (is used during compilation)
-
- Debugging:
- A step-through debugger -d (with separate compilation as well)
- Called -> qcdb Optionally alias to qcvm -d :)
-
- We should be able to see the assembly and source it matches to
- and the state of OFS_* and calls.
-
Testsuite:
The following are things we'd like to see added to the testsuite
in the distant future:
- Multithreading:
- Chances are when we start adding more and more tests, executing
- them individually will be midly slow (even if that's a whole minute)
- It would be nice to add a -j paramater to allow multiple threads to
- be used and so we can execute many tests in parallel.
-
Interface:
Ability to select individual tests, or set parameters manually
opposed to using the static task-template files. (A method to
override them rather).
-
-
-Assembler:
- Possibly support for a future assembler for QCASM. But we're not
- entirely sure if it makes sense.
ast_instantiate(ast_binary, ctx, ast_binary_delete);
ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_binary_codegen);
+ if (ast_istype(right, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
+ ast_expression *normal = ((ast_unary*)right)->operand;
+
+ /* make a-(-b) => a + b */
+ if (op == INSTR_SUB_F) {
+ op = INSTR_ADD_F;
+ right = normal;
+ ++opts_optimizationcount[OPTIM_PEEPHOLE];
+ } else if (op == INSTR_SUB_V) {
+ op = INSTR_ADD_V;
+ right = normal;
+ ++opts_optimizationcount[OPTIM_PEEPHOLE];
+ }
+ }
+
self->op = op;
self->left = left;
self->right = right;
if (!vtype) {
compile_error(ast_ctx(self), "internal error: ast_function_new condition 0");
goto cleanup;
- } else if (vtype->hasvalue || vtype->expression.vtype != TYPE_FUNCTION) {
} else if (vtype->hasvalue || vtype->expression.vtype != TYPE_FUNCTION) {
compile_error(ast_ctx(self), "internal error: ast_function_new condition %i %i type=%i (probably 2 bodies?)",
(int)!vtype,
self->fixedparams = NULL;
self->return_value = NULL;
+ self->static_names = NULL;
+ self->static_count = 0;
+
return self;
cleanup:
*/
ast_unref(self->vtype);
}
+ for (i = 0; i < vec_size(self->static_names); ++i)
+ mem_d(self->static_names[i]);
+ vec_free(self->static_names);
for (i = 0; i < vec_size(self->blocks); ++i)
ast_delete(self->blocks[i]);
vec_free(self->blocks);
int builtin;
+ /* list of used-up names for statics without the count suffix */
+ char **static_names;
+ /* number of static variables, by convention this includes the
+ * ones without the count-suffix - remember this when dealing
+ * with savegames. uint instead of size_t as %zu in printf is
+ * C99, so no windows support. */
+ unsigned int static_count;
+
ir_function *ir_func;
ir_block *curblock;
ir_block **breakblocks;
DROPBOX := dropbox_uploader.sh
UNAME := $(shell uname -m)
DOWNLOAD:= ../doc/html/download.c
-BRANCH := $(shell git branch | sed -n -e 's/^\* \(.*\)/\1/p')
+BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
ifneq ($(shell uname -m), x86_64)
$(error Cannot build packages without an x86_64 capable CPU)
endif
instead, as such this warning only works when -std=qcc.
.It Fl W Ns Cm directive-inmacro
Warn about the use of preprocessor directives inside macros.
+.It Fl W Ns Cm builtins
+When using a function that is not explicitly defined, the compiler
+will search its intrinsics table for something that matches that
+function name by appending "__builtin_" to it. This behaviour may
+be unexpected, so enabling this will produce a diagnostic when
+such a function is resolved to a builtin.
.El
.Sh COMPILE FLAGS
.Bl -tag -width Ds
static GMQCC_INLINE vec3_t vec3_sub(vec3_t a, vec3_t b) {
vec3_t out;
- out.x = a.x + b.x;
- out.y = a.y + b.y;
- out.z = a.z + b.z;
+ out.x = a.x - b.x;
+ out.y = a.y - b.y;
+ out.z = a.z - b.z;
return out;
}
static GMQCC_INLINE vec3_t vec3_not(vec3_t a) {
vec3_t out;
- out.x = (qcfloat_t)(~((qcint_t)a.x));
- out.y = (qcfloat_t)(~((qcint_t)a.y));
- out.z = (qcfloat_t)(~((qcint_t)a.z));
+ out.x = -1-a.x;
+ out.y = -1-a.y;
+ out.z = -1-a.z;
return out;
}
}
static GMQCC_INLINE bool vec3_pbool(vec3_t a) {
- return (a.x && a.y && a.z);
+ return (a.x || a.y || a.z);
}
static GMQCC_INLINE vec3_t vec3_cross(vec3_t a, vec3_t b) {
(void)fold_constgen_float (fold, 0.0f);
(void)fold_constgen_float (fold, 1.0f);
(void)fold_constgen_float (fold, -1.0f);
+ (void)fold_constgen_float (fold, 2.0f);
(void)fold_constgen_vector(fold, vec3_create(0.0f, 0.0f, 0.0f));
(void)fold_constgen_vector(fold, vec3_create(-1.0f, -1.0f, -1.0f));
if (fold_can_2(a, b))
return fold_constgen_float(fold, (qcfloat_t)(((qcint_t)fold_immvalue_float(a)) ^ ((qcint_t)fold_immvalue_float(b))));
} else {
- if (isvector(b)) {
- if (fold_can_2(a, b))
+ if (fold_can_2(a, b)) {
+ if (isvector(b))
return fold_constgen_vector(fold, vec3_xor(fold_immvalue_vector(a), fold_immvalue_vector(b)));
- } else {
- if (fold_can_2(a, b))
+ else
return fold_constgen_vector(fold, vec3_xorvf(fold_immvalue_vector(a), fold_immvalue_float(b)));
}
}
static GMQCC_INLINE ast_expression *fold_op_andor(fold_t *fold, ast_value *a, ast_value *b, float expr) {
if (fold_can_2(a, b)) {
if (OPTS_FLAG(PERL_LOGIC)) {
- if (fold_immediate_true(fold, a))
- return (ast_expression*)b;
+ if (expr)
+ return (fold_immediate_true(fold, a)) ? (ast_expression*)a : (ast_expression*)b;
+ else
+ return (fold_immediate_true(fold, a)) ? (ast_expression*)b : (ast_expression*)a;
} else {
return fold_constgen_float (
fold,
static GMQCC_INLINE ast_expression *fold_op_cmp(fold_t *fold, ast_value *a, ast_value *b, bool ne) {
if (fold_can_2(a, b)) {
- return fold_constgen_float(
- fold,
- (ne) ? (fold_immvalue_float(a) != fold_immvalue_float(b))
- : (fold_immvalue_float(a) == fold_immvalue_float(b))
- );
+ if (isfloat(a) && isfloat(b)) {
+ float la = fold_immvalue_float(a);
+ float lb = fold_immvalue_float(b);
+ return (ast_expression*)fold->imm_float[!(ne ? la == lb : la != lb)];
+ } if (isvector(a) && isvector(b)) {
+ vec3_t la = fold_immvalue_vector(a);
+ vec3_t lb = fold_immvalue_vector(b);
+ return (ast_expression*)fold->imm_float[!(ne ? vec3_cmp(la, lb) : !vec3_cmp(la, lb))];
+ }
}
return NULL;
}
static GMQCC_INLINE ast_expression *fold_op_bnot(fold_t *fold, ast_value *a) {
if (isfloat(a)) {
if (fold_can_1(a))
- return fold_constgen_float(fold, ~((qcint_t)fold_immvalue_float(a)));
+ return fold_constgen_float(fold, -1-fold_immvalue_float(a));
} else {
if (isvector(a)) {
if (fold_can_1(a))
* folding, primarly: individual functions for each intrinsics to fold,
* and a generic selection function.
*/
+static GMQCC_INLINE ast_expression *fold_intrin_isfinite(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, isfinite(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_isinf(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, isinf(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_isnan(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, isnan(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_isnormal(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, isnormal(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_signbit(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, signbit(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intirn_acosh(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, acoshf(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_asinh(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, asinhf(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_atanh(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, atanhf(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_exp(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, expf(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_exp2(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, exp2f(fold_immvalue_float(a)));
+}
+static GMQCC_INLINE ast_expression *fold_intrin_expm1(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, expm1f(fold_immvalue_float(a)));
+}
static GMQCC_INLINE ast_expression *fold_intrin_mod(fold_t *fold, ast_value *lhs, ast_value *rhs) {
- return fold_constgen_float(
- fold,
- fmodf(
- fold_immvalue_float(lhs),
- fold_immvalue_float(rhs)
- )
- );
+ return fold_constgen_float(fold, fmodf(fold_immvalue_float(lhs), fold_immvalue_float(rhs)));
}
-
static GMQCC_INLINE ast_expression *fold_intrin_pow(fold_t *fold, ast_value *lhs, ast_value *rhs) {
- return fold_constgen_float(
- fold,
- powf(
- fold_immvalue_float(lhs),
- fold_immvalue_float(rhs)
- )
- );
-}
-
-static GMQCC_INLINE ast_expression *fold_intrin_exp(fold_t *fold, ast_value *value) {
- return fold_constgen_float(fold, exp(fold_immvalue_float(value)));
+ return fold_constgen_float(fold, powf(fold_immvalue_float(lhs), fold_immvalue_float(rhs)));
}
-
-static GMQCC_INLINE ast_expression *fold_intrin_isnan(fold_t *fold, ast_value *value) {
- return fold_constgen_float(fold, isnan(fold_immvalue_float(value)) != 0.0f);
+static GMQCC_INLINE ast_expression *fold_intrin_fabs(fold_t *fold, ast_value *a) {
+ return fold_constgen_float(fold, fabsf(fold_immvalue_float(a)));
}
-static GMQCC_INLINE ast_expression *fold_intrin_fabs(fold_t *fold, ast_value *value) {
- return fold_constgen_float(fold, fabs(fold_immvalue_float(value)));
-}
ast_expression *fold_intrin(fold_t *fold, const char *intrin, ast_expression **arg) {
ast_expression *ret = NULL;
-
- if (!strcmp(intrin, "mod")) ret = fold_intrin_mod (fold, (ast_value*)arg[0], (ast_value*)arg[1]);
- if (!strcmp(intrin, "pow")) ret = fold_intrin_pow (fold, (ast_value*)arg[0], (ast_value*)arg[1]);
- if (!strcmp(intrin, "exp")) ret = fold_intrin_exp (fold, (ast_value*)arg[0]);
- if (!strcmp(intrin, "isnan")) ret = fold_intrin_isnan(fold, (ast_value*)arg[0]);
- if (!strcmp(intrin, "fabs")) ret = fold_intrin_fabs (fold, (ast_value*)arg[0]);
+ ast_value *a = (ast_value*)arg[0];
+ ast_value *b = (ast_value*)arg[1];
+
+ if (!strcmp(intrin, "isfinite")) ret = fold_intrin_isfinite(fold, a);
+ if (!strcmp(intrin, "isinf")) ret = fold_intrin_isinf(fold, a);
+ if (!strcmp(intrin, "isnan")) ret = fold_intrin_isnan(fold, a);
+ if (!strcmp(intrin, "isnormal")) ret = fold_intrin_isnormal(fold, a);
+ if (!strcmp(intrin, "signbit")) ret = fold_intrin_signbit(fold, a);
+ if (!strcmp(intrin, "acosh")) ret = fold_intirn_acosh(fold, a);
+ if (!strcmp(intrin, "asinh")) ret = fold_intrin_asinh(fold, a);
+ if (!strcmp(intrin, "atanh")) ret = fold_intrin_atanh(fold, a);
+ if (!strcmp(intrin, "exp")) ret = fold_intrin_exp(fold, a);
+ if (!strcmp(intrin, "exp2")) ret = fold_intrin_exp2(fold, a);
+ if (!strcmp(intrin, "expm1")) ret = fold_intrin_expm1(fold, a);
+ if (!strcmp(intrin, "mod")) ret = fold_intrin_mod(fold, a, b);
+ if (!strcmp(intrin, "pow")) ret = fold_intrin_pow(fold, a, b);
+ if (!strcmp(intrin, "fabs")) ret = fold_intrin_fabs(fold, a);
if (ret)
++opts_optimizationcount[OPTIM_CONST_FOLD];
vec_free (create);
}
+static const char *ftepp_math_constants[][2] = {
+ { "M_E", "2.7182818284590452354" }, /* e */
+ { "M_LOG2E", "1.4426950408889634074" }, /* log_2 e */
+ { "M_LOG10E", "0.43429448190325182765" }, /* log_10 e */
+ { "M_LN2", "0.69314718055994530942" }, /* log_e 2 */
+ { "M_LN10", "2.30258509299404568402" }, /* log_e 10 */
+ { "M_PI", "3.14159265358979323846" }, /* pi */
+ { "M_PI_2", "1.57079632679489661923" }, /* pi/2 */
+ { "M_PI_4", "0.78539816339744830962" }, /* pi/4 */
+ { "M_1_PI", "0.31830988618379067154" }, /* 1/pi */
+ { "M_2_PI", "0.63661977236758134308" }, /* 2/pi */
+ { "M_2_SQRTPI", "1.12837916709551257390" }, /* 2/sqrt(pi) */
+ { "M_SQRT2", "1.41421356237309504880" }, /* sqrt(2) */
+ { "M_SQRT1_2", "0.70710678118654752440" }, /* 1/sqrt(2) */
+ { "M_TAU", "6.28318530717958647692" } /* pi*2 */
+};
+
ftepp_t *ftepp_create()
{
ftepp_t *ftepp;
char minor[32];
char major[32];
+ size_t i;
ftepp = ftepp_new();
if (!ftepp)
*/
ftepp_add_macro(ftepp, "__NULL__", "nil");
+ /* add all the math constants */
+ for (i = 0; i < GMQCC_ARRAY_COUNT(ftepp_math_constants); i++)
+ ftepp_add_macro(ftepp, ftepp_math_constants[i][0], ftepp_math_constants[i][1]);
+
return ftepp;
}
#define GMQCC_HDR
#include <stdarg.h>
#include <stddef.h>
-#include <time.h> /* TODO: remove?*/
-
-/*
- * Disable some over protective warnings in visual studio because fixing them is a waste
- * of my time.
- */
-#ifdef _MSC_VER
-# pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */
-#endif /*! _MSC_VER */
+#include <time.h>
#define GMQCC_VERSION_MAJOR 0
#define GMQCC_VERSION_MINOR 3
#define GMQCC_VERSION_PATCH 6
-#define GMQCC_VERSION_BUILD(J,N,P) (((J)<<16)|((N)<<8)|(P))
-#define GMQCC_VERSION \
- GMQCC_VERSION_BUILD(GMQCC_VERSION_MAJOR, GMQCC_VERSION_MINOR, GMQCC_VERSION_PATCH)
-/* Undefine the following on a release-tag: */
-#define GMQCC_VERSION_TYPE_DEVEL
-
-/* Full version string in case we need it */
-#ifdef GMQCC_VERSION_TYPE_DEVEL
+#define GMQCC_VERSION ((GMQCC_VERSION_MAJOR<<16)|(GMQCC_VERSION_MINOR<<8)|GMQCC_VERSION_PATCH)
+
+#ifdef GMQCC_VERSION_TYPE_RELEASE
# ifdef GMQCC_GITINFO
# define GMQCC_DEV_VERSION_STRING "git build: " GMQCC_GITINFO "\n"
# elif defined(GMQCC_VERSION_TYPE_DEVEL)
" Built " __DATE__ " " __TIME__ \
"\n" GMQCC_DEV_VERSION_STRING
-/*
- * We cannot rely on C99 at all, since compilers like MSVC
- * simply don't support it. We define our own boolean type
- * as a result (since we cannot include <stdbool.h>). For
- * compilers that are in 1999 mode (C99 compliant) we can use
- * the language keyword _Bool which can allow for better code
- * on GCC and GCC-like compilers, opposed to `int`.
- */
#ifndef __cplusplus
-# ifdef false
-# undef false
-# endif /*! false */
-# ifdef true
-# undef true
-# endif /*! true */
-# define false (unsigned)(0)
-# define true (unsigned)(1)
-# ifdef __STDC_VERSION__
-# if __STDC_VERSION__ < 199901L && __GNUC__ < 3
- typedef int bool;
-# else
- typedef _Bool bool;
-# endif /*! __STDC_VERSION__ < 199901L && __GNUC__ < 3 */
-# else
- typedef int bool;
-# endif /*! __STDC_VERSION__ */
-#endif /*! __cplusplus */
+# define false (unsigned char)(0)
+# define true (unsigned char)(1)
+ typedef unsigned char bool;
+#endif
-/*
- * Of some functions which are generated we want to make sure
- * that the result isn't ignored. To find such function calls,
- * we use this macro.
- */
#if defined(__GNUC__) || defined(__CLANG__)
-# define GMQCC_WARN __attribute__((warn_unused_result))
-# define GMQCC_USED __attribute__((used))
-#else
-# define GMQCC_WARN
-# define GMQCC_USED
-#endif /*! defined(__GNUC__) || defined (__CLANG__) */
-
-/*
- * Inline is not supported in < C90, however some compilers
- * like gcc and clang might have an inline attribute we can
- * use if present.
- */
-#ifdef __STDC_VERSION__
-# if __STDC_VERSION__ < 199901L
-# if defined(__GNUC__) || defined (__CLANG__)
-# if __GNUC__ < 2
-# define GMQCC_INLINE
-# else
-# define GMQCC_INLINE __attribute__ ((always_inline))
-# endif /*! __GNUC__ < 2 */
-# else
-# define GMQCC_INLINE
-# endif /*! defined(__GNUC__) || defined (__CLANG__) */
-# else
-# define GMQCC_INLINE inline
-# endif /*! __STDC_VERSION < 199901L */
-/*
- * Visual studio has __forcinline we can use. So lets use that
- * I suspect it also has just __inline of some sort, but our use
- * of inline is correct (not guessed), WE WANT IT TO BE INLINE
- */
-#elif defined(_MSC_VER)
-# define GMQCC_INLINE __forceinline
-#else
-# define GMQCC_INLINE
-#endif /*! __STDC_VERSION__ */
-
-/*
- * noreturn is present in GCC and clang
- * it's required for _ast_node_destory otherwise -Wmissing-noreturn
- * in clang complains about there being no return since abort() is
- * called.
- */
-#if (defined(__GNUC__) && __GNUC__ >= 2) || defined(__CLANG__)
-# define GMQCC_NORETURN __attribute__ ((noreturn))
-#else
-# define GMQCC_NORETURN
-#endif /*! (defined(__GNUC__) && __GNUC__ >= 2) || defined (__CLANG__) */
-
-#if (defined(__GNUC__)) || defined(__CLANG__)
+# include <stdint.h>
+# if (__GNUC__ >= 2) || defined(__CLANG__)
+# define GMQCC_NORETURN __attribute__((noreturn))
+# define GMQCC_FORCEINLINE __attribute__((always_inline))
+# define GMQCC_INLINE __inline
+# endif
# define GMQCC_LIKELY(X) __builtin_expect((X), 1)
# define GMQCC_UNLIKELY(X) __builtin_expect((X), 0)
+# define GMQCC_WARN __attribute__((warn_unused_result))
+# define GMQCC_USED __attribute__((used))
+# define GMQCC_RESTRICT __restrict__
#else
+# ifdef _MSC_VER
+ /* conversion from 'int' to 'float', possible loss of data */
+# pragma warning(disable : 4244)
+
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+ typedef unsigned __int64 uint64_t;
+ typedef __int16 int16_t;
+ typedef __int32 int32_t;
+ typedef __int64 int64_t;
+# define GMQCC_NORETURN __declspec(noreturn)
+# define GMQCC_FORCEINLINE __forceinline
+# define GMQCC_INLINE __inline
+# define GMQCC_RESTRICT __restrict
+# else
+# define GMQCC_NORETURN
+# define GMQCC_FORCEINLINE
+# define GMQCC_INLINE
+# define GMQCC_RESTRICT
+# endif
# define GMQCC_LIKELY(X) (X)
# define GMQCC_UNLIKELY(X) (X)
+# define GMQCC_WARN
+# define GMQCC_USED
#endif
-#define GMQCC_ARRAY_COUNT(X) (sizeof(X) / sizeof((X)[0]))
-
-#ifndef _MSC_VER
-# include <stdint.h>
-#else
- typedef unsigned __int8 uint8_t;
- typedef unsigned __int16 uint16_t;
- typedef unsigned __int32 uint32_t;
- typedef unsigned __int64 uint64_t;
-
- typedef __int16 int16_t;
- typedef __int32 int32_t;
- typedef __int64 int64_t;
-#endif /*! _MSC_VER */
-
-/*
- * Very roboust way at determining endianess at compile time: this handles
- * almost every possible situation. Otherwise a runtime check has to be
- * performed.
- */
#define GMQCC_BYTE_ORDER_LITTLE 1234
#define GMQCC_BYTE_ORDER_BIG 4321
# else
# define PLATFORM_BYTE_ORDER -1
# endif
-#endif /*! !defined (PLATFORM_BYTE_ORDER) */
+#endif
+
+#define GMQCC_ARRAY_COUNT(X) (sizeof(X) / sizeof((X)[0]))
/* stat.c */
void stat_info (void);
extern opts_cmd_t opts;
#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< (unsigned)((i)%32))))
+
#define OPTS_FLAG(i) OPTS_GENERIC(opts.flags, (i))
#define OPTS_WARN(i) OPTS_GENERIC(opts.warn, (i))
#define OPTS_WERROR(i) OPTS_GENERIC(opts.werror, (i))
#define OPTS_OPTIMIZATION(i) OPTS_GENERIC(opts.optimization, (i))
+
#define OPTS_OPTION_DUPED(X) (opts.options[X].allocated)
-#define OPTS_OPTION_BOOL(X) (opts.options[X].data.b)
-#define OPTS_OPTION_U16(X) (opts.options[X].data.u16)
-#define OPTS_OPTION_U32(X) (opts.options[X].data.u32)
-#define OPTS_OPTION_DUP(X) *(OPTS_OPTION_DUPED(X)=true, &(opts.options[X].data.str.p))
-#define OPTS_OPTION_STR(X) (opts.options[X].data.str.c)
+#define OPTS_OPTION_BOOL(X) (opts.options[X].data.b)
+#define OPTS_OPTION_U16(X) (opts.options[X].data.u16)
+#define OPTS_OPTION_U32(X) (opts.options[X].data.u32)
+#define OPTS_OPTION_STR(X) (opts.options[X].data.str.c)
+#define OPTS_OPTION_DUP(X) *(OPTS_OPTION_DUPED(X)=true, &(opts.options[X].data.str.p))
#endif /*! GMQCC_HDR */
DIRECTIVE_INMACRO = true
+ #When using a function that is not explicitly defined, the compiler
+ #will search its intrinsics table for something that matches that
+ #function name by appending "__builtin_" to it. This behaviour may
+ #be unexpected, so enabling this will produce a diagnostic when
+ #such a function is resolved to a builtin.
+
+ BUILTINS = true
+
[optimizations]
#Some general peephole optimizations. For instance the code `a = b
vec_push(intrin->parser->globals, (ast_expression*)value);
}
-#define QC_M_E 2.71828182845905f
+#define QC_POW_EPSILON 0.00001f
+
+/*
+ * since some intrinsics depend on each other there is the possibility
+ * that an intrinsic will fail to get a 'depended' function that a
+ * builtin needs, causing some dependency in the chain to have a NULL
+ * function. This will cause a segmentation fault at code generation,
+ * even though an error was raised. To contiue to allow it (instead
+ * of stopping compilation right away). We need to return from the
+ * parser, before compilation stops after all the collected errors.
+ */
+static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from);
+static ast_expression *intrin_nullfunc(intrin_t *intrin) {
+ ast_value *value = NULL;
+ ast_function *func = intrin_value(intrin, &value, NULL, TYPE_VOID);
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_isfinite(intrin_t *intrin) {
+ /*
+ * float isfinite(float x) {
+ * return !(isnan(x) || isinf(x));
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "isfinite", TYPE_FLOAT);
+ ast_call *callisnan = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "isnan", "isfinite"));
+ ast_call *callisinf = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "isinf", "isfinite"));
+ ast_block *block = ast_block_new(intrin_ctx(intrin));
+
+ /* float x; */
+ vec_push(value->expression.params, x);
+
+ /* <callisnan> = isnan(x); */
+ vec_push(callisnan->params, (ast_expression*)x);
+
+ /* <callisinf> = isinf(x); */
+ vec_push(callisinf->params, (ast_expression*)x);
+
+ /* return (!<callisnan> || <callisinf>); */
+ vec_push(block->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_unary_new(
+ intrin_ctx(intrin),
+ INSTR_NOT_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_OR,
+ (ast_expression*)callisnan,
+ (ast_expression*)callisinf
+ )
+ )
+ )
+ );
+
+ vec_push(func->blocks, block);
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;;
+}
+
+static ast_expression *intrin_isinf(intrin_t *intrin) {
+ /*
+ * float isinf(float x) {
+ * return (x != 0.0) && (x + x == x);
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "isinf", TYPE_FLOAT);
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_AND,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_NE_F,
+ (ast_expression*)x,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_EQ_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)x,
+ (ast_expression*)x
+ ),
+ (ast_expression*)x
+ )
+ )
+ )
+ );
+
+ vec_push(value->expression.params, x);
+ vec_push(func->blocks, body);
+
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_isnan(intrin_t *intrin) {
+ /*
+ * float isnan(float x) {
+ * float local;
+ * local = x;
+ *
+ * return (x != local);
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_value *local = ast_value_new(intrin_ctx(intrin), "local", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "isnan", TYPE_FLOAT);
+
+ vec_push(body->locals, local);
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)local,
+ (ast_expression*)arg1
+ )
+ );
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_NE_F,
+ (ast_expression*)arg1,
+ (ast_expression*)local
+ )
+ )
+ );
+
+ vec_push(value->expression.params, arg1);
+ vec_push(func->blocks, body);
+
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_isnormal(intrin_t *intrin) {
+ /*
+ * float isnormal(float x) {
+ * return isfinite(x);
+ * }
+ */
+ ast_value *value = NULL;
+ ast_call *callisfinite = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "isfinite", "isnormal"));
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "isnormal", TYPE_FLOAT);
+
+ vec_push(value->expression.params, x);
+ vec_push(callisfinite->params, (ast_expression*)x);
+
+ /* return <callisfinite> */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)callisfinite
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_signbit(intrin_t *intrin) {
+ /*
+ * float signbit(float x) {
+ * return (x < 0);
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "signbit", TYPE_FLOAT);
+
+ vec_push(value->expression.params, x);
+
+ /* return (x < 0); */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_ternary_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LT,
+ (ast_expression*)x,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)intrin->fold->imm_float[0]
+ )
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_acosh(intrin_t *intrin) {
+ /*
+ * float acosh(float x) {
+ * return log(x + sqrt((x * x) - 1));
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_call *calllog = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "acosh"));
+ ast_call *callsqrt = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "acosh"));
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "acosh", TYPE_FLOAT);
+
+ vec_push(value->expression.params, x);
+
+ /* <callsqrt> = sqrt((x * x) - 1); */
+ vec_push(callsqrt->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_SUB_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)x,
+ (ast_expression*)x
+ ),
+ (ast_expression*)intrin->fold->imm_float[1]
+ )
+ );
+
+ /* <calllog> = log(x + <callsqrt>); */
+ vec_push(calllog->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)x,
+ (ast_expression*)callsqrt
+ )
+ );
+
+ /* return <calllog>; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)calllog
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_asinh(intrin_t *intrin) {
+ /*
+ * float asinh(float x) {
+ * return log(x + sqrt((x * x) + 1));
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_call *calllog = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "asinh"));
+ ast_call *callsqrt = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "asinh"));
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "asinh", TYPE_FLOAT);
+
+ vec_push(value->expression.params, x);
+
+ /* <callsqrt> = sqrt((x * x) + 1); */
+ vec_push(callsqrt->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)x,
+ (ast_expression*)x
+ ),
+ (ast_expression*)intrin->fold->imm_float[1]
+ )
+ );
+
+ /* <calllog> = log(x + <callsqrt>); */
+ vec_push(calllog->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)x,
+ (ast_expression*)callsqrt
+ )
+ );
+
+ /* return <calllog>; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)calllog
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_atanh(intrin_t *intrin) {
+ /*
+ * float atanh(float x) {
+ * return 0.5 * log((1 + x) / (1 - x))
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_call *calllog = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "atanh"));
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "atanh", TYPE_FLOAT);
+
+ vec_push(value->expression.params, x);
+
+ /* <callog> = log((1 + x) / (1 - x)); */
+ vec_push(calllog->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)x
+ ),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_SUB_F,
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)x
+ )
+ )
+ );
+
+ /* return 0.5 * <calllog>; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)fold_constgen_float(intrin->fold, 0.5),
+ (ast_expression*)calllog
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_exp(intrin_t *intrin) {
+ /*
+ * float exp(float x) {
+ * float sum = 1.0;
+ * float acc = 1.0;
+ * float i;
+ * for (i = 1; i < 200; ++i)
+ * sum += (acc *= x / i);
+ *
+ * return sum;
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_value *sum = ast_value_new(intrin_ctx(intrin), "sum", TYPE_FLOAT);
+ ast_value *acc = ast_value_new(intrin_ctx(intrin), "acc", TYPE_FLOAT);
+ ast_value *i = ast_value_new(intrin_ctx(intrin), "i", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "exp", TYPE_FLOAT);
+
+ vec_push(value->expression.params, x);
+ vec_push(body->locals, sum);
+ vec_push(body->locals, acc);
+ vec_push(body->locals, i);
+
+ /* sum = 1.0; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)sum,
+ (ast_expression*)intrin->fold->imm_float[1]
+ )
+ );
+
+ /* acc = 1.0; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)acc,
+ (ast_expression*)intrin->fold->imm_float[1]
+ )
+ );
+
+ /*
+ * for (i = 1; i < 200; ++i)
+ * sum += (acc *= x / i);
+ */
+ vec_push(body->exprs,
+ (ast_expression*)ast_loop_new(
+ intrin_ctx(intrin),
+ /* i = 1; */
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)i,
+ (ast_expression*)intrin->fold->imm_float[1]
+ ),
+ /* i < 200; */
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LT,
+ (ast_expression*)i,
+ (ast_expression*)fold_constgen_float(intrin->fold, 200.0f)
+ ),
+ false,
+ NULL,
+ false,
+ /* ++i; */
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_ADD_F,
+ (ast_expression*)i,
+ (ast_expression*)intrin->fold->imm_float[1]
+ ),
+ /* sum += (acc *= (x / i)) */
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_ADD_F,
+ (ast_expression*)sum,
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_MUL_F,
+ (ast_expression*)acc,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)x,
+ (ast_expression*)i
+ )
+ )
+ )
+ )
+ );
+
+ /* return sum; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)sum
+ )
+ );
+
+ vec_push(func->blocks, body);
+
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_exp2(intrin_t *intrin) {
+ /*
+ * float exp2(float x) {
+ * return pow(2, x);
+ * }
+ */
+ ast_value *value = NULL;
+ ast_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", "exp2"));
+ ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "exp2", TYPE_FLOAT);
+
+ vec_push(value->expression.params, arg1);
+
+ vec_push(callpow->params, (ast_expression*)intrin->fold->imm_float[3]);
+ vec_push(callpow->params, (ast_expression*)arg1);
+
+ /* return <callpow> */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)callpow
+ )
+ );
+
+ vec_push(func->blocks, body);
+
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_expm1(intrin_t *intrin) {
+ /*
+ * float expm1(float x) {
+ * return exp(x) - 1;
+ * }
+ */
+ ast_value *value = NULL;
+ ast_call *callexp = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "exp", "expm1"));
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "expm1", TYPE_FLOAT);
+
+ vec_push(value->expression.params, x);
+
+ /* <callexp> = exp(x); */
+ vec_push(callexp->params, (ast_expression*)x);
+
+ /* return <callexp> - 1; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_SUB_F,
+ (ast_expression*)callexp,
+ (ast_expression*)intrin->fold->imm_float[1]
+ )
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_pow(intrin_t *intrin) {
+ /*
+ *
+ * float pow(float base, float exp) {
+ * float result;
+ * float low;
+ * float high;
+ * float mid;
+ * float square;
+ * float accumulate;
+ *
+ * if (exp == 0.0)
+ * return 1;
+ * if (exp == 1.0)
+ * return base;
+ * if (exp < 0)
+ * return 1.0 / pow(base, -exp);
+ * if (exp >= 1) {
+ * result = pow(base, exp / 2);
+ * return result * result;
+ * }
+ *
+ * low = 0.0f;
+ * high = 1.0f;
+ * square = sqrt(base);
+ * accumulate = square;
+ * mid = high / 2.0f
+ *
+ * while (fabs(mid - exp) > QC_POW_EPSILON) {
+ * square = sqrt(square);
+ * if (mid < exp) {
+ * low = mid;
+ * accumulate *= square;
+ * } else {
+ * high = mid;
+ * accumulate *= (1.0f / square);
+ * }
+ * mid = (low + high) / 2;
+ * }
+ * return accumulate;
+ * }
+ */
+ ast_value *value = NULL;
+ ast_function *func = intrin_value(intrin, &value, "pow", TYPE_FLOAT);
+
+ /* prepare some calls for later */
+ ast_call *callpow1 = ast_call_new(intrin_ctx(intrin), (ast_expression*)value); /* for pow(base, -exp) */
+ ast_call *callpow2 = ast_call_new(intrin_ctx(intrin), (ast_expression*)value); /* for pow(vase, exp / 2) */
+ ast_call *callsqrt1 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(base) */
+ ast_call *callsqrt2 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(square) */
+ ast_call *callfabs = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "fabs", "pow")); /* for fabs(mid - exp) */
+
+ /* prepare some blocks for later */
+ ast_block *expgt1 = ast_block_new(intrin_ctx(intrin));
+ ast_block *midltexp = ast_block_new(intrin_ctx(intrin));
+ ast_block *midltexpelse = ast_block_new(intrin_ctx(intrin));
+ ast_block *whileblock = ast_block_new(intrin_ctx(intrin));
+
+ /* float pow(float base, float exp) */
+ ast_value *base = ast_value_new(intrin_ctx(intrin), "base", TYPE_FLOAT);
+ ast_value *exp = ast_value_new(intrin_ctx(intrin), "exp", TYPE_FLOAT);
+ /* { */
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+
+ /*
+ * float result;
+ * float low;
+ * float high;
+ * float square;
+ * float accumulate;
+ * float mid;
+ */
+ ast_value *result = ast_value_new(intrin_ctx(intrin), "result", TYPE_FLOAT);
+ ast_value *low = ast_value_new(intrin_ctx(intrin), "low", TYPE_FLOAT);
+ ast_value *high = ast_value_new(intrin_ctx(intrin), "high", TYPE_FLOAT);
+ ast_value *square = ast_value_new(intrin_ctx(intrin), "square", TYPE_FLOAT);
+ ast_value *accumulate = ast_value_new(intrin_ctx(intrin), "accumulate", TYPE_FLOAT);
+ ast_value *mid = ast_value_new(intrin_ctx(intrin), "mid", TYPE_FLOAT);
+ vec_push(body->locals, result);
+ vec_push(body->locals, low);
+ vec_push(body->locals, high);
+ vec_push(body->locals, square);
+ vec_push(body->locals, accumulate);
+ vec_push(body->locals, mid);
+
+ vec_push(value->expression.params, base);
+ vec_push(value->expression.params, exp);
+
+ /*
+ * if (exp == 0.0)
+ * return 1;
+ */
+ vec_push(body->exprs,
+ (ast_expression*)ast_ifthen_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_EQ_F,
+ (ast_expression*)exp,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)intrin->fold->imm_float[1]
+ ),
+ NULL
+ )
+ );
+
+ /*
+ * if (exp == 1.0)
+ * return base;
+ */
+ vec_push(body->exprs,
+ (ast_expression*)ast_ifthen_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_EQ_F,
+ (ast_expression*)exp,
+ (ast_expression*)intrin->fold->imm_float[1]
+ ),
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)base
+ ),
+ NULL
+ )
+ );
+
+ /* <callpow1> = pow(base, -exp) */
+ vec_push(callpow1->params, (ast_expression*)base);
+ vec_push(callpow1->params,
+ (ast_expression*)ast_unary_new(
+ intrin_ctx(intrin),
+ VINSTR_NEG_F,
+ (ast_expression*)exp
+ )
+ );
+
+ /*
+ * if (exp < 0)
+ * return 1.0 / <callpow1>;
+ */
+ vec_push(body->exprs,
+ (ast_expression*)ast_ifthen_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LT,
+ (ast_expression*)exp,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)callpow1
+ )
+ ),
+ NULL
+ )
+ );
+
+ /* <callpow2> = pow(base, exp / 2) */
+ vec_push(callpow2->params, (ast_expression*)base);
+ vec_push(callpow2->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)exp,
+ (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
+ )
+ );
+
+ /*
+ * <expgt1> = {
+ * result = <callpow2>;
+ * return result * result;
+ * }
+ */
+ vec_push(expgt1->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)result,
+ (ast_expression*)callpow2
+ )
+ );
+ vec_push(expgt1->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)result,
+ (ast_expression*)result
+ )
+ )
+ );
+
+ /*
+ * if (exp >= 1) {
+ * <expgt1>
+ * }
+ */
+ vec_push(body->exprs,
+ (ast_expression*)ast_ifthen_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_GE,
+ (ast_expression*)exp,
+ (ast_expression*)intrin->fold->imm_float[1]
+ ),
+ (ast_expression*)expgt1,
+ NULL
+ )
+ );
+
+ /*
+ * <callsqrt1> = sqrt(base)
+ */
+ vec_push(callsqrt1->params, (ast_expression*)base);
+
+ /*
+ * low = 0.0f;
+ * high = 1.0f;
+ * square = sqrt(base);
+ * accumulate = square;
+ * mid = high / 2.0f;
+ */
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)low,
+ (ast_expression*)intrin->fold->imm_float[0]
+ )
+ );
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)high,
+ (ast_expression*)intrin->fold->imm_float[1]
+ )
+ );
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)square,
+ (ast_expression*)callsqrt1
+ )
+ );
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)accumulate,
+ (ast_expression*)square
+ )
+ );
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)mid,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)high,
+ (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
+ )
+ )
+ );
+
+ /*
+ * <midltexp> = {
+ * low = mid;
+ * accumulate *= square;
+ * }
+ */
+ vec_push(midltexp->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)low,
+ (ast_expression*)mid
+ )
+ );
+ vec_push(midltexp->exprs,
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_MUL_F,
+ (ast_expression*)accumulate,
+ (ast_expression*)square
+ )
+ );
+
+ /*
+ * <midltexpelse> = {
+ * high = mid;
+ * accumulate *= (1.0 / square);
+ * }
+ */
+ vec_push(midltexpelse->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)high,
+ (ast_expression*)mid
+ )
+ );
+ vec_push(midltexpelse->exprs,
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_MUL_F,
+ (ast_expression*)accumulate,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)square
+ )
+ )
+ );
-static ast_expression *intrin_pow (intrin_t *intrin) {
/*
- * float pow(float x, float y) {
- * float local = 1.0f;
- * while (y > 0) {
- * while (!(y & 1)) {
- * y >>= 2;
- * x *= x;
- * }
- * y--;
- * local *= x;
+ * <callsqrt2> = sqrt(square)
+ */
+ vec_push(callsqrt2->params, (ast_expression*)square);
+
+ /*
+ * <whileblock> = {
+ * square = <callsqrt2>;
+ * if (mid < exp)
+ * <midltexp>;
+ * else
+ * <midltexpelse>;
+ *
+ * mid = (low + high) / 2;
+ * }
+ */
+ vec_push(whileblock->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)square,
+ (ast_expression*)callsqrt2
+ )
+ );
+ vec_push(whileblock->exprs,
+ (ast_expression*)ast_ifthen_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LT,
+ (ast_expression*)mid,
+ (ast_expression*)exp
+ ),
+ (ast_expression*)midltexp,
+ (ast_expression*)midltexpelse
+ )
+ );
+ vec_push(whileblock->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)mid,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)low,
+ (ast_expression*)high
+ ),
+ (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
+ )
+ )
+ );
+
+ /*
+ * <callabs> = fabs(mid - exp)
+ */
+ vec_push(callfabs->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_SUB_F,
+ (ast_expression*)mid,
+ (ast_expression*)exp
+ )
+ );
+
+ /*
+ * while (<callfabs> > epsilon)
+ * <whileblock>
+ */
+ vec_push(body->exprs,
+ (ast_expression*)ast_loop_new(
+ intrin_ctx(intrin),
+ /* init */
+ NULL,
+ /* pre condition */
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_GT,
+ (ast_expression*)callfabs,
+ (ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON)
+ ),
+ /* pre not */
+ false,
+ /* post condition */
+ NULL,
+ /* post not */
+ false,
+ /* increment expression */
+ NULL,
+ /* code block */
+ (ast_expression*)whileblock
+ )
+ );
+
+ /* return accumulate */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)accumulate
+ )
+ );
+
+ /* } */
+ vec_push(func->blocks, body);
+
+ intrin_reg(intrin, value, func);
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_mod(intrin_t *intrin) {
+ /*
+ * float mod(float a, float b) {
+ * float div = a / b;
+ * float sign = (div < 0.0f) ? -1 : 1;
+ * return a - b * sign * floor(sign * div);
+ * }
+ */
+ ast_value *value = NULL;
+ ast_call *call = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", "mod"));
+ ast_value *a = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
+ ast_value *b = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
+ ast_value *div = ast_value_new(intrin_ctx(intrin), "div", TYPE_FLOAT);
+ ast_value *sign = ast_value_new(intrin_ctx(intrin), "sign", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "mod", TYPE_FLOAT);
+
+ vec_push(value->expression.params, a);
+ vec_push(value->expression.params, b);
+
+ vec_push(body->locals, div);
+ vec_push(body->locals, sign);
+
+ /* div = a / b; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)div,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)a,
+ (ast_expression*)b
+ )
+ )
+ );
+
+ /* sign = (div < 0.0f) ? -1 : 1; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)sign,
+ (ast_expression*)ast_ternary_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LT,
+ (ast_expression*)div,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)intrin->fold->imm_float[2],
+ (ast_expression*)intrin->fold->imm_float[1]
+ )
+ )
+ );
+
+ /* floor(sign * div) */
+ vec_push(call->params,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)sign,
+ (ast_expression*)div
+ )
+ );
+
+ /* return a - b * sign * <call> */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_SUB_F,
+ (ast_expression*)a,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)b,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)sign,
+ (ast_expression*)call
+ )
+ )
+ )
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_fabs(intrin_t *intrin) {
+ /*
+ * float fabs(float x) {
+ * return x < 0 ? -x : x;
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "fabs", TYPE_FLOAT);
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_ternary_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LE,
+ (ast_expression*)arg1,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)ast_unary_new(
+ intrin_ctx(intrin),
+ VINSTR_NEG_F,
+ (ast_expression*)arg1
+ ),
+ (ast_expression*)arg1
+ )
+ )
+ );
+
+ vec_push(value->expression.params, arg1);
+ vec_push(func->blocks, body);
+
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_epsilon(intrin_t *intrin) {
+ /*
+ * float epsilon(void) {
+ * float eps = 1.0f;
+ * do { eps /= 2.0f; } while ((1.0f + (eps / 2.0f)) != 1.0f);
+ * return eps;
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *eps = ast_value_new(intrin_ctx(intrin), "eps", TYPE_FLOAT);
+ ast_block *body = ast_block_new(intrin_ctx(intrin));
+ ast_function *func = intrin_value(intrin, &value, "epsilon", TYPE_FLOAT);
+
+ vec_push(body->locals, eps);
+
+ /* eps = 1.0f; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)eps,
+ (ast_expression*)intrin->fold->imm_float[0]
+ )
+ );
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_loop_new(
+ intrin_ctx(intrin),
+ NULL,
+ NULL,
+ false,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_NE_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)eps,
+ (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
+ )
+ ),
+ (ast_expression*)intrin->fold->imm_float[1]
+ ),
+ false,
+ NULL,
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_DIV_F,
+ (ast_expression*)eps,
+ (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
+ )
+ )
+ );
+
+ /* return eps; */
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)eps
+ )
+ );
+
+ vec_push(func->blocks, body);
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_nan(intrin_t *intrin) {
+ /*
+ * float nan(void) {
+ * float x = 0.0f;
+ * return x / x;
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "nan", TYPE_FLOAT);
+ ast_block *block = ast_block_new(intrin_ctx(intrin));
+
+ vec_push(block->locals, x);
+
+ vec_push(block->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)x,
+ (ast_expression*)intrin->fold->imm_float[0]
+ )
+ );
+
+ vec_push(block->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)x,
+ (ast_expression*)x
+ )
+ )
+ );
+
+ vec_push(func->blocks, block);
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_inf(intrin_t *intrin) {
+ /*
+ * float inf(void) {
+ * float x = 1.0f;
+ * float y = 0.0f;
+ * return x / y;
+ * }
+ */
+ ast_value *value = NULL;
+ ast_value *x = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
+ ast_value *y = ast_value_new(intrin_ctx(intrin), "y", TYPE_FLOAT);
+ ast_function *func = intrin_value(intrin, &value, "inf", TYPE_FLOAT);
+ ast_block *block = ast_block_new(intrin_ctx(intrin));
+ size_t i;
+
+ vec_push(block->locals, x);
+ vec_push(block->locals, y);
+
+ /* to keep code size down */
+ for (i = 0; i <= 1; i++) {
+ vec_push(block->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)((i == 0) ? x : y),
+ (ast_expression*)intrin->fold->imm_float[i]
+ )
+ );
+ }
+
+ vec_push(block->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)x,
+ (ast_expression*)y
+ )
+ )
+ );
+
+ vec_push(func->blocks, block);
+ intrin_reg(intrin, value, func);
+
+ return (ast_expression*)value;
+}
+
+static ast_expression *intrin_ln(intrin_t *intrin) {
+ /*
+ * float log(float power, float base) {
+ * float whole;
+ * float nth
+ * float sign = 1.0f;
+ * float eps = epsilon();
+ *
+ * if (power <= 1.0f || bbase <= 1.0) {
+ * if (power <= 0.0f || base <= 0.0f)
+ * return nan();
+ *
+ * if (power < 1.0f) {
+ * power = 1.0f / power;
+ * sign *= -1.0f;
+ * }
+ *
+ * if (base < 1.0f) {
+ * sign *= -1.0f;
+ * base = 1.0f / base;
+ * }
+ * }
+ *
+ * float A_i = 1;
+ * float B_i = 0;
+ * float A_iminus1 = 0;
+ * float B_iminus1 = 1;
+ *
+ * for (;;) {
+ * whole = power;
+ * nth = 0.0f;
+ *
+ * while (whole >= base) {
+ * float base2 = base;
+ * float n2 = 1.0f;
+ * float newbase2 = base2 * base2;
+ *
+ * while (whole >= newbase2) {
+ * base2 = newbase2;
+ * n2 *= 2;
+ * newbase2 *= newbase2;
+ * }
+ *
+ * whole /= base2;
+ * nth += n2;
+ * }
+ *
+ * float b_iplus1 = n;
+ * float A_iplus1 = b_iplus1 * A_i + A_iminus1;
+ * float B_iplus1 = b_iplus1 * B_i + B_iminus1;
+ *
+ * A_iminus1 = A_i;
+ * B_iminus1 = B_i;
+ * A_i = A_iplus1;
+ * B_i = B_iplus1;
+ *
+ * if (whole <= 1.0f + eps)
+ * break;
+ *
+ * power = base;
+ * bower = whole;
* }
- * return local;
+ * return sign * A_i / B_i;
* }
*/
- ast_value *value = NULL;
- ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
- ast_value *arg2 = ast_value_new(intrin_ctx(intrin), "y", TYPE_FLOAT);
- ast_value *local = ast_value_new(intrin_ctx(intrin), "local", TYPE_FLOAT);
- ast_block *body = ast_block_new(intrin_ctx(intrin));
- ast_block *l1b = ast_block_new(intrin_ctx(intrin)); /* loop 1 body */
- ast_block *l2b = ast_block_new(intrin_ctx(intrin)); /* loop 2 body */
- ast_loop *loop1 = NULL;
- ast_loop *loop2 = NULL;
- ast_function *func = intrin_value(intrin, &value, "pow", TYPE_FLOAT);
- /* arguments */
- vec_push(value->expression.params, arg1);
- vec_push(value->expression.params, arg2);
+ ast_value *value = NULL;
+ ast_value *power = ast_value_new(intrin_ctx(intrin), "power", TYPE_FLOAT);
+ ast_value *base = ast_value_new(intrin_ctx(intrin), "base", TYPE_FLOAT);
+ ast_value *whole = ast_value_new(intrin_ctx(intrin), "whole", TYPE_FLOAT);
+ ast_value *nth = ast_value_new(intrin_ctx(intrin), "nth", TYPE_FLOAT);
+ ast_value *sign = ast_value_new(intrin_ctx(intrin), "sign", TYPE_FLOAT);
+ ast_value *A_i = ast_value_new(intrin_ctx(intrin), "A_i", TYPE_FLOAT);
+ ast_value *B_i = ast_value_new(intrin_ctx(intrin), "B_i", TYPE_FLOAT);
+ ast_value *A_iminus1 = ast_value_new(intrin_ctx(intrin), "A_iminus1", TYPE_FLOAT);
+ ast_value *B_iminus1 = ast_value_new(intrin_ctx(intrin), "B_iminus1", TYPE_FLOAT);
+ ast_value *b_iplus1 = ast_value_new(intrin_ctx(intrin), "b_iplus1", TYPE_FLOAT);
+ ast_value *A_iplus1 = ast_value_new(intrin_ctx(intrin), "A_iplus1", TYPE_FLOAT);
+ ast_value *B_iplus1 = ast_value_new(intrin_ctx(intrin), "B_iplus1", TYPE_FLOAT);
+ ast_value *eps = ast_value_new(intrin_ctx(intrin), "eps", TYPE_FLOAT);
+ ast_value *base2 = ast_value_new(intrin_ctx(intrin), "base2", TYPE_FLOAT);
+ ast_value *n2 = ast_value_new(intrin_ctx(intrin), "n2", TYPE_FLOAT);
+ ast_value *newbase2 = ast_value_new(intrin_ctx(intrin), "newbase2", TYPE_FLOAT);
+ ast_block *block = ast_block_new(intrin_ctx(intrin));
+ ast_block *plt1orblt1 = ast_block_new(intrin_ctx(intrin)); /* (power <= 1.0f || base <= 1.0f) */
+ ast_block *plt1 = ast_block_new(intrin_ctx(intrin)); /* (power < 1.0f) */
+ ast_block *blt1 = ast_block_new(intrin_ctx(intrin)); /* (base < 1.0f) */
+ ast_block *forloop = ast_block_new(intrin_ctx(intrin)); /* for(;;) */
+ ast_block *whileloop = ast_block_new(intrin_ctx(intrin)); /* while (whole >= base) */
+ ast_block *nestwhile = ast_block_new(intrin_ctx(intrin)); /* while (whole >= newbase2) */
+ ast_function *func = intrin_value(intrin, &value, "ln", TYPE_FLOAT);
+ size_t i;
- /* local */
- vec_push(body->locals, local);
+ vec_push(value->expression.params, power);
+ vec_push(value->expression.params, base);
- /* assignment to local of value 1.0f */
- vec_push(body->exprs,
- (ast_expression*)ast_store_new (
+ vec_push(block->locals, whole);
+ vec_push(block->locals, nth);
+ vec_push(block->locals, sign);
+ vec_push(block->locals, eps);
+ vec_push(block->locals, A_i);
+ vec_push(block->locals, B_i);
+ vec_push(block->locals, A_iminus1);
+ vec_push(block->locals, B_iminus1);
+
+ /* sign = 1.0f; */
+ vec_push(block->exprs,
+ (ast_expression*)ast_store_new(
intrin_ctx(intrin),
INSTR_STORE_F,
- (ast_expression*)local,
- (ast_expression*)intrin->fold->imm_float[1] /* 1 == 1.0f */
+ (ast_expression*)sign,
+ (ast_expression*)intrin->fold->imm_float[1]
)
);
- /* y >>= 2 */
- vec_push(l2b->exprs,
- (ast_expression*)ast_binstore_new (
+ /* eps = __builtin_epsilon(); */
+ vec_push(block->exprs,
+ (ast_expression*)ast_store_new(
intrin_ctx(intrin),
INSTR_STORE_F,
- INSTR_MUL_F,
- (ast_expression*)arg2,
- (ast_expression*)fold_constgen_float(intrin->parser->fold, 0.25f)
+ (ast_expression*)eps,
+ (ast_expression*)ast_call_new(
+ intrin_ctx(intrin),
+ intrin_func_self(intrin, "__builtin_epsilon", "ln")
+ )
)
);
- /* x *= x */
- vec_push(l2b->exprs,
- (ast_expression*)ast_binstore_new (
+ /*
+ * A_i = 1;
+ * B_i = 0;
+ * A_iminus1 = 0;
+ * B_iminus1 = 1;
+ */
+ for (i = 0; i <= 1; i++) {
+ int j;
+ for (j = 1; j >= 0; j--) {
+ vec_push(block->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)((j) ? ((i) ? B_iminus1 : A_i)
+ : ((i) ? A_iminus1 : B_i)),
+ (ast_expression*)intrin->fold->imm_float[j]
+ )
+ );
+ }
+ }
+
+ /*
+ * <plt1> = {
+ * power = 1.0f / power;
+ * sign *= -1.0f;
+ * }
+ * <blt1> = {
+ * base = 1.0f / base;
+ * sign *= -1.0f;
+ * }
+ */
+ for (i = 0; i <= 1; i++) {
+ vec_push(((i) ? blt1 : plt1)->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)((i) ? base : power),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_DIV_F,
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)((i) ? base : power)
+ )
+ )
+ );
+ vec_push(plt1->exprs,
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_MUL_F,
+ (ast_expression*)sign,
+ (ast_expression*)intrin->fold->imm_float[2]
+ )
+ );
+ }
+
+ /*
+ * <plt1orblt1> = {
+ * if (power <= 0.0 || base <= 0.0f)
+ * return __builtin_nan();
+ * if (power < 1.0f)
+ * <plt1>
+ * if (base < 1.0f)
+ * <blt1>
+ * }
+ */
+ vec_push(plt1orblt1->exprs,
+ (ast_expression*)ast_ifthen_new(
intrin_ctx(intrin),
- INSTR_STORE_F,
- INSTR_MUL_F,
- (ast_expression*)arg1,
- (ast_expression*)arg1
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_OR,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LE,
+ (ast_expression*)power,
+ (ast_expression*)intrin->fold->imm_float[0]
+ ),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LE,
+ (ast_expression*)base,
+ (ast_expression*)intrin->fold->imm_float[0]
+ )
+ ),
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_call_new(
+ intrin_ctx(intrin),
+ intrin_func_self(intrin, "__builtin_nan", "ln")
+ )
+ ),
+ NULL
)
);
- /* while (!(y&1)) */
- loop2 = ast_loop_new (
- intrin_ctx(intrin),
- NULL,
- (ast_expression*)ast_binary_new (
- intrin_ctx(intrin),
- INSTR_AND,
- (ast_expression*)arg2,
- (ast_expression*)intrin->fold->imm_float[1] /* 1 == 1.0f */
- ),
- true, /* ! not */
- NULL,
- false,
- NULL,
- (ast_expression*)l2b
- );
+ for (i = 0; i <= 1; i++) {
+ vec_push(plt1orblt1->exprs,
+ (ast_expression*)ast_ifthen_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_LT,
+ (ast_expression*)((i) ? base : power),
+ (ast_expression*)intrin->fold->imm_float[1]
+ ),
+ (ast_expression*)((i) ? blt1 : plt1),
+ NULL
+ )
+ );
+ }
+
+ vec_push(block->exprs, (ast_expression*)plt1orblt1);
- /* push nested loop into loop expressions */
- vec_push(l1b->exprs, (ast_expression*)loop2);
- /* y-- */
- vec_push(l1b->exprs,
- (ast_expression*)ast_binstore_new (
+ /* whole = power; */
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_store_new(
intrin_ctx(intrin),
INSTR_STORE_F,
- INSTR_SUB_F,
- (ast_expression*)arg2,
- (ast_expression*)intrin->fold->imm_float[1] /* 1 == 1.0f */
+ (ast_expression*)whole,
+ (ast_expression*)power
)
);
- /* local *= x */
- vec_push(l1b->exprs,
- (ast_expression*)ast_binstore_new (
+
+ /* nth = 0.0f; */
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_store_new(
intrin_ctx(intrin),
INSTR_STORE_F,
- INSTR_MUL_F,
- (ast_expression*)local,
- (ast_expression*)arg1
+ (ast_expression*)nth,
+ (ast_expression*)intrin->fold->imm_float[0]
)
);
- /* while (y > 0) */
- loop1 = ast_loop_new (
- intrin_ctx(intrin),
- NULL,
- (ast_expression*)ast_binary_new (
+ /* base2 = base; */
+ vec_push(whileloop->exprs,
+ (ast_expression*)ast_store_new(
intrin_ctx(intrin),
- INSTR_GT,
- (ast_expression*)arg2,
- (ast_expression*)intrin->fold->imm_float[0] /* 0 == 0.0f */
- ),
- false,
- NULL,
- false,
- NULL,
- (ast_expression*)l1b
+ INSTR_STORE_F,
+ (ast_expression*)base2,
+ (ast_expression*)base
+ )
);
- /* push the loop1 into the body for the function */
- vec_push(body->exprs, (ast_expression*)loop1);
-
- /* return local; */
- vec_push(body->exprs,
- (ast_expression*)ast_return_new (
+ /* n2 = 1.0f; */
+ vec_push(whileloop->exprs,
+ (ast_expression*)ast_store_new(
intrin_ctx(intrin),
- (ast_expression*)local
+ INSTR_STORE_F,
+ (ast_expression*)n2,
+ (ast_expression*)intrin->fold->imm_float[1]
)
);
- /* push block and register intrin for codegen */
- vec_push(func->blocks, body);
+ /* newbase2 = base2 * base2; */
+ vec_push(whileloop->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)newbase2,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)base2,
+ (ast_expression*)base2
+ )
+ )
+ );
- intrin_reg(intrin, value, func);
+ /* while loop locals */
+ vec_push(whileloop->locals, base2);
+ vec_push(whileloop->locals, n2);
+ vec_push(whileloop->locals, newbase2);
- return (ast_expression*)value;
-}
+ /* base2 = newbase2; */
+ vec_push(nestwhile->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)base2,
+ (ast_expression*)newbase2
+ )
+ );
-static ast_expression *intrin_mod(intrin_t *intrin) {
- /*
- * float mod(float x, float y) {
- * return x - y * floor(x / y);
- * }
- */
- ast_value *value = NULL;
- ast_call *call = ast_call_new (intrin_ctx(intrin), intrin_func(intrin, "floor"));
- ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
- ast_value *arg2 = ast_value_new(intrin_ctx(intrin), "y", TYPE_FLOAT);
- ast_block *body = ast_block_new(intrin_ctx(intrin));
- ast_function *func = intrin_value(intrin, &value, "mod", TYPE_FLOAT);
+ /* n2 *= 2; */
+ vec_push(nestwhile->exprs,
+ (ast_expression*)ast_binstore_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ INSTR_MUL_F,
+ (ast_expression*)n2,
+ (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
+ )
+ );
- /* floor(x/y) */
- vec_push(call->params,
- (ast_expression*)ast_binary_new (
+ /* newbase2 *= newbase2; */
+ vec_push(nestwhile->exprs,
+ (ast_expression*)ast_binstore_new(
intrin_ctx(intrin),
- INSTR_DIV_F,
- (ast_expression*)arg1,
- (ast_expression*)arg2
+ INSTR_STORE_F,
+ INSTR_MUL_F,
+ (ast_expression*)newbase2,
+ (ast_expression*)newbase2
)
);
- vec_push(body->exprs,
- (ast_expression*)ast_return_new(
+ /* while (whole >= newbase2) */
+ vec_push(whileloop->exprs,
+ (ast_expression*)ast_loop_new(
intrin_ctx(intrin),
+ NULL,
(ast_expression*)ast_binary_new(
intrin_ctx(intrin),
- INSTR_SUB_F,
- (ast_expression*)arg1,
- (ast_expression*)ast_binary_new(
- intrin_ctx(intrin),
- INSTR_MUL_F,
- (ast_expression*)arg2,
- (ast_expression*)call
- )
- )
+ INSTR_GE,
+ (ast_expression*)whole,
+ (ast_expression*)newbase2
+ ),
+ false,
+ NULL,
+ false,
+ NULL,
+ (ast_expression*)nestwhile
)
);
- vec_push(value->expression.params, arg1); /* float x (for param) */
- vec_push(value->expression.params, arg2); /* float y (for param) */
-
- vec_push(func->blocks, body); /* {{{ body }}} */
-
- intrin_reg(intrin, value, func);
-
- return (ast_expression*)value;
-}
-
-static ast_expression *intrin_exp(intrin_t *intrin) {
- /*
- * float exp(float x) {
- * return pow(QC_M_E, x);
- * }
- */
- ast_value *value = NULL;
- ast_call *call = ast_call_new (intrin_ctx(intrin), intrin_func(intrin, "pow"));
- ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
- ast_block *body = ast_block_new(intrin_ctx(intrin));
- ast_function *func = intrin_value(intrin, &value, "exp", TYPE_FLOAT);
-
- /* push arguments for params to call */
- vec_push(call->params, (ast_expression*)fold_constgen_float(intrin->fold, QC_M_E));
- vec_push(call->params, (ast_expression*)arg1);
-
- /* return pow(QC_M_E, x) */
- vec_push(body->exprs,
- (ast_expression*)ast_return_new(
+ /* whole /= base2; */
+ vec_push(whileloop->exprs,
+ (ast_expression*)ast_binstore_new(
intrin_ctx(intrin),
- (ast_expression*)call
+ INSTR_STORE_F,
+ INSTR_DIV_F,
+ (ast_expression*)whole,
+ (ast_expression*)base2
)
);
- vec_push(value->expression.params, arg1); /* float x (for param) */
-
- vec_push(func->blocks, body); /* {{{ body }}} */
-
- intrin_reg(intrin, value, func);
-
- return (ast_expression*)value;
-}
-
-static ast_expression *intrin_isnan(intrin_t *intrin) {
- /*
- * float isnan(float x) {
- * float local;
- * local = x;
- *
- * return (x != local);
- * }
- */
- ast_value *value = NULL;
- ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
- ast_value *local = ast_value_new(intrin_ctx(intrin), "local", TYPE_FLOAT);
- ast_block *body = ast_block_new(intrin_ctx(intrin));
- ast_function *func = intrin_value(intrin, &value, "isnan", TYPE_FLOAT);
-
- vec_push(body->locals, local);
- vec_push(body->exprs,
- (ast_expression*)ast_store_new(
+ /* nth += n2; */
+ vec_push(whileloop->exprs,
+ (ast_expression*)ast_binstore_new(
intrin_ctx(intrin),
INSTR_STORE_F,
- (ast_expression*)local,
- (ast_expression*)arg1
+ INSTR_ADD_F,
+ (ast_expression*)nth,
+ (ast_expression*)n2
)
);
- vec_push(body->exprs,
- (ast_expression*)ast_return_new(
+ /* while (whole >= base) */
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_loop_new(
intrin_ctx(intrin),
+ NULL,
(ast_expression*)ast_binary_new(
intrin_ctx(intrin),
- INSTR_NE_F,
- (ast_expression*)arg1,
- (ast_expression*)local
- )
+ INSTR_GE,
+ (ast_expression*)whole,
+ (ast_expression*)base
+ ),
+ false,
+ NULL,
+ false,
+ NULL,
+ (ast_expression*)whileloop
)
);
- vec_push(value->expression.params, arg1);
- vec_push(func->blocks, body);
+ vec_push(forloop->locals, b_iplus1);
+ vec_push(forloop->locals, A_iplus1);
+ vec_push(forloop->locals, B_iplus1);
- intrin_reg(intrin, value, func);
+ /* b_iplus1 = nth; */
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)b_iplus1,
+ (ast_expression*)nth
+ )
+ );
- return (ast_expression*)value;
-}
+ /*
+ * A_iplus1 = b_iplus1 * A_i + A_iminus1;
+ * B_iplus1 = b_iplus1 * B_i + B_iminus1;
+ */
+ for (i = 0; i <= 1; i++) {
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)((i) ? B_iplus1 : A_iplus1),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_ADD_F,
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)b_iplus1,
+ (ast_expression*) ((i) ? B_i : A_i)
+ ),
+ (ast_expression*)((i) ? B_iminus1 : A_iminus1)
+ )
+ )
+ );
+ }
-static ast_expression *intrin_fabs(intrin_t *intrin) {
/*
- * float fabs(float x) {
- * return x < 0 ? -x : x;
- * }
+ * A_iminus1 = A_i;
+ * B_iminus1 = B_i;
*/
- ast_value *value = NULL;
- ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
- ast_block *body = ast_block_new(intrin_ctx(intrin));
- ast_function *func = intrin_value(intrin, &value, "fabs", TYPE_FLOAT);
+ for (i = 0; i <= 1; i++) {
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)((i) ? B_iminus1 : A_iminus1),
+ (ast_expression*)((i) ? B_i : A_i)
+ )
+ );
+ }
- vec_push(body->exprs,
- (ast_expression*)ast_return_new(
+ /*
+ * A_i = A_iplus1;
+ * B_i = B_iplus1;
+ */
+ for (i = 0; i <= 1; i++) {
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)((i) ? B_i : A_i),
+ (ast_expression*)((i) ? B_iplus1 : A_iplus1)
+ )
+ );
+ }
+
+ /*
+ * if (whole <= 1.0f + eps)
+ * break;
+ */
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_ifthen_new(
intrin_ctx(intrin),
- (ast_expression*)ast_ternary_new(
+ (ast_expression*)ast_binary_new(
intrin_ctx(intrin),
+ INSTR_LE,
+ (ast_expression*)whole,
(ast_expression*)ast_binary_new(
intrin_ctx(intrin),
- INSTR_LE,
- (ast_expression*)arg1,
- (ast_expression*)intrin->fold->imm_float[0]
- ),
+ INSTR_ADD_F,
+ (ast_expression*)intrin->fold->imm_float[1],
+ (ast_expression*)eps
+ )
+ ),
+ (ast_expression*)ast_breakcont_new(
+ intrin_ctx(intrin),
+ false,
+ 0
+ ),
+ NULL
+ )
+ );
+
+ /*
+ * power = base;
+ * base = whole;
+ */
+ for (i = 0; i <= 1; i++) {
+ vec_push(forloop->exprs,
+ (ast_expression*)ast_store_new(
+ intrin_ctx(intrin),
+ INSTR_STORE_F,
+ (ast_expression*)((i) ? base : power),
+ (ast_expression*)((i) ? whole : base)
+ )
+ );
+ }
+
+ /* add the for loop block */
+ vec_push(block->exprs,
+ (ast_expression*)ast_loop_new(
+ intrin_ctx(intrin),
+ NULL,
+ /* for(; 1; ) ?? (can this be NULL too?) */
+ (ast_expression*)intrin->fold->imm_float[1],
+ false,
+ NULL,
+ false,
+ NULL,
+ (ast_expression*)forloop
+ )
+ );
+
+ /* return sign * A_i / B_il */
+ vec_push(block->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ INSTR_MUL_F,
+ (ast_expression*)sign,
(ast_expression*)ast_binary_new(
intrin_ctx(intrin),
- INSTR_SUB_F,
- (ast_expression*)intrin->fold->imm_float[0],
- (ast_expression*)arg1
- ),
- (ast_expression*)arg1
+ INSTR_DIV_F,
+ (ast_expression*)A_i,
+ (ast_expression*)B_i
+ )
)
)
);
- vec_push(value->expression.params, arg1);
- vec_push(func->blocks, body);
-
+ vec_push(func->blocks, block);
intrin_reg(intrin, value, func);
return (ast_expression*)value;
}
+#define LOG_VARIANT(NAME, BASE) \
+static ast_expression *intrin_##NAME(intrin_t *intrin) { \
+ ast_value *value = NULL; \
+ ast_call *callln = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "__builtin_ln", #NAME)); \
+ ast_value *arg1 = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT); \
+ ast_block *body = ast_block_new(intrin_ctx(intrin)); \
+ ast_function *func = intrin_value(intrin, &value, #NAME, TYPE_FLOAT); \
+ vec_push(value->expression.params, arg1); \
+ vec_push(callln->params, (ast_expression*)arg1); \
+ vec_push(callln->params, (ast_expression*)fold_constgen_float(intrin->fold, BASE)); \
+ vec_push(body->exprs, \
+ (ast_expression*)ast_return_new( \
+ intrin_ctx(intrin), \
+ (ast_expression*)callln \
+ ) \
+ ); \
+ vec_push(func->blocks, body); \
+ intrin_reg(intrin, value, func); \
+ return (ast_expression*)value; \
+}
+LOG_VARIANT(log, 2.7182818284590452354)
+LOG_VARIANT(log10, 10)
+LOG_VARIANT(log2, 2)
+LOG_VARIANT(logb, 2) /* FLT_RADIX == 2 for now */
+#undef LOG_VARIANT
+
/*
* TODO: make static (and handle ast_type_string) here for the builtin
* instead of in SYA parse close.
}
static const intrin_func_t intrinsics[] = {
- {&intrin_exp, "__builtin_exp", "exp", 1},
- {&intrin_mod, "__builtin_mod", "mod", 2},
- {&intrin_pow, "__builtin_pow", "pow", 2},
- {&intrin_isnan, "__builtin_isnan", "isnan", 1},
- {&intrin_fabs, "__builtin_fabs", "fabs", 1},
- {&intrin_debug_typestring, "__builtin_debug_typestring", "", 0}
+ {&intrin_isfinite, "__builtin_isfinite", "isfinite", 1},
+ {&intrin_isinf, "__builtin_isinf", "isinf", 1},
+ {&intrin_isnan, "__builtin_isnan", "isnan", 1},
+ {&intrin_isnormal, "__builtin_isnormal", "isnormal", 1},
+ {&intrin_signbit, "__builtin_signbit", "signbit", 1},
+ {&intrin_acosh, "__builtin_acosh", "acosh", 1},
+ {&intrin_asinh, "__builtin_asinh", "asinh", 1},
+ {&intrin_atanh, "__builtin_atanh", "atanh", 1},
+ {&intrin_exp, "__builtin_exp", "exp", 1},
+ {&intrin_exp2, "__builtin_exp2", "exp2", 1},
+ {&intrin_expm1, "__builtin_expm1", "expm1", 1},
+ {&intrin_mod, "__builtin_mod", "mod", 2},
+ {&intrin_pow, "__builtin_pow", "pow", 2},
+ {&intrin_fabs, "__builtin_fabs", "fabs", 1},
+ {&intrin_log, "__builtin_log", "log", 1},
+ {&intrin_log10, "__builtin_log10", "log10", 1},
+ {&intrin_log2, "__builtin_log2", "log2", 1},
+ {&intrin_logb, "__builtin_logb", "logb", 1},
+ {&intrin_epsilon, "__builtin_epsilon", "", 0},
+ {&intrin_nan, "__builtin_nan", "", 0},
+ {&intrin_inf, "__builtin_inf", "", 0},
+ {&intrin_ln, "__builtin_ln", "", 2},
+ {&intrin_debug_typestring, "__builtin_debug_typestring", "", 0},
+ {&intrin_nullfunc, "#nullfunc", "", 0}
};
static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
return NULL;
}
-ast_expression *intrin_func(intrin_t *intrin, const char *name) {
+static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from) {
size_t i;
ast_expression *find;
if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, alias), name)))
return find;
- intrin_error(intrin, "need function: `%s` compiler depends on it", name);
+ if (from) {
+ intrin_error(intrin, "need function `%s', compiler depends on it for `__builtin_%s'", name, from);
+ return intrin_func_self(intrin, "#nullfunc", NULL);
+ }
return NULL;
}
+
+ast_expression *intrin_func(intrin_t *intrin, const char *name) {
+ return intrin_func_self(intrin, name, NULL);
+}
case VINSTR_NEG_F:
return ir_block_create_general_instr(self, ctx, label, INSTR_SUB_F, NULL, operand, ot);
case VINSTR_NEG_V:
- return ir_block_create_general_instr(self, ctx, label, INSTR_SUB_V, NULL, operand, ot);
+ return ir_block_create_general_instr(self, ctx, label, INSTR_SUB_V, NULL, operand, TYPE_VECTOR);
default:
ot = operand->vtype;
return r;
}
-
-#if 0
-token* token_new()
-{
- token *tok = (token*)mem_a(sizeof(token));
- if (!tok)
- return NULL;
- memset(tok, 0, sizeof(*tok));
- return tok;
-}
-
-void token_delete(token *self)
-{
- if (self->next && self->next->prev == self)
- self->next->prev = self->prev;
- if (self->prev && self->prev->next == self)
- self->prev->next = self->next;
- MEM_VECTOR_CLEAR(self, value);
- mem_d(self);
-}
-
-token* token_copy(const token *cp)
-{
- token* self = token_new();
- if (!self)
- return NULL;
- /* copy the value */
- self->value_alloc = cp->value_count + 1;
- self->value_count = cp->value_count;
- self->value = (char*)mem_a(self->value_alloc);
- if (!self->value) {
- mem_d(self);
- return NULL;
- }
- memcpy(self->value, cp->value, cp->value_count);
- self->value[self->value_alloc-1] = 0;
-
- /* rest */
- self->ctx = cp->ctx;
- self->ttype = cp->ttype;
- memcpy(&self->constval, &cp->constval, sizeof(self->constval));
- return self;
-}
-
-void token_delete_all(token *t)
-{
- token *n;
-
- do {
- n = t->next;
- token_delete(t);
- t = n;
- } while(t);
-}
-
-token* token_copy_all(const token *cp)
-{
- token *cur;
- token *out;
-
- out = cur = token_copy(cp);
- if (!out)
- return NULL;
-
- while (cp->next) {
- cp = cp->next;
- cur->next = token_copy(cp);
- if (!cur->next) {
- token_delete_all(out);
- return NULL;
- }
- cur->next->prev = cur;
- cur = cur->next;
- }
-
- return out;
-}
-#else
static void lex_token_new(lex_file *lex)
{
-#if 0
- if (lex->tok)
- token_delete(lex->tok);
- lex->tok = token_new();
-#else
if (lex->tok.value)
vec_shrinkto(lex->tok.value, 0);
lex->tok.ctx.line = lex->sline;
lex->tok.ctx.file = lex->name;
lex->tok.ctx.column = lex->column;
-#endif
}
-#endif
+
+static void lex_ungetch(lex_file *lex, int ch);
+static int lex_getch(lex_file *lex);
lex_file* lex_open(const char *file)
{
lex_file *lex;
fs_file_t *in = fs_file_open(file, "rb");
+ uint32_t read;
if (!in) {
lexerror(NULL, "open failed: '%s'\n", file);
lex->peekpos = 0;
lex->eof = false;
+ /* handle BOM */
+ if ((read = (lex_getch(lex) << 16) | (lex_getch(lex) << 8) | lex_getch(lex)) != 0xEFBBBF) {
+ lex_ungetch(lex, (read & 0x0000FF));
+ lex_ungetch(lex, (read & 0x00FF00) >> 8);
+ lex_ungetch(lex, (read & 0xFF0000) >> 16);
+ } else {
+ /*
+ * otherwise the lexer has advanced 3 bytes for the BOM, we need
+ * to set the column back to 0
+ */
+ lex->column = 0;
+ }
+
vec_push(lex_filenames, lex->name);
return lex;
}
if (lex->file)
fs_file_close(lex->file);
-#if 0
- if (lex->tok)
- token_delete(lex->tok);
-#else
+
vec_free(lex->tok.value);
-#endif
+
/* mem_d(lex->name); collected in lex_filenames */
mem_d(lex);
}
+
+
static int lex_fgetc(lex_file *lex)
{
if (lex->file) {
* are working on.
* The are merely wrapping get/put in order to count line numbers.
*/
-static void lex_ungetch(lex_file *lex, int ch);
static int lex_try_trigraph(lex_file *lex, int old)
{
int c2, c3;
if (lex->flags.preprocessing) {
haswhite = true;
- /*
- lex_tokench(lex, '/');
- lex_tokench(lex, '/');
- */
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
/* multiline comment */
if (lex->flags.preprocessing) {
haswhite = true;
- /*
- lex_tokench(lex, '/');
- lex_tokench(lex, '*');
- */
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
ch = lex_getch(lex);
if (ch == '/') {
if (lex->flags.preprocessing) {
- /*
- lex_tokench(lex, '*');
- lex_tokench(lex, '/');
- */
lex_tokench(lex, ' ');
lex_tokench(lex, ' ');
}
if (ch == '\n')
lex_tokench(lex, '\n');
else
- lex_tokench(lex, ' '); /* ch); */
+ lex_tokench(lex, ' ');
}
}
ch = ' '; /* cause TRUE in the isspace check */
bool hadwhite = false;
lex_token_new(lex);
-#if 0
- if (!lex->tok)
- return TOKEN_FATAL;
-#endif
while (true) {
ch = lex_skipwhite(lex, hadwhite);
*/
switch (ch)
{
- /*
- case '+':
- case '-':
- */
case '*':
case '/':
case '<':
return (lex->tok.ttype = TOKEN_OPERATOR);
}
- /*
- if (ch == '^' || ch == '~' || ch == '!')
- {
- lex_tokench(lex, ch);
- lex_endtoken(lex);
- return (lex->tok.ttype = TOKEN_OPERATOR);
- }
- */
-
if (ch == '*' || ch == '/') /* *=, /= */
{
lex_tokench(lex, ch);
*/
#ifndef GMQCC_LEXER_HDR
#define GMQCC_LEXER_HDR
+#include "gmqcc.h"
+
typedef struct token_s token;
struct token_s {
{ "++", 1, opid3('+','+','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
{ "--", 1, opid3('-','-','P'), ASSOC_RIGHT, 16, OP_PREFIX, false},
- { "**", 2, opid2('*','*'), ASSOC_RIGHT, 15, 0, true},
-
+ { "**", 2, opid2('*','*'), ASSOC_RIGHT, 14, 0, true},
{ "!", 1, opid2('!','P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
{ "~", 1, opid2('~','P'), ASSOC_RIGHT, 14, OP_PREFIX, true},
{ "+", 1, opid2('+','P'), ASSOC_RIGHT, 14, OP_PREFIX, false},
opts_set(opts.warn, WARN_PARENTHESIS, true);
opts_set(opts.warn, WARN_CONST_OVERWRITE, true);
opts_set(opts.warn, WARN_DIRECTIVE_INMACRO, true);
+ opts_set(opts.warn, WARN_BUILTINS, true);
/* flags */
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, true);
GMQCC_DEFINE_FLAG(BREAKDEF)
GMQCC_DEFINE_FLAG(CONST_OVERWRITE)
GMQCC_DEFINE_FLAG(DIRECTIVE_INMACRO)
+ GMQCC_DEFINE_FLAG(BUILTINS)
#endif
#ifdef GMQCC_TYPE_OPTIMIZATIONS
type_name[exprs[0]->vtype]);
return false;
}
- out = (ast_expression*)ast_unary_new(ctx, (VINSTR_NEG_F-TYPE_FLOAT) + exprs[0]->vtype, exprs[0]);
+ if (exprs[0]->vtype == TYPE_FLOAT)
+ out = (ast_expression*)ast_unary_new(ctx, VINSTR_NEG_F, exprs[0]);
+ else
+ out = (ast_expression*)ast_unary_new(ctx, VINSTR_NEG_V, exprs[0]);
break;
case opid2('!','P'):
var = intrin_func(parser->intrin, parser_tokval(parser));
}
+ /*
+ * Try it again, intrin_func deals with the alias method as well
+ * the first one masks for __builtin though, we emit warning here.
+ */
+ if (!var) {
+ if ((var = intrin_func(parser->intrin, parser_tokval(parser)))) {
+ (void)!compile_warning(
+ parser_ctx(parser),
+ WARN_BUILTINS,
+ "using implicitly defined builtin `__builtin_%s' for `%s'",
+ parser_tokval(parser),
+ parser_tokval(parser)
+ );
+ }
+ }
+
+
if (!var) {
char *correct = NULL;
size_t i;
*/
char *defname = NULL;
size_t prefix_len, ln;
+ size_t sn, sn_size;
ln = strlen(parser->function->name);
vec_append(defname, ln, parser->function->name);
/* now rename the global */
ln = strlen(var->name);
vec_append(defname, ln, var->name);
+ /* if a variable of that name already existed, add the
+ * counter value.
+ * The counter is incremented either way.
+ */
+ sn_size = vec_size(parser->function->static_names);
+ for (sn = 0; sn != sn_size; ++sn) {
+ if (strcmp(parser->function->static_names[sn], var->name) == 0)
+ break;
+ }
+ if (sn != sn_size) {
+ char *num = NULL;
+ int len = util_asprintf(&num, "#%u", parser->function->static_count);
+ vec_append(defname, len, num);
+ mem_d(num);
+ }
+ else
+ vec_push(parser->function->static_names, util_strdup(var->name));
+ parser->function->static_count++;
ast_value_set_name(var, defname);
/* push it to the to-be-generated globals */
if (!cexp)
break;
- if (!localblock) {
+ if (!localblock || is_static) {
cval = (ast_value*)cexp;
if (cval != parser->nil &&
(!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
)
{
- parseerror(parser, "cannot initialize a global constant variable with a non-constant expression");
+ parseerror(parser, "initializer is non constant");
}
else
{
- if (!OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
+ if (!is_static &&
+ !OPTS_FLAG(INITIALIZED_NONCONSTANTS) &&
qualifier != CV_VAR)
{
var->cvq = CV_CONST;
*/
#if 1
#define GMQCC_ROTL32(X, R) (((X) << (R)) | ((X) >> (32 - (R))))
-GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) {
+size_t util_hthash(hash_table_t *ht, const char *key) {
const unsigned char *data = (const unsigned char *)key;
const size_t len = strlen(key);
const size_t block = len / 4;
* information.
*/
static void stat_dump_mem_contents(stat_mem_block_t *block, uint16_t cols) {
- unsigned char *buffer = mem_a(cols);
+ unsigned char *buffer = (unsigned char *)mem_a(cols);
unsigned char *memory = (unsigned char *)(block + 1);
size_t i;
}
/*
- * CRC algorithms vary in the width of the polynomial, the value of said polynomial,
- * the initial value used for the register, weather the bits of each byte are reflected
- * before being processed, weather the algorithm itself feeds input bytes through the
- * register or XORs them with a byte from one end and then straight into the table, as
- * well as (but not limited to the idea of reflected versions) where the final register
- * value becomes reversed, and finally weather the value itself is used to XOR the final
- * register value. AS such you can already imagine how painfully annoying CRCs are,
- * of course we stand to target Quake, which expects it's certain set of rules for proper
- * calculation of a CRC.
- *
- * In most traditional CRC algorithms on uses a reflected table driven method where a value
- * or register is reflected if it's bits are swapped around it's center. For example:
- * take the bits 0101 is the 4-bit reflection of 1010, and respectfully 0011 would be the
- * reflection of 1100. Quake however expects a NON-Reflected CRC on the output, but still
- * requires a final XOR on the values (0xFFFF and 0x0000) this is a standard CCITT CRC-16
- * which I respectfully as a programmer don't agree with.
+* Based On:
+* Slicing-by-8 algorithms by Michael E.
+* Kounavis and Frank L. Berry from Intel Corp.
+* http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
+*
+* This code was made to be slightly less confusing with macros, which
+* I suppose is somewhat ironic.
+*
+* The code had to be changed for non reflected on the output register
+* since that's the method Quake uses.
+*
+* The code also had to be changed for CRC16, which is slightly harder
+* since the CRC32 method in the original Intel paper used a different
+* bit order convention.
+*
+* Notes about the table:
+* - It's exactly 4K in size
+* - 64 elements fit in a cache line
+* - can do 8 iterations unrolled 8 times for free
+* - The first 256 elements of the table are standard CRC16 table
+*
+* Table can be generated with the following utility:
+*/
+#if 0
+#include <stdio.h>
+#include <stdint.h>
+int main(void) {
+ for (unsigned i = 0; i < 0x100; ++i) {
+ uint16_t x = i << 8;
+ for (int j = 0; j < 8; ++j)
+ x = (x << 1) ^ ((x & 0x8000) ? 0x1021 : 0);
+ tab[0][i] = x;
+ }
+ for (unsigned i = 0; i < 0x100; ++i) {
+ uint16_t c = tab[0][i];
+ for (unsigned j = 1; j < 8; ++j) {
+ c = tab[0][c >> 8] ^ (c << 8);
+ tab[j][i] = c;
+ }
+ }
+ printf("static const uint16_t util_crc16_table[8][256] = {");
+ for (int i = 0; i < 8; ++i) {
+ printf("{\n");
+ for (int j = 0; j < 0x100; ++j) {
+ printf((j & 7) ? " " : " ");
+ printf((j != 0x100-1) ? "0x%04X," : "0x%04X", tab[i][j]);
+ if ((j & 7) == 7)
+ printf("\n");
+ }
+ printf((i != 7) ? "}," : "}");
+ }
+ printf("};\n");
+ return 0;
+}
+#endif
+/*
+ * Non-Reflective version is present as well as a reference.
*
- * So now you know what we target, and why we target it, despite how unsettling it may seem
- * but those are what Quake seems to request.
+ * TODO:
+ * combine the crc16 into u32s and mask off low high for byte order
+ * to make the arrays smaller.
*/
-static const uint16_t util_crc16_table[] = {
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
- 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
- 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
- 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
- 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
- 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
- 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
- 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
- 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
- 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
- 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
- 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
- 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
- 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
- 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
- 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
- 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
- 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
- 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
- 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
- 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
- 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
- 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
- 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
- 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
- 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
- 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
-};
+static const uint16_t util_crc16_table[8][256] = {{
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+},{
+ 0x0000, 0x3331, 0x6662, 0x5553, 0xCCC4, 0xFFF5, 0xAAA6, 0x9997,
+ 0x89A9, 0xBA98, 0xEFCB, 0xDCFA, 0x456D, 0x765C, 0x230F, 0x103E,
+ 0x0373, 0x3042, 0x6511, 0x5620, 0xCFB7, 0xFC86, 0xA9D5, 0x9AE4,
+ 0x8ADA, 0xB9EB, 0xECB8, 0xDF89, 0x461E, 0x752F, 0x207C, 0x134D,
+ 0x06E6, 0x35D7, 0x6084, 0x53B5, 0xCA22, 0xF913, 0xAC40, 0x9F71,
+ 0x8F4F, 0xBC7E, 0xE92D, 0xDA1C, 0x438B, 0x70BA, 0x25E9, 0x16D8,
+ 0x0595, 0x36A4, 0x63F7, 0x50C6, 0xC951, 0xFA60, 0xAF33, 0x9C02,
+ 0x8C3C, 0xBF0D, 0xEA5E, 0xD96F, 0x40F8, 0x73C9, 0x269A, 0x15AB,
+ 0x0DCC, 0x3EFD, 0x6BAE, 0x589F, 0xC108, 0xF239, 0xA76A, 0x945B,
+ 0x8465, 0xB754, 0xE207, 0xD136, 0x48A1, 0x7B90, 0x2EC3, 0x1DF2,
+ 0x0EBF, 0x3D8E, 0x68DD, 0x5BEC, 0xC27B, 0xF14A, 0xA419, 0x9728,
+ 0x8716, 0xB427, 0xE174, 0xD245, 0x4BD2, 0x78E3, 0x2DB0, 0x1E81,
+ 0x0B2A, 0x381B, 0x6D48, 0x5E79, 0xC7EE, 0xF4DF, 0xA18C, 0x92BD,
+ 0x8283, 0xB1B2, 0xE4E1, 0xD7D0, 0x4E47, 0x7D76, 0x2825, 0x1B14,
+ 0x0859, 0x3B68, 0x6E3B, 0x5D0A, 0xC49D, 0xF7AC, 0xA2FF, 0x91CE,
+ 0x81F0, 0xB2C1, 0xE792, 0xD4A3, 0x4D34, 0x7E05, 0x2B56, 0x1867,
+ 0x1B98, 0x28A9, 0x7DFA, 0x4ECB, 0xD75C, 0xE46D, 0xB13E, 0x820F,
+ 0x9231, 0xA100, 0xF453, 0xC762, 0x5EF5, 0x6DC4, 0x3897, 0x0BA6,
+ 0x18EB, 0x2BDA, 0x7E89, 0x4DB8, 0xD42F, 0xE71E, 0xB24D, 0x817C,
+ 0x9142, 0xA273, 0xF720, 0xC411, 0x5D86, 0x6EB7, 0x3BE4, 0x08D5,
+ 0x1D7E, 0x2E4F, 0x7B1C, 0x482D, 0xD1BA, 0xE28B, 0xB7D8, 0x84E9,
+ 0x94D7, 0xA7E6, 0xF2B5, 0xC184, 0x5813, 0x6B22, 0x3E71, 0x0D40,
+ 0x1E0D, 0x2D3C, 0x786F, 0x4B5E, 0xD2C9, 0xE1F8, 0xB4AB, 0x879A,
+ 0x97A4, 0xA495, 0xF1C6, 0xC2F7, 0x5B60, 0x6851, 0x3D02, 0x0E33,
+ 0x1654, 0x2565, 0x7036, 0x4307, 0xDA90, 0xE9A1, 0xBCF2, 0x8FC3,
+ 0x9FFD, 0xACCC, 0xF99F, 0xCAAE, 0x5339, 0x6008, 0x355B, 0x066A,
+ 0x1527, 0x2616, 0x7345, 0x4074, 0xD9E3, 0xEAD2, 0xBF81, 0x8CB0,
+ 0x9C8E, 0xAFBF, 0xFAEC, 0xC9DD, 0x504A, 0x637B, 0x3628, 0x0519,
+ 0x10B2, 0x2383, 0x76D0, 0x45E1, 0xDC76, 0xEF47, 0xBA14, 0x8925,
+ 0x991B, 0xAA2A, 0xFF79, 0xCC48, 0x55DF, 0x66EE, 0x33BD, 0x008C,
+ 0x13C1, 0x20F0, 0x75A3, 0x4692, 0xDF05, 0xEC34, 0xB967, 0x8A56,
+ 0x9A68, 0xA959, 0xFC0A, 0xCF3B, 0x56AC, 0x659D, 0x30CE, 0x03FF
+},{
+ 0x0000, 0x3730, 0x6E60, 0x5950, 0xDCC0, 0xEBF0, 0xB2A0, 0x8590,
+ 0xA9A1, 0x9E91, 0xC7C1, 0xF0F1, 0x7561, 0x4251, 0x1B01, 0x2C31,
+ 0x4363, 0x7453, 0x2D03, 0x1A33, 0x9FA3, 0xA893, 0xF1C3, 0xC6F3,
+ 0xEAC2, 0xDDF2, 0x84A2, 0xB392, 0x3602, 0x0132, 0x5862, 0x6F52,
+ 0x86C6, 0xB1F6, 0xE8A6, 0xDF96, 0x5A06, 0x6D36, 0x3466, 0x0356,
+ 0x2F67, 0x1857, 0x4107, 0x7637, 0xF3A7, 0xC497, 0x9DC7, 0xAAF7,
+ 0xC5A5, 0xF295, 0xABC5, 0x9CF5, 0x1965, 0x2E55, 0x7705, 0x4035,
+ 0x6C04, 0x5B34, 0x0264, 0x3554, 0xB0C4, 0x87F4, 0xDEA4, 0xE994,
+ 0x1DAD, 0x2A9D, 0x73CD, 0x44FD, 0xC16D, 0xF65D, 0xAF0D, 0x983D,
+ 0xB40C, 0x833C, 0xDA6C, 0xED5C, 0x68CC, 0x5FFC, 0x06AC, 0x319C,
+ 0x5ECE, 0x69FE, 0x30AE, 0x079E, 0x820E, 0xB53E, 0xEC6E, 0xDB5E,
+ 0xF76F, 0xC05F, 0x990F, 0xAE3F, 0x2BAF, 0x1C9F, 0x45CF, 0x72FF,
+ 0x9B6B, 0xAC5B, 0xF50B, 0xC23B, 0x47AB, 0x709B, 0x29CB, 0x1EFB,
+ 0x32CA, 0x05FA, 0x5CAA, 0x6B9A, 0xEE0A, 0xD93A, 0x806A, 0xB75A,
+ 0xD808, 0xEF38, 0xB668, 0x8158, 0x04C8, 0x33F8, 0x6AA8, 0x5D98,
+ 0x71A9, 0x4699, 0x1FC9, 0x28F9, 0xAD69, 0x9A59, 0xC309, 0xF439,
+ 0x3B5A, 0x0C6A, 0x553A, 0x620A, 0xE79A, 0xD0AA, 0x89FA, 0xBECA,
+ 0x92FB, 0xA5CB, 0xFC9B, 0xCBAB, 0x4E3B, 0x790B, 0x205B, 0x176B,
+ 0x7839, 0x4F09, 0x1659, 0x2169, 0xA4F9, 0x93C9, 0xCA99, 0xFDA9,
+ 0xD198, 0xE6A8, 0xBFF8, 0x88C8, 0x0D58, 0x3A68, 0x6338, 0x5408,
+ 0xBD9C, 0x8AAC, 0xD3FC, 0xE4CC, 0x615C, 0x566C, 0x0F3C, 0x380C,
+ 0x143D, 0x230D, 0x7A5D, 0x4D6D, 0xC8FD, 0xFFCD, 0xA69D, 0x91AD,
+ 0xFEFF, 0xC9CF, 0x909F, 0xA7AF, 0x223F, 0x150F, 0x4C5F, 0x7B6F,
+ 0x575E, 0x606E, 0x393E, 0x0E0E, 0x8B9E, 0xBCAE, 0xE5FE, 0xD2CE,
+ 0x26F7, 0x11C7, 0x4897, 0x7FA7, 0xFA37, 0xCD07, 0x9457, 0xA367,
+ 0x8F56, 0xB866, 0xE136, 0xD606, 0x5396, 0x64A6, 0x3DF6, 0x0AC6,
+ 0x6594, 0x52A4, 0x0BF4, 0x3CC4, 0xB954, 0x8E64, 0xD734, 0xE004,
+ 0xCC35, 0xFB05, 0xA255, 0x9565, 0x10F5, 0x27C5, 0x7E95, 0x49A5,
+ 0xA031, 0x9701, 0xCE51, 0xF961, 0x7CF1, 0x4BC1, 0x1291, 0x25A1,
+ 0x0990, 0x3EA0, 0x67F0, 0x50C0, 0xD550, 0xE260, 0xBB30, 0x8C00,
+ 0xE352, 0xD462, 0x8D32, 0xBA02, 0x3F92, 0x08A2, 0x51F2, 0x66C2,
+ 0x4AF3, 0x7DC3, 0x2493, 0x13A3, 0x9633, 0xA103, 0xF853, 0xCF63
+},{
+ 0x0000, 0x76B4, 0xED68, 0x9BDC, 0xCAF1, 0xBC45, 0x2799, 0x512D,
+ 0x85C3, 0xF377, 0x68AB, 0x1E1F, 0x4F32, 0x3986, 0xA25A, 0xD4EE,
+ 0x1BA7, 0x6D13, 0xF6CF, 0x807B, 0xD156, 0xA7E2, 0x3C3E, 0x4A8A,
+ 0x9E64, 0xE8D0, 0x730C, 0x05B8, 0x5495, 0x2221, 0xB9FD, 0xCF49,
+ 0x374E, 0x41FA, 0xDA26, 0xAC92, 0xFDBF, 0x8B0B, 0x10D7, 0x6663,
+ 0xB28D, 0xC439, 0x5FE5, 0x2951, 0x787C, 0x0EC8, 0x9514, 0xE3A0,
+ 0x2CE9, 0x5A5D, 0xC181, 0xB735, 0xE618, 0x90AC, 0x0B70, 0x7DC4,
+ 0xA92A, 0xDF9E, 0x4442, 0x32F6, 0x63DB, 0x156F, 0x8EB3, 0xF807,
+ 0x6E9C, 0x1828, 0x83F4, 0xF540, 0xA46D, 0xD2D9, 0x4905, 0x3FB1,
+ 0xEB5F, 0x9DEB, 0x0637, 0x7083, 0x21AE, 0x571A, 0xCCC6, 0xBA72,
+ 0x753B, 0x038F, 0x9853, 0xEEE7, 0xBFCA, 0xC97E, 0x52A2, 0x2416,
+ 0xF0F8, 0x864C, 0x1D90, 0x6B24, 0x3A09, 0x4CBD, 0xD761, 0xA1D5,
+ 0x59D2, 0x2F66, 0xB4BA, 0xC20E, 0x9323, 0xE597, 0x7E4B, 0x08FF,
+ 0xDC11, 0xAAA5, 0x3179, 0x47CD, 0x16E0, 0x6054, 0xFB88, 0x8D3C,
+ 0x4275, 0x34C1, 0xAF1D, 0xD9A9, 0x8884, 0xFE30, 0x65EC, 0x1358,
+ 0xC7B6, 0xB102, 0x2ADE, 0x5C6A, 0x0D47, 0x7BF3, 0xE02F, 0x969B,
+ 0xDD38, 0xAB8C, 0x3050, 0x46E4, 0x17C9, 0x617D, 0xFAA1, 0x8C15,
+ 0x58FB, 0x2E4F, 0xB593, 0xC327, 0x920A, 0xE4BE, 0x7F62, 0x09D6,
+ 0xC69F, 0xB02B, 0x2BF7, 0x5D43, 0x0C6E, 0x7ADA, 0xE106, 0x97B2,
+ 0x435C, 0x35E8, 0xAE34, 0xD880, 0x89AD, 0xFF19, 0x64C5, 0x1271,
+ 0xEA76, 0x9CC2, 0x071E, 0x71AA, 0x2087, 0x5633, 0xCDEF, 0xBB5B,
+ 0x6FB5, 0x1901, 0x82DD, 0xF469, 0xA544, 0xD3F0, 0x482C, 0x3E98,
+ 0xF1D1, 0x8765, 0x1CB9, 0x6A0D, 0x3B20, 0x4D94, 0xD648, 0xA0FC,
+ 0x7412, 0x02A6, 0x997A, 0xEFCE, 0xBEE3, 0xC857, 0x538B, 0x253F,
+ 0xB3A4, 0xC510, 0x5ECC, 0x2878, 0x7955, 0x0FE1, 0x943D, 0xE289,
+ 0x3667, 0x40D3, 0xDB0F, 0xADBB, 0xFC96, 0x8A22, 0x11FE, 0x674A,
+ 0xA803, 0xDEB7, 0x456B, 0x33DF, 0x62F2, 0x1446, 0x8F9A, 0xF92E,
+ 0x2DC0, 0x5B74, 0xC0A8, 0xB61C, 0xE731, 0x9185, 0x0A59, 0x7CED,
+ 0x84EA, 0xF25E, 0x6982, 0x1F36, 0x4E1B, 0x38AF, 0xA373, 0xD5C7,
+ 0x0129, 0x779D, 0xEC41, 0x9AF5, 0xCBD8, 0xBD6C, 0x26B0, 0x5004,
+ 0x9F4D, 0xE9F9, 0x7225, 0x0491, 0x55BC, 0x2308, 0xB8D4, 0xCE60,
+ 0x1A8E, 0x6C3A, 0xF7E6, 0x8152, 0xD07F, 0xA6CB, 0x3D17, 0x4BA3
+},{
+ 0x0000, 0xAA51, 0x4483, 0xEED2, 0x8906, 0x2357, 0xCD85, 0x67D4,
+ 0x022D, 0xA87C, 0x46AE, 0xECFF, 0x8B2B, 0x217A, 0xCFA8, 0x65F9,
+ 0x045A, 0xAE0B, 0x40D9, 0xEA88, 0x8D5C, 0x270D, 0xC9DF, 0x638E,
+ 0x0677, 0xAC26, 0x42F4, 0xE8A5, 0x8F71, 0x2520, 0xCBF2, 0x61A3,
+ 0x08B4, 0xA2E5, 0x4C37, 0xE666, 0x81B2, 0x2BE3, 0xC531, 0x6F60,
+ 0x0A99, 0xA0C8, 0x4E1A, 0xE44B, 0x839F, 0x29CE, 0xC71C, 0x6D4D,
+ 0x0CEE, 0xA6BF, 0x486D, 0xE23C, 0x85E8, 0x2FB9, 0xC16B, 0x6B3A,
+ 0x0EC3, 0xA492, 0x4A40, 0xE011, 0x87C5, 0x2D94, 0xC346, 0x6917,
+ 0x1168, 0xBB39, 0x55EB, 0xFFBA, 0x986E, 0x323F, 0xDCED, 0x76BC,
+ 0x1345, 0xB914, 0x57C6, 0xFD97, 0x9A43, 0x3012, 0xDEC0, 0x7491,
+ 0x1532, 0xBF63, 0x51B1, 0xFBE0, 0x9C34, 0x3665, 0xD8B7, 0x72E6,
+ 0x171F, 0xBD4E, 0x539C, 0xF9CD, 0x9E19, 0x3448, 0xDA9A, 0x70CB,
+ 0x19DC, 0xB38D, 0x5D5F, 0xF70E, 0x90DA, 0x3A8B, 0xD459, 0x7E08,
+ 0x1BF1, 0xB1A0, 0x5F72, 0xF523, 0x92F7, 0x38A6, 0xD674, 0x7C25,
+ 0x1D86, 0xB7D7, 0x5905, 0xF354, 0x9480, 0x3ED1, 0xD003, 0x7A52,
+ 0x1FAB, 0xB5FA, 0x5B28, 0xF179, 0x96AD, 0x3CFC, 0xD22E, 0x787F,
+ 0x22D0, 0x8881, 0x6653, 0xCC02, 0xABD6, 0x0187, 0xEF55, 0x4504,
+ 0x20FD, 0x8AAC, 0x647E, 0xCE2F, 0xA9FB, 0x03AA, 0xED78, 0x4729,
+ 0x268A, 0x8CDB, 0x6209, 0xC858, 0xAF8C, 0x05DD, 0xEB0F, 0x415E,
+ 0x24A7, 0x8EF6, 0x6024, 0xCA75, 0xADA1, 0x07F0, 0xE922, 0x4373,
+ 0x2A64, 0x8035, 0x6EE7, 0xC4B6, 0xA362, 0x0933, 0xE7E1, 0x4DB0,
+ 0x2849, 0x8218, 0x6CCA, 0xC69B, 0xA14F, 0x0B1E, 0xE5CC, 0x4F9D,
+ 0x2E3E, 0x846F, 0x6ABD, 0xC0EC, 0xA738, 0x0D69, 0xE3BB, 0x49EA,
+ 0x2C13, 0x8642, 0x6890, 0xC2C1, 0xA515, 0x0F44, 0xE196, 0x4BC7,
+ 0x33B8, 0x99E9, 0x773B, 0xDD6A, 0xBABE, 0x10EF, 0xFE3D, 0x546C,
+ 0x3195, 0x9BC4, 0x7516, 0xDF47, 0xB893, 0x12C2, 0xFC10, 0x5641,
+ 0x37E2, 0x9DB3, 0x7361, 0xD930, 0xBEE4, 0x14B5, 0xFA67, 0x5036,
+ 0x35CF, 0x9F9E, 0x714C, 0xDB1D, 0xBCC9, 0x1698, 0xF84A, 0x521B,
+ 0x3B0C, 0x915D, 0x7F8F, 0xD5DE, 0xB20A, 0x185B, 0xF689, 0x5CD8,
+ 0x3921, 0x9370, 0x7DA2, 0xD7F3, 0xB027, 0x1A76, 0xF4A4, 0x5EF5,
+ 0x3F56, 0x9507, 0x7BD5, 0xD184, 0xB650, 0x1C01, 0xF2D3, 0x5882,
+ 0x3D7B, 0x972A, 0x79F8, 0xD3A9, 0xB47D, 0x1E2C, 0xF0FE, 0x5AAF
+},{
+ 0x0000, 0x45A0, 0x8B40, 0xCEE0, 0x06A1, 0x4301, 0x8DE1, 0xC841,
+ 0x0D42, 0x48E2, 0x8602, 0xC3A2, 0x0BE3, 0x4E43, 0x80A3, 0xC503,
+ 0x1A84, 0x5F24, 0x91C4, 0xD464, 0x1C25, 0x5985, 0x9765, 0xD2C5,
+ 0x17C6, 0x5266, 0x9C86, 0xD926, 0x1167, 0x54C7, 0x9A27, 0xDF87,
+ 0x3508, 0x70A8, 0xBE48, 0xFBE8, 0x33A9, 0x7609, 0xB8E9, 0xFD49,
+ 0x384A, 0x7DEA, 0xB30A, 0xF6AA, 0x3EEB, 0x7B4B, 0xB5AB, 0xF00B,
+ 0x2F8C, 0x6A2C, 0xA4CC, 0xE16C, 0x292D, 0x6C8D, 0xA26D, 0xE7CD,
+ 0x22CE, 0x676E, 0xA98E, 0xEC2E, 0x246F, 0x61CF, 0xAF2F, 0xEA8F,
+ 0x6A10, 0x2FB0, 0xE150, 0xA4F0, 0x6CB1, 0x2911, 0xE7F1, 0xA251,
+ 0x6752, 0x22F2, 0xEC12, 0xA9B2, 0x61F3, 0x2453, 0xEAB3, 0xAF13,
+ 0x7094, 0x3534, 0xFBD4, 0xBE74, 0x7635, 0x3395, 0xFD75, 0xB8D5,
+ 0x7DD6, 0x3876, 0xF696, 0xB336, 0x7B77, 0x3ED7, 0xF037, 0xB597,
+ 0x5F18, 0x1AB8, 0xD458, 0x91F8, 0x59B9, 0x1C19, 0xD2F9, 0x9759,
+ 0x525A, 0x17FA, 0xD91A, 0x9CBA, 0x54FB, 0x115B, 0xDFBB, 0x9A1B,
+ 0x459C, 0x003C, 0xCEDC, 0x8B7C, 0x433D, 0x069D, 0xC87D, 0x8DDD,
+ 0x48DE, 0x0D7E, 0xC39E, 0x863E, 0x4E7F, 0x0BDF, 0xC53F, 0x809F,
+ 0xD420, 0x9180, 0x5F60, 0x1AC0, 0xD281, 0x9721, 0x59C1, 0x1C61,
+ 0xD962, 0x9CC2, 0x5222, 0x1782, 0xDFC3, 0x9A63, 0x5483, 0x1123,
+ 0xCEA4, 0x8B04, 0x45E4, 0x0044, 0xC805, 0x8DA5, 0x4345, 0x06E5,
+ 0xC3E6, 0x8646, 0x48A6, 0x0D06, 0xC547, 0x80E7, 0x4E07, 0x0BA7,
+ 0xE128, 0xA488, 0x6A68, 0x2FC8, 0xE789, 0xA229, 0x6CC9, 0x2969,
+ 0xEC6A, 0xA9CA, 0x672A, 0x228A, 0xEACB, 0xAF6B, 0x618B, 0x242B,
+ 0xFBAC, 0xBE0C, 0x70EC, 0x354C, 0xFD0D, 0xB8AD, 0x764D, 0x33ED,
+ 0xF6EE, 0xB34E, 0x7DAE, 0x380E, 0xF04F, 0xB5EF, 0x7B0F, 0x3EAF,
+ 0xBE30, 0xFB90, 0x3570, 0x70D0, 0xB891, 0xFD31, 0x33D1, 0x7671,
+ 0xB372, 0xF6D2, 0x3832, 0x7D92, 0xB5D3, 0xF073, 0x3E93, 0x7B33,
+ 0xA4B4, 0xE114, 0x2FF4, 0x6A54, 0xA215, 0xE7B5, 0x2955, 0x6CF5,
+ 0xA9F6, 0xEC56, 0x22B6, 0x6716, 0xAF57, 0xEAF7, 0x2417, 0x61B7,
+ 0x8B38, 0xCE98, 0x0078, 0x45D8, 0x8D99, 0xC839, 0x06D9, 0x4379,
+ 0x867A, 0xC3DA, 0x0D3A, 0x489A, 0x80DB, 0xC57B, 0x0B9B, 0x4E3B,
+ 0x91BC, 0xD41C, 0x1AFC, 0x5F5C, 0x971D, 0xD2BD, 0x1C5D, 0x59FD,
+ 0x9CFE, 0xD95E, 0x17BE, 0x521E, 0x9A5F, 0xDFFF, 0x111F, 0x54BF
+},{
+ 0x0000, 0xB861, 0x60E3, 0xD882, 0xC1C6, 0x79A7, 0xA125, 0x1944,
+ 0x93AD, 0x2BCC, 0xF34E, 0x4B2F, 0x526B, 0xEA0A, 0x3288, 0x8AE9,
+ 0x377B, 0x8F1A, 0x5798, 0xEFF9, 0xF6BD, 0x4EDC, 0x965E, 0x2E3F,
+ 0xA4D6, 0x1CB7, 0xC435, 0x7C54, 0x6510, 0xDD71, 0x05F3, 0xBD92,
+ 0x6EF6, 0xD697, 0x0E15, 0xB674, 0xAF30, 0x1751, 0xCFD3, 0x77B2,
+ 0xFD5B, 0x453A, 0x9DB8, 0x25D9, 0x3C9D, 0x84FC, 0x5C7E, 0xE41F,
+ 0x598D, 0xE1EC, 0x396E, 0x810F, 0x984B, 0x202A, 0xF8A8, 0x40C9,
+ 0xCA20, 0x7241, 0xAAC3, 0x12A2, 0x0BE6, 0xB387, 0x6B05, 0xD364,
+ 0xDDEC, 0x658D, 0xBD0F, 0x056E, 0x1C2A, 0xA44B, 0x7CC9, 0xC4A8,
+ 0x4E41, 0xF620, 0x2EA2, 0x96C3, 0x8F87, 0x37E6, 0xEF64, 0x5705,
+ 0xEA97, 0x52F6, 0x8A74, 0x3215, 0x2B51, 0x9330, 0x4BB2, 0xF3D3,
+ 0x793A, 0xC15B, 0x19D9, 0xA1B8, 0xB8FC, 0x009D, 0xD81F, 0x607E,
+ 0xB31A, 0x0B7B, 0xD3F9, 0x6B98, 0x72DC, 0xCABD, 0x123F, 0xAA5E,
+ 0x20B7, 0x98D6, 0x4054, 0xF835, 0xE171, 0x5910, 0x8192, 0x39F3,
+ 0x8461, 0x3C00, 0xE482, 0x5CE3, 0x45A7, 0xFDC6, 0x2544, 0x9D25,
+ 0x17CC, 0xAFAD, 0x772F, 0xCF4E, 0xD60A, 0x6E6B, 0xB6E9, 0x0E88,
+ 0xABF9, 0x1398, 0xCB1A, 0x737B, 0x6A3F, 0xD25E, 0x0ADC, 0xB2BD,
+ 0x3854, 0x8035, 0x58B7, 0xE0D6, 0xF992, 0x41F3, 0x9971, 0x2110,
+ 0x9C82, 0x24E3, 0xFC61, 0x4400, 0x5D44, 0xE525, 0x3DA7, 0x85C6,
+ 0x0F2F, 0xB74E, 0x6FCC, 0xD7AD, 0xCEE9, 0x7688, 0xAE0A, 0x166B,
+ 0xC50F, 0x7D6E, 0xA5EC, 0x1D8D, 0x04C9, 0xBCA8, 0x642A, 0xDC4B,
+ 0x56A2, 0xEEC3, 0x3641, 0x8E20, 0x9764, 0x2F05, 0xF787, 0x4FE6,
+ 0xF274, 0x4A15, 0x9297, 0x2AF6, 0x33B2, 0x8BD3, 0x5351, 0xEB30,
+ 0x61D9, 0xD9B8, 0x013A, 0xB95B, 0xA01F, 0x187E, 0xC0FC, 0x789D,
+ 0x7615, 0xCE74, 0x16F6, 0xAE97, 0xB7D3, 0x0FB2, 0xD730, 0x6F51,
+ 0xE5B8, 0x5DD9, 0x855B, 0x3D3A, 0x247E, 0x9C1F, 0x449D, 0xFCFC,
+ 0x416E, 0xF90F, 0x218D, 0x99EC, 0x80A8, 0x38C9, 0xE04B, 0x582A,
+ 0xD2C3, 0x6AA2, 0xB220, 0x0A41, 0x1305, 0xAB64, 0x73E6, 0xCB87,
+ 0x18E3, 0xA082, 0x7800, 0xC061, 0xD925, 0x6144, 0xB9C6, 0x01A7,
+ 0x8B4E, 0x332F, 0xEBAD, 0x53CC, 0x4A88, 0xF2E9, 0x2A6B, 0x920A,
+ 0x2F98, 0x97F9, 0x4F7B, 0xF71A, 0xEE5E, 0x563F, 0x8EBD, 0x36DC,
+ 0xBC35, 0x0454, 0xDCD6, 0x64B7, 0x7DF3, 0xC592, 0x1D10, 0xA571
+},{
+ 0x0000, 0x47D3, 0x8FA6, 0xC875, 0x0F6D, 0x48BE, 0x80CB, 0xC718,
+ 0x1EDA, 0x5909, 0x917C, 0xD6AF, 0x11B7, 0x5664, 0x9E11, 0xD9C2,
+ 0x3DB4, 0x7A67, 0xB212, 0xF5C1, 0x32D9, 0x750A, 0xBD7F, 0xFAAC,
+ 0x236E, 0x64BD, 0xACC8, 0xEB1B, 0x2C03, 0x6BD0, 0xA3A5, 0xE476,
+ 0x7B68, 0x3CBB, 0xF4CE, 0xB31D, 0x7405, 0x33D6, 0xFBA3, 0xBC70,
+ 0x65B2, 0x2261, 0xEA14, 0xADC7, 0x6ADF, 0x2D0C, 0xE579, 0xA2AA,
+ 0x46DC, 0x010F, 0xC97A, 0x8EA9, 0x49B1, 0x0E62, 0xC617, 0x81C4,
+ 0x5806, 0x1FD5, 0xD7A0, 0x9073, 0x576B, 0x10B8, 0xD8CD, 0x9F1E,
+ 0xF6D0, 0xB103, 0x7976, 0x3EA5, 0xF9BD, 0xBE6E, 0x761B, 0x31C8,
+ 0xE80A, 0xAFD9, 0x67AC, 0x207F, 0xE767, 0xA0B4, 0x68C1, 0x2F12,
+ 0xCB64, 0x8CB7, 0x44C2, 0x0311, 0xC409, 0x83DA, 0x4BAF, 0x0C7C,
+ 0xD5BE, 0x926D, 0x5A18, 0x1DCB, 0xDAD3, 0x9D00, 0x5575, 0x12A6,
+ 0x8DB8, 0xCA6B, 0x021E, 0x45CD, 0x82D5, 0xC506, 0x0D73, 0x4AA0,
+ 0x9362, 0xD4B1, 0x1CC4, 0x5B17, 0x9C0F, 0xDBDC, 0x13A9, 0x547A,
+ 0xB00C, 0xF7DF, 0x3FAA, 0x7879, 0xBF61, 0xF8B2, 0x30C7, 0x7714,
+ 0xAED6, 0xE905, 0x2170, 0x66A3, 0xA1BB, 0xE668, 0x2E1D, 0x69CE,
+ 0xFD81, 0xBA52, 0x7227, 0x35F4, 0xF2EC, 0xB53F, 0x7D4A, 0x3A99,
+ 0xE35B, 0xA488, 0x6CFD, 0x2B2E, 0xEC36, 0xABE5, 0x6390, 0x2443,
+ 0xC035, 0x87E6, 0x4F93, 0x0840, 0xCF58, 0x888B, 0x40FE, 0x072D,
+ 0xDEEF, 0x993C, 0x5149, 0x169A, 0xD182, 0x9651, 0x5E24, 0x19F7,
+ 0x86E9, 0xC13A, 0x094F, 0x4E9C, 0x8984, 0xCE57, 0x0622, 0x41F1,
+ 0x9833, 0xDFE0, 0x1795, 0x5046, 0x975E, 0xD08D, 0x18F8, 0x5F2B,
+ 0xBB5D, 0xFC8E, 0x34FB, 0x7328, 0xB430, 0xF3E3, 0x3B96, 0x7C45,
+ 0xA587, 0xE254, 0x2A21, 0x6DF2, 0xAAEA, 0xED39, 0x254C, 0x629F,
+ 0x0B51, 0x4C82, 0x84F7, 0xC324, 0x043C, 0x43EF, 0x8B9A, 0xCC49,
+ 0x158B, 0x5258, 0x9A2D, 0xDDFE, 0x1AE6, 0x5D35, 0x9540, 0xD293,
+ 0x36E5, 0x7136, 0xB943, 0xFE90, 0x3988, 0x7E5B, 0xB62E, 0xF1FD,
+ 0x283F, 0x6FEC, 0xA799, 0xE04A, 0x2752, 0x6081, 0xA8F4, 0xEF27,
+ 0x7039, 0x37EA, 0xFF9F, 0xB84C, 0x7F54, 0x3887, 0xF0F2, 0xB721,
+ 0x6EE3, 0x2930, 0xE145, 0xA696, 0x618E, 0x265D, 0xEE28, 0xA9FB,
+ 0x4D8D, 0x0A5E, 0xC22B, 0x85F8, 0x42E0, 0x0533, 0xCD46, 0x8A95,
+ 0x5357, 0x1484, 0xDCF1, 0x9B22, 0x5C3A, 0x1BE9, 0xD39C, 0x944F
+}};
/* Non - Reflected */
-uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
+uint16_t util_crc16(uint16_t current, const char *GMQCC_RESTRICT k, size_t len) {
register uint16_t h = current;
- for (; len; --len, ++k)
- h = util_crc16_table[(h>>8)^((unsigned char)*k)]^(h<<8);
+
+ /* don't load twice */
+ const uint8_t *GMQCC_RESTRICT data = (const uint8_t *GMQCC_RESTRICT)k;
+ size_t n;
+
+ /* deal with the first bytes as bytes until we reach an 8 byte boundary */
+ while (len & 7) {
+ h = (uint16_t)(h << 8) ^ (*util_crc16_table)[(h >> 8) ^ *data++];
+ --len;
+ }
+
+ #define SELECT_BULK(X, MOD) util_crc16_table[(X)][data[7-(X)] ^ (MOD)]
+ #define SELECT_DATA(X) util_crc16_table[(X)][data[7-(X)]]
+
+ for (n = len / 8; n; --n) {
+ h = SELECT_BULK(7, (h >> 8)) ^
+ SELECT_BULK(6, (h & 0xFF)) ^
+ SELECT_DATA(5) ^
+ SELECT_DATA(4) ^
+ SELECT_DATA(3) ^
+ SELECT_DATA(2) ^
+ SELECT_DATA(1) ^
+ SELECT_DATA(0);
+ data += 8;
+ len -= 8;
+ }
+
+ #undef SELECT_BULK
+ #undef SELECT_DATA
+
+ /* deal with the rest with the byte method */
+ for (n = len & 7; n; --n)
+ h = (uint16_t)(h << 8) ^ (*util_crc16_table)[(h >> 8) ^ *data++];
+
return h;
}
-/* Reflective Variation (for reference) */
-#if 0
-uint16_t util_crc16(const char *k, int len, const short clamp) {
- register uint16_t h= (uint16_t)0xFFFFFFFF;
- for (; len; --len, ++k)
- h = util_crc16_table[(h^((unsigned char)*k))&0xFF]^(h>>8);
- return (~h)%clamp;
-}
-#endif
/*
* modifier is the match to make and the transposition from it, while add is the upper-value that determines the
* transposition from uppercase to lower case.
*/
-static GMQCC_INLINE size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
+static size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
size_t sz = 1;
for (; *in && sz < outsz; ++in, ++out, ++sz) {
*out = (*in == mod[0])