From 1dfa2971999b4adf36a33866b0b07af07188da08 Mon Sep 17 00:00:00 2001 From: Carson Fleming Date: Tue, 31 Mar 2026 16:30:29 -1000 Subject: math n shi --- codegen.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 140 insertions(+), 27 deletions(-) (limited to 'codegen.c') diff --git a/codegen.c b/codegen.c index 216d41a..662097e 100644 --- a/codegen.c +++ b/codegen.c @@ -23,6 +23,11 @@ static const struct storage_location RV_LOC = { .type = STO_REG, .reg = &RAX, }; +static const struct storage_location MULDIV_LOC = RV_LOC; +static const struct storage_location MULDIV_OVERFLOW_LOC = { + .type = STO_REG, + .reg = &RDX, +}; #define RETURN_LABEL_FMT "%s@coda" #define FULL_REG_SZ 8 @@ -30,6 +35,42 @@ static const struct storage_location RV_LOC = { static struct scope* scope; static const struct fn_decl_node* active_fn; +static struct lval_def allocate_register(unsigned long long sz) { + return (struct lval_def) { + .loc = { + .type = STO_REG, + .reg = &RAX, /* TODO: no real register coloring happening LOL */ + }, + .sz = sz, + }; +} + +static struct lval_def allocate_stack(FILE* outfile, unsigned long long sz) { + fprintf(outfile, "\tsub rsp, %llu\n", sz); + scope->bp_offset += sz; + return (struct lval_def) { + .loc = { + .type = STO_STACK, + .bp_offset = scope->bp_offset, + }, + .sz = sz, + }; +} + +static struct lval_def allocate_temporary( + FILE* outfile, + unsigned long long sz +) { + return allocate_stack(outfile, sz); +} + +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; + } +} + static void emit_storage_loc( FILE* outfile, const struct storage_location* loc, @@ -83,6 +124,13 @@ static bool locs_equal( CGEN_PANIC("unhandled storage type case"); } +static void emit_size_const(FILE* outfile, unsigned long long sz) { + if (sz > 4) fprintf(outfile, "qword "); + else if (sz > 2) fprintf(outfile, "dword "); + else if (sz > 1) fprintf(outfile, "word "); + else fprintf(outfile, "byte "); +} + static void emit_mov( FILE* outfile, const struct lval_def* dst, @@ -107,25 +155,14 @@ static void emit_mov( case STO_STACK: if (src->type == STO_STACK) { /* `mov mem, mem` is illegal in x86_64 */ - emit_mov( - outfile, - &(struct lval_def) { - .loc = RV_LOC, - .sz = dst->sz, - }, - src); - emit_mov(outfile, dst, &RV_LOC); + struct lval_def tmp = allocate_register(dst->sz); + emit_mov(outfile, &tmp, src); + emit_mov(outfile, dst, &tmp.loc); return; } fprintf(outfile, "\tmov "); - if (src->type == STO_IMM) { - /* must specify size to move immediates into memory*/ - if (dst->sz > 4) fprintf(outfile, "qword "); - else if (dst->sz > 2) fprintf(outfile, "dword "); - else if (dst->sz > 1) fprintf(outfile, "word "); - else fprintf(outfile, "byte "); - } + if (src->type == STO_IMM) emit_size_const(outfile, dst->sz); emit_storage_loc(outfile, &dst->loc, dst->sz); fprintf(outfile, ", "); @@ -148,20 +185,11 @@ static unsigned long long get_type_size(const struct type_node* type) { return type->def.sz; } -static struct lval_def make_stack_lval( +static inline struct lval_def make_stack_lval( FILE* outfile, const struct type_node* type ) { - unsigned long long type_sz = get_type_size(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 = type_sz, - }; + return allocate_stack(outfile, get_type_size(type)); } static void emit_expr( @@ -336,7 +364,7 @@ static void emit_call( emit_mov(outfile, dst, &RV_LOC); } - /* pop our argument temporaries off the stack */ + /* mass-pop our argument temporaries off the stack */ scope->bp_offset = orig_bp_offset; if (orig_bp_offset > 0) fprintf(outfile, "\tlea rsp, [rbp - %llu]\n", orig_bp_offset); @@ -344,6 +372,85 @@ static void emit_call( fprintf(outfile, "\tmov rsp, rbp\n"); } +static void emit_unary( + FILE* outfile, + const struct unary_node* node, + const struct lval_def* dst +) { + emit_expr(outfile, node->expr, dst); + if (dst == NULL) return; + + 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); + fprintf(outfile, "\n"); + break; + } +} + +/* TODO: tighten up/enforce with regard to up-casting smaller operands */ +static void emit_binary( + FILE* outfile, + const struct binary_node* node, + const struct lval_def* dst +) { + if (dst == NULL) { + emit_expr(outfile, node->lhs, NULL); + emit_expr(outfile, node->rhs, NULL); + return; + } + + /* LHS goes in RAX explicitly because imul and idiv are weird */ + struct lval_def rhs_dst = allocate_temporary(outfile, dst->sz); + emit_expr(outfile, node->rhs, &rhs_dst); + struct lval_def lhs_dst = (struct lval_def) { + .loc = MULDIV_LOC, + .sz = dst->sz, + }; + 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); + fprintf(outfile, ", "); + break; + case BINARY_SUB: + fprintf(outfile, "\tsub "); + emit_storage_loc(outfile, &lhs_dst.loc, dst->sz); + fprintf(outfile, ", "); + break; + case BINARY_MUL: + fprintf(outfile, "\timul "); + if (rhs_dst.loc.type == STO_STACK) + emit_size_const(outfile, dst->sz); + break; + case BINARY_DIV: + /* nothing in the top half reg */ + fprintf(outfile, "\txor "); + emit_storage_loc(outfile, &MULDIV_OVERFLOW_LOC, FULL_REG_SZ); + fprintf(outfile, ", "); + emit_storage_loc(outfile, &MULDIV_OVERFLOW_LOC, FULL_REG_SZ); + fprintf(outfile, "\n"); + + fprintf(outfile, "\tidiv "); + if (rhs_dst.loc.type == STO_STACK) + emit_size_const(outfile, dst->sz); + break; + } + + emit_storage_loc(outfile, &rhs_dst.loc, dst->sz); + fprintf(outfile, "\n"); + + /* TODO: deal with RDX overflow shit for imul and idiv */ + emit_mov(outfile, dst, &lhs_dst.loc); + + deallocate_temporary(outfile, &lhs_dst); + deallocate_temporary(outfile, &rhs_dst); +} + static void emit_expr( FILE* outfile, const struct expr_node* node, @@ -371,6 +478,12 @@ static void emit_expr( case EXPR_CALL: emit_call(outfile, &node->as._call, dst); break; + case EXPR_UNARY: + emit_unary(outfile, &node->as._unary, dst); + break; + case EXPR_BINARY: + emit_binary(outfile, &node->as._binary, dst); + break; } } -- cgit v1.2.3