diff options
Diffstat (limited to 'codegen.c')
| -rw-r--r-- | codegen.c | 145 |
1 files changed, 72 insertions, 73 deletions
@@ -15,8 +15,8 @@ } struct lval_def { + const struct type_def* type; struct storage_location loc; - unsigned long long sz; }; static const struct storage_location RV_LOC = { @@ -36,39 +36,42 @@ static struct scope* scope; static const struct fn_decl_node* active_fn; static unsigned long long branch_counter = 0; -static struct lval_def allocate_register(unsigned long long sz) { +static struct lval_def allocate_register(const struct type_def* type) { return (struct lval_def) { .loc = { .type = STO_REG, .reg = &RAX, /* TODO: no real register coloring happening LOL */ }, - .sz = sz, + .type = type, }; } -static struct lval_def allocate_stack(FILE* outfile, unsigned long long sz) { - fprintf(outfile, "\tsub rsp, %llu\n", sz); - scope->bp_offset += sz; +static struct lval_def allocate_stack( + FILE* outfile, + const struct type_def* type +) { + fprintf(outfile, "\tsub rsp, %llu\n", type->sz); + scope->bp_offset += type->sz; return (struct lval_def) { .loc = { .type = STO_STACK, .bp_offset = scope->bp_offset, }, - .sz = sz, + .type = type, }; } static struct lval_def allocate_temporary( FILE* outfile, - unsigned long long sz + const struct type_def* type ) { - return allocate_stack(outfile, sz); + return allocate_stack(outfile, type); } static void deallocate_temporary(FILE* outfile, const struct lval_def* tmp) { if (tmp->loc.type == STO_STACK) { - fprintf(outfile, "\tadd rsp, %llu\n", tmp->sz); - scope->bp_offset -= tmp->sz; + fprintf(outfile, "\tadd rsp, %llu\n", tmp->type->sz); + scope->bp_offset -= tmp->type->sz; } } @@ -146,32 +149,32 @@ static void emit_mov( switch (dst->loc.type) { case STO_REG: - if (src->type == STO_REG && dst->sz < 4) { + if (src->type == STO_REG && dst->type->sz < 4) { fprintf(outfile, "\tmovzx "); emit_storage_loc(outfile, &dst->loc, FULL_REG_SZ); } else { fprintf(outfile, "\tmov "); - emit_storage_loc(outfile, &dst->loc, dst->sz); + emit_storage_loc(outfile, &dst->loc, dst->type->sz); } fprintf(outfile, ", "); - emit_storage_loc(outfile, src, dst->sz); + emit_storage_loc(outfile, src, dst->type->sz); break; case STO_STACK: if (src->type == STO_STACK) { /* `mov mem, mem` is illegal in x86_64 */ - struct lval_def tmp = allocate_register(dst->sz); + struct lval_def tmp = allocate_register(dst->type); emit_mov(outfile, &tmp, src); emit_mov(outfile, dst, &tmp.loc); return; } fprintf(outfile, "\tmov "); - if (src->type == STO_IMM) emit_size_const(outfile, dst->sz); + if (src->type == STO_IMM) emit_size_const(outfile, dst->type->sz); - emit_storage_loc(outfile, &dst->loc, dst->sz); + emit_storage_loc(outfile, &dst->loc, dst->type->sz); fprintf(outfile, ", "); - emit_storage_loc(outfile, src, dst->sz); + emit_storage_loc(outfile, src, dst->type->sz); break; case STO_LABEL: case STO_IMM: @@ -186,11 +189,11 @@ static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) { fprintf(outfile, "\tcmp "); switch (lval->loc.type) { case STO_REG: - emit_storage_loc(outfile, &lval->loc, lval->sz); + emit_storage_loc(outfile, &lval->loc, lval->type->sz); break; case STO_STACK: - emit_size_const(outfile, lval->sz); - emit_storage_loc(outfile, &lval->loc, lval->sz); + emit_size_const(outfile, lval->type->sz); + emit_storage_loc(outfile, &lval->loc, lval->type->sz); break; case STO_LABEL: case STO_IMM: @@ -201,17 +204,17 @@ static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) { fprintf(outfile, ", 0\n"); } -/* TODO: move this utility to the type checker and use evaluated_type */ -static unsigned long long get_type_size(const struct type_node* type) { +/* TODO: move this utility to the type checker and use resolved_type */ +static unsigned long long get_type_size(const struct type_ref_node* type) { if (type->ptr_level > 0) return PTR_SIZE; - return type->def->sz; + return type->def_ref->sz; } static inline struct lval_def make_stack_lval( FILE* outfile, - const struct type_node* type + const struct type_def* type ) { - return allocate_stack(outfile, get_type_size(type)); + return allocate_stack(outfile, type); } static void emit_expr( @@ -270,8 +273,8 @@ static void emit_str_lit( } } -static struct var_def get_var(const char* name) { - struct var_def var_def; +static struct var_def* get_var(const char* name) { + struct var_def* var_def; if (!scope_get_var(scope, &var_def, name)) CGEN_PANIC("reference to undefined variable %s", name); return var_def; @@ -283,25 +286,19 @@ static void emit_var_ref( const struct lval_def* dst ) { if (dst != NULL) { - struct var_def var_def = get_var(node->ident); - emit_mov(outfile, dst, &var_def.loc); + emit_mov(outfile, dst, &get_var(node->ident)->loc); } } static void emit_stmt(FILE* outfile, const struct stmt_node* node); -static struct var_def emit_var_decl( +static struct var_def* emit_var_decl( FILE* outfile, const struct var_decl_node* node ) { - /* TODO: type checker should define vars, we just set their loc */ - struct lval_def var_dst = make_stack_lval(outfile, &node->type); - struct var_def var_def = { - .name = node->ident, - .loc = var_dst.loc, - .sz = var_dst.sz, - }; - scope_define_var(scope, var_def); + struct lval_def var_dst = make_stack_lval(outfile, node->type.def_ref); + struct var_def* var_def = node->def_ref; + var_def->loc = var_dst.loc; return var_def; } @@ -309,14 +306,20 @@ static struct lval_def emit_lval( FILE* outfile, const struct lval_node* node ) { - struct var_def var_def; + struct var_def* var_def; switch (node->type) { case LVAL_VAR_DECL: var_def = emit_var_decl(outfile, &node->inner.var_decl); - return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; + return (struct lval_def) { + .loc = var_def->loc, + .type = var_def->resolved_type, + }; case LVAL_VAR_REF: var_def = get_var(node->inner.var_ref.ident); - return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz}; + return (struct lval_def) { + .loc = var_def->loc, + .type = var_def->resolved_type, + }; } CGEN_PANIC("unknown lval type: %d", node->type); } @@ -343,7 +346,7 @@ static void emit_call( struct args_eval_node* arg_eval = node->args; while (arg_decl != NULL && arg_eval != NULL) { struct lval_def arg_dst = - make_stack_lval(outfile, &arg_decl->decl->type); + make_stack_lval(outfile, arg_decl->decl->type.def_ref); emit_expr(outfile, arg_eval->expr, &arg_dst); arg_decl = arg_decl->next; @@ -368,14 +371,14 @@ static void emit_call( struct lval_def arg_dst; if (arg_regnum < CC_N_REGS) arg_dst = (struct lval_def) { + .type = arg_decl->decl->type.def_ref, .loc = (struct storage_location) { .type = STO_REG, .reg = CALLING_CONV[arg_regnum++], }, - .sz = type_sz, }; else - arg_dst = make_stack_lval(outfile, &arg_decl->decl->type); + arg_dst = make_stack_lval(outfile, arg_decl->decl->type.def_ref); emit_mov(outfile, &arg_dst, &(struct storage_location) { .type = STO_STACK, @@ -411,8 +414,11 @@ static void emit_unary( switch (node->op) { case UNARY_NEG: fprintf(outfile, "\tneg "); - if (dst->loc.type == STO_STACK) emit_size_const(outfile, dst->sz); - emit_storage_loc(outfile, &dst->loc, dst->sz); + + if (dst->loc.type == STO_STACK) + emit_size_const(outfile, dst->type->sz); + + emit_storage_loc(outfile, &dst->loc, dst->type->sz); fprintf(outfile, "\n"); break; } @@ -431,29 +437,29 @@ static void emit_binary( } /* LHS goes in RAX explicitly because imul and idiv are weird */ - struct lval_def rhs_dst = allocate_temporary(outfile, dst->sz); + struct lval_def rhs_dst = allocate_temporary(outfile, dst->type); emit_expr(outfile, node->rhs, &rhs_dst); struct lval_def lhs_dst = (struct lval_def) { .loc = MULDIV_LOC, - .sz = dst->sz, + .type = dst->type, }; emit_expr(outfile, node->lhs, &lhs_dst); switch (node->op) { case BINARY_ADD: fprintf(outfile, "\tadd "); - emit_storage_loc(outfile, &lhs_dst.loc, dst->sz); + emit_storage_loc(outfile, &lhs_dst.loc, dst->type->sz); fprintf(outfile, ", "); break; case BINARY_SUB: fprintf(outfile, "\tsub "); - emit_storage_loc(outfile, &lhs_dst.loc, dst->sz); + emit_storage_loc(outfile, &lhs_dst.loc, dst->type->sz); fprintf(outfile, ", "); break; case BINARY_MUL: fprintf(outfile, "\timul "); if (rhs_dst.loc.type == STO_STACK) - emit_size_const(outfile, dst->sz); + emit_size_const(outfile, dst->type->sz); break; case BINARY_DIV: /* nothing in the top half reg */ @@ -465,11 +471,11 @@ static void emit_binary( fprintf(outfile, "\tidiv "); if (rhs_dst.loc.type == STO_STACK) - emit_size_const(outfile, dst->sz); + emit_size_const(outfile, dst->type->sz); break; } - emit_storage_loc(outfile, &rhs_dst.loc, dst->sz); + emit_storage_loc(outfile, &rhs_dst.loc, dst->type->sz); fprintf(outfile, "\n"); /* TODO: deal with RDX overflow shit for imul and idiv */ @@ -517,10 +523,10 @@ static void emit_expr( static void emit_return(FILE* outfile, const struct return_node* node) { if (active_fn == NULL) CGEN_PANIC("must be inside a function to return"); - unsigned long long return_type_sz = get_type_size(&active_fn->return_type); + const struct type_def* return_type = active_fn->return_type.def_ref; if (node->ret_val != NULL) { - if (return_type_sz == 0) + if (return_type->sz == 0) CGEN_PANIC( "returning a value from void function %s", active_fn->name); @@ -529,9 +535,9 @@ static void emit_return(FILE* outfile, const struct return_node* node) { node->ret_val, &(struct lval_def) { .loc = RV_LOC, - .sz = return_type_sz, + .type = return_type, }); - } else if (return_type_sz > 0) { + } else if (return_type > 0) { CGEN_PANIC( "non-void function %s should return a value", active_fn->name); } @@ -561,8 +567,9 @@ static void emit_group(FILE* outfile, const struct group_node* node) { } static void emit_if(FILE* outfile, const struct if_node* node) { - /* TODO: use type checked cond result size; using full reg size causes a segfault */ - struct lval_def cond_result = allocate_temporary(outfile, FULL_REG_SZ); + /* TODO: make type checking real so we aren't passing a null pointer here */ + struct lval_def cond_result = + allocate_temporary(outfile, node->cond->resolved_type); emit_expr(outfile, node->cond, &cond_result); emit_cmp_zero(outfile, &cond_result); @@ -622,17 +629,11 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { long long spilled_bp_ofs = -16; // return address + old bp unsigned char arg_regnum = 0; struct args_decl_node* arg_decl = node->args; - while (arg_decl != NULL) { + for (; arg_decl != NULL; arg_decl = arg_decl->next) { + struct var_def* arg_def = arg_decl->decl->def_ref; struct lval_def arg_dst = - make_stack_lval(outfile, &arg_decl->decl->type); - /* TODO: type checker should define vars, we just set their loc */ - scope_define_var( - scope, - (struct var_def) { - .name = arg_decl->decl->ident, - .loc = arg_dst.loc, - .sz = arg_dst.sz, - }); + make_stack_lval(outfile, arg_decl->decl->type.def_ref); + arg_def->loc = arg_dst.loc; struct storage_location arg_src; if (arg_regnum < CC_N_REGS) { @@ -645,11 +646,9 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { .type = STO_STACK, .bp_offset = spilled_bp_ofs, }; - spilled_bp_ofs -= arg_dst.sz; + spilled_bp_ofs -= arg_decl->decl->type.def_ref->sz; } emit_mov(outfile, &arg_dst, &arg_src); - - arg_decl = arg_decl->next; } emit_group_contents(outfile, &node->body); |
