commit 6e2a5e989a36626ac46ee36586aedcacc83a415f
parent f361fdfe6301828a0d29bf5d400d8ce1c601f4ae
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Sat, 25 Dec 2021 22:15:42 -0600
combine struct out and decl abstractions into struct place
struct place represents any 'place' data can be stored, and how to
access it. For now, it only operates on 8-byte things, but should be
expanded to i32 soon.
Diffstat:
M | main.c | | | 227 | ++++++++++++++++++++++++++++++------------------------------------------------- |
M | nooc.h | | | 33 | ++++++++++++++++----------------- |
M | parse.c | | | 6 | ++++-- |
3 files changed, 105 insertions(+), 161 deletions(-)
diff --git a/main.c b/main.c
@@ -73,19 +73,20 @@ void
decl_set(struct decl *decl, void *ptr)
{
struct type *type = &types.data[decl->type];
- memcpy(&data_seg.data[decl->loc.addr - DATA_OFFSET], ptr, type->size);
+ assert(decl->place.kind == PLACE_ABS);
+ memcpy(&data_seg.data[decl->place.l.addr - DATA_OFFSET], ptr, type->size);
}
void
decl_alloc(struct block *block, struct decl *decl)
{
struct type *type = &types.data[decl->type];
- switch (decl->kind) {
- case DECL_DATA:
- decl->loc.addr = data_pushzero(type->size);
+ switch (decl->place.kind) {
+ case PLACE_ABS:
+ decl->place.l.addr = data_pushzero(type->size);
break;
- case DECL_STACK:
- decl->loc.off = block->datasize;
+ case PLACE_FRAME:
+ decl->place.l.off = block->datasize;
block->datasize += type->size;
break;
default:
@@ -93,118 +94,55 @@ decl_alloc(struct block *block, struct decl *decl)
}
}
-/* FIXME: handle things beside 64-bit integers */
size_t
-decl_fromreg(char *buf, struct decl *decl, enum reg reg)
+place_move(char *buf, struct place *dest, struct place *src)
{
- struct type *type = &types.data[decl->type];
-
size_t total = 0;
- switch (decl->kind) {
- case DECL_DATA:
- switch (type->size) {
- case 8:
- total += mov_m64_r64(buf ? buf + total : NULL, decl->loc.addr, reg);
+ switch (src->kind) {
+ case PLACE_REG:
+ switch (dest->kind) {
+ case PLACE_REG:
+ total += mov_r64_r64(buf ? buf + total : NULL, dest->l.reg, src->l.reg);
+ break;
+ case PLACE_REGADDR:
+ total += mov_mr64_r64(buf ? buf + total : NULL, dest->l.reg, src->l.reg);
break;
- case 4:
- total += mov_m32_r32(buf ? buf + total : NULL, decl->loc.addr, reg);
+ case PLACE_FRAME:
+ total += mov_disp8_m64_r64(buf ? buf + total : NULL, RBP, -dest->l.off, src->l.reg);
break;
default:
- die("decl_fromreg: unsupported size for mov_mn_rn");
+ die("place_move: unhandled dest case for PLACE_REG");
}
break;
- case DECL_STACK:
- switch (type->size) {
- case 8:
- total += mov_disp8_m64_r64(buf, reg, -decl->loc.off, RBP);
- break;
- case 4:
- total += mov_disp8_m32_r32(buf, reg, -decl->loc.off, RBP);
+ case PLACE_REGADDR:
+ switch (dest->kind) {
+ case PLACE_REG:
+ total += mov_r64_mr64(buf ? buf + total : NULL, dest->l.reg, src->l.reg);
break;
default:
- die("decl_toreg: unsupported size for mov_disp8_mn_rn");
+ die("place_move: unhandled dest case for PLACE_REGADDR");
}
break;
- default:
- die("decl_fromreg: unknown decl kind");
- }
-
- return total;
-}
-
-/* FIXME: handle things beside 64-bit integers */
-size_t
-decl_toreg(char *buf, enum reg reg, struct decl *decl)
-{
- struct type *type = &types.data[decl->type];
- size_t total = 0;
- switch (decl->kind) {
- case DECL_DATA:
- switch (type->size) {
- case 8:
- total += mov_r64_m64(buf ? buf + total : NULL, reg, decl->loc.addr);
- break;
- case 4:
- total += mov_r32_m32(buf ? buf + total : NULL, reg, decl->loc.addr);
+ case PLACE_FRAME:
+ switch (dest->kind) {
+ case PLACE_REG:
+ total += mov_disp8_r64_m64(buf ? buf + total : NULL, dest->l.reg, RBP, -src->l.off);
break;
default:
- die("decl_toreg: unsupported size for mov_mn_rn");
+ die("place_move: unhandled dest case for PLACE_FRAME");
}
break;
- case DECL_STACK:
- switch (type->size) {
- case 8:
- total += mov_disp8_r64_m64(buf, reg, RBP, -decl->loc.off);
- break;
- case 4:
- total += mov_disp8_r32_m32(buf, reg, RBP, -decl->loc.off);
+ case PLACE_ABS:
+ switch (dest->kind) {
+ case PLACE_REG:
+ total += mov_r64_m64(buf ? buf + total : NULL, dest->l.reg, src->l.addr);
break;
default:
- die("decl_fromreg: unsupported size for mov_mn_rn");
+ die("place_move: unhandled dest case for PLACE_ABS");
}
break;
default:
- die("unknown decl type!");
- }
-
- return total;
-}
-
-size_t
-out_write(char *buf, struct out *out, enum reg reg)
-{
- size_t total = 0;
- switch (out->kind) {
- case OUT_ADDR:
- total += mov_mr64_r64(buf ? buf + total : buf, out->reg, reg);
- break;
- case OUT_REG:
- total += mov_r64_r64(buf ? buf + total : buf, out->reg, reg);
- break;
- case OUT_IGNORE:
- break;
- default:
- die("unhandled OUT_*");
- }
-
- return total;
-}
-
-size_t
-out_read(char *buf, enum reg reg, struct out *out)
-{
- size_t total = 0;
- switch (out->kind) {
- case OUT_ADDR:
- total += mov_r64_mr64(buf ? buf + total : buf, reg, out->reg);
- break;
- case OUT_REG:
- total += mov_r64_r64(buf ? buf + total : buf, reg, out->reg);
- break;
- case OUT_IGNORE:
- break;
- default:
- die("unhandled OUT_*");
+ die("place_move: unhandled src case");
}
return total;
@@ -363,7 +301,7 @@ check:
}
}
-size_t genexpr(char *buf, size_t idx, struct out *out);
+size_t genexpr(char *buf, size_t idx, struct place *place);
size_t genproc(char *buf, struct proc *proc);
size_t genblock(char *buf, struct block *block, bool toplevel);
@@ -375,28 +313,28 @@ gencall(char *buf, size_t addr, struct expr *expr)
if (params->len > 7)
error(expr->start->line, expr->start->col, "syscall can take at most 7 parameters");
- struct out out = {OUT_REG, getreg()};
+ struct place place = {PLACE_REG, .l.reg = getreg()};
for (int i = 0; i < params->len; i++) {
- len += genexpr(buf ? buf + len : NULL, params->data[i], &out);
- len += push_r64(buf ? buf + len : NULL, out.reg);
+ len += genexpr(buf ? buf + len : NULL, params->data[i], &place);
+ len += push_r64(buf ? buf + len : NULL, place.l.reg);
}
- len += mov_r64_imm(buf ? buf + len : NULL, out.reg, addr);
- len += call(buf ? buf + len : NULL, out.reg);
+ len += mov_r64_imm(buf ? buf + len : NULL, place.l.reg, addr);
+ len += call(buf ? buf + len : NULL, place.l.reg);
- freereg(out.reg);
+ freereg(place.l.reg);
return len;
}
size_t
-gensyscall(char *buf, struct expr *expr, struct out *out)
+gensyscall(char *buf, struct expr *expr, struct place *place)
{
unsigned short pushed = 0;
size_t len = 0;
struct fparams *params = &expr->d.call.params;
- struct out tempout = { .kind = OUT_REG };
+ struct place reg = { .kind = PLACE_REG };
if (params->len > 7)
error(expr->start->line, expr->start->col, "syscall can take at most 7 parameters");
@@ -408,20 +346,22 @@ gensyscall(char *buf, struct expr *expr, struct out *out)
} else {
used_reg |= (1 << abi_arg[i]);
}
- tempout.reg = abi_arg[i];
- len += genexpr(buf ? buf + len : NULL, params->data[i], &tempout);
+ reg.l.reg = abi_arg[i];
+ len += genexpr(buf ? buf + len : NULL, params->data[i], ®);
}
if (buf) {
char syscall[] = {0x0f, 0x05};
memcpy(buf + len, syscall, 2);
}
-
len += 2;
- len += out_write(buf ? buf + len : NULL, out, RAX);
+
+ reg.l.reg = RAX;
+ len += place_move(buf ? buf + len : NULL, place, ®);
for (int i = params->len - 1; i >= 0; i--) {
- if (pushed & (1 << abi_arg[i]) && (out->kind != OUT_REG || abi_arg[i] != out->reg)) {
+ // FIXME: we shouldn't have to touch the place structure here
+ if (pushed & (1 << abi_arg[i]) && (place->kind != PLACE_REG || abi_arg[i] != place->l.reg)) {
len += pop_r64(buf ? buf + len : NULL, abi_arg[i]);
} else {
freereg(abi_arg[i]);
@@ -432,63 +372,65 @@ gensyscall(char *buf, struct expr *expr, struct out *out)
}
size_t
-genexpr(char *buf, size_t idx, struct out *out)
+genexpr(char *buf, size_t idx, struct place *out)
{
size_t total = 0;
struct expr *expr = &exprs.data[idx];
if (expr->kind == EXPR_LIT) {
- enum reg reg = getreg();
+ struct place src = {PLACE_REG, .l.reg = getreg()};
switch (expr->class) {
case C_INT:
- total += mov_r64_imm(buf ? buf + total : buf, reg, expr->d.v.v.i64);
+ total += mov_r64_imm(buf ? buf + total : buf, src.l.reg, expr->d.v.v.i64);
break;
case C_STR: {
int addr = data_push(expr->d.v.v.s.data, expr->d.v.v.s.len);
- total += mov_r64_imm(buf ? buf + total : buf, reg, addr);
+ total += mov_r64_imm(buf ? buf + total : buf, src.l.reg, addr);
break;
}
default:
error(expr->start->line, expr->start->col, "genexpr: unknown value type!");
}
- total += out_write(buf ? buf + total : NULL, out, reg);
- freereg(reg);
-
+ total += place_move(buf ? buf + total : NULL, out, &src);
+ freereg(src.l.reg);
} else if (expr->kind == EXPR_BINARY) {
total += genexpr(buf ? buf + total : buf, expr->left, out);
- struct out out2 = { OUT_REG, getreg() };
- total += genexpr(buf ? buf + total : buf, expr->right, &out2);
+ struct place place2 = { PLACE_REG, .l.reg = getreg() };
+ total += genexpr(buf ? buf + total : buf, expr->right, &place2);
- enum reg reg = getreg();
+ struct place regbuf = { PLACE_REG, .l.reg = getreg() };
- total += out_read(buf ? buf + total : buf, reg, out);
+ total += place_move(buf ? buf + total : buf, ®buf, out);
+ // FIXME: abstract these to act on places, so that we can generate more efficient code
switch (expr->d.op) {
case OP_PLUS: {
- total += add_r64_r64(buf ? buf + total : buf, reg, out2.reg);
+ total += add_r64_r64(buf ? buf + total : buf, regbuf.l.reg, place2.l.reg);
break;
}
case OP_MINUS: {
- total += sub_r64_r64(buf ? buf + total : buf, reg, out2.reg);
+ total += sub_r64_r64(buf ? buf + total : buf, regbuf.l.reg, place2.l.reg);
break;
}
case OP_GREATER: {
- total += cmp_r64_r64(buf ? buf + total : buf, reg, out2.reg);
+ total += cmp_r64_r64(buf ? buf + total : buf, regbuf.l.reg, place2.l.reg);
break;
}
default:
error(expr->start->line, expr->start->col, "genexpr: unknown binary op!");
}
- freereg(out2.reg);
- freereg(reg);
+ freereg(place2.l.reg);
+
+ total += place_move(buf ? buf + total : buf, out, ®buf);
+ freereg(regbuf.l.reg);
} else if (expr->kind == EXPR_IDENT) {
struct decl *decl = finddecl(expr->d.s);
if (decl == NULL) {
error(expr->start->line, expr->start->col, "genexpr: unknown name '%.*s'", expr->d.s.len, expr->d.s.data);
}
- total += decl_toreg(buf ? buf + total : NULL, out->reg, decl);
+ total += place_move(buf ? buf + total : NULL, out, &decl->place);
return total;
} else if (expr->kind == EXPR_FCALL) {
@@ -500,15 +442,14 @@ genexpr(char *buf, size_t idx, struct out *out)
error(expr->start->line, expr->start->col, "unknown function!");
}
- total += gencall(buf ? buf + total : NULL, decl->loc.addr, expr);
+ total += gencall(buf ? buf + total : NULL, decl->place.l.addr, expr);
}
} else if (expr->kind == EXPR_COND) {
struct expr *binary = &exprs.data[expr->d.cond.cond];
// FIXME this should go away
assert(binary->kind == EXPR_BINARY);
- struct out tempout = {OUT_REG, getreg()};
- total += genexpr(buf ? buf + total : NULL, expr->d.cond.cond, &tempout);
- freereg(tempout.reg);
+ struct place tempplace = {PLACE_REG, .l.reg = getreg()};
+ total += genexpr(buf ? buf + total : NULL, expr->d.cond.cond, &tempplace);
size_t iflen = genblock(NULL, &expr->d.cond.bif, false) + jmp(NULL, 0);
size_t elselen = genblock(NULL, &expr->d.cond.belse, false);
switch (binary->d.op) {
@@ -518,6 +459,7 @@ genexpr(char *buf, size_t idx, struct out *out)
default:
error(expr->start->line, expr->start->col, "unknown binop for conditional");
}
+ freereg(tempplace.l.reg);
total += genblock(buf ? buf + total : NULL, &expr->d.cond.bif, false);
total += jmp(buf ? buf + total: NULL, elselen);
total += genblock(buf ? buf + total : NULL, &expr->d.cond.belse, false);
@@ -563,27 +505,28 @@ genblock(char *buf, struct block *block, bool toplevel)
for (int i = 0; i < block->len; i++) {
struct item *item = &block->data[i];
if (item->kind == ITEM_EXPR) {
- struct out tempout = {OUT_IGNORE};
+ struct place tempout = {PLACE_REG, .l.reg = getreg()};
total += genexpr(buf ? buf + total : NULL, item->idx, &tempout);
+ freereg(tempout.l.reg);
} else if (item->kind == ITEM_DECL) {
struct decl *decl = &block->decls.data[item->idx];
struct expr *expr = &exprs.data[decl->val];
- decl->kind = toplevel ? DECL_DATA : DECL_STACK;
+ decl->place.kind = toplevel ? PLACE_ABS : PLACE_FRAME;
decl_alloc(block, decl);
if (toplevel) {
if (expr->class == C_PROC) {
- block->decls.data[item->idx].loc.addr = total + TEXT_OFFSET;
+ block->decls.data[item->idx].place.l.addr = total + TEXT_OFFSET;
total += genproc(buf ? buf + total : NULL, &(expr->d.proc));
} else {
evalexpr(decl);
}
} else {
- struct out tempout = {OUT_REG, getreg()};
+ struct place tempout = {PLACE_REG, .l.reg = getreg()};
total += genexpr(buf ? buf + total : NULL, block->decls.data[item->idx].val, &tempout);
- total += decl_fromreg(buf ? buf + total : NULL, decl, tempout.reg);
- freereg(tempout.reg);
+ total += place_move(buf ? buf + total : NULL, &decl->place, &tempout);
+ freereg(tempout.l.reg);
}
decl->declared = true;
@@ -601,10 +544,10 @@ genblock(char *buf, struct block *block, bool toplevel)
error(assgn->start->line, assgn->start->col, "reassignment of procedure not allowed (yet)");
}
- struct out tempout = {OUT_REG, getreg()};
+ struct place tempout = {PLACE_REG, .l.reg = getreg()};
total += genexpr(buf ? buf + total : NULL, assgn->val, &tempout);
- total += decl_fromreg(buf ? buf + total : NULL, decl, tempout.reg);
- freereg(tempout.reg);
+ total += place_move(buf ? buf + total : NULL, &decl->place, &tempout);
+ freereg(tempout.l.reg);
} else if (item->kind == ITEM_RETURN) {
total += mov_r64_r64(buf ? buf + total : NULL, RSP, RBP);
total += pop_r64(buf ? buf + total : NULL, RBP);
@@ -695,7 +638,7 @@ main(int argc, char *argv[])
blockpop();
munmap(addr, statbuf.st_size);
- elf(main->loc.addr, text, len, data_seg.data, data_seg.len, out);
+ elf(main->place.l.addr, text, len, data_seg.data, data_seg.len, out);
fclose(out);
}
diff --git a/nooc.h b/nooc.h
@@ -105,19 +105,27 @@ struct assgns {
struct assgn *data;
};
+struct place {
+ enum {
+ PLACE_ABS = 1,
+ PLACE_FRAME,
+ PLACE_STACK,
+ PLACE_REG,
+ PLACE_REGADDR,
+ } kind;
+ union {
+ size_t addr;
+ int64_t off;
+ int reg;
+ } l;
+};
+
struct decl {
struct slice s;
size_t type;
size_t val; // struct exprs
bool declared;
- enum {
- DECL_STACK,
- DECL_DATA
- } kind;
- union {
- int64_t off;
- size_t addr;
- } loc;
+ struct place place;
struct token *start;
};
@@ -224,12 +232,3 @@ struct exprs {
size_t len;
struct expr *data;
};
-
-struct out {
- enum {
- OUT_REG,
- OUT_ADDR,
- OUT_IGNORE,
- } kind;
- int reg;
-};
diff --git a/parse.c b/parse.c
@@ -161,12 +161,14 @@ parseexpr(struct block *block)
parsenametypes(&expr.d.proc.in);
if (tok->type == TOK_LPAREN)
parsenametypes(&expr.d.proc.out);
+
for (int i = expr.d.proc.in.len - 1; i >= 0; i--) {
decl.s = expr.d.proc.in.data[i].name;
decl.type = expr.d.proc.in.data[i].type;
+ decl.place.kind = PLACE_FRAME;
type = &types.data[decl.type];
offset += type->size;
- decl.loc.off = -offset - 8;
+ decl.place.l.off = -offset - 8;
array_add((&expr.d.proc.block.decls), decl);
}
@@ -176,7 +178,7 @@ parseexpr(struct block *block)
decl.declared = true;
type = &types.data[decl.type];
offset += type->size;
- decl.loc.off = -offset;
+ decl.place.l.off = -offset;
array_add((&expr.d.proc.block.decls), decl);
}
parseblock(&expr.d.proc.block);