Minor refactor of function call setup to allow for multiple arguments.
This commit is contained in:
1 parent
72691b4909
commit
f19ba32fdd
3 files changed
+102
-22
No files matched your search
@@ -30,7 +30,9 @@ struct inst {
|
|||||||
// are bound, and even then only for instructions which bind.
|
// are bound, and even then only for instructions which bind.
|
||||||
struct inst* bound_by;
|
struct inst* bound_by;
|
||||||
char* symbol;
|
char* symbol;
|
||||||
|
|
||||||
block subfn;
|
block subfn;
|
||||||
|
block arglist;
|
||||||
|
|
||||||
// This instruction is compiled as part of which function?
|
// This instruction is compiled as part of which function?
|
||||||
// (only used during block_compile)
|
// (only used during block_compile)
|
||||||
@@ -47,6 +49,7 @@ static inst* inst_new(opcode op) {
|
|||||||
i->bound_by = 0;
|
i->bound_by = 0;
|
||||||
i->symbol = 0;
|
i->symbol = 0;
|
||||||
i->subfn = gen_noop();
|
i->subfn = gen_noop();
|
||||||
|
i->arglist = gen_noop();
|
||||||
i->source = UNKNOWN_LOCATION;
|
i->source = UNKNOWN_LOCATION;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@@ -56,6 +59,9 @@ static void inst_free(struct inst* i) {
|
|||||||
if (opcode_describe(i->op)->flags & OP_HAS_BLOCK) {
|
if (opcode_describe(i->op)->flags & OP_HAS_BLOCK) {
|
||||||
block_free(i->subfn);
|
block_free(i->subfn);
|
||||||
}
|
}
|
||||||
|
if (opcode_describe(i->op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
|
||||||
|
block_free(i->arglist);
|
||||||
|
}
|
||||||
if (opcode_describe(i->op)->flags & OP_HAS_CONSTANT) {
|
if (opcode_describe(i->op)->flags & OP_HAS_CONSTANT) {
|
||||||
jv_free(i->imm.constant);
|
jv_free(i->imm.constant);
|
||||||
}
|
}
|
||||||
@@ -186,30 +192,11 @@ block gen_op_block_bound(opcode op, block binder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
block gen_op_call(opcode op, block arglist) {
|
block gen_op_call(opcode op, block arglist) {
|
||||||
|
assert(op == CALL_1_1);
|
||||||
assert(opcode_describe(op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST);
|
assert(opcode_describe(op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST);
|
||||||
inst* i = inst_new(op);
|
inst* i = inst_new(op);
|
||||||
block prelude = gen_noop();
|
i->arglist = arglist;
|
||||||
block call = inst_block(i);
|
return block_join(inst_block(i), inst_block(inst_new(CALLSEQ_END)));
|
||||||
int nargs = 0;
|
|
||||||
inst* curr = 0;
|
|
||||||
while ((curr = block_take(&arglist))) {
|
|
||||||
assert(opcode_describe(curr->op)->flags & OP_IS_CALL_PSEUDO);
|
|
||||||
block bcurr = inst_block(curr);
|
|
||||||
switch (curr->op) {
|
|
||||||
default: assert(0 && "Unknown type of parameter"); break;
|
|
||||||
case CLOSURE_REF:
|
|
||||||
block_append(&call, bcurr);
|
|
||||||
break;
|
|
||||||
case CLOSURE_CREATE:
|
|
||||||
block_append(&prelude, bcurr);
|
|
||||||
block_append(&call, gen_op_block_bound(CLOSURE_REF, bcurr));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
nargs++;
|
|
||||||
}
|
|
||||||
assert(nargs < 100); //FIXME
|
|
||||||
i->imm.intval = nargs;
|
|
||||||
return block_join(prelude, call);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inst_join(inst* a, inst* b) {
|
static void inst_join(inst* a, inst* b) {
|
||||||
@@ -220,6 +207,32 @@ static void inst_join(inst* a, inst* b) {
|
|||||||
b->prev = a;
|
b->prev = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void block_insert_after(inst* i, block b) {
|
||||||
|
if (b.first) {
|
||||||
|
assert(b.last);
|
||||||
|
if (i->next) {
|
||||||
|
inst* j = i->next;
|
||||||
|
i->next = 0;
|
||||||
|
j->prev = 0;
|
||||||
|
inst_join(b.last, j);
|
||||||
|
}
|
||||||
|
inst_join(i, b.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void block_insert_before(inst* i, block b) {
|
||||||
|
if (b.first) {
|
||||||
|
assert(b.last);
|
||||||
|
if (i->prev) {
|
||||||
|
inst* j = i->prev;
|
||||||
|
i->prev = 0;
|
||||||
|
j->next = 0;
|
||||||
|
inst_join(j, b.first);
|
||||||
|
}
|
||||||
|
inst_join(b.last, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void block_append(block* b, block b2) {
|
void block_append(block* b, block b2) {
|
||||||
if (b2.first) {
|
if (b2.first) {
|
||||||
if (b->last) {
|
if (b->last) {
|
||||||
@@ -266,6 +279,10 @@ static void block_bind_subblock(block binder, block body, int bindflags) {
|
|||||||
// binding recurses into closures
|
// binding recurses into closures
|
||||||
block_bind_subblock(binder, i->subfn, bindflags);
|
block_bind_subblock(binder, i->subfn, bindflags);
|
||||||
}
|
}
|
||||||
|
if (flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
|
||||||
|
// binding recurses into argument list
|
||||||
|
block_bind_subblock(binder, i->arglist, bindflags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,12 +474,70 @@ static int count_cfunctions(block b) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Expands call instructions into a calling sequence
|
||||||
|
// Checking for argument count compatibility happens later
|
||||||
|
static void expand_call_arglist(struct bytecode* bc, block b) {
|
||||||
|
for (inst* curr = b.first; curr; curr = curr->next) {
|
||||||
|
if (opcode_describe(curr->op)->flags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
|
||||||
|
assert(curr->op == CALL_1_1);
|
||||||
|
assert(curr->next && curr->next->op == CALLSEQ_END);
|
||||||
|
// We expand the argument list as a series of instructions
|
||||||
|
block arglist = curr->arglist;
|
||||||
|
curr->arglist = gen_noop();
|
||||||
|
assert(arglist.first && "zeroth argument (function to call) must be present");
|
||||||
|
inst* function = arglist.first->bound_by;
|
||||||
|
assert(function);
|
||||||
|
|
||||||
|
switch (function->op) {
|
||||||
|
default: assert(0 && "Unknown parameter type"); break;
|
||||||
|
case CLOSURE_CREATE:
|
||||||
|
case CLOSURE_PARAM: {
|
||||||
|
block prelude = gen_noop();
|
||||||
|
block callargs = gen_noop();
|
||||||
|
int nargs = 0;
|
||||||
|
for (inst* i; (i = block_take(&arglist));) {
|
||||||
|
assert(opcode_describe(i->op)->flags & OP_IS_CALL_PSEUDO);
|
||||||
|
block b = inst_block(i);
|
||||||
|
switch (i->op) {
|
||||||
|
default: assert(0 && "Unknown type of parameter"); break;
|
||||||
|
case CLOSURE_REF:
|
||||||
|
block_append(&callargs, b);
|
||||||
|
break;
|
||||||
|
case CLOSURE_CREATE:
|
||||||
|
block_append(&prelude, b);
|
||||||
|
block_append(&callargs, gen_op_block_bound(CLOSURE_REF, b));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nargs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!arglist.first);
|
||||||
|
block_insert_before(curr, prelude);
|
||||||
|
block_insert_after(curr, callargs);
|
||||||
|
curr->imm.intval = nargs;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CLOSURE_CREATE_C:
|
||||||
|
// Arguments to C functions not yet supported
|
||||||
|
assert(block_is_single(arglist));
|
||||||
|
assert(arglist.first->op == CLOSURE_REF);
|
||||||
|
block_insert_after(curr, arglist);
|
||||||
|
curr->imm.intval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int var_frame_idx = 0;
|
int var_frame_idx = 0;
|
||||||
bc->nsubfunctions = 0;
|
bc->nsubfunctions = 0;
|
||||||
bc->nclosures = 0;
|
bc->nclosures = 0;
|
||||||
|
expand_call_arglist(bc, b);
|
||||||
for (inst* curr = b.first; curr; curr = curr->next) {
|
for (inst* curr = b.first; curr; curr = curr->next) {
|
||||||
if (!curr->next) assert(curr == b.last);
|
if (!curr->next) assert(curr == b.last);
|
||||||
pos += opcode_length(curr->op);
|
pos += opcode_length(curr->op);
|
||||||
@@ -484,6 +559,7 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
|||||||
assert(curr->bound_by == curr);
|
assert(curr->bound_by == curr);
|
||||||
curr->imm.intval = bc->nsubfunctions++;
|
curr->imm.intval = bc->nsubfunctions++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curr->op == CLOSURE_PARAM) {
|
if (curr->op == CLOSURE_PARAM) {
|
||||||
assert(curr->bound_by == curr);
|
assert(curr->bound_by == curr);
|
||||||
curr->imm.intval = bc->nclosures++;
|
curr->imm.intval = bc->nclosures++;
|
||||||
@@ -524,9 +600,11 @@ static int compile(struct locfile* locations, struct bytecode* bc, block b) {
|
|||||||
int opflags = op->flags;
|
int opflags = op->flags;
|
||||||
assert(!(op->flags & OP_IS_CALL_PSEUDO));
|
assert(!(op->flags & OP_IS_CALL_PSEUDO));
|
||||||
if (opflags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
|
if (opflags & OP_HAS_VARIABLE_LENGTH_ARGLIST) {
|
||||||
|
assert(curr->op == CALL_1_1);
|
||||||
int nargs = curr->imm.intval;
|
int nargs = curr->imm.intval;
|
||||||
assert(nargs > 0);
|
assert(nargs > 0);
|
||||||
code[pos++] = (uint16_t)nargs;
|
code[pos++] = (uint16_t)nargs;
|
||||||
|
|
||||||
int desired_params = 0;
|
int desired_params = 0;
|
||||||
for (int i=0; i<nargs; i++) {
|
for (int i=0; i<nargs; i++) {
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#define BRANCH OP_HAS_BRANCH, 2
|
#define BRANCH OP_HAS_BRANCH, 2
|
||||||
#define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2
|
#define CFUNC (OP_HAS_SYMBOL | OP_HAS_CFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2
|
||||||
#define UFUNC (OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2
|
#define UFUNC (OP_HAS_UFUNC | OP_HAS_VARIABLE_LENGTH_ARGLIST), 2
|
||||||
|
#define CALLSEQ_END_IMM (OP_IS_CALL_PSEUDO), 0
|
||||||
#define CLOSURE_PARAM_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
|
#define CLOSURE_PARAM_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
|
||||||
#define CLOSURE_CREATE_IMM (OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
|
#define CLOSURE_CREATE_IMM (OP_HAS_BLOCK | OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
|
||||||
#define CLOSURE_CREATE_C_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
|
#define CLOSURE_CREATE_C_IMM (OP_IS_CALL_PSEUDO | OP_HAS_BINDING), 0
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ OP(CALL_BUILTIN_3_1, CFUNC, 3, 1)
|
|||||||
OP(CALL_1_1, UFUNC, 1, 1)
|
OP(CALL_1_1, UFUNC, 1, 1)
|
||||||
OP(RET, NONE, 1, 1)
|
OP(RET, NONE, 1, 1)
|
||||||
|
|
||||||
|
OP(CALLSEQ_END, CALLSEQ_END_IMM, 0, 0)
|
||||||
OP(CLOSURE_PARAM, CLOSURE_PARAM_IMM, 0, 0)
|
OP(CLOSURE_PARAM, CLOSURE_PARAM_IMM, 0, 0)
|
||||||
OP(CLOSURE_REF, CLOSURE_REF_IMM, 0, 0)
|
OP(CLOSURE_REF, CLOSURE_REF_IMM, 0, 0)
|
||||||
OP(CLOSURE_CREATE, CLOSURE_CREATE_IMM, 0, 0)
|
OP(CLOSURE_CREATE, CLOSURE_CREATE_IMM, 0, 0)
|
||||||
|
|||||||
Reference in new issue
Block a user