issue #98 Start work generating linear IR

parser
Dibyendu Majumdar 4 years ago
parent 7b06b524ca
commit 6cb6ef838f

@ -71,6 +71,7 @@ struct var_type {
type_code is RAVI_TUSERDATA */
};
struct pseudo;
struct lua_symbol;
DECLARE_PTR_LIST(lua_symbol_list, struct lua_symbol);
@ -92,7 +93,7 @@ struct lua_symbol {
struct {
const TString *var_name; /* name of the variable */
struct block_scope *block; /* NULL if global symbol, as globals are never added to a scope */
void *backend_data; /* Place for backend to hold some data for the symbol */
struct pseudo *pseudo; /* backend data for the symbol */
} var;
struct {
const TString *label_name;
@ -289,9 +290,9 @@ struct instruction;
struct node;
struct basic_block;
struct edge;
struct pseudo;
struct cfg;
struct proc;
struct constant;
DECLARE_PTR_LIST(instruction_list, struct instruction);
DECLARE_PTR_LIST(edge_list, struct edge);
@ -302,10 +303,15 @@ DECLARE_PTR_LIST(proc_list, struct proc);
enum opcode { OP_NOP };
enum pseudo_type { PSEUDO_LOCAL, PSEUDO_TEMP, PSEUDO_TEMP_INT, PSEUDO_TEMP_ANY, PSEUDO_CONSTANT };
/* pseudo represents a pseudo (virtual) register */
struct pseudo {
unsigned regnum : 16;
struct lua_symbol *symbol; /* If local var this should be set */
unsigned type : 4, regnum : 16;
union {
struct lua_symbol *symbol; /* If local var this should be set */
struct constant *constant;
};
};
/* single instruction */
@ -333,11 +339,11 @@ struct basic_block {
struct instruction_list *insns;
};
#define CFG_FIELDS \
#define CFG_FIELDS \
unsigned node_count; \
unsigned allocated; \
unsigned allocated; \
struct node **nodes; \
struct node *entry; \
struct node *entry; \
struct node *exit
struct cfg {
@ -363,21 +369,22 @@ struct constant {
/* proc is a type of cfg */
struct proc {
CFG_FIELDS;
struct proc_list* procs; /* procs defined in this proc */
struct proc* parent; /* enclosing proc */
struct ast_node* function_expr; /* function ast that we are compiling */
struct linearizer *linearizer;
struct proc_list *procs; /* procs defined in this proc */
struct proc *parent; /* enclosing proc */
struct ast_node *function_expr; /* function ast that we are compiling */
struct block_scope *current_scope;
struct pseudo_generator local_pseudos; /* locals */
struct basic_block* current_bb;
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 */
struct pseudo_generator temp_pseudos; /* All other temporaries */
struct pseudo_generator temp_pseudos; /* All other temporaries */
struct set *constants;
unsigned num_constants;
};
static inline struct basic_block * n2bb(struct node *n) { return (struct basic_block *)n; }
static inline struct node * bb2n(struct basic_block *bb) { return (struct node *)bb; }
static inline struct basic_block *n2bb(struct node *n) { return (struct basic_block *)n; }
static inline struct node *bb2n(struct basic_block *bb) { return (struct node *)bb; }
struct linearizer {
struct allocator instruction_allocator;
@ -389,9 +396,9 @@ struct linearizer {
struct allocator unsized_allocator;
struct allocator constant_allocator;
struct ast_container *ast_container;
struct proc* main_proc; /* The root of the compiled chunk of code */
struct proc *main_proc; /* The root of the compiled chunk of code */
struct proc_list *all_procs; /* All procs allocated by the linearizer */
struct proc *current_proc; /* proc being compiled */
struct proc *current_proc; /* proc being compiled */
};
void raviA_ast_linearize(struct linearizer *linearizer, struct ast_container *container);

@ -9,7 +9,6 @@ Copyright (C) 2018-2020 Dibyendu Majumdar
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <ravi_ast.h>
static inline unsigned alloc_reg(struct pseudo_generator *generator) {
if (generator->free_pos > 0) {
@ -24,7 +23,7 @@ static inline void free_reg(struct pseudo_generator *generator, unsigned reg) {
fprintf(stderr, "Out of register space\n");
abort();
}
generator->free_regs[generator->free_pos++] = (uint8_t) reg;
generator->free_regs[generator->free_pos++] = (uint8_t)reg;
}
/* Linearizer - WIP */
@ -41,7 +40,8 @@ static void ravi_init_linearizer(struct linearizer *linearizer, struct ast_conta
sizeof(double), CHUNK);
dmrC_allocator_init(&linearizer->proc_allocator, "proc_allocator", sizeof(struct proc), sizeof(double), CHUNK);
dmrC_allocator_init(&linearizer->unsized_allocator, "unsized_allocator", 0, sizeof(double), CHUNK);
dmrC_allocator_init(&linearizer->constant_allocator, "constant_allocator", sizeof(struct constant), sizeof(double), CHUNK);
dmrC_allocator_init(&linearizer->constant_allocator, "constant_allocator", sizeof(struct constant), sizeof(double),
CHUNK);
}
static void ravi_destroy_linearizer(struct linearizer *linearizer) {
@ -49,7 +49,8 @@ static void ravi_destroy_linearizer(struct linearizer *linearizer) {
FOR_EACH_PTR(linearizer->all_procs, proc) {
if (proc->constants)
set_destroy(proc->constants, NULL);
} END_FOR_EACH_PTR(proc);
}
END_FOR_EACH_PTR(proc);
dmrC_allocator_destroy(&linearizer->edge_allocator);
dmrC_allocator_destroy(&linearizer->instruction_allocator);
dmrC_allocator_destroy(&linearizer->ptrlist_allocator);
@ -73,11 +74,52 @@ static int compare_constants(const void *a, const void *b) {
return c1->s == c2->s;
}
static uint32_t hash_constant(const void *c) {
return fnv1_hash_data(c, sizeof(struct constant));
static uint32_t hash_constant(const void *c) { return fnv1_hash_data(c, sizeof(struct constant)); }
static int allocate_constant(struct linearizer *linearizer, struct ast_node *node) {
assert(node->type == AST_LITERAL_EXPR);
struct proc *proc = linearizer->current_proc;
struct constant c = {.type = node->literal_expr.type.type_code};
if (c.type == RAVI_TNUMINT)
c.i = node->literal_expr.u.i;
else if (c.type == RAVI_TNUMFLT)
c.n = node->literal_expr.u.n;
else
c.s = node->literal_expr.u.s;
struct set_entry *entry = set_search(proc->constants, &c);
if (entry == NULL) {
int reg = proc->num_constants++;
struct constant *c1 = dmrC_allocator_allocate(&linearizer->constant_allocator, 0);
assert(c1);
memcpy(c1, &c, sizeof *c1);
c1->index = reg;
set_add(proc->constants, c1);
return reg;
}
else {
const struct constant *c1 = entry->key;
return c1->index;
}
}
struct pseudo *allocate_local_pseudo(struct proc *proc, struct lua_symbol *sym, unsigned reg) {
assert(sym->symbol_type == SYM_LOCAL);
assert(sym->var.pseudo == NULL);
struct pseudo *pseudo = dmrC_allocator_allocate(&proc->linearizer->pseudo_allocator, 0);
pseudo->type = PSEUDO_LOCAL;
pseudo->symbol = sym;
pseudo->regnum = reg;
sym->var.pseudo = pseudo;
return pseudo;
}
struct pseudo *allocate_constant_pseudo(struct proc *proc, struct constant *constant) {
struct pseudo *pseudo = dmrC_allocator_allocate(&proc->linearizer->pseudo_allocator, 0);
pseudo->type = PSEUDO_CONSTANT;
pseudo->constant = constant;
pseudo->regnum = constant->index;
return pseudo;
}
/**
* Allocate a new proc. If there is a current proc, then the new proc gets added to the
@ -93,6 +135,7 @@ static struct proc *allocate_proc(struct linearizer *linearizer, struct ast_node
ptrlist_add((struct ptr_list **)&linearizer->current_proc->procs, proc, &linearizer->ptrlist_allocator);
}
proc->constants = set_create(hash_constant, compare_constants);
proc->linearizer = linearizer;
return proc;
}
@ -112,8 +155,7 @@ static void linearize_function_args(struct linearizer *linearizer) {
struct ast_node *func_expr = proc->function_expr;
struct lua_symbol *sym;
FOR_EACH_PTR(func_expr->function_expr.args, sym) {
uint8_t reg = alloc_reg(&proc->local_pseudos);
printf("Assigning register %d to argument %s\n", (int)reg, getstr(sym->var.var_name));
// printf("Assigning register %d to argument %s\n", (int)reg, getstr(sym->var.var_name));
}
END_FOR_EACH_PTR(sym);
}
@ -121,58 +163,30 @@ static void linearize_function_args(struct linearizer *linearizer) {
static void linearize_statement(struct linearizer *linearizer, struct ast_node *node);
static void linearize_statement_list(struct linearizer *linearizer, struct ast_node_list *list) {
struct ast_node *node;
FOR_EACH_PTR(list, node) {
linearize_statement(linearizer, node); }
FOR_EACH_PTR(list, node) { linearize_statement(linearizer, node); }
END_FOR_EACH_PTR(node);
}
static int allocate_constant(struct linearizer *linearizer, struct ast_node *node) {
assert(node->type == AST_LITERAL_EXPR);
struct proc *proc = linearizer->current_proc;
struct constant c;
c.type = node->literal_expr.type.type_code;
if (c.type == RAVI_TNUMINT)
c.i = node->literal_expr.u.i;
else if (c.type == RAVI_TNUMFLT)
c.n = node->literal_expr.u.n;
else
c.s = node->literal_expr.u.s;
struct set_entry* entry = set_search(proc->constants, &c);
if (entry == NULL) {
int reg = proc->num_constants++;
struct constant *c1 = dmrC_allocator_allocate(&linearizer->constant_allocator, 0);
assert(c1);
memcpy(c1, &c, sizeof *c1);
c1->index = reg;
set_add(proc->constants, c1);
return reg;
}
else {
const struct constant *c1 = entry->key;
return c1->index;
}
}
static void linearize_statement(struct linearizer *linearizer, struct ast_node *node) {
switch (node->type) {
case AST_FUNCTION_EXPR: {
/* args need type assertions but those have no ast - i.e. code gen should do it */
//typecheck_ast_list(container, function, node->function_expr.function_statement_list);
// typecheck_ast_list(container, function, node->function_expr.function_statement_list);
break;
}
case AST_NONE: {
break;
}
case AST_RETURN_STMT: {
//typecheck_ast_list(container, function, node->return_stmt.expr_list);
// typecheck_ast_list(container, function, node->return_stmt.expr_list);
break;
}
case AST_LOCAL_STMT: {
//typecheck_local_statement(container, function, node);
// typecheck_local_statement(container, function, node);
break;
}
case AST_FUNCTION_STMT: {
//typecheck_ast_node(container, function, node->function_stmt.function_expr);
// typecheck_ast_node(container, function, node->function_stmt.function_expr);
break;
}
case AST_LABEL_STMT: {
@ -185,49 +199,49 @@ static void linearize_statement(struct linearizer *linearizer, struct ast_node *
break;
}
case AST_EXPR_STMT: {
//typecheck_expr_statement(container, function, node);
// typecheck_expr_statement(container, function, node);
break;
}
case AST_IF_STMT: {
//typecheck_if_statement(container, function, node);
// typecheck_if_statement(container, function, node);
break;
}
case AST_WHILE_STMT:
case AST_REPEAT_STMT: {
//typecheck_while_or_repeat_statement(container, function, node);
// typecheck_while_or_repeat_statement(container, function, node);
break;
}
case AST_FORIN_STMT: {
//typecheck_for_in_statment(container, function, node);
// typecheck_for_in_statment(container, function, node);
break;
}
case AST_FORNUM_STMT: {
//typecheck_for_num_statment(container, function, node);
// typecheck_for_num_statment(container, function, node);
break;
}
case AST_SUFFIXED_EXPR: {
//typecheck_suffixedexpr(container, function, node);
// typecheck_suffixedexpr(container, function, node);
break;
}
case AST_FUNCTION_CALL_EXPR: {
//if (node->function_call_expr.method_name) {
// if (node->function_call_expr.method_name) {
//}
//else {
// else {
//}
//typecheck_ast_list(container, function, node->function_call_expr.arg_list);
// typecheck_ast_list(container, function, node->function_call_expr.arg_list);
break;
}
case AST_SYMBOL_EXPR: {
/* symbol type should have been set when symbol was created */
//copy_type(node->symbol_expr.type, node->symbol_expr.var->value_type);
// copy_type(node->symbol_expr.type, node->symbol_expr.var->value_type);
break;
}
case AST_BINARY_EXPR: {
//typecheck_binaryop(container, function, node);
// typecheck_binaryop(container, function, node);
break;
}
case AST_UNARY_EXPR: {
//typecheck_unaryop(container, function, node);
// typecheck_unaryop(container, function, node);
break;
}
case AST_LITERAL_EXPR: {
@ -235,23 +249,23 @@ static void linearize_statement(struct linearizer *linearizer, struct ast_node *
break;
}
case AST_FIELD_SELECTOR_EXPR: {
//typecheck_ast_node(container, function, node->index_expr.expr);
// typecheck_ast_node(container, function, node->index_expr.expr);
break;
}
case AST_Y_INDEX_EXPR: {
//typecheck_ast_node(container, function, node->index_expr.expr);
// typecheck_ast_node(container, function, node->index_expr.expr);
break;
}
case AST_INDEXED_ASSIGN_EXPR: {
//if (node->indexed_assign_expr.index_expr) {
// if (node->indexed_assign_expr.index_expr) {
// typecheck_ast_node(container, function, node->indexed_assign_expr.index_expr);
//}
//typecheck_ast_node(container, function, node->indexed_assign_expr.value_expr);
//copy_type(node->indexed_assign_expr.type, node->indexed_assign_expr.value_expr->common_expr.type);
// typecheck_ast_node(container, function, node->indexed_assign_expr.value_expr);
// copy_type(node->indexed_assign_expr.type, node->indexed_assign_expr.value_expr->common_expr.type);
break;
}
case AST_TABLE_EXPR: {
//typecheck_ast_list(container, function, node->table_expr.expr_list);
// typecheck_ast_list(container, function, node->table_expr.expr_list);
break;
}
default:
@ -259,28 +273,79 @@ static void linearize_statement(struct linearizer *linearizer, struct ast_node *
}
}
static struct basic_block *allocate_basic_block(struct linearizer *linearizer) {
struct proc *proc = linearizer->current_proc;
/**
* Creates and initializes a basic block to be an empty block. Returns the new basic block.
*/
static struct basic_block *create_block(struct proc *proc) {
if (proc->node_count >= proc->allocated) {
unsigned new_size = proc->allocated + 25;
struct node ** new_data = dmrC_allocator_allocate(&linearizer->unsized_allocator, new_size * sizeof(struct node *));
struct node **new_data = dmrC_allocator_allocate(&proc->linearizer->unsized_allocator, new_size * sizeof(struct node *));
assert(new_data != NULL);
if (proc->node_count > 0) {
memcpy(new_data, proc->nodes, proc->allocated*sizeof(struct node *));
memcpy(new_data, proc->nodes, proc->allocated * sizeof(struct node *));
}
proc->allocated = new_size;
proc->nodes = new_data;
}
assert(proc->node_count < proc->allocated);
struct basic_block *new_block = dmrC_allocator_allocate(&linearizer->basic_block_allocator, 0);
struct basic_block *new_block = dmrC_allocator_allocate(&proc->linearizer->basic_block_allocator, 0);
proc->nodes[proc->node_count++] = bb2n(new_block);
return new_block;
}
static void init_blocks(struct linearizer *linearizer) {
struct proc *proc = linearizer->current_proc;
/**
* Takes a basic block as an argument and makes it the current block.
* All future instructions will be added to the end of this block
*/
static void start_block(struct proc *proc, struct basic_block *bb) {
proc->current_bb = bb;
}
/**
* Create the initial blocks entry and exit for the proc.
* sets current block to entry block.
*/
static void initialize_graph(struct proc *proc) {
assert(proc != NULL);
proc->entry = bb2n(allocate_basic_block(linearizer));
proc->exit = bb2n(allocate_basic_block(linearizer));
proc->entry = bb2n(create_block(proc));
proc->exit = bb2n(create_block(proc));
start_block(proc, n2bb(proc->entry));
}
/**
* Makes given scope the current scope, and allocates registers for locals.
*/
static void start_scope(struct linearizer *linearizer, struct proc *proc, struct block_scope *scope) {
proc->current_scope = scope;
struct lua_symbol *sym;
FOR_EACH_PTR(scope->symbol_list, sym) {
if (sym->symbol_type == SYM_LOCAL) {
uint8_t reg = alloc_reg(&proc->local_pseudos);
allocate_local_pseudo(proc, sym, reg);
printf("Assigning register %d to local %s\n", (int)reg, getstr(sym->var.var_name));
}
}
END_FOR_EACH_PTR(sym);
}
/**
* Deallocate local registers when the scope ends, in reverse order
* so that we have a stack discipline, and then changes current scope to be the
* parent scope.
*/
static void end_scope(struct linearizer *linearizer, struct proc *proc) {
struct block_scope *scope = proc->current_scope;
struct lua_symbol *sym;
FOR_EACH_PTR_REVERSE(scope->symbol_list, sym) {
if (sym->symbol_type == SYM_LOCAL) {
struct pseudo *pseudo = sym->var.pseudo;
assert(pseudo && pseudo->type == PSEUDO_LOCAL && pseudo->symbol == sym);
printf("Free register %d for local %s\n", (int)pseudo->regnum, getstr(sym->var.var_name));
free_reg(&proc->local_pseudos, pseudo->regnum);
}
}
END_FOR_EACH_PTR_REVERSE(sym);
proc->current_scope = scope->parent;
}
static void linearize_function(struct linearizer *linearizer) {
@ -288,10 +353,11 @@ static void linearize_function(struct linearizer *linearizer) {
assert(proc != NULL);
struct ast_node *func_expr = proc->function_expr;
assert(func_expr->type == AST_FUNCTION_EXPR);
init_blocks(linearizer);
proc->current_scope = func_expr->function_expr.main_block;
initialize_graph(proc);
start_scope(linearizer, proc, func_expr->function_expr.main_block);
linearize_function_args(linearizer);
linearize_statement_list(linearizer, func_expr->function_expr.function_statement_list);
end_scope(linearizer, proc);
}
void raviA_ast_linearize(struct linearizer *linearizer, struct ast_container *container) {

@ -118,7 +118,7 @@ static struct lua_symbol *new_local_symbol(struct parser_state *parser, TString
symbol->symbol_type = SYM_LOCAL;
symbol->var.block = scope;
symbol->var.var_name = name;
symbol->var.backend_data = NULL;
symbol->var.pseudo = NULL;
add_symbol(parser->container, &scope->symbol_list, symbol); // Add to the end of the symbol list
add_symbol(parser->container, &scope->function->function_expr.locals, symbol);
// Note that Lua allows multiple local declarations of the same name

Loading…
Cancel
Save