diff --git a/ast.c b/ast.c index c965947..00ab611 100644 --- a/ast.c +++ b/ast.c @@ -939,6 +939,9 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value ir_block *bincrement, *end_bincrement; ir_block *bout, *bin; + /* let's at least move the outgoing block to the end */ + size_t bout_id; + /* 'break' and 'continue' need to be able to find the right blocks */ ir_block *bcontinue = NULL; ir_block *bbreak = NULL; @@ -946,6 +949,8 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value ir_block *old_bcontinue; ir_block *old_bbreak; + ir_block *tmpblock; + (void)lvalue; (void)out; @@ -1014,6 +1019,7 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value bpostcond = end_bpostcond = NULL; } + bout_id = func->ir_func->blocks_count; bout = ir_function_create_block(func->ir_func, ast_function_label(func, "after_loop")); if (!bout) return false; @@ -1072,15 +1078,16 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value end_bincrement = func->curblock; } + /* In any case now, we continue from the outgoing block */ + func->curblock = bout; + /* Now all blocks are in place */ /* From 'bin' we jump to whatever comes first */ - if (bprecond && !ir_block_create_jump(bin, bprecond)) - return false; - else if (bbody && !ir_block_create_jump(bin, bbody)) - return false; - else if (bpostcond && !ir_block_create_jump(bin, bpostcond)) - return false; - else if ( !ir_block_create_jump(bin, bout)) + if (bprecond) tmpblock = bprecond; + else if (bbody) tmpblock = bbody; + else if (bpostcond) tmpblock = bpostcond; + else tmpblock = bout; + if (!ir_block_create_jump(bin, tmpblock)) return false; /* From precond */ @@ -1099,26 +1106,22 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value /* from body */ if (bbody) { - if (bincrement && !ir_block_create_jump(end_bbody, bincrement)) - return false; - else if (bpostcond && !ir_block_create_jump(end_bbody, bpostcond)) - return false; - else if (bprecond && !ir_block_create_jump(end_bbody, bprecond)) - return false; - else if (!ir_block_create_jump(end_bbody, bout)) + if (bincrement) tmpblock = bincrement; + else if (bpostcond) tmpblock = bpostcond; + else if (bprecond) tmpblock = bprecond; + else tmpblock = bout; + if (!ir_block_create_jump(end_bbody, tmpblock)) return false; } /* from increment */ if (bincrement) { - if (bpostcond && !ir_block_create_jump(end_bincrement, bpostcond)) - return false; - else if (bprecond && !ir_block_create_jump(end_bincrement, bprecond)) - return false; - else if (bbody && !ir_block_create_jump(end_bincrement, bbody)) - return false; - else if (!ir_block_create_jump(end_bincrement, bout)) + if (bpostcond) tmpblock = bpostcond; + else if (bprecond) tmpblock = bprecond; + else if (bbody) tmpblock = bbody; + else tmpblock = bout; + if (!ir_block_create_jump(end_bincrement, tmpblock)) return false; } @@ -1135,5 +1138,13 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value return false; } + /* Move 'bout' to the end */ + if (!ir_function_blocks_remove(func->ir_func, bout_id) || + !ir_function_blocks_add(func->ir_func, bout)) + { + ir_block_delete(bout); + return false; + } + return true; } diff --git a/ir.c b/ir.c index 2a33065..8e8ffb7 100644 --- a/ir.c +++ b/ir.c @@ -582,8 +582,13 @@ bool ir_values_overlap(ir_value *a, ir_value *b) /* check if the entries overlap, for that, * both must start before the other one ends. */ +#if defined(LIFE_RANGE_WITHOUT_LAST_READ) if (la->start <= lb->end && lb->start <= la->end) +#else + if (la->start < lb->end && + lb->start < la->end) +#endif { return true; } @@ -1473,14 +1478,19 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change ir_instr *instr; ir_value *value; bool tempbool; - size_t i, o, p, rd; + size_t i, o, p; /* bitmasks which operands are read from or written to */ size_t read, write; +#if defined(LIFE_RANGE_WITHOUT_LAST_READ) + size_t rd; new_reads_t new_reads; +#endif char dbg_ind[16] = { '#', '0' }; (void)dbg_ind; +#if defined(LIFE_RANGE_WITHOUT_LAST_READ) MEM_VECTOR_INIT(&new_reads, v); +#endif if (prev) { @@ -1497,16 +1507,19 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change for (p = 0; p < instr->phi_count; ++p) { value = instr->phi[p].value; - /* used this before new_reads - puts the last read into the life range as well - if (!ir_block_living_find(self, value, NULL)) - ir_block_living_add(self, value); - */ - /* fprintf(stderr, "read: %s\n", value->_name); */ +#if ! defined(LIFE_RANGE_WITHOUT_LAST_READ) + if (!ir_block_living_find(self, value, NULL) && + !ir_block_living_add(self, value)) + { + goto on_error; + } +#else if (!new_reads_t_v_find(&new_reads, value, NULL)) { if (!new_reads_t_v_add(&new_reads, value)) goto on_error; } +#endif } /* See which operands are read and write operands */ @@ -1528,16 +1541,20 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change /* read operands */ if (read & (1<_name); */ if (!new_reads_t_v_find(&new_reads, value, NULL)) { if (!new_reads_t_v_add(&new_reads, value)) goto on_error; } +#endif } /* write operands */ @@ -1547,10 +1564,15 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change */ if (write & (1<run_id == self->owner->run_id) @@ -1622,7 +1649,9 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change return true; on_error: +#if defined(LIFE_RANGE_WITHOUT_LAST_READ) MEM_VECTOR_CLEAR(&new_reads, v); +#endif return false; } diff --git a/test/ast-macros.h b/test/ast-macros.h new file mode 100644 index 0000000..efbf7b6 --- /dev/null +++ b/test/ast-macros.h @@ -0,0 +1,76 @@ +#ifndef TEST_AST_MACROS_HDR +#define TEST_AST_MACROS_HDR + +#define TESTVARS() \ +ast_block *curblock; \ +lex_ctx ctx + +#define TESTINIT() \ +ctx.file = NULL; \ +ctx.line = 1; + +#define DEFVAR(name) \ +ast_value *name + +#define VAR(type, name) \ +name = ast_value_new(ctx, #name, type) + +#define MKGLOBAL(name) \ +assert(globals_add(name) >= 0) + +#define MKCONSTFLOAT(name, value) \ +do { \ + name->isconst = true; \ + name->constval.vfloat = value; \ + MKGLOBAL(name); \ +} while(0) + +#define STATE(a) \ +do { \ + ast_expression *exp = (ast_expression*)(a); \ + assert(ast_block_exprs_add(curblock, exp)); \ +} while(0) + +#define ASSIGN(op, a, b) \ +(ast_expression*)ast_store_new(ctx, INSTR_##op, (a), (ast_expression*)(b)) + +#define BIN(op, a, b) \ +(ast_expression*)ast_binary_new(ctx, INSTR_##op, (ast_expression*)(a), (ast_expression*)(b)) + +#define WHILE(cond) \ +do { \ + ast_expression *wh_cond = (ast_expression*)(cond); \ + ast_block *wh_body = ast_block_new(ctx); \ + ast_block *oldcur = curblock; \ + ast_loop *loop; \ + curblock = wh_body; + +#define ENDWHILE() \ + curblock = oldcur; \ + loop = ast_loop_new(ctx, NULL, (ast_expression*)wh_cond, \ + NULL, NULL, (ast_expression*)wh_body); \ + assert(loop); \ + STATE(loop); \ +} while(0) + +#define FUNCTION(name) \ +do { \ + ast_function *func_##name; \ + ast_block *my_funcblock; \ + DEFVAR(var_##name); \ + VAR(TYPE_FUNCTION, var_##name); \ + MKGLOBAL(var_##name); \ + func_##name = ast_function_new(ctx, #name, var_##name); \ + assert(functions_add(func_##name) >= 0); \ + my_funcblock = ast_block_new(ctx); \ + assert(my_funcblock); \ + assert(ast_function_blocks_add(func_##name, my_funcblock)); \ + curblock = my_funcblock; + +#define MKLOCAL(var) \ + assert(ast_block_locals_add(curblock, var)) + +#define ENDFUNCTION(name) \ +} while(0) + +#endif diff --git a/test/ast-test.c b/test/ast-test.c index 1f8a7f6..eb4e1e9 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -12,6 +12,7 @@ VECTOR_MAKE(ast_value*, globals); VECTOR_MAKE(ast_function*, functions); +#if 0 int main() { /* AST */ @@ -124,6 +125,94 @@ int main() assert(!"finalize on function failed..."); } + /* dump */ + ir_builder_dump(ir, printf); + + /* ir cleanup */ + ir_builder_delete(ir); + + /* cleanup */ + /* Functions must be deleted FIRST since their expressions + * reference global variables. + */ + for (i = 0; i < functions_elements; ++i) { + ast_function_delete(functions_data[i]); + } + if (functions_data) + mem_d(functions_data); + + /* We must delete not only globals, but also the functions' + * ast_values (their type and name), that's why we added them to the globals vector. + */ + for (i = 0; i < globals_elements; ++i) { + ast_value_delete(globals_data[i]); + } + if (globals_data) + mem_d(globals_data); + return 0; +} +#endif + +#include "ast-macros.h" + +int main() +{ + size_t i; + + ir_builder *ir; + + TESTVARS(); + + DEFVAR(vi); + DEFVAR(vx); + DEFVAR(f0); + DEFVAR(f1); + DEFVAR(f5); + + TESTINIT(); +VAR(TYPE_FLOAT, f0); +VAR(TYPE_FLOAT, f1); +VAR(TYPE_FLOAT, f5); +MKCONSTFLOAT(f0, 0.0); +MKCONSTFLOAT(f1, 1.0); +MKCONSTFLOAT(f5, 5.0); + +FUNCTION(main); + +VAR(TYPE_FLOAT, vi); +VAR(TYPE_FLOAT, vx); + +MKLOCAL(vi); +MKLOCAL(vx); + +STATE(ASSIGN(STORE_F, vi, f0)); +WHILE(BIN(LT, vi, f5)); +STATE(ASSIGN(STORE_F, vx, BIN(MUL_F, vi, f5))); +STATE(ASSIGN(STORE_F, vi, BIN(ADD_F, vi, f1))); +ENDWHILE(); + +ENDFUNCTION(main); + + ir = ir_builder_new("ast_test"); + assert(ir); + + /* gen globals */ + for (i = 0; i < globals_elements; ++i) { + if (!ast_global_codegen(globals_data[i], ir)) { + assert(!"failed to generate global"); + } + } + + /* gen functions */ + for (i = 0; i < functions_elements; ++i) { + if (!ast_function_codegen(functions_data[i], ir)) { + assert(!"failed to generate function"); + } + if (!ir_function_finalize(functions_data[i]->ir_func)) + assert(!"finalize on function failed..."); + } + + /* dump */ ir_builder_dump(ir, printf);