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;
* }
* }
*
- * float out;
* float A_i = 1;
* float B_i = 0;
* float A_iminus1 = 0;
* 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;
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);
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(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);
)
);
- /* 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
)
);
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));
+
+ 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) {
+ ast_value *value = NULL;
+ ast_call *callpow = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", 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);
+
+ vec_push(callpow->params, (ast_expression*)intrin->fold->imm_float[3]);
+ vec_push(callpow->params, (ast_expression*)b);
+
+ vec_push(body->exprs,
+ (ast_expression*)ast_return_new(
+ intrin_ctx(intrin),
+ (ast_expression*)ast_binary_new(
+ intrin_ctx(intrin),
+ instr,
+ (ast_expression*)a,
+ (ast_expression*)callpow
+ )
+ )
+ );
+
+ 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
{&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}
};