X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=intrin.c;h=c1b84ed230c9165619bdcca9f8461b5589125271;hp=a6d35209e00ca128a07ec69da28825d54255112b;hb=641136fee3e2f589f93ad6a7b3213b0247107303;hpb=50d1bfe7830291743498124f65c991ca060f28ed diff --git a/intrin.c b/intrin.c index a6d3520..c1b84ed 100644 --- a/intrin.c +++ b/intrin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 + * Copyright (C) 2012, 2013, 2014 * 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, @@ -539,7 +539,7 @@ static ast_expression *intrin_exp(intrin_t *intrin) { ) ); - vec_push(func->blocks, body); /* {{{ body }}} */ + vec_push(func->blocks, body); intrin_reg(intrin, value, func); return (ast_expression*)value; @@ -559,7 +559,7 @@ static ast_expression *intrin_exp2(intrin_t *intrin) { 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*)intrin->fold->imm_float[3]); vec_push(callpow->params, (ast_expression*)arg1); /* return */ @@ -784,7 +784,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { intrin_ctx(intrin), INSTR_DIV_F, (ast_expression*)exp, - (ast_expression*)fold_constgen_float(intrin->fold, 2.0f) + (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */ ) ); @@ -860,6 +860,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { (ast_expression*)intrin->fold->imm_float[1] ) ); + vec_push(body->exprs, (ast_expression*)ast_store_new( intrin_ctx(intrin), @@ -868,6 +869,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { (ast_expression*)callsqrt1 ) ); + vec_push(body->exprs, (ast_expression*)ast_store_new( intrin_ctx(intrin), @@ -885,7 +887,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { intrin_ctx(intrin), INSTR_DIV_F, (ast_expression*)high, - (ast_expression*)fold_constgen_float(intrin->fold, 2.0f) + (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */ ) ) ); @@ -994,7 +996,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) { (ast_expression*)low, (ast_expression*)high ), - (ast_expression*)fold_constgen_float(intrin->fold, 2.0f) + (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */ ) ) ); @@ -1025,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, @@ -1192,6 +1194,803 @@ static ast_expression *intrin_fabs(intrin_t *intrin) { 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 sign * A_i / B_i; + * } + */ + + 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; + + vec_push(value->expression.params, power); + vec_push(value->expression.params, base); + + 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*)sign, + (ast_expression*)intrin->fold->imm_float[1] + ) + ); + + /* eps = __builtin_epsilon(); */ + vec_push(block->exprs, + (ast_expression*)ast_store_new( + intrin_ctx(intrin), + INSTR_STORE_F, + (ast_expression*)eps, + (ast_expression*)ast_call_new( + intrin_ctx(intrin), + intrin_func_self(intrin, "__builtin_epsilon", "ln") + ) + ) + ); + + /* + * 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] + ) + ); + } + } + + /* + * = { + * power = 1.0f / power; + * sign *= -1.0f; + * } + * = { + * 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] + ) + ); + } + + /* + * = { + * if (power <= 0.0 || base <= 0.0f) + * return __builtin_nan(); + * if (power < 1.0f) + * + * if (base < 1.0f) + * + * } + */ + vec_push(plt1orblt1->exprs, + (ast_expression*)ast_ifthen_new( + intrin_ctx(intrin), + (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 + ) + ); + + 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); + + + /* whole = power; */ + vec_push(forloop->exprs, + (ast_expression*)ast_store_new( + intrin_ctx(intrin), + INSTR_STORE_F, + (ast_expression*)whole, + (ast_expression*)power + ) + ); + + /* nth = 0.0f; */ + vec_push(forloop->exprs, + (ast_expression*)ast_store_new( + intrin_ctx(intrin), + INSTR_STORE_F, + (ast_expression*)nth, + (ast_expression*)intrin->fold->imm_float[0] + ) + ); + + /* 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*)base2 + ) + ); + + /* 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*)n2 + ) + ); + + /* 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_GE, + (ast_expression*)whole, + (ast_expression*)base + ), + false, + NULL, + false, + NULL, + (ast_expression*)whileloop + ) + ); + + vec_push(forloop->locals, b_iplus1); + vec_push(forloop->locals, A_iplus1); + vec_push(forloop->locals, B_iplus1); + + /* 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 + ) + ); + + /* + * 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) + ) + ) + ); + } + + /* + * A_iminus1 = A_i; + * B_iminus1 = B_i; + */ + 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) + ) + ); + } + + /* + * 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_binary_new( + intrin_ctx(intrin), + INSTR_LE, + (ast_expression*)whole, + (ast_expression*)ast_binary_new( + intrin_ctx(intrin), + 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_DIV_F, + (ast_expression*)A_i, + (ast_expression*)B_i + ) + ) + ) + ); + + vec_push(func->blocks, block); + 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); +} + /* * TODO: make static (and handle ast_type_string) here for the builtin * instead of in SYA parse close. @@ -1216,8 +2015,17 @@ 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_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} };