nooc

nooc programming language compiler
git clone git://git.nihaljere.xyz/nooc
Log | Files | Refs | LICENSE

commit ff44515007b9436695136c7cb97009409b5fe45f
parent 6e2a5e989a36626ac46ee36586aedcacc83a415f
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Sun, 26 Dec 2021 13:13:17 -0600

add i32 support in new 'place' scheme

If we are using a value from memory, we check the width and use the
appropriate width instruction. Registers are treated as 64-bit always.

Diffstat:
Mmain.c | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mnooc.h | 1+
Mparse.c | 1+
Mx64.c | 36+++++++++++++++++++++++++++++++++++-
Mx64.h | 6++++++
5 files changed, 130 insertions(+), 24 deletions(-)

diff --git a/main.c b/main.c @@ -81,6 +81,7 @@ void decl_alloc(struct block *block, struct decl *decl) { struct type *type = &types.data[decl->type]; + decl->place.size = type->size; switch (decl->place.kind) { case PLACE_ABS: decl->place.l.addr = data_pushzero(type->size); @@ -105,40 +106,103 @@ place_move(char *buf, struct place *dest, struct place *src) 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); + switch (dest->size) { + case 8: + total += mov_mr64_r64(buf ? buf + total : NULL, dest->l.reg, src->l.reg); + break; + case 4: + total += mov_mr32_r32(buf ? buf + total : NULL, dest->l.reg, src->l.reg); + break; + default: + die("place_move: REG -> REGADDR: unhandled size"); + } break; case PLACE_FRAME: - total += mov_disp8_m64_r64(buf ? buf + total : NULL, RBP, -dest->l.off, src->l.reg); + switch (dest->size) { + case 8: + total += mov_disp8_m64_r64(buf ? buf + total : NULL, RBP, -dest->l.off, src->l.reg); + break; + case 4: + total += mov_disp8_m32_r32(buf ? buf + total : NULL, RBP, -dest->l.off, src->l.reg); + break; + default: + die("place_move: REG -> REGADDR: unhandled size"); + } break; default: die("place_move: unhandled dest case for PLACE_REG"); } break; case PLACE_REGADDR: - switch (dest->kind) { - case PLACE_REG: - total += mov_r64_mr64(buf ? buf + total : NULL, dest->l.reg, src->l.reg); + switch (src->size) { + case 8: + switch (dest->kind) { + case PLACE_REG: + total += mov_r64_mr64(buf ? buf + total : NULL, dest->l.reg, src->l.reg); + break; + default: + die("place_move: unhandled dest case for PLACE_REGADDR"); + } + break; + case 4: + switch (dest->kind) { + case PLACE_REG: + total += mov_r32_mr32(buf ? buf + total : NULL, dest->l.reg, src->l.reg); + break; + default: + die("place_move: unhandled dest case for PLACE_REGADDR"); + } break; default: - die("place_move: unhandled dest case for PLACE_REGADDR"); + die("place_move: REGADDR: src unhandled size"); } break; 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); + switch (src->size) { + case 8: + 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("place_move: unhandled dest case for PLACE_FRAME"); + } + break; + case 4: + switch (dest->kind) { + case PLACE_REG: + total += mov_disp8_r32_m32(buf ? buf + total : NULL, dest->l.reg, RBP, -src->l.off); + break; + default: + die("place_move: unhandled dest case for PLACE_FRAME"); + } break; default: - die("place_move: unhandled dest case for PLACE_FRAME"); + die("place_move: FRAME: src unhandled size"); } break; case PLACE_ABS: - switch (dest->kind) { - case PLACE_REG: - total += mov_r64_m64(buf ? buf + total : NULL, dest->l.reg, src->l.addr); + switch(src->size) { + case 8: + switch (dest->kind) { + case PLACE_REG: + total += mov_r64_m64(buf ? buf + total : NULL, dest->l.reg, src->l.addr); + break; + default: + die("place_move: unhandled dest case for PLACE_ABS"); + } + break; + case 4: + switch (dest->kind) { + case PLACE_REG: + total += mov_r32_m32(buf ? buf + total : NULL, dest->l.reg, src->l.addr); + break; + default: + die("place_move: unhandled dest case for PLACE_ABS"); + } break; default: - die("place_move: unhandled dest case for PLACE_ABS"); + die("place_move: ABS: src unhandled size"); } break; default: @@ -313,7 +377,7 @@ 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 place place = {PLACE_REG, .l.reg = getreg()}; + struct place place = {PLACE_REG, .size = 8, .l.reg = getreg()}; for (int i = 0; i < params->len; i++) { len += genexpr(buf ? buf + len : NULL, params->data[i], &place); @@ -334,7 +398,7 @@ 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 place reg = { .kind = PLACE_REG }; + struct place reg = { .kind = PLACE_REG, .size = 8 }; if (params->len > 7) error(expr->start->line, expr->start->col, "syscall can take at most 7 parameters"); @@ -378,7 +442,7 @@ genexpr(char *buf, size_t idx, struct place *out) struct expr *expr = &exprs.data[idx]; if (expr->kind == EXPR_LIT) { - struct place src = {PLACE_REG, .l.reg = getreg()}; + struct place src = {PLACE_REG, .size = 8, .l.reg = getreg()}; switch (expr->class) { case C_INT: total += mov_r64_imm(buf ? buf + total : buf, src.l.reg, expr->d.v.v.i64); @@ -396,10 +460,10 @@ genexpr(char *buf, size_t idx, struct place *out) freereg(src.l.reg); } else if (expr->kind == EXPR_BINARY) { total += genexpr(buf ? buf + total : buf, expr->left, out); - struct place place2 = { PLACE_REG, .l.reg = getreg() }; + struct place place2 = { PLACE_REG, .size = 8, .l.reg = getreg() }; total += genexpr(buf ? buf + total : buf, expr->right, &place2); - struct place regbuf = { PLACE_REG, .l.reg = getreg() }; + struct place regbuf = { PLACE_REG, .size = 8, .l.reg = getreg() }; total += place_move(buf ? buf + total : buf, &regbuf, out); @@ -448,7 +512,7 @@ genexpr(char *buf, size_t idx, struct place *out) struct expr *binary = &exprs.data[expr->d.cond.cond]; // FIXME this should go away assert(binary->kind == EXPR_BINARY); - struct place tempplace = {PLACE_REG, .l.reg = getreg()}; + struct place tempplace = {PLACE_REG, .size = 8, .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); @@ -505,7 +569,7 @@ 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 place tempout = {PLACE_REG, .l.reg = getreg()}; + struct place tempout = {PLACE_REG, .size = 8, .l.reg = getreg()}; total += genexpr(buf ? buf + total : NULL, item->idx, &tempout); freereg(tempout.l.reg); } else if (item->kind == ITEM_DECL) { @@ -523,7 +587,7 @@ genblock(char *buf, struct block *block, bool toplevel) evalexpr(decl); } } else { - struct place tempout = {PLACE_REG, .l.reg = getreg()}; + struct place tempout = {PLACE_REG, .size = 8, .l.reg = getreg()}; total += genexpr(buf ? buf + total : NULL, block->decls.data[item->idx].val, &tempout); total += place_move(buf ? buf + total : NULL, &decl->place, &tempout); freereg(tempout.l.reg); @@ -544,7 +608,7 @@ genblock(char *buf, struct block *block, bool toplevel) error(assgn->start->line, assgn->start->col, "reassignment of procedure not allowed (yet)"); } - struct place tempout = {PLACE_REG, .l.reg = getreg()}; + struct place tempout = {PLACE_REG, .size = 8, .l.reg = getreg()}; total += genexpr(buf ? buf + total : NULL, assgn->val, &tempout); total += place_move(buf ? buf + total : NULL, &decl->place, &tempout); freereg(tempout.l.reg); diff --git a/nooc.h b/nooc.h @@ -118,6 +118,7 @@ struct place { int64_t off; int reg; } l; + size_t size; }; struct decl { diff --git a/parse.c b/parse.c @@ -167,6 +167,7 @@ parseexpr(struct block *block) decl.type = expr.d.proc.in.data[i].type; decl.place.kind = PLACE_FRAME; type = &types.data[decl.type]; + decl.place.size = type->size; offset += type->size; decl.place.l.off = -offset - 8; array_add((&expr.d.proc.block.decls), decl); diff --git a/x64.c b/x64.c @@ -185,6 +185,17 @@ mov_mr64_r64(char *buf, enum reg dest, enum reg src) } size_t +mov_mr32_r32(char *buf, enum reg dest, enum reg src) +{ + if (buf) { + *(buf++) = 0x8B; + *(buf++) = (MOD_INDIRECT << 6) | (src << 3) | dest; + } + + return 2; +} + +size_t mov_r64_mr64(char *buf, enum reg dest, enum reg src) { if (buf) { @@ -197,6 +208,17 @@ mov_r64_mr64(char *buf, enum reg dest, enum reg src) } size_t +mov_r32_mr32(char *buf, enum reg dest, enum reg src) +{ + if (buf) { + *(buf++) = 0x89; + *(buf++) = (MOD_INDIRECT << 6) | (dest << 3) | src; + } + + return 2; +} + +size_t mov_r64_r64(char *buf, enum reg dest, enum reg src) { if (buf) { @@ -209,6 +231,18 @@ mov_r64_r64(char *buf, enum reg dest, enum reg src) } size_t +mov_r32_r32(char *buf, enum reg dest, enum reg src) +{ + if (buf) { + if (src >= 8 || dest >= 8) *(buf++) = (src >= 8 ? REX_R : 0) | (dest >= 8 ? REX_B : 0); + *(buf++) = 0x89; + *(buf++) = (MOD_DIRECT << 6) | (src << 3) | dest; + } + + return (src >= 8 || dest >= 8) ? 3 : 2; +} + +size_t mov_disp8_m64_r64(char *buf, enum reg dest, int8_t disp, enum reg src) { assert(src != 4); @@ -229,7 +263,7 @@ mov_disp8_m32_r32(char *buf, enum reg dest, int8_t disp, enum reg src) assert(src != 4); if (buf) { *(buf++) = 0x89; - *(buf++) = (MOD_DISP8 << 6) | (dest << 3) | src; + *(buf++) = (MOD_DISP8 << 6) | (src << 3) | dest; *(buf++) = disp; } diff --git a/x64.h b/x64.h @@ -27,12 +27,18 @@ void freereg(enum reg reg); size_t add_r64_imm(char *buf, enum reg reg, uint64_t imm); size_t mov_r64_imm(char *buf, enum reg reg, uint64_t imm); size_t mov_r64_m64(char *buf, enum reg reg, uint64_t addr); +size_t mov_r32_m32(char *buf, enum reg dest, uint32_t addr); size_t mov_m64_r64(char *buf, uint64_t addr, enum reg reg); +size_t mov_m32_r32(char *buf, uint64_t addr, enum reg src); size_t mov_mr64_r64(char *buf, enum reg dest, enum reg src); +size_t mov_mr32_r32(char *buf, enum reg dest, enum reg src); size_t mov_r64_mr64(char *buf, enum reg dest, enum reg src); +size_t mov_r32_mr32(char *buf, enum reg dest, enum reg src); size_t mov_r64_r64(char *buf, enum reg dest, enum reg src); size_t mov_disp8_m64_r64(char *buf, enum reg dest, int8_t disp, enum reg src); +size_t mov_disp8_m32_r32(char *buf, enum reg dest, int8_t disp, enum reg src); size_t mov_disp8_r64_m64(char *buf, enum reg dest, enum reg src, int8_t disp); +size_t mov_disp8_r32_m32(char *buf, enum reg dest, enum reg src, int8_t disp); size_t add_r64_r64(char *buf, enum reg reg1, enum reg reg2); size_t sub_r64_r64(char *buf, enum reg reg1, enum reg reg2); size_t sub_r64_imm(char *buf, enum reg reg1, int32_t imm);