Fix calculation of labels and jump destinations.

Previously, all calculations regarding stack depth and label depth
were broken. *All* of them. Off-by-ones, the logic was wrong, etc.
Variables are still screwed up, but I'm *almost* there, where
"there" is being able to generate functioning programs, hopefully?
master
James T. Martin 2022-10-19 15:42:04 -07:00
parent 68ce32a6df
commit d9edbab10c
Signed by: james
GPG Key ID: D6FB2F9892F9B225
3 changed files with 37 additions and 31 deletions

View File

@ -120,6 +120,7 @@ symbol new_symbol(void) {
void define_executable_symbol(symbol s) {
struct symbol* sym = &symbols[s];
assert(sym->vaddr == (uint64_t) -1);
sym->vaddr = file_here;
}

View File

@ -38,10 +38,7 @@ static uint32_t label_depth = 0;
static struct label labels[MAX_LABELS];
void init_ir(var* argc, var* argv, var* env) {
assert(stack_depth == 0);
// seems like this should be necessary. it really feels like there's some
// off-by-one arrows going on around here, but I can't figure it out.
//enter();
assert(stack_depth == 0 && stack_frame == 0);
x86_inst_mov_r64_r64(BP, SP);
x86_inst_add_r64_imm8(BP, 8 * 3);
*env = stack_depth++;
@ -51,7 +48,8 @@ void init_ir(var* argc, var* argv, var* env) {
void enter(void) {
assert(stack_frame < MAX_STACK_FRAMES);
struct stack_frame frame = { stack_depth, label_depth };
printf("ENTERING: %i, %i\n", stack_depth, label_depth);
struct stack_frame frame = { .depth = stack_depth, .label_depth = label_depth };
stack_frames[stack_frame] = frame;
stack_frame++;
// exit label
@ -61,15 +59,16 @@ void enter(void) {
void leave(var* args) {
assert(stack_frame > 0);
struct stack_frame frame = stack_frames[stack_frame - 1];
stack_frame--;
stack_depth = frame.depth;
label_depth = frame.label_depth;
define(frame.label_depth, args);
stack_frame--;
}
label declare(uint32_t argc) {
assert(label_depth < MAX_LABELS);
symbol sym = new_symbol();
struct label label = { stack_frame, argc, sym };
struct label label = { .frame = stack_frame, .argc = argc, .symbol = sym };
labels[label_depth] = label;
return label_depth++;
}
@ -82,18 +81,13 @@ label declare_exit(uint32_t argc) {
void define(label l, var* args) {
struct label* label = &labels[l];
printf("DEFINING %i (%i)\n", l, label->argc);
define_executable_symbol(label->symbol);
// possibly wrong. do I need to do any clean-up of the old frame here?
stack_frame = label->frame;
struct stack_frame* frame = &stack_frames[stack_frame - 1];
label_depth = frame->label_depth;
assert(label->frame == stack_frame);
for (uint32_t i = 0; i < label->argc; i++) {
args[i] = frame->depth + i;
args[i] = stack_depth + i;
}
// probably wrong. seems like I ought to create a new frame or something?
// wouldn't this make the old frame too deep?
// but on the other hand, if I enter a new frame, how do I decide when to leave it?
frame->depth += label->argc;
stack_depth += label->argc;
}
void load_var(reg reg, var var) {
@ -109,13 +103,11 @@ var push_var(reg reg) {
}
void load_args(struct label* label, var* args) {
struct stack_frame* cur_frame = &stack_frames[stack_frame - 1];
struct stack_frame* dest_frame = &stack_frames[label->frame];
uint32_t depth_diff = cur_frame->depth - dest_frame->depth;
uint32_t depth_diff = stack_depth - dest_frame->depth;
if (depth_diff > 0) {
// FIXME: should be immX!!!
// FIXME: this should be necessary! stack depth is never getting decreased!
//x86_inst_add_r64_imm8(SP, depth_diff);
x86_inst_add_r64_imm8(SP, depth_diff);
}
for (uint32_t arg = 0; arg < label->argc; arg++) {
load_var(AX, args[arg]);
@ -125,6 +117,7 @@ void load_args(struct label* label, var* args) {
void jump(label l, var* args) {
struct label* label = &labels[l];
printf("JUMP %i (%i)\n", l, label->argc);
load_args(label, args);
inst_jump(label->symbol);
}
@ -135,6 +128,7 @@ void jump_table(size_t branches, label* labels, var index, var* args) {
void jump_if(label l, var cond, var* args) {
struct label* label = &labels[l];
printf("JUMP_IF %i (%i)\n", l, label->argc);
load_var(BX, cond);
load_args(label, args);
inst_jump_if_not_zero(label->symbol, BX);
@ -142,6 +136,7 @@ void jump_if(label l, var cond, var* args) {
void jump_unless(label l, var cond, var* args) {
struct label* label = &labels[l];
printf("JUMP_UNLESS %i (%i)\n", l, label->argc);
load_var(BX, cond);
load_args(label, args);
inst_jump_if_zero(label->symbol, BX);

View File

@ -34,6 +34,7 @@ enum if_state {
IF_COND,
IF_THEN,
IF_ELSE,
IF_END,
};
struct if_crumb {
@ -336,6 +337,7 @@ void enter_block(void) {
struct if_crumb ifc = ctx->data.if_;
switch (ifc.state) {
case IF_COND:
case IF_END:
assert(0);
case IF_THEN:
define(ifc.then, NULL);
@ -351,6 +353,7 @@ void enter_block(void) {
assert(loopc->state == LOOP_CLEAN);
loopc->state = LOOP_BODY;
loopc->next = declare(loopc->assignment_count);
printf("LOOP %i END %i\n", loopc->next, loopc->exit);
var args[MAX_ASSIGNMENTS];
define(loopc->next, args);
// TODO NOTE: is this the correct order?
@ -392,9 +395,9 @@ void stmt_expr(void) {
void exit_block(void) {
printf("** exit_block\n");
struct crumb ctx = context[context_depth - 1];
assert(ctx.type == BLOCK_CRUMB);
struct block_crumb blockc = ctx.data.block;
struct crumb* ctx = &context[context_depth - 1];
assert(ctx->type == BLOCK_CRUMB);
struct block_crumb blockc = ctx->data.block;
assert(blockc.state == BLOCK_CLEAN);
var ret = blockc.final;
if (ret == (var) -1) {
@ -402,21 +405,26 @@ void exit_block(void) {
ret = lit(0);
}
context_depth--;
ctx = context[context_depth - 1];
switch (ctx.type) {
ctx = &context[context_depth - 1];
switch (ctx->type) {
case EXPR_CRUMB: {
push_argument(ret);
break;
}
case IF_CRUMB: {
struct if_crumb ifc = ctx.data.if_;
assert(ifc.state != IF_COND);
jump(ifc.end, &ret);
struct if_crumb* ifc = &ctx->data.if_;
assert(ifc->state == IF_THEN || ifc->state == IF_ELSE);
jump(ifc->end, &ret);
if (ifc->state == IF_THEN) {
ifc->state = IF_ELSE;
} else if (ifc->state == IF_ELSE) {
ifc->state = IF_END;
}
break;
}
case LOOP_CRUMB: {
// unlike with `if`, there is no `exit_loop`, so we do clean-up here.
struct loop_crumb loopc = ctx.data.loop;
struct loop_crumb loopc = ctx->data.loop;
assert(loopc.state == LOOP_BODY);
jump(loopc.exit, &ret);
context_depth--;
@ -501,6 +509,7 @@ void enter_if(void) {
label then = declare(0);
label else_ = declare(0);
label end = declare_exit(1);
printf("IF THEN %i ELSE %i EXIT %i\n", then, else_, end);
struct if_crumb ifc = {
.state = IF_COND,
.then = then,
@ -524,14 +533,15 @@ void exit_if(void) {
struct if_crumb ifc = ctx.data.if_;
switch (ifc.state) {
case IF_COND:
case IF_THEN:
assert(0);
case IF_THEN: {
case IF_ELSE: {
define(ifc.else_, NULL);
var ret = lit(0);
jump(ifc.end, &ret);
break;
}
case IF_ELSE:
case IF_END:
break;
}
var ret;