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:
M | main.c | | | 110 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
M | nooc.h | | | 1 | + |
M | parse.c | | | 1 | + |
M | x64.c | | | 36 | +++++++++++++++++++++++++++++++++++- |
M | x64.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, ®buf, 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);