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
parent
68ce32a6df
commit
d9edbab10c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
src/ir.c
35
src/ir.c
|
@ -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);
|
||||||
|
|
32
src/lang.c
32
src/lang.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue