stage1 解决defer实现的缺陷
This commit is contained in:
1 parent
2594a81034
commit
5de4937637
2 files changed
+63
-33
No files matched your search
+62
-33
@@ -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_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);
|
||||
/* 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 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,
|
||||
@@ -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;
|
||||
}
|
||||
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));
|
||||
if (n->block.tail_expr)
|
||||
return emit_expr(a, n->block.tail_expr);
|
||||
return 0;
|
||||
spl_ir_node_ref_t value = 0;
|
||||
if (!a->ir->terminated && n->block.tail_expr)
|
||||
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_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};
|
||||
ctx.cont_blk = cont_blk;
|
||||
ctx.defer_base = vec_size(a->defer_stack);
|
||||
ctx.label = NULL;
|
||||
ctx.result_slot = result_slot;
|
||||
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;
|
||||
}
|
||||
|
||||
spl_loop_ctx_t *target = NULL;
|
||||
usize target_index = vec_size(a->loop_stack);
|
||||
if (lbl) {
|
||||
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
||||
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
||||
if (c->label && strcmp(c->label, lbl) == 0) {
|
||||
target = c;
|
||||
target_index = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
@@ -1518,11 +1549,9 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||
if (n->statement_ret.expr)
|
||||
v = emit_expr(a, n->statement_ret.expr);
|
||||
|
||||
while (vec_size(a->defer_stack) > a->cur_defer_base) {
|
||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
||||
emit_stmt(a, d);
|
||||
}
|
||||
emit_deferred_until(a, a->cur_defer_base);
|
||||
|
||||
if (!a->ir->terminated)
|
||||
spl_ir_builder_control_ret(a->ir, ret_ir, v);
|
||||
return;
|
||||
}
|
||||
@@ -1566,21 +1595,26 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||
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) {
|
||||
target_index = vec_size(a->loop_stack);
|
||||
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
||||
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
||||
if (c->label && strcmp(c->label, lbl) == 0) {
|
||||
spl_ir_builder_control_jmp_fixup(a->ir, jmp, c->cont_blk);
|
||||
target_index = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (target_index == vec_size(a->loop_stack))
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
usize cont = vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).cont_blk;
|
||||
spl_ir_builder_control_jmp_fixup(a->ir, jmp, cont);
|
||||
spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
|
||||
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;
|
||||
}
|
||||
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)
|
||||
emit_expr(a, n->fn_decl.body);
|
||||
|
||||
if (!a->ir->terminated) {
|
||||
while (vec_size(a->defer_stack) > defer_base) {
|
||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
||||
emit_stmt(a, d);
|
||||
}
|
||||
if (!a->ir->terminated)
|
||||
emit_deferred_until(a, defer_base);
|
||||
|
||||
if (!a->ir->terminated) {
|
||||
if (ret_is_unit) {
|
||||
spl_ir_builder_control_ret(a->ir, ret_ir, 0);
|
||||
} 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) {
|
||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
||||
(void)d;
|
||||
}
|
||||
a->defer_stack.size = defer_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);
|
||||
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 {
|
||||
usize cont_blk;
|
||||
usize defer_base;
|
||||
const char *label;
|
||||
spl_ir_node_ref_vec_t breaks;
|
||||
spl_ir_node_ref_t result_slot;
|
||||
|
||||
Reference in new issue
Block a user