X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=intrin.c;h=9ddb1a2670ad0d2356e2bc795fb796df0e73b969;hp=f7975eb58342f44add16a40b12e367d099c2e533;hb=41a76ab91dc6f872b03cd64f51aba86578f330c0;hpb=f19d32b29b165ee24dc26fc1638763b41b0b6c69 diff --git a/intrin.c b/intrin.c index f7975eb..9ddb1a2 100644 --- a/intrin.c +++ b/intrin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 + * Copyright (C) 2012, 2013, 2014, 2015 * Dale Weiler * * Permission is hereby granted, free of charge, to any person obtaining a copy of @@ -422,7 +422,7 @@ static ast_expression *intrin_atanh(intrin_t *intrin) { (ast_expression*)ast_binary_new( intrin_ctx(intrin), INSTR_MUL_F, - (ast_expression*)fold_constgen_float(intrin->fold, 0.5), + (ast_expression*)fold_constgen_float(intrin->fold, 0.5, false), (ast_expression*)calllog ) ); @@ -496,7 +496,7 @@ static ast_expression *intrin_exp(intrin_t *intrin) { intrin_ctx(intrin), INSTR_LT, (ast_expression*)i, - (ast_expression*)fold_constgen_float(intrin->fold, 200.0f) + (ast_expression*)fold_constgen_float(intrin->fold, 200.0f, false) ), false, NULL, @@ -1027,7 +1027,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { intrin_ctx(intrin), INSTR_GT, (ast_expression*)callfabs, - (ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON) + (ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON, false) ), /* pre not */ false, @@ -1310,7 +1310,7 @@ static ast_expression *intrin_nan(intrin_t *intrin) { static ast_expression *intrin_inf(intrin_t *intrin) { /* - * float nan(void) { + * float inf(void) { * float x = 1.0f; * float y = 0.0f; * return x / y; @@ -1379,7 +1379,6 @@ static ast_expression *intrin_ln(intrin_t *intrin) { * } * } * - * float out; * float A_i = 1; * float B_i = 0; * float A_iminus1 = 0; @@ -1390,8 +1389,18 @@ static ast_expression *intrin_ln(intrin_t *intrin) { * nth = 0.0f; * * while (whole >= base) { - * whole /= base; - * nth++; + * 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; @@ -1419,7 +1428,6 @@ static ast_expression *intrin_ln(intrin_t *intrin) { 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 *out = ast_value_new(intrin_ctx(intrin), "out", 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); @@ -1428,12 +1436,16 @@ static ast_expression *intrin_ln(intrin_t *intrin) { 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; @@ -1444,7 +1456,6 @@ static ast_expression *intrin_ln(intrin_t *intrin) { vec_push(block->locals, nth); vec_push(block->locals, sign); vec_push(block->locals, eps); - vec_push(block->locals, out); vec_push(block->locals, A_i); vec_push(block->locals, B_i); vec_push(block->locals, A_iminus1); @@ -1608,25 +1619,116 @@ static ast_expression *intrin_ln(intrin_t *intrin) { ) ); - /* whole /= base; */ + /* base2 = base; */ + vec_push(whileloop->exprs, + (ast_expression*)ast_store_new( + intrin_ctx(intrin), + INSTR_STORE_F, + (ast_expression*)base2, + (ast_expression*)base + ) + ); + + /* n2 = 1.0f; */ + vec_push(whileloop->exprs, + (ast_expression*)ast_store_new( + intrin_ctx(intrin), + INSTR_STORE_F, + (ast_expression*)n2, + (ast_expression*)intrin->fold->imm_float[1] + ) + ); + + /* 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 + ) + ) + ); + + /* while loop locals */ + vec_push(whileloop->locals, base2); + vec_push(whileloop->locals, n2); + vec_push(whileloop->locals, newbase2); + + /* base2 = newbase2; */ + vec_push(nestwhile->exprs, + (ast_expression*)ast_store_new( + intrin_ctx(intrin), + INSTR_STORE_F, + (ast_expression*)base2, + (ast_expression*)newbase2 + ) + ); + + /* 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 */ + ) + ); + + /* newbase2 *= newbase2; */ + vec_push(nestwhile->exprs, + (ast_expression*)ast_binstore_new( + intrin_ctx(intrin), + INSTR_STORE_F, + INSTR_MUL_F, + (ast_expression*)newbase2, + (ast_expression*)newbase2 + ) + ); + + /* 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_GE, + (ast_expression*)whole, + (ast_expression*)newbase2 + ), + false, + NULL, + false, + NULL, + (ast_expression*)nestwhile + ) + ); + + /* whole /= base2; */ vec_push(whileloop->exprs, (ast_expression*)ast_binstore_new( intrin_ctx(intrin), INSTR_STORE_F, INSTR_DIV_F, (ast_expression*)whole, - (ast_expression*)base + (ast_expression*)base2 ) ); - /* nth ++; */ + /* nth += n2; */ vec_push(whileloop->exprs, (ast_expression*)ast_binstore_new( intrin_ctx(intrin), INSTR_STORE_F, INSTR_ADD_F, (ast_expression*)nth, - (ast_expression*)intrin->fold->imm_float[1] + (ast_expression*)n2 ) ); @@ -1799,31 +1901,95 @@ static ast_expression *intrin_ln(intrin_t *intrin) { 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; \ +static ast_expression *intrin_log_variant(intrin_t *intrin, const char *name, float base) { + 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, false)); + + 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; +} + +static ast_expression *intrin_log(intrin_t *intrin) { + return intrin_log_variant(intrin, "log", 2.7182818284590452354); +} +static ast_expression *intrin_log10(intrin_t *intrin) { + return intrin_log_variant(intrin, "log10", 10); +} +static ast_expression *intrin_log2(intrin_t *intrin) { + return intrin_log_variant(intrin, "log2", 2); +} +static ast_expression *intrin_logb(intrin_t *intrin) { + /* FLT_RADIX == 2 for now */ + return intrin_log_variant(intrin, "log2", 2); +} + +static ast_expression *intrin_shift_variant(intrin_t *intrin, const char *name, size_t instr) { + /* + * float [shift] (float a, float b) { + * return floor(a [instr] pow(2, b)); + */ + ast_value *value = NULL; + ast_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", name)); + ast_call *callfloor = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", name)); + 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_block *body = ast_block_new(intrin_ctx(intrin)); + ast_function *func = intrin_value(intrin, &value, name, TYPE_FLOAT); + + vec_push(value->expression.params, a); + vec_push(value->expression.params, b); + + /* = pow(2, b) */ + vec_push(callpow->params, (ast_expression*)intrin->fold->imm_float[3]); + vec_push(callpow->params, (ast_expression*)b); + + /* = floor(a [instr] ) */ + vec_push( + callfloor->params, + (ast_expression*)ast_binary_new( + intrin_ctx(intrin), + instr, + (ast_expression*)a, + (ast_expression*)callpow + ) + ); + + /* return */ + vec_push(body->exprs, + (ast_expression*)ast_return_new( + intrin_ctx(intrin), + (ast_expression*)callfloor + ) + ); + + vec_push(func->blocks, body); + intrin_reg(intrin, value, func); + return (ast_expression*)value; +} + +static ast_expression *intrin_lshift(intrin_t *intrin) { + return intrin_shift_variant(intrin, "lshift", INSTR_MUL_F); +} + +static ast_expression *intrin_rshift(intrin_t *intrin) { + return intrin_shift_variant(intrin, "rshift", INSTR_DIV_F); } -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 @@ -1849,14 +2015,16 @@ static const intrin_func_t intrinsics[] = { {&intrin_mod, "__builtin_mod", "mod", 2}, {&intrin_pow, "__builtin_pow", "pow", 2}, {&intrin_fabs, "__builtin_fabs", "fabs", 1}, - {&intrin_epsilon, "__builtin_epsilon", "", 0}, - {&intrin_nan, "__builtin_nan", "", 0}, - {&intrin_inf, "__builtin_inf", "", 0}, - {&intrin_ln, "__builtin_ln", "", 2}, {&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_lshift, "__builtin_lshift", "", 2}, + {&intrin_rshift, "__builtin_rshift", "", 2}, + {&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} };