stage1 解决defer实现的缺陷
This commit is contained in:
1 parent
2594a81034
commit
5de4937637
2 files changed
+62
-32
No files matched your search
+61
-32
@@ -28,6 +28,26 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n);
|
|||||||
static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
|
/* Emit one exit path without consuming the lexical registrations needed by
|
||||||
|
* sibling paths. A private stack also allows cleanup bodies to register defer. */
|
||||||
|
static void emit_deferred_until(spl_ast2ir_t *a, usize base) {
|
||||||
|
if (vec_size(a->defer_stack) <= base)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spl_defer_stack_t saved = a->defer_stack;
|
||||||
|
vec_init(a->defer_stack);
|
||||||
|
for (usize i = 0; i < vec_size(saved); ++i)
|
||||||
|
vec_push(a->defer_stack, vec_at(saved, i));
|
||||||
|
|
||||||
|
while (!a->ir->terminated && vec_size(a->defer_stack) > base) {
|
||||||
|
spl_ast_node_ref_t body = vec_pop(a->defer_stack);
|
||||||
|
emit_stmt(a, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec_free(a->defer_stack);
|
||||||
|
a->defer_stack = saved;
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n);
|
static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n);
|
||||||
static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
|
static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
|
||||||
@@ -1105,11 +1125,16 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_BLOCK: {
|
case SPL_AST_EXPR_BLOCK: {
|
||||||
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
|
usize defer_base = vec_size(a->defer_stack);
|
||||||
|
for (usize i = 0; i < vec_size(n->block.stmts) && !a->ir->terminated; ++i)
|
||||||
emit_stmt(a, vec_at(n->block.stmts, i));
|
emit_stmt(a, vec_at(n->block.stmts, i));
|
||||||
if (n->block.tail_expr)
|
spl_ir_node_ref_t value = 0;
|
||||||
return emit_expr(a, n->block.tail_expr);
|
if (!a->ir->terminated && n->block.tail_expr)
|
||||||
return 0;
|
value = emit_expr(a, n->block.tail_expr);
|
||||||
|
if (!a->ir->terminated)
|
||||||
|
emit_deferred_until(a, defer_base);
|
||||||
|
a->defer_stack.size = defer_base;
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_IF:
|
case SPL_AST_EXPR_IF:
|
||||||
case SPL_AST_EXPR_IFVAR:
|
case SPL_AST_EXPR_IFVAR:
|
||||||
@@ -1422,6 +1447,7 @@ static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
|
|||||||
|
|
||||||
spl_loop_ctx_t ctx = {0};
|
spl_loop_ctx_t ctx = {0};
|
||||||
ctx.cont_blk = cont_blk;
|
ctx.cont_blk = cont_blk;
|
||||||
|
ctx.defer_base = vec_size(a->defer_stack);
|
||||||
ctx.label = NULL;
|
ctx.label = NULL;
|
||||||
ctx.result_slot = result_slot;
|
ctx.result_slot = result_slot;
|
||||||
ctx.result_tid = result_t;
|
ctx.result_tid = result_t;
|
||||||
@@ -1480,29 +1506,34 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
|||||||
lbl = ln->label.name;
|
lbl = ln->label.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_loop_ctx_t *target = NULL;
|
usize target_index = vec_size(a->loop_stack);
|
||||||
if (lbl) {
|
if (lbl) {
|
||||||
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
||||||
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
||||||
if (c->label && strcmp(c->label, lbl) == 0) {
|
if (c->label && strcmp(c->label, lbl) == 0) {
|
||||||
target = c;
|
target_index = i - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
target = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
|
target_index = vec_size(a->loop_stack) - 1;
|
||||||
}
|
}
|
||||||
if (!target)
|
if (target_index == vec_size(a->loop_stack))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (n->statement_break.expr && target->result_slot) {
|
/* Emitting a value or a cleanup can grow/reallocate loop_stack. */
|
||||||
|
spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
|
||||||
|
if (n->statement_break.expr && target.result_slot) {
|
||||||
spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr);
|
spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr);
|
||||||
if (bv)
|
if (bv)
|
||||||
spl_ir_builder_mem_store(a->ir, target->result_tid, target->result_slot, bv);
|
spl_ir_builder_mem_store(a->ir, target.result_tid, target.result_slot, bv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit_deferred_until(a, target.defer_base);
|
||||||
|
if (a->ir->terminated)
|
||||||
|
return;
|
||||||
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
|
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
|
||||||
vec_push(target->breaks, jmp);
|
vec_push(vec_at(a->loop_stack, target_index).breaks, jmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||||
@@ -1518,12 +1549,10 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
if (n->statement_ret.expr)
|
if (n->statement_ret.expr)
|
||||||
v = emit_expr(a, n->statement_ret.expr);
|
v = emit_expr(a, n->statement_ret.expr);
|
||||||
|
|
||||||
while (vec_size(a->defer_stack) > a->cur_defer_base) {
|
emit_deferred_until(a, a->cur_defer_base);
|
||||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
|
||||||
emit_stmt(a, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
spl_ir_builder_control_ret(a->ir, ret_ir, v);
|
if (!a->ir->terminated)
|
||||||
|
spl_ir_builder_control_ret(a->ir, ret_ir, v);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SPL_AST_STATEMENT_DEFER:
|
case SPL_AST_STATEMENT_DEFER:
|
||||||
@@ -1566,21 +1595,26 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
lbl = ln->label.name;
|
lbl = ln->label.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
|
usize target_index = vec_size(a->loop_stack) - 1;
|
||||||
|
|
||||||
if (lbl) {
|
if (lbl) {
|
||||||
|
target_index = vec_size(a->loop_stack);
|
||||||
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
||||||
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
||||||
if (c->label && strcmp(c->label, lbl) == 0) {
|
if (c->label && strcmp(c->label, lbl) == 0) {
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, jmp, c->cont_blk);
|
target_index = i - 1;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
if (target_index == vec_size(a->loop_stack))
|
||||||
|
return;
|
||||||
|
|
||||||
usize cont = vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).cont_blk;
|
spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, jmp, cont);
|
emit_deferred_until(a, target.defer_base);
|
||||||
|
if (!a->ir->terminated) {
|
||||||
|
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, jmp, target.cont_blk);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_BLOCK:
|
case SPL_AST_EXPR_BLOCK:
|
||||||
@@ -1691,12 +1725,10 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
|||||||
if (n->fn_decl.body)
|
if (n->fn_decl.body)
|
||||||
emit_expr(a, n->fn_decl.body);
|
emit_expr(a, n->fn_decl.body);
|
||||||
|
|
||||||
if (!a->ir->terminated) {
|
if (!a->ir->terminated)
|
||||||
while (vec_size(a->defer_stack) > defer_base) {
|
emit_deferred_until(a, defer_base);
|
||||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
|
||||||
emit_stmt(a, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!a->ir->terminated) {
|
||||||
if (ret_is_unit) {
|
if (ret_is_unit) {
|
||||||
spl_ir_builder_control_ret(a->ir, ret_ir, 0);
|
spl_ir_builder_control_ret(a->ir, ret_ir, 0);
|
||||||
} else if (ret_ir) {
|
} else if (ret_ir) {
|
||||||
@@ -1707,10 +1739,7 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (vec_size(a->defer_stack) > defer_base) {
|
a->defer_stack.size = defer_base;
|
||||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
|
||||||
(void)d;
|
|
||||||
}
|
|
||||||
while (vec_size(a->loop_stack) > loop_base) {
|
while (vec_size(a->loop_stack) > loop_base) {
|
||||||
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
|
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
|
||||||
vec_free(top->breaks);
|
vec_free(top->breaks);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t;
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
usize cont_blk;
|
usize cont_blk;
|
||||||
|
usize defer_base;
|
||||||
const char *label;
|
const char *label;
|
||||||
spl_ir_node_ref_vec_t breaks;
|
spl_ir_node_ref_vec_t breaks;
|
||||||
spl_ir_node_ref_t result_slot;
|
spl_ir_node_ref_t result_slot;
|
||||||
|
|||||||
Reference in new issue
Block a user