Skip to content

Commit

Permalink
issue #31 Linezrise enhanced to generate op_close instruction to clos…
Browse files Browse the repository at this point in the history
…e upvalues
  • Loading branch information
Dibyendu Majumdar committed Aug 9, 2020
1 parent c6fe971 commit 161d5ea
Show file tree
Hide file tree
Showing 7 changed files with 1,629 additions and 43 deletions.
114 changes: 100 additions & 14 deletions src/linearizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1593,29 +1593,35 @@ encountered a goto statement but we did not know the block then.
static void linearize_label_statement(struct proc *proc, struct ast_node *node)
{
/* If the current block is empty then we can use it as the label target */
struct basic_block* block = proc->current_bb;
if (ptrlist_size((const struct ptr_list*)block->insns) > 0) {
/* Create new block as label target */
block = create_block(proc);
struct basic_block* block;
if (node->label_stmt.symbol->label.pseudo != NULL) {
assert(node->label_stmt.symbol->label.pseudo->block != NULL);
block = node->label_stmt.symbol->label.pseudo->block;
start_block(proc, block);
}
if (node->label_stmt.symbol->label.pseudo != NULL) {
/* label pseudo was created by a goto statement */
assert(node->label_stmt.symbol->label.pseudo->block == NULL);
node->label_stmt.symbol->label.pseudo->block = block;
} else {
else {
block = proc->current_bb;
if (ptrlist_size((const struct ptr_list*)block->insns) > 0) {
/* Create new block as label target */
block = create_block(proc);
start_block(proc, block);
}
node->label_stmt.symbol->label.pseudo = allocate_block_pseudo(proc, block);
}
}

/* TODO move this logic to parser? */
/* Search for a label going up scopes starting from the scope where the goto statement appeared. */
static struct lua_symbol *find_label(struct proc *proc, struct block_scope *block,
const struct string_object *label_name)
const struct string_object *label_name, struct block_scope **min_closing_block)
{
struct ast_node *function = block->function; /* We need to stay inside the function when lookng for the label */
*min_closing_block = NULL;
while (block != NULL && block->function == function) {
struct lua_symbol *symbol;
if (block->need_close) {
*min_closing_block = block;
}
FOR_EACH_PTR_REVERSE(block->symbol_list, symbol)
{
if (symbol->symbol_type == SYM_LABEL && symbol->label.label_name == label_name) {
Expand All @@ -1628,6 +1634,57 @@ static struct lua_symbol *find_label(struct proc *proc, struct block_scope *bloc
return NULL;
}

struct block_scope *find_min_closing_block(struct block_scope *block, struct block_scope *target_block)
{
struct ast_node *function = block->function; /* We need to stay inside the function when lookng for the label */
struct block_scope *min_closing_block = NULL;
while (block != NULL && block->function == function) {
if (block->need_close) {
min_closing_block = block;
}
if (block == target_block)
break;
block = block->parent;
}
return min_closing_block;
}

static bool is_already_closed(struct proc *proc, struct basic_block *block)
{
struct instruction *last_insn = raviX_last_instruction(block);
if (last_insn == NULL)
return false;
if (last_insn->opcode == op_ret)
return true;
if (last_insn->opcode == op_close) {
// hmmm
assert(false);
}
return false;
}

static void instruct_close(struct proc *proc, struct basic_block *block, struct block_scope *scope)
{
if (is_already_closed(proc, block))
return;
/* temporarily make block current */
struct basic_block *prev_current = proc->current_bb;
proc->current_bb = block;
struct lua_symbol *symbol;
FOR_EACH_PTR(scope->symbol_list, symbol)
{
if (symbol->symbol_type == SYM_LOCAL && symbol->variable.escaped) {
assert(symbol->variable.pseudo);
struct instruction *insn = allocate_instruction(proc, op_close);
add_instruction_operand(proc, insn, symbol->variable.pseudo);
add_instruction(proc, insn);
break;
}
}
END_FOR_EACH_PTR(symbol)
proc->current_bb = prev_current;
}

/*
When linearizing the goto statement we create a pseudo for the label if it hasn't been already created.
But at this point we may not know the target basic block to goto, which we expect to be filled when the label is
Expand All @@ -1640,22 +1697,34 @@ static void linearize_goto_statement(struct proc *proc, const struct ast_node *n
if (proc->current_break_target == NULL) {
handle_error(proc->linearizer->ast_container, "no current break target");
}
struct block_scope *min_closing_block = find_min_closing_block(node->goto_stmt.goto_scope, proc->current_break_scope);
instruct_br(proc, allocate_block_pseudo(proc, proc->current_break_target));
start_block(proc, create_block(proc));
if (min_closing_block) {
instruct_close(proc, proc->current_break_target, min_closing_block);
}
return;
}
/* The AST does not provide link to the label so we have to search for the label in the goto scope
and above */
if (node->goto_stmt.goto_scope) {
struct lua_symbol *symbol = find_label(proc, node->goto_stmt.goto_scope, node->goto_stmt.name);
struct block_scope *min_closing_block = NULL;
struct lua_symbol *symbol = find_label(proc, node->goto_stmt.goto_scope, node->goto_stmt.name, &min_closing_block);
if (symbol) {
/* label found */
if (symbol->label.pseudo == NULL) {
/* No pseudo? create with NULL target block, must be filled by a label statement */
symbol->label.pseudo = allocate_block_pseudo(proc, NULL);
/* No pseudo? create with target block to be processed later when label is encountered */
symbol->label.pseudo = allocate_block_pseudo(proc, create_block(proc));
}
else {
assert(symbol->label.pseudo->block != NULL);
}
instruct_br(proc, symbol->label.pseudo);
start_block(proc, create_block(proc));
if (min_closing_block) {
/* close intruction needs to go after the label */
instruct_close(proc, symbol->label.pseudo->block, min_closing_block);
}
return;
}
}
Expand Down Expand Up @@ -1783,7 +1852,9 @@ static void linearize_for_num_statement(struct proc *proc, struct ast_node *node
struct basic_block *Lbody = create_block(proc);
struct basic_block *Lend = create_block(proc);
struct basic_block *previous_break_target = proc->current_break_target;
struct block_scope *previous_break_scope = proc->current_break_scope;
proc->current_break_target = Lend;
proc->current_break_scope = proc->current_scope;

start_block(proc, L1);
create_binary_instruction(proc, op_addii, index_var_pseudo, step_pseudo, index_var_pseudo);
Expand All @@ -1804,6 +1875,10 @@ static void linearize_for_num_statement(struct proc *proc, struct ast_node *node
linearize_statement_list(proc, node->for_stmt.for_statement_list);
end_scope(proc->linearizer, proc);

if (proc->current_break_scope->need_close) {
/* need to put close instruction in current basic block */
instruct_close(proc, proc->current_bb, proc->current_break_scope);
}
instruct_br(proc, allocate_block_pseudo(proc, L1));

end_scope(proc->linearizer, proc);
Expand All @@ -1817,6 +1892,7 @@ static void linearize_for_num_statement(struct proc *proc, struct ast_node *node
start_block(proc, Lend);

proc->current_break_target = previous_break_target;
proc->current_break_scope = previous_break_scope;
}

static void linearize_while_statment(struct proc *proc, struct ast_node *node)
Expand All @@ -1825,7 +1901,9 @@ static void linearize_while_statment(struct proc *proc, struct ast_node *node)
struct basic_block *body_block = create_block(proc);
struct basic_block *end_block = create_block(proc);
struct basic_block *previous_break_target = proc->current_break_target;
struct block_scope *previous_break_scope = proc->current_break_scope;
proc->current_break_target = end_block;
proc->current_break_scope = node->while_or_repeat_stmt.loop_scope;

if (node->type == STMT_REPEAT) {
instruct_br(proc, allocate_block_pseudo(proc, body_block));
Expand All @@ -1840,11 +1918,16 @@ static void linearize_while_statment(struct proc *proc, struct ast_node *node)
start_scope(proc->linearizer, proc, node->while_or_repeat_stmt.loop_scope);
linearize_statement_list(proc, node->while_or_repeat_stmt.loop_statement_list);
end_scope(proc->linearizer, proc);

if (proc->current_break_scope->need_close) {
instruct_close(proc, proc->current_bb, proc->current_break_scope);
}
instruct_br(proc, allocate_block_pseudo(proc, test_block));

start_block(proc, end_block);

proc->current_break_target = previous_break_target;
proc->current_break_scope = previous_break_scope;
}

static void linearize_function_statement(struct proc *proc, struct ast_node *node)
Expand Down Expand Up @@ -2050,6 +2133,9 @@ static void end_scope(struct linearizer_state *linearizer, struct proc *proc)
{
struct block_scope *scope = proc->current_scope;
struct lua_symbol *sym;
if (scope->need_close) {
instruct_close(proc, proc->current_bb, scope);
}
FOR_EACH_PTR_REVERSE(scope->symbol_list, sym)
{
if (sym->symbol_type == SYM_LOCAL) {
Expand Down Expand Up @@ -2177,7 +2263,7 @@ static const char *op_codenames[] = {
"PUTik", "PUTsk", "TPUT", "TPUTik", "TPUTsk", "IAPUT", "IAPUTiv", "FAPUT", "FAPUTfv",
"CBR", "BR", "MOV", "MOVi", "MOVif", "MOVf", "MOVfi", "CALL", "GET",
"GETik", "GETsk", "TGET", "TGETik", "TGETsk", "IAGET", "IAGETik", "FAGET", "FAGETik",
"STOREGLOBAL"};
"STOREGLOBAL", "CLOSE"};

static void output_pseudo_list(struct pseudo_list *list, membuff_t *mb)
{
Expand Down
5 changes: 4 additions & 1 deletion src/linearizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ enum opcode {
op_faget,
op_faget_ikey,
op_storeglobal,
op_close
};

enum pseudo_type {
Expand Down Expand Up @@ -191,7 +192,9 @@ struct proc {
struct ast_node *function_expr; /* function ast that we are compiling */
struct block_scope *current_scope;
struct basic_block *current_bb;
struct basic_block *current_break_target; /* track the current break target, previous target must be saved / restored in stack discipline */
struct basic_block *current_break_target; /* track the current break target, previous target must be saved /
restored in stack discipline */
struct block_scope *current_break_scope; /* as above track the block scope */
struct pseudo_generator local_pseudos; /* locals */
struct pseudo_generator temp_int_pseudos; /* temporaries known to be integer type */
struct pseudo_generator temp_flt_pseudos; /* temporaries known to be number type */
Expand Down
8 changes: 6 additions & 2 deletions src/parser.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
A parser and syntax tree builder for Ravi.
A parser and syntax tree builder for Ravi.
Note that the overall structure of the parser is loosely based on the Lua 5.3 parser.
The parser retains the syntactic structure - including constant expressions and some redundant
Expand Down Expand Up @@ -254,7 +254,9 @@ static bool add_upvalue_in_function(struct parser_state *parser, struct ast_node
(const struct ptr_list *)function->function_expr.upvalues); /* position of upvalue in function */
copy_type(&upvalue->upvalue.value_type, &sym->variable.value_type);
add_symbol(parser->container, &function->function_expr.upvalues, upvalue);
sym->variable.escaped = 1; /* mark original variable as having escaped */
sym->variable.escaped = 1; /* mark original variable as having escaped */
sym->variable.block->need_close = 1; /* mark block containing variable as needing close operation */
sym->variable.block->function->function_expr.need_close = 1;
return true;
}

Expand Down Expand Up @@ -1454,6 +1456,7 @@ static struct block_scope *new_scope(struct parser_state *parser)
scope->symbol_list = NULL;
// scope->do_statement_list = NULL;
scope->function = parser->current_function;
scope->need_close = 0;
assert(scope->function && scope->function->type == EXPR_FUNCTION);
scope->parent = parser->current_scope;
parser->current_scope = scope;
Expand All @@ -1480,6 +1483,7 @@ static struct ast_node *new_function(struct parser_state *parser)
set_type(&node->function_expr.type, RAVI_TFUNCTION);
node->function_expr.is_method = false;
node->function_expr.is_vararg = false;
node->function_expr.need_close = false;
node->function_expr.proc_id = 0;
node->function_expr.args = NULL;
node->function_expr.child_functions = NULL;
Expand Down
6 changes: 4 additions & 2 deletions src/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct block_scope {
struct ast_node *function; /* function owning this block - of type FUNCTION_EXPR */
struct block_scope *parent; /* parent block, may belong to parent function */
struct lua_symbol_list *symbol_list; /* symbols defined in this block */
unsigned need_close: 1; /* When we exit scope of this block the upvalues need to be closed */
};

/*STMT_RETURN */
Expand Down Expand Up @@ -248,8 +249,9 @@ struct binary_expression {
};
struct function_expression {
BASE_EXPRESSION_FIELDS;
unsigned int is_vararg : 1;
unsigned int is_method : 1;
unsigned is_vararg : 1;
unsigned is_method : 1;
unsigned need_close : 1;
uint32_t proc_id; /* Backend allocated id */
struct ast_node *parent_function; /* parent function or NULL if main chunk */
struct block_scope *main_block; /* the function's main block */
Expand Down
Loading

0 comments on commit 161d5ea

Please sign in to comment.