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) { void define_executable_symbol(symbol s) {
struct symbol* sym = &symbols[s]; struct symbol* sym = &symbols[s];
assert(sym->vaddr == (uint64_t) -1);
sym->vaddr = file_here; sym->vaddr = file_here;
} }

View File

@ -38,10 +38,7 @@ static uint32_t label_depth = 0;
static struct label labels[MAX_LABELS]; static struct label labels[MAX_LABELS];
void init_ir(var* argc, var* argv, var* env) { void init_ir(var* argc, var* argv, var* env) {
assert(stack_depth == 0); assert(stack_depth == 0 && stack_frame == 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();
x86_inst_mov_r64_r64(BP, SP); x86_inst_mov_r64_r64(BP, SP);
x86_inst_add_r64_imm8(BP, 8 * 3); x86_inst_add_r64_imm8(BP, 8 * 3);
*env = stack_depth++; *env = stack_depth++;
@ -51,7 +48,8 @@ void init_ir(var* argc, var* argv, var* env) {
void enter(void) { void enter(void) {
assert(stack_frame < MAX_STACK_FRAMES); 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_frames[stack_frame] = frame;
stack_frame++; stack_frame++;
// exit label // exit label
@ -61,15 +59,16 @@ void enter(void) {
void leave(var* args) { void leave(var* args) {
assert(stack_frame > 0); assert(stack_frame > 0);
struct stack_frame frame = stack_frames[stack_frame - 1]; struct stack_frame frame = stack_frames[stack_frame - 1];
stack_frame--;
stack_depth = frame.depth; stack_depth = frame.depth;
label_depth = frame.label_depth;
define(frame.label_depth, args); define(frame.label_depth, args);
stack_frame--;
} }
label declare(uint32_t argc) { label declare(uint32_t argc) {
assert(label_depth < MAX_LABELS); assert(label_depth < MAX_LABELS);
symbol sym = new_symbol(); 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; labels[label_depth] = label;
return label_depth++; return label_depth++;
} }
@ -82,18 +81,13 @@ label declare_exit(uint32_t argc) {
void define(label l, var* args) { void define(label l, var* args) {
struct label* label = &labels[l]; struct label* label = &labels[l];
printf("DEFINING %i (%i)\n", l, label->argc);
define_executable_symbol(label->symbol); define_executable_symbol(label->symbol);
// possibly wrong. do I need to do any clean-up of the old frame here? assert(label->frame == stack_frame);
stack_frame = label->frame;
struct stack_frame* frame = &stack_frames[stack_frame - 1];
label_depth = frame->label_depth;
for (uint32_t i = 0; i < label->argc; i++) { 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? stack_depth += label->argc;
// 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;
} }
void load_var(reg reg, var var) { void load_var(reg reg, var var) {
@ -109,13 +103,11 @@ var push_var(reg reg) {
} }
void load_args(struct label* label, var* args) { 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]; 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) { if (depth_diff > 0) {
// FIXME: should be immX!!! // 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++) { for (uint32_t arg = 0; arg < label->argc; arg++) {
load_var(AX, args[arg]); load_var(AX, args[arg]);
@ -125,6 +117,7 @@ void load_args(struct label* label, var* args) {
void jump(label l, var* args) { void jump(label l, var* args) {
struct label* label = &labels[l]; struct label* label = &labels[l];
printf("JUMP %i (%i)\n", l, label->argc);
load_args(label, args); load_args(label, args);
inst_jump(label->symbol); 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) { void jump_if(label l, var cond, var* args) {
struct label* label = &labels[l]; struct label* label = &labels[l];
printf("JUMP_IF %i (%i)\n", l, label->argc);
load_var(BX, cond); load_var(BX, cond);
load_args(label, args); load_args(label, args);
inst_jump_if_not_zero(label->symbol, BX); 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) { void jump_unless(label l, var cond, var* args) {
struct label* label = &labels[l]; struct label* label = &labels[l];
printf("JUMP_UNLESS %i (%i)\n", l, label->argc);
load_var(BX, cond); load_var(BX, cond);
load_args(label, args); load_args(label, args);
inst_jump_if_zero(label->symbol, BX); inst_jump_if_zero(label->symbol, BX);

View File

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