More compiler intrinsics for math functions

This commit is contained in:
Dale Weiler 2013-11-23 21:14:13 -05:00
parent 87a43777ab
commit 63c0917d24
2 changed files with 598 additions and 273 deletions

90
fold.c
View file

@ -701,51 +701,69 @@ ast_expression *fold_op(fold_t *fold, const oper_info *info, ast_expression **op
* 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, isinff(fold_immvalue_float(a)));
}
static GMQCC_INLINE ast_expression *fold_intrin_isnan(fold_t *fold, ast_value *a) {
return fold_constgen_float(fold, isnanf(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)
)
);
return fold_constgen_float(fold, powf(fold_immvalue_float(lhs), fold_immvalue_float(rhs)));
}
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_exp(fold_t *fold, ast_value *value) {
return fold_constgen_float(fold, exp(fold_immvalue_float(value)));
}
static GMQCC_INLINE ast_expression *fold_intrin_exp2(fold_t *fold, ast_value *value) {
return fold_constgen_float(fold, pow(2, fold_immvalue_float(value)));
}
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 *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;
ast_value *a = (ast_value*)arg[0];
ast_value *b = (ast_value*)arg[1];
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, "exp2")) ret = fold_intrin_exp2 (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]);
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];

781
intrin.c
View file

@ -77,6 +77,540 @@ static ast_expression *intrin_nullfunc(intrin_t *intrin) {
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, NULL, 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); /* {{{ 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*)fold_constgen_float(intrin->fold, 2.0f));
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) {
/*
*
@ -612,242 +1146,7 @@ static ast_expression *intrin_mod(intrin_t *intrin) {
)
);
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) {
* 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, "mexp", 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); /* {{{ 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*)fold_constgen_float(intrin->fold, 2.0f));
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_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;
@ -903,14 +1202,22 @@ ast_expression *intrin_debug_typestring(intrin_t *intrin) {
}
static const intrin_func_t intrinsics[] = {
{&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_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}
};