Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve stdlib #97

Merged
merged 13 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions compiler/main/avr_code_gen/cg_avr_basic_block.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <stdbool.h>
#include <stdio.h>

#include "compiler/cli/flags/flags.h"
#include "tables/symtable/symtable.h"

#include "tac/tac.h"
Expand All @@ -21,6 +22,10 @@ void emit_asm_avr_basic_block(struct BasicBlock* block, struct Ctx* ctx, struct
if (block == NULL || block->visited_emit_asm)
return;

if (flags_debug(ctx_flags(ctx))) {
printf("%s\n", __func__);
}

block->visited_emit_asm = true;

//create register allocation table for the basic block.
Expand All @@ -32,15 +37,16 @@ void emit_asm_avr_basic_block(struct BasicBlock* block, struct Ctx* ctx, struct
//TODO: use better approach
allocate_registers(block->buffer, rat, ctx_tables(ctx));

if (flags_debug(ctx_flags(ctx))) {
rat_print(rat);
}

for (size_t i = 0; i < tacbuffer_count(block->buffer); i++) {
struct TAC* t = tacbuffer_get(block->buffer, i);

emit_asm_avr_single_tac(rat, t, ctx, ibu);
}

//if(ctx->flags->debug)
//rat_print(rat);

rat_dtor(rat);

//false/default branch gets emitted first,
Expand Down Expand Up @@ -119,12 +125,16 @@ static void allocate_registers_single_tac(struct TAC* t, struct RAT* rat, struct

case TAC_LOAD_CONST_ADDR:
rat_ensure_register(rat, t->dest, false, true);
//TODO: know the width of the load
break;

case TAC_LOAD:
//sadly we do not know what is all going to be added/subtracted
//from what we load there, could be a pointer, so it must be wide
rat_ensure_register(rat, t->dest, false, true);
{
const bool iswide = t->const_value >= 2;
rat_ensure_register(rat, t->dest, false, iswide);
}
break;

default: break;
Expand Down
15 changes: 14 additions & 1 deletion compiler/main/avr_code_gen/compile_ir/compile_tac_call.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ void compile_tac_call(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu, str
int reg_dest = rat_get_register(rat, tac->dest);
const int RAT_SCRATCH_REG = rat_scratch_reg(rat);

const bool wide_dest = rat_is_wide(rat, tac->dest);

//in case of tests, where SST may not be filled correctly
char* function_name = "main";

Expand All @@ -23,9 +25,15 @@ void compile_tac_call(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu, str

call(function_name, "TAC_CALL");

if (reg_dest != 0)
if (reg_dest != 0) {
mov(reg_dest, 0, "TAC_CALL");

if (wide_dest) {
// TODO: check if function return type is wide
mov(reg_dest + 1, 1, "TAC_CALL");
}
}

struct SST* sst = ctx_tables(ctx)->sst;

//for the case of tests on raw TACBuffers
Expand All @@ -40,4 +48,9 @@ void compile_tac_call(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu, str
for (uint32_t i = 0; i < size; i++) {
pop(RAT_SCRATCH_REG, "remove call params");
}

// load possibly corrupted frame pointer
//load base pointer Y
in(YL, SPL, "restore frame pointer Y after call");
in(YH, SPH, "restore frame pointer Y after call");
}
10 changes: 9 additions & 1 deletion compiler/main/avr_code_gen/compile_ir/compile_tac_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,20 @@ void compile_tac_load(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu) {
else
ldi(XH, 0, c);

if (rat_is_wide(rat, tac->dest)) {
// TODO: make a 'wide' property in struct TAC
// to avoid encoding this in different places
const bool tac_says_wide = tac->const_value == 2;

if (tac_says_wide) {

// what if we want to load a 16 bit value?
ldXpostInc(reg_dest, c);
ldX(reg_dest + 1, c);
} else {
ldX(reg_dest, c);

if (rat_is_wide(rat, tac->dest)) {
clr(reg_dest + 1, c);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#include <stdio.h>

#include "tac/tacbuffer.h"
#include "tac/tac.h"
#include "avr_code_gen/compile_ir/compile_tac.h"
Expand All @@ -8,7 +6,13 @@ void compile_tac_load_const_addr(struct RAT* rat, struct TAC* tac, struct IBuffe

const int reg_dest = rat_get_register(rat, tac->dest);

const bool is_wide = rat_is_wide(rat, tac->dest);

const uint32_t addr = tac->const_value;

lds(reg_dest, addr, "TAC_LOAD_CONST_ADDR");

if (is_wide) {
lds(reg_dest + 1, addr + 1, "TAC_LOAD_CONST_ADDR");
}
}
24 changes: 20 additions & 4 deletions compiler/main/avr_code_gen/compile_ir/compile_tac_param.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

#include "rat/rat.h"

Expand All @@ -8,12 +9,27 @@

void compile_tac_param(struct RAT* rat, struct TAC* tac, struct IBuffer* ibu) {

const char* c = "TAC_PARAM";
char* c = "TAC_PARAM";

const int reg_dest = rat_get_register(rat, tac->dest);

push(reg_dest, c);
assert(tac->const_value % 8 == 0);
assert(tac->const_value <= 64);

if (tac->const_value == 16) {
// this means it's a 16 bit parameter
// so we must push twice

//TODO: ensure that the temporary has the correct width in RAT
//assert(rat_is_wide(rat, tac->dest));

if (rat_is_wide(rat, tac->dest) && tac->const_value == 16)
push(reg_dest + 1, c);
if (rat_is_wide(rat, tac->dest)) {
push(reg_dest + 1, c);
} else {
ldi(rat_scratch_reg(rat), 0, c);
push(rat_scratch_reg(rat), c);
}
}

push(reg_dest, c);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,11 @@ void compile_tac_store_const_addr(struct RAT* rat, struct TAC* tac, struct IBuff

const uint32_t addr = tac->const_value;

sts(addr, reg_src, "TAC_STORE_CONST_ADDR");
char* c = "TAC_STORE_CONST_ADDR";

sts(addr, reg_src, c);

if (rat_is_wide(rat, tac->arg1)) {
sts(addr + 1, reg_src + 1, c);
}
}
8 changes: 6 additions & 2 deletions compiler/main/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,20 @@ bool compile(struct Flags* flags) {
ast->namespaces[i] = ns;
}

struct Ctx* ctx = ctx_ctor(flags, st_ctor(flags_debug(flags)));
struct Ctx* ctx = ctx_ctor(flags, st_ctor());

fill_tables(ast, ctx);

struct TCError* errors = typecheck_ast(ast, ctx_tables(ctx), true);
struct TCError* errors = typecheck_ast(ast, ctx, true);

if (errors != NULL) {
return false;
}

if (flags_debug(flags)) {
printf("[debug] running analyzers...\n");
}

analyze_functions(ctx_tables(ctx), ast);
analyze_dead_code(ctx_tables(ctx), ast);
analyze_termination(ctx_tables(ctx));
Expand Down
79 changes: 70 additions & 9 deletions compiler/main/gen_tac/gen_tac_call.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "tac/tac.h"
#include "tac/tacbuffer.h"
Expand All @@ -11,26 +12,86 @@

#include "gen_tac.h"

void tac_call(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) {
static void tac_call_case_sst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx);
static void tac_call_case_lvst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx);

const char* fname = call->callable->simple_var->name;
static void tac_call_prep_param(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, int i, const bool push16) {
struct Expr* expr = call->args[i];

struct SST* sst = ctx_tables(ctx)->sst;
struct SSTLine* line = sst_get(sst, fname);
tac_expr(buffer, expr, ctx);

struct TAC* t = makeTACParam(tacbuffer_last_dest(buffer), push16);

tacbuffer_append(buffer, t);
}

static void tac_call_prep_params_case_sst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, struct MethodDecl* decl) {
for (size_t i = 0; i < call->count_args; i++) {
const uint32_t param_width = lvst_sizeof_type(decl->args[i]->type);
assert(param_width <= 8);
const bool push16 = param_width == 2;

tac_call_prep_param(buffer, call, ctx, i, push16);
}
}

struct Expr* expr = call->args[i];
static void tac_call_prep_params_case_lvst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx, struct LVSTLine* line) {
for (size_t i = 0; i < call->count_args; i++) {
struct Type* arg_type = line->type->basic_type->subr_type->arg_types[i];
const uint32_t param_width = lvst_sizeof_type(arg_type);
assert(param_width <= 8);
const bool push16 = param_width == 2;

tac_expr(buffer, expr, ctx);
tac_call_prep_param(buffer, call, ctx, i, push16);
}
}

const bool push16 = 16 == lvst_sizeof_type(line->method->decl->args[i]->type);
void tac_call(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) {

struct TAC* t = makeTACParam(tacbuffer_last_dest(buffer), push16);
char* fname = call->callable->simple_var->name;
struct SST* sst = ctx_tables(ctx)->sst;
struct LVST* lvst = ctx_tables(ctx)->lvst;

tacbuffer_append(buffer, t);
if (sst_contains(sst, fname)) {
tac_call_case_sst(buffer, call, ctx);
return;
}
if (lvst_contains(lvst, fname)) {
tac_call_case_lvst(buffer, call, ctx);
return;
}

fprintf(stderr, "did not find symbol '%s' in LVST or SST, cannot call.\n", fname);
fprintf(stderr, "exiting.");
exit(1);
}

static void tac_call_case_lvst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) {

struct LVST* lvst = ctx_tables(ctx)->lvst;
char* fname = call->callable->simple_var->name;

struct LVSTLine* line = lvst_get(lvst, fname);
tac_call_prep_params_case_lvst(buffer, call, ctx, line);
uint32_t tmp = make_temp();
struct TAC* t1 = makeTACLoadLocal(tmp, lvst_index_of(lvst, fname));
struct TAC* t2 = makeTACICall(make_temp(), tmp);

tacbuffer_append(buffer, t1);
tacbuffer_append(buffer, t2);
}

static void tac_call_case_sst(struct TACBuffer* buffer, struct Call* call, struct Ctx* ctx) {

const char* fname = call->callable->simple_var->name;

struct SST* sst = ctx_tables(ctx)->sst;
struct SSTLine* line = sst_get(sst, fname);

struct MethodDecl* decl = line->method->decl;

tac_call_prep_params_case_sst(buffer, call, ctx, decl);

if (call->callable->member_access != NULL) {
printf("member access calls currently unsupported on avr_code_gen\n");
exit(1);
Expand Down
3 changes: 2 additions & 1 deletion compiler/main/gen_tac/gen_tac_mdirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ static void case_variable_addr(struct TACBuffer* buffer, struct Expr* expr, stru

tac_expr(buffer, expr, ctx);

struct TAC* t = makeTACLoad(make_temp(), tacbuffer_last_dest(buffer));
// TODO: for x86, this needs to be 8 bytes, not 2
struct TAC* t = makeTACLoad(make_temp(), tacbuffer_last_dest(buffer), 2);

tacbuffer_append(buffer, t);
}
5 changes: 4 additions & 1 deletion compiler/main/gen_tac/gen_tac_simplevar.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ void tac_simplevar(struct TACBuffer* buffer, struct SimpleVar* v, struct Ctx* ct

uint32_t tlast = tacbuffer_last_dest(buffer);

tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast));
struct LVST* lvst = ctx_tables(ctx)->lvst;
const uint8_t simplevar_width = lvst_sizeof_var(lvst, v->name);

tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast, simplevar_width));
}

void tac_simplevar_addr(struct TACBuffer* buffer, struct SimpleVar* sv, struct Ctx* ctx) {
Expand Down
5 changes: 4 additions & 1 deletion compiler/main/gen_tac/gen_tac_variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ void tac_variable(struct TACBuffer* buffer, struct Variable* v, struct Ctx* ctx)

uint32_t tlast = tacbuffer_last_dest(buffer);

tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast));
// TODO: do not assume the variable has 2 bytes
// on avr, it can only be 1 byte
// on x86 it can be up to 8
tacbuffer_append(buffer, makeTACLoad(make_temp(), tlast, 2));
}

void tac_variable_addr(struct TACBuffer* buffer, struct Variable* v, struct Ctx* ctx) {
Expand Down
3 changes: 2 additions & 1 deletion compiler/main/gen_tac/helper_gen_tac_derefll.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ void tac_derefll_single(struct TACBuffer* buffer, struct DerefLL* dll, struct Ty
} break;

case DEREFLL_DEREF:
tacbuffer_append(buffer, makeTACLoad(make_temp(), tacbuffer_last_dest(buffer)));
// TODO: the width there needs to be architecture specific, for x86 it's not 2 but 8 bytes
tacbuffer_append(buffer, makeTACLoad(make_temp(), tacbuffer_last_dest(buffer), 2));
break;
}
}
4 changes: 4 additions & 0 deletions compiler/main/typechecker/tc_assignstmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ static bool check_type_rules_assign(struct AssignStmt* a, struct TCCtx* tcctx);

bool tc_assignstmt(struct AssignStmt* a, struct TCCtx* tcctx) {

if (tcctx->debug) {
printf("[debug] typecheck assign stmt\n");
}

tcctx->current_line_num = a->super.line_num;

struct LVSTLine* line = lvst_get(tcctx->st->lvst, a->var->simple_var->name);
Expand Down
6 changes: 5 additions & 1 deletion compiler/main/typechecker/tc_forstmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

bool tc_forstmt(struct ForStmt* f, struct TCCtx* tcctx) {

if (tcctx->debug) {
printf("[debug] typecheck for stmt\n");
}

tcctx->current_line_num = f->super.line_num;

if (!tc_range(f->range, tcctx)) { return false; }
Expand All @@ -25,4 +29,4 @@ bool tc_forstmt(struct ForStmt* f, struct TCCtx* tcctx) {
tcctx->depth_inside_loop--;

return is_ok;
}
}
4 changes: 4 additions & 0 deletions compiler/main/typechecker/tc_ifstmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

bool tc_ifstmt(struct IfStmt* i, struct TCCtx* tcctx) {

if (tcctx->debug) {
printf("[debug] typecheck if stmt\n");
}

tcctx->current_line_num = i->super.line_num;

struct Type* type = infer_type_expr(tcctx->st, i->condition);
Expand Down
Loading