diff --git a/src/ir.c b/src/ir.c index 0d5e7d0..387ebb2 100644 --- a/src/ir.c +++ b/src/ir.c @@ -103,16 +103,17 @@ var push_var(reg reg) { } void load_args(struct label* label, var* args) { - struct stack_frame* dest_frame = &stack_frames[label->frame]; + struct stack_frame* dest_frame = &stack_frames[label->frame - 1]; uint32_t depth_diff = stack_depth - dest_frame->depth; if (depth_diff > 0) { // FIXME: should be immX!!! - x86_inst_add_r64_imm8(SP, depth_diff); + x86_inst_add_r64_imm8(SP, depth_diff * 8); } for (uint32_t arg = 0; arg < label->argc; arg++) { load_var(AX, args[arg]); x86_inst_push_r64(AX); } + stack_depth = dest_frame->depth + label->argc; } void jump(label l, var* args) { @@ -126,20 +127,15 @@ void jump_table(size_t branches, label* labels, var index, var* args) { assert(0); // UNIMPLEMENTED } -void jump_if(label l, var cond, var* args) { - struct label* label = &labels[l]; - printf("JUMP_IF %i (%i)\n", l, label->argc); +void jump_if(label t, label e, var cond, var* args) { + struct label* then = &labels[t]; + struct label* else_ = &labels[e]; + printf("JUMP_IF %i ELSE %i (%i)\n", t, e, then->argc); + assert(then->argc == else_->argc && then->frame == else_->frame); load_var(BX, cond); - load_args(label, args); - inst_jump_if_not_zero(label->symbol, BX); -} - -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); + load_args(then, args); + inst_jump_if_not_zero(then->symbol, BX); + inst_jump(else_->symbol); } var lit(uint64_t lit) { diff --git a/src/ir.h b/src/ir.h index 408cd27..94d53a5 100644 --- a/src/ir.h +++ b/src/ir.h @@ -7,6 +7,40 @@ typedef uint32_t var; typedef uint32_t label; +struct jump_target { + label label; + var* args; +}; + +/// Declare a new label in the current scope with the provided number +/// of arguments. +/// +/// Local variables (not part of a stack frame generated by `define` or `enter`) +/// will not be in scope of the definition of the label. +label declare(uint32_t argc); + +/// Define a label and create a new scope for local variables. +/// +/// The new scope will have access to all of the variables +/// of the parent scope of the label and the label's arguments, +/// but not any local variables from previous definitions. +void define(label label, var* args); + +/// Create a new scope which encompasses all local variables defined up to this point. +/// +/// This allows nested definitions to have access to local variables. +void enter(void); + +/// Jump to label, unconditionally. Ends the continuation. +void jump(struct jump_target dest); + +/// Jump to `then` if `cond` is not zero; jump to `else` otherwise. +/// Ends the continuation. +void jump_if(struct jump_target then, struct jump_target else_, var cond); + +/// Jump to the `index`th destination. Ends the continuation. +void jump_table(uint32_t destc, struct jump_target* destinations, var index); + /// Call this at the beginning of execution. /// It performs initialization and stuff. void init_ir(var* argc, var* argv, var* env); @@ -61,11 +95,8 @@ void jump(label label, var* args); /// `index` must not be out of bounds. void jump_table(size_t branches, label* labels, var index, var* args); -/// Jump to label if `cond` is not zero. -void jump_if(label label, var cond, var* args); - -/// Jump to label if `cond` is zero. -void jump_unless(label label, var cond, var* args); +/// Jump to `then` if cond is not zero, `else` if cond is zero. +void jump_if(label then, label else_, var cond, var* args); /// Integer literal. var lit(uint64_t lit); diff --git a/src/lang.c b/src/lang.c index bd15142..bcc2583 100644 --- a/src/lang.c +++ b/src/lang.c @@ -473,8 +473,7 @@ void exit_expr(void) { case IF_CRUMB: { struct if_crumb* ifc = &ctx->data.if_; assert(ifc->state == IF_COND); - jump_unless(ifc->else_, ret, NULL); - //jump(ifc->then_, NULL); + jump_if(ifc->then, ifc->else_, ret, NULL); ifc->state = IF_THEN; break; }