nooc

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

commit a1d655b3ecc7d71e3a27ac1a9be28ea053ed6a57
parent af471ce9faad92173994dd4d2183a38d09dcbcb4
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Thu, 23 Dec 2021 22:06:49 -0600

add i32 type

This breaks the out_read/out_write functions, which only deal in
64-bit right now. This abstraction will be extended to deal with
all function parameters, and have a size attribute (later).

Diffstat:
Mmain.c | 50++++++++++++++++++++++++++++++++++++++++++++------
Mnooc.h | 2+-
Mparse.c | 2+-
Atest/i32.pass.nooc | 6++++++
Mtype.c | 12++++++++++--
Mx64.c | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
6 files changed, 150 insertions(+), 18 deletions(-)

diff --git a/main.c b/main.c @@ -91,16 +91,35 @@ decl_alloc(struct block *block, struct decl *decl) size_t decl_fromreg(char *buf, struct decl *decl, enum reg reg) { + struct type *type = &types.data[decl->type]; + size_t total = 0; switch (decl->kind) { case DECL_DATA: - total += mov_m64_r64(buf ? buf + total : NULL, decl->loc.addr, reg); + switch (type->size) { + case 8: + total += mov_m64_r64(buf ? buf + total : NULL, decl->loc.addr, reg); + break; + case 4: + total += mov_m32_r32(buf ? buf + total : NULL, decl->loc.addr, reg); + break; + default: + die("decl_fromreg: unsupported size for mov_mn_rn"); + } break; case DECL_STACK: - total += mov_disp8_m64_r64(buf, reg, -decl->loc.off, RBP); + 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); + break; + default: + die("decl_toreg: unsupported size for mov_disp8_mn_rn"); + } break; default: - fprintf(stderr, "%d\n", decl->kind); die("decl_fromreg: unknown decl kind"); } @@ -111,13 +130,32 @@ decl_fromreg(char *buf, struct decl *decl, enum reg reg) 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: - total += mov_r64_m64(buf ? buf + total : NULL, reg, decl->loc.addr); + 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); + break; + default: + die("decl_toreg: unsupported size for mov_mn_rn"); + } break; case DECL_STACK: - total += mov_disp8_r64_m64(buf, reg, RBP, -decl->loc.off); + 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); + break; + default: + die("decl_fromreg: unsupported size for mov_mn_rn"); + } break; default: die("unknown decl type!"); @@ -285,7 +323,7 @@ typecheck(struct block *block) col = decl->start->col; check: switch (type->class) { - case TYPE_I64: + case TYPE_INT: if (expr->class != C_INT) error(line, col, "expected integer expression for integer declaration"); break; diff --git a/nooc.h b/nooc.h @@ -60,7 +60,7 @@ struct typelist { }; enum typeclass { - TYPE_I64 = 1, + TYPE_INT = 1, TYPE_STR, TYPE_PROC, }; diff --git a/parse.c b/parse.c @@ -107,7 +107,7 @@ enum class typetoclass(struct type *type) { switch (type->class) { - case TYPE_I64: + case TYPE_INT: return C_INT; case TYPE_STR: return C_STR; diff --git a/test/i32.pass.nooc b/test/i32.pass.nooc @@ -0,0 +1,6 @@ +let main proc() = proc() { + let a i64 = 100 + let b i32 = 0 + + syscall(60, b) +} diff --git a/type.c b/type.c @@ -40,10 +40,17 @@ inittypes() // first one should be 0 type_put(&type); - type.class = TYPE_I64; + type.class = TYPE_INT; type.size = 8; size_t idx = type_put(&type); mapkey(&key, "i64", 3); + mapput(typesmap, &key)->n = idx; + + type.class = TYPE_INT; + type.size = 4; + idx = type_put(&type); + mapkey(&key, "i32", 3); + mapput(typesmap, &key)->n = idx; mapput(typesmap, &key)->n = idx; @@ -61,7 +68,8 @@ hashtype(struct type *type, uint8_t *out) blake3_init(&b3); - blake3_update(&b3, &type->class, sizeof(enum typeclass)); + blake3_update(&b3, &type->class, sizeof(type->class)); + blake3_update(&b3, &type->size, sizeof(type->size)); switch (type->class) { case TYPE_PROC: blake3_update(&b3, type->d.params.in.data, type->d.params.in.len * sizeof(*type->d.params.in.data)); diff --git a/x64.c b/x64.c @@ -72,15 +72,32 @@ mov_r64_imm(char *buf, enum reg dest, uint64_t imm) { if (buf) { *(buf++) = REX_W | (dest >= 8 ? REX_B : 0); - *(buf++) = 0xc7; - *(buf++) = (MOD_DIRECT << 6) | (dest & 0x7); + *(buf++) = 0xb8 + (dest & 0x7); *(buf++) = imm & 0xFF; *(buf++) = (imm >> 8) & 0xFF; *(buf++) = (imm >> 16) & 0xFF; *(buf++) = (imm >> 24) & 0xFF; + *(buf++) = (imm >> 32) & 0xFF; + *(buf++) = (imm >> 40) & 0xFF; + *(buf++) = (imm >> 48) & 0xFF; + *(buf++) = (imm >> 56) & 0xFF; } - return 7; + return 10; +} + +size_t +mov_r32_imm(char *buf, enum reg dest, uint32_t imm) +{ + if (buf) { + *(buf++) = 0xb8 + (dest & 0x7); + *(buf++) = imm & 0xFF; + *(buf++) = (imm >> 8) & 0xFF; + *(buf++) = (imm >> 16) & 0xFF; + *(buf++) = (imm >> 24) & 0xFF; + } + + return 5; } size_t @@ -102,21 +119,57 @@ mov_r64_m64(char *buf, enum reg dest, uint64_t addr) } size_t +mov_r32_m32(char *buf, enum reg dest, uint32_t addr) +{ + if (buf) { + if (dest >= 8) *(buf++) = REX_R; + *(buf++) = 0x8b; + *(buf++) = (MOD_INDIRECT << 6) | ((dest & 7) << 3) | 4; + *(buf++) = 0x25; + *(buf++) = addr & 0xFF; + *(buf++) = (addr >> 8) & 0xFF; + *(buf++) = (addr >> 16) & 0xFF; + *(buf++) = (addr >> 24) & 0xFF; + } + + return dest >= 8 ? 8 : 7; +} + +size_t mov_m64_r64(char *buf, uint64_t addr, enum reg src) { - uint8_t sib = 0x25; if (buf) { *(buf++) = REX_W; - *(buf++) = 0x89; - *(buf++) = (MOD_INDIRECT << 6) | (src << 3) | 4; - *(buf++) = sib; + *(buf++) = 0xA3; *(buf++) = addr & 0xFF; *(buf++) = (addr >> 8) & 0xFF; *(buf++) = (addr >> 16) & 0xFF; *(buf++) = (addr >> 24) & 0xFF; + *(buf++) = (addr >> 32) & 0xFF; + *(buf++) = (addr >> 40) & 0xFF; + *(buf++) = (addr >> 48) & 0xFF; + *(buf++) = (addr >> 56) & 0xFF; } - return 8; + return 10; +} + +size_t +mov_m32_r32(char *buf, uint64_t addr, enum reg src) +{ + if (buf) { + *(buf++) = 0xA3; + *(buf++) = addr & 0xFF; + *(buf++) = (addr >> 8) & 0xFF; + *(buf++) = (addr >> 16) & 0xFF; + *(buf++) = (addr >> 24) & 0xFF; + *(buf++) = (addr >> 32) & 0xFF; + *(buf++) = (addr >> 40) & 0xFF; + *(buf++) = (addr >> 48) & 0xFF; + *(buf++) = (addr >> 56) & 0xFF; + } + + return 9; } size_t @@ -169,6 +222,20 @@ mov_disp8_m64_r64(char *buf, enum reg dest, int8_t disp, enum reg src) return 4; } +// FIXME: we don't handle r8-r15 properly in most of these +size_t +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++) = disp; + } + + return 3; +} + size_t mov_disp8_r64_m64(char *buf, enum reg dest, enum reg src, int8_t disp) { @@ -184,6 +251,19 @@ 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) +{ + assert(src != 4); + if (buf) { + *(buf++) = 0x8b; + *(buf++) = (MOD_DISP8 << 6) | (dest << 3) | src; + *(buf++) = disp; + } + + return 3; +} + +size_t add_r64_r64(char *buf, enum reg dest, enum reg src) { if (buf) {