X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=intrin.c;h=74d952cfacb496f332e7399de2540d52bb9a598e;hb=23904bad5209112dcfd08224b6cf5fc06b523e56;hp=0ab278986bbbb7483e361eade69f98d6cbe05cff;hpb=e2bfaf8109631880ec25cc23d4ce36f4d05e1485;p=xonotic%2Fgmqcc.git diff --git a/intrin.c b/intrin.c index 0ab2789..74d952c 100644 --- a/intrin.c +++ b/intrin.c @@ -58,7 +58,6 @@ static GMQCC_INLINE void intrin_reg(intrin_t *intrin, ast_value *const value, as vec_push(intrin->parser->globals, (ast_expression*)value); } -#define QC_M_E 2.718281828459045f #define QC_POW_EPSILON 0.00001f /* @@ -90,6 +89,8 @@ static ast_expression *intrin_pow(intrin_t *intrin) { * float accumulate; * * if (exp == 0.0) + * return 1; + * if (exp == 1.0) * return base; * if (exp < 0) * return 1.0 / pow(base, -exp); @@ -122,8 +123,8 @@ static ast_expression *intrin_pow(intrin_t *intrin) { 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) */ @@ -166,7 +167,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { /* * if (exp == 0.0) - * return base; + * return 1; */ vec_push(body->exprs, (ast_expression*)ast_ifthen_new( @@ -177,6 +178,27 @@ static ast_expression *intrin_pow(intrin_t *intrin) { (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 @@ -484,7 +506,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { ) ); - /* return midvalue */ + /* return accumulate */ vec_push(body->exprs, (ast_expression*)ast_return_new( intrin_ctx(intrin), @@ -599,45 +621,107 @@ static ast_expression *intrin_mod(intrin_t *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 / 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 ) ); @@ -678,6 +762,52 @@ static ast_expression *intrin_exp2(intrin_t *intrin) { 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) { @@ -778,6 +908,7 @@ static const intrin_func_t intrinsics[] = { {&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} @@ -855,12 +986,11 @@ static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, cons 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) {