vec_push(intrin->parser->globals, (ast_expression*)value);
}
-#define QC_M_E 2.718281828459045f
#define QC_POW_EPSILON 0.00001f
/*
* float accumulate;
*
* if (exp == 0.0)
+ * return 1;
+ * if (exp == 1.0)
* return base;
* if (exp < 0)
* return 1.0 / pow(base, -exp);
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 *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) */
/*
* if (exp == 0.0)
- * return base;
+ * return 1;
*/
vec_push(body->exprs,
(ast_expression*)ast_ifthen_new(
(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
)
);
- /* return midvalue */
+ /* return accumulate */
vec_push(body->exprs,
(ast_expression*)ast_return_new(
intrin_ctx(intrin),
static ast_expression *intrin_exp(intrin_t *intrin) {
/*
* float exp(float x) {
- * // mul 10 to round increments of 0.1f
- * return floor((pow(QC_M_E, x) * 10) + 0.5) / 10;
+ * 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_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", "exp"));
- ast_call *callfloor = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", "exp"));
- 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);
+ 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, "mexp", TYPE_FLOAT);
- vec_push(value->expression.params, arg1);
+ vec_push(value->expression.params, x);
+ vec_push(body->locals, sum);
+ vec_push(body->locals, acc);
+ vec_push(body->locals, i);
- vec_push(callpow->params, (ast_expression*)fold_constgen_float(intrin->fold, QC_M_E));
- vec_push(callpow->params, (ast_expression*)arg1);
- vec_push(callfloor->params,
- (ast_expression*)ast_binary_new(
+ /* 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_ADD_F,
+ 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_MUL_F,
- (ast_expression*)callpow,
- (ast_expression*)fold_constgen_float(intrin->fold, 10.0f)
+ 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]
),
- (ast_expression*)fold_constgen_float(intrin->fold, 0.5f)
+ /* 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 <callfloor> / 10.0f */
+ /* return sum; */
vec_push(body->exprs,
(ast_expression*)ast_return_new(
intrin_ctx(intrin),
- (ast_expression*)ast_binary_new(
- intrin_ctx(intrin),
- INSTR_DIV_F,
- (ast_expression*)callfloor,
- (ast_expression*)fold_constgen_float(intrin->fold, 10.0f)
- )
+ (ast_expression*)sum
)
);
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) {
{&intrin_mod, "__builtin_mod", "mod", 2},
{&intrin_pow, "__builtin_pow", "pow", 2},
{&intrin_isnan, "__builtin_isnan", "isnan", 1},
+ {&intrin_isinf, "__builtin_isinf", "isinf", 1},
{&intrin_fabs, "__builtin_fabs", "fabs", 1},
{&intrin_debug_typestring, "__builtin_debug_typestring", "", 0},
{&intrin_nullfunc, "#nullfunc", "", 0}
if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, alias), name)))
return find;
- if (from)
+ if (from) {
intrin_error(intrin, "need function `%s', compiler depends on it for `__builtin_%s'", name, from);
- else
- intrin_error(intrin, "need function `%s', compiler depends on it", name);
-
- return intrin_func(intrin, "#nullfunc");
+ return intrin_func_self(intrin, "#nullfunc", NULL);
+ }
+ return NULL;
}
ast_expression *intrin_func(intrin_t *intrin, const char *name) {