nooc

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

commit e479aac9bba98833a5f00a10d408461d6d9ef482
parent 7f78583070c776aa77f7059322381dd116d37eba
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Wed, 12 Jan 2022 20:08:14 -0600

remove extra allocation when generating code

This required updating all the generation functions in x64.c since
they all write to a buffer. Now they write to a `struct data` array.

Diffstat:
Marray.h | 3+++
Mir.c | 10+---------
Mir.h | 4++--
Mmain.c | 8+-------
Msiphash.c | 3++-
Mtype.c | 1-
Mx64.c | 557+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mx64.h | 2--
8 files changed, 300 insertions(+), 288 deletions(-)

diff --git a/array.h b/array.h @@ -1,6 +1,9 @@ #define array_add(arr, new) \ _array_add((void **) &(arr->data), &(arr->len), &(arr->cap), &new, sizeof(new), 1); +#define array_addlit(arr, new) \ + do {temp = new; array_add(arr, temp); } while (0); + #define array_push(arr, new, count) \ _array_add((void **) &(arr->data), &(arr->len), &(arr->cap), new, sizeof(*(arr->data)), count); diff --git a/ir.c b/ir.c @@ -2,7 +2,6 @@ #include <stdbool.h> #include <stddef.h> #include <stdint.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> @@ -409,17 +408,10 @@ genproc(struct decl *decl, struct proc *proc) } genblock(out, &proc->block); - chooseregs(&iproc); - - size_t len = targ.emitproc(NULL, out); - void *buf = xcalloc(1, len); // FIXME: unnecessary - len = targ.emitproc(buf, out); - array_push((&toplevel.text), buf, len); - free(buf); array_add((&toplevel.code), iproc); blockpop(); - return len; + return targ.emitproc(&toplevel.text, out); } diff --git a/ir.h b/ir.h @@ -64,6 +64,6 @@ size_t genproc(struct decl *decl, struct proc *proc); struct target { uint32_t reserved; - size_t (*emitsyscall)(char *buf, uint8_t paramcount); - size_t (*emitproc)(char *buf, struct iproc *proc); + size_t (*emitsyscall)(struct data *text, uint8_t paramcount); + size_t (*emitproc)(struct data *text, struct iproc *proc); }; diff --git a/main.c b/main.c @@ -102,7 +102,6 @@ gentoplevel(struct toplevel *toplevel, struct block *block) char syscallname[] = "syscall0"; blockpush(block); typecheck(block); - size_t len = 0; struct iproc iproc = { 0 }; uint64_t curaddr = TEXT_OFFSET; @@ -111,13 +110,8 @@ gentoplevel(struct toplevel *toplevel, struct block *block) syscallname[7]++; iproc.s.data = strdup(syscallname); iproc.addr = curaddr; - len = targ.emitsyscall(NULL, i); - void *buf = xcalloc(1, len); // FIXME: unnecessary - len = targ.emitsyscall(buf, i); - array_push((&toplevel->text), buf, len); - free(buf); array_add((&toplevel->code), iproc); - curaddr += len; + curaddr += targ.emitsyscall(&toplevel->text, i); } for (int i = 0; i < block->len; i++) { struct item *item = &block->data[i]; diff --git a/siphash.c b/siphash.c @@ -17,7 +17,7 @@ #include <assert.h> #include <stdint.h> -#include <stdio.h> +#include <stddef.h> /* default: SipHash-2-4 */ #ifndef cROUNDS @@ -65,6 +65,7 @@ #ifdef DEBUG #define TRACE \ +#include <stdio.h> do { \ printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \ printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \ diff --git a/type.c b/type.c @@ -3,7 +3,6 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> -#include <stdio.h> #include "nooc.h" #include "parse.h" diff --git a/x64.c b/x64.c @@ -8,6 +8,7 @@ #include "ir.h" #include "x64.h" #include "util.h" +#include "array.h" enum rex { REX_B = 0x41, @@ -31,180 +32,190 @@ unsigned short used_reg; extern struct toplevel toplevel; static size_t -add_r64_imm(char *buf, enum reg dest, uint64_t imm) +add_r64_imm(struct data *text, enum reg dest, uint64_t imm) { - if (buf) { - *(buf++) = REX_W; - *(buf++) = 0x81;; - *(buf++) = (MOD_DIRECT << 6) | dest; - *(buf++) = imm & 0xFF; - *(buf++) = (imm >> 8) & 0xFF; - *(buf++) = (imm >> 16) & 0xFF; - *(buf++) = (imm >> 24) & 0xFF; + uint8_t temp; + if (text) { + array_addlit(text, REX_W); + array_addlit(text, 0x81); + array_addlit(text, (MOD_DIRECT << 6) | dest); + array_addlit(text, imm & 0xFF); + array_addlit(text, (imm >> 8) & 0xFF); + array_addlit(text, (imm >> 16) & 0xFF); + array_addlit(text, (imm >> 24) & 0xFF); } return 7; } static size_t -mov_r64_imm(char *buf, enum reg dest, uint64_t imm) +mov_r64_imm(struct data *text, enum reg dest, uint64_t imm) { - if (buf) { - *(buf++) = REX_W | (dest >= 8 ? REX_B : 0); - *(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; + uint8_t temp; + if (text) { + array_addlit(text, REX_W | (dest >= 8 ? REX_B : 0)); + array_addlit(text, 0xb8 + (dest & 0x7)); + array_addlit(text, imm & 0xFF); + array_addlit(text, (imm >> 8) & 0xFF); + array_addlit(text, (imm >> 16) & 0xFF); + array_addlit(text, (imm >> 24) & 0xFF); + array_addlit(text, (imm >> 32) & 0xFF); + array_addlit(text, (imm >> 40) & 0xFF); + array_addlit(text, (imm >> 48) & 0xFF); + array_addlit(text, (imm >> 56) & 0xFF); } return 10; } static size_t -mov_r32_imm(char *buf, enum reg dest, uint32_t imm) +mov_r32_imm(struct data *text, 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; + uint8_t temp; + if (text) { + array_addlit(text, 0xb8 + (dest & 0x7)); + array_addlit(text, imm & 0xFF); + array_addlit(text, (imm >> 8) & 0xFF); + array_addlit(text, (imm >> 16) & 0xFF); + array_addlit(text, (imm >> 24) & 0xFF); } return 5; } static size_t -mov_r16_imm(char *buf, enum reg dest, uint16_t imm) +mov_r16_imm(struct data *text, enum reg dest, uint16_t imm) { - if (buf) { - *(buf++) = OP_SIZE_OVERRIDE; - *(buf++) = 0xb8; - *(buf++) = imm & 0xFF; - *(buf++) = (imm >> 8) & 0xFF; + uint8_t temp; + if (text) { + array_addlit(text, OP_SIZE_OVERRIDE); + array_addlit(text, 0xb8); + array_addlit(text, imm & 0xFF); + array_addlit(text, (imm >> 8) & 0xFF); } return 4; } static size_t -mov_r8_imm(char *buf, enum reg dest, uint8_t imm) +mov_r8_imm(struct data *text, enum reg dest, uint8_t imm) { - if (buf) { - *(buf++) = 0xb0 + (dest & 0x7); - *(buf++) = imm; + uint8_t temp; + if (text) { + array_addlit(text, 0xb0 + (dest & 0x7)); + array_addlit(text, imm); } return 2; } static size_t -mov_r64_m64(char *buf, enum reg dest, uint64_t addr) +mov_r64_m64(struct data *text, enum reg dest, uint64_t addr) { - uint8_t sib = 0x25; - if (buf) { - *(buf++) = REX_W | (dest >= 8 ? REX_R : 0); - *(buf++) = 0x8b; - *(buf++) = (MOD_INDIRECT << 6) | ((dest & 7) << 3) | 4; - *(buf++) = sib; - *(buf++) = addr & 0xFF; - *(buf++) = (addr >> 8) & 0xFF; - *(buf++) = (addr >> 16) & 0xFF; - *(buf++) = (addr >> 24) & 0xFF; + uint8_t temp; + if (text) { + array_addlit(text, REX_W | (dest >= 8 ? REX_R : 0)); + array_addlit(text, 0x8b); + array_addlit(text, (MOD_INDIRECT << 6) | ((dest & 7) << 3) | 4); + array_addlit(text, 0x25); + array_addlit(text, addr & 0xFF); + array_addlit(text, (addr >> 8) & 0xFF); + array_addlit(text, (addr >> 16) & 0xFF); + array_addlit(text, (addr >> 24) & 0xFF); } return 8; } static size_t -mov_r32_m32(char *buf, enum reg dest, uint32_t addr) +mov_r32_m32(struct data *text, 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; + uint8_t temp; + if (text) { + if (dest >= 8) array_addlit(text, REX_R); + array_addlit(text, 0x8b); + array_addlit(text, (MOD_INDIRECT << 6) | ((dest & 7) << 3) | 4); + array_addlit(text, 0x25); + array_addlit(text, addr & 0xFF); + array_addlit(text, (addr >> 8) & 0xFF); + array_addlit(text, (addr >> 16) & 0xFF); + array_addlit(text, (addr >> 24) & 0xFF); } return dest >= 8 ? 8 : 7; } static size_t -mov_r16_m16(char *buf, enum reg dest, uint32_t addr) +mov_r16_m16(struct data *text, enum reg dest, uint32_t addr) { - if (buf) { - *(buf++) = OP_SIZE_OVERRIDE; - 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; + uint8_t temp; + if (text) { + array_addlit(text, OP_SIZE_OVERRIDE); + if (dest >= 8) array_addlit(text, REX_R); + array_addlit(text, 0x8b); + array_addlit(text, (MOD_INDIRECT << 6) | ((dest & 7) << 3) | 4); + array_addlit(text, 0x25); + array_addlit(text, addr & 0xFF); + array_addlit(text, (addr >> 8) & 0xFF); + array_addlit(text, (addr >> 16) & 0xFF); + array_addlit(text, (addr >> 24) & 0xFF); } return dest >= 8 ? 9 : 8; } static size_t -mov_r8_m8(char *buf, enum reg dest, uint32_t addr) +mov_r8_m8(struct data *text, enum reg dest, uint32_t addr) { - if (buf) { - if (dest >= 8) *(buf++) = REX_R; - *(buf++) = 0x8a; - *(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; + uint8_t temp; + if (text) { + if (dest >= 8) array_addlit(text, REX_R); + array_addlit(text, 0x8a); + array_addlit(text, (MOD_INDIRECT << 6) | ((dest & 7) << 3) | 4); + array_addlit(text, 0x25); + array_addlit(text, addr & 0xFF); + array_addlit(text, (addr >> 8) & 0xFF); + array_addlit(text, (addr >> 16) & 0xFF); + array_addlit(text, (addr >> 24) & 0xFF); } return dest >= 8 ? 8 : 7; } static size_t -mov_m64_r64(char *buf, uint64_t addr, enum reg src) +mov_m64_r64(struct data *text, uint64_t addr, enum reg src) { - if (buf) { - *(buf++) = REX_W; - *(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; + uint8_t temp; + if (text) { + array_addlit(text, REX_W); + array_addlit(text, 0xA3); + array_addlit(text, addr & 0xFF); + array_addlit(text, (addr >> 8) & 0xFF); + array_addlit(text, (addr >> 16) & 0xFF); + array_addlit(text, (addr >> 24) & 0xFF); + array_addlit(text, (addr >> 32) & 0xFF); + array_addlit(text, (addr >> 40) & 0xFF); + array_addlit(text, (addr >> 48) & 0xFF); + array_addlit(text, (addr >> 56) & 0xFF); } return 10; } static size_t -mov_m32_r32(char *buf, uint64_t addr, enum reg src) +mov_m32_r32(struct data *text, 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; + uint8_t temp; + if (text) { + array_addlit(text, 0xA3); + array_addlit(text, addr & 0xFF); + array_addlit(text, (addr >> 8) & 0xFF); + array_addlit(text, (addr >> 16) & 0xFF); + array_addlit(text, (addr >> 24) & 0xFF); + array_addlit(text, (addr >> 32) & 0xFF); + array_addlit(text, (addr >> 40) & 0xFF); + array_addlit(text, (addr >> 48) & 0xFF); + array_addlit(text, (addr >> 56) & 0xFF); } return 9; @@ -214,21 +225,21 @@ mov_m32_r32(char *buf, uint64_t addr, enum reg src) #define MOVE_TOREG 1 static size_t -_move_between_reg_and_memaddr_in_reg(char *buf, enum reg reg, enum reg mem, uint8_t opsize, bool dir) +_move_between_reg_and_memaddr_in_reg(struct data *text, enum reg reg, enum reg mem, uint8_t opsize, bool dir) { - uint8_t rex = opsize == 8 ? REX_W : 0; + uint8_t temp, rex = opsize == 8 ? REX_W : 0; rex |= (reg >= 8 ? REX_R : 0) | (mem >= 8 ? REX_B : 0); - if (buf) { + if (text) { if (opsize == 2) - *(buf++) = OP_SIZE_OVERRIDE; + array_addlit(text, OP_SIZE_OVERRIDE); if (rex) - *(buf++) = rex; + array_addlit(text, rex); - *(buf++) = 0x88 + (opsize != 1) + 2*dir; + array_addlit(text, 0x88 + (opsize != 1) + 2*dir); - *(buf++) = (MOD_INDIRECT << 6) | ((reg & 7) << 3) | (mem & 7); + array_addlit(text, (MOD_INDIRECT << 6) | ((reg & 7) << 3) | (mem & 7)); } // 8 and 2 have a length of 3, but 4 and 1 have a length of 2 @@ -236,101 +247,101 @@ _move_between_reg_and_memaddr_in_reg(char *buf, enum reg reg, enum reg mem, uint } static size_t -mov_mr64_r64(char *buf, enum reg dest, enum reg src) +mov_mr64_r64(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, src, dest, 8, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg(text, src, dest, 8, MOVE_FROMREG); } static size_t -mov_mr32_r32(char *buf, enum reg dest, enum reg src) +mov_mr32_r32(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, src, dest, 4, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg(text, src, dest, 4, MOVE_FROMREG); } static size_t -mov_mr16_r16(char *buf, enum reg dest, enum reg src) +mov_mr16_r16(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, src, dest, 2, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg(text, src, dest, 2, MOVE_FROMREG); } static size_t -mov_mr8_r8(char *buf, enum reg dest, enum reg src) +mov_mr8_r8(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, src, dest, 1, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg(text, src, dest, 1, MOVE_FROMREG); } static size_t -mov_r64_mr64(char *buf, enum reg dest, enum reg src) +mov_r64_mr64(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, dest, src, 8, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg(text, dest, src, 8, MOVE_TOREG); } static size_t -mov_r32_mr32(char *buf, enum reg dest, enum reg src) +mov_r32_mr32(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, dest, src, 4, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg(text, dest, src, 4, MOVE_TOREG); } static size_t -mov_r16_mr16(char *buf, enum reg dest, enum reg src) +mov_r16_mr16(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, dest, src, 2, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg(text, dest, src, 2, MOVE_TOREG); } static size_t -mov_r8_mr8(char *buf, enum reg dest, enum reg src) +mov_r8_mr8(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_memaddr_in_reg(buf, dest, src, 1, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg(text, dest, src, 1, MOVE_TOREG); } static size_t -_move_between_reg_and_reg(char *buf, enum reg dest, enum reg src, uint8_t opsize) +_move_between_reg_and_reg(struct data *text, enum reg dest, enum reg src, uint8_t opsize) { - uint8_t rex = (src >= 8 ? REX_R : 0) | (dest >= 8 ? REX_B : 0) | (opsize == 8 ? REX_W : 0); - if (buf) { + uint8_t temp, rex = (src >= 8 ? REX_R : 0) | (dest >= 8 ? REX_B : 0) | (opsize == 8 ? REX_W : 0); + if (text) { if (opsize == 2) - *(buf++) = OP_SIZE_OVERRIDE; + array_addlit(text, OP_SIZE_OVERRIDE); if (rex) - *(buf++) = rex; + array_addlit(text, rex); - *(buf++) = 0x88 + (opsize != 1); - *(buf++) = (MOD_DIRECT << 6) | ((src & 7) << 3) | (dest & 7); + array_addlit(text, 0x88 + (opsize != 1)); + array_addlit(text, (MOD_DIRECT << 6) | ((src & 7) << 3) | (dest & 7)); } return 2 + !!rex + (opsize == 2); } static size_t -mov_r64_r64(char *buf, enum reg dest, enum reg src) +mov_r64_r64(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_reg(buf, dest, src, 8); + return _move_between_reg_and_reg(text, dest, src, 8); } static size_t -mov_r32_r32(char *buf, enum reg dest, enum reg src) +mov_r32_r32(struct data *text, enum reg dest, enum reg src) { - return _move_between_reg_and_reg(buf, dest, src, 4); + return _move_between_reg_and_reg(text, dest, src, 4); } static size_t -_move_between_reg_and_memaddr_in_reg_with_disp(char *buf, enum reg reg, enum reg mem, int8_t disp, uint8_t opsize, bool dir) +_move_between_reg_and_memaddr_in_reg_with_disp(struct data *text, enum reg reg, enum reg mem, int8_t disp, uint8_t opsize, bool dir) { assert((reg & 7) != 4 && (mem & 7) != 4); - uint8_t rex = opsize == 8 ? REX_W : 0; + uint8_t temp, rex = opsize == 8 ? REX_W : 0; rex |= (reg >= 8 ? REX_R : 0) | (mem >= 8 ? REX_B : 0); - if (buf) { + if (text) { if (opsize == 2) - *(buf++) = OP_SIZE_OVERRIDE; + array_addlit(text, OP_SIZE_OVERRIDE); if (rex) - *(buf++) = rex; + array_addlit(text, rex); - *(buf++) = 0x88 + (opsize != 1) + 2*dir; + array_addlit(text, 0x88 + (opsize != 1) + 2*dir); - *(buf++) = (MOD_DISP8 << 6) | ((reg & 7) << 3) | (mem & 7); - *(buf++) = disp; + array_addlit(text, (MOD_DISP8 << 6) | ((reg & 7) << 3) | (mem & 7)); + array_addlit(text, disp); } // 8 and 2 have a length of 3, but 4 and 1 have a length of 2 @@ -338,127 +349,133 @@ _move_between_reg_and_memaddr_in_reg_with_disp(char *buf, enum reg reg, enum reg } static size_t -mov_disp8_m64_r64(char *buf, enum reg dest, int8_t disp, enum reg src) +mov_disp8_m64_r64(struct data *text, enum reg dest, int8_t disp, enum reg src) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, src, dest, disp, 8, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, src, dest, disp, 8, MOVE_FROMREG); } static size_t -mov_disp8_m32_r32(char *buf, enum reg dest, int8_t disp, enum reg src) +mov_disp8_m32_r32(struct data *text, enum reg dest, int8_t disp, enum reg src) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, src, dest, disp, 4, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, src, dest, disp, 4, MOVE_FROMREG); } static size_t -mov_disp8_m16_r16(char *buf, enum reg dest, int8_t disp, enum reg src) +mov_disp8_m16_r16(struct data *text, enum reg dest, int8_t disp, enum reg src) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, src, dest, disp, 2, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, src, dest, disp, 2, MOVE_FROMREG); } static size_t -mov_disp8_m8_r8(char *buf, enum reg dest, int8_t disp, enum reg src) +mov_disp8_m8_r8(struct data *text, enum reg dest, int8_t disp, enum reg src) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, src, dest, disp, 1, MOVE_FROMREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, src, dest, disp, 1, MOVE_FROMREG); } static size_t -mov_disp8_r64_m64(char *buf, enum reg dest, enum reg src, int8_t disp) +mov_disp8_r64_m64(struct data *text, enum reg dest, enum reg src, int8_t disp) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, dest, src, disp, 8, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, dest, src, disp, 8, MOVE_TOREG); } static size_t -mov_disp8_r32_m32(char *buf, enum reg dest, enum reg src, int8_t disp) +mov_disp8_r32_m32(struct data *text, enum reg dest, enum reg src, int8_t disp) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, dest, src, disp, 4, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, dest, src, disp, 4, MOVE_TOREG); } static size_t -mov_disp8_r16_m16(char *buf, enum reg dest, enum reg src, int8_t disp) +mov_disp8_r16_m16(struct data *text, enum reg dest, enum reg src, int8_t disp) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, dest, src, disp, 2, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, dest, src, disp, 2, MOVE_TOREG); } static size_t -mov_disp8_r8_m8(char *buf, enum reg dest, enum reg src, int8_t disp) +mov_disp8_r8_m8(struct data *text, enum reg dest, enum reg src, int8_t disp) { - return _move_between_reg_and_memaddr_in_reg_with_disp(buf, dest, src, disp, 1, MOVE_TOREG); + return _move_between_reg_and_memaddr_in_reg_with_disp(text, dest, src, disp, 1, MOVE_TOREG); } static size_t -lea_disp8(char *buf, enum reg dest, enum reg src, int8_t disp) +lea_disp8(struct data *text, enum reg dest, enum reg src, int8_t disp) { + uint8_t temp; assert(src != 4); - if (buf) { - *(buf++) = REX_W; - *(buf++) = 0x8d; - *(buf++) = (MOD_DISP8 << 6) | (dest << 3) | src; - *(buf++) = disp; + if (text) { + array_addlit(text, REX_W); + array_addlit(text, 0x8d); + array_addlit(text, (MOD_DISP8 << 6) | (dest << 3) | src); + array_addlit(text, disp); } return 4; } static size_t -add_r64_r64(char *buf, enum reg dest, enum reg src) +add_r64_r64(struct data *text, enum reg dest, enum reg src) { - if (buf) { - *(buf++) = REX_W; - *(buf++) = 0x03; - *(buf++) = (MOD_DIRECT << 6) | (dest << 3) | src; + uint8_t temp; + if (text) { + array_addlit(text, REX_W); + array_addlit(text, 0x03); + array_addlit(text, (MOD_DIRECT << 6) | (dest << 3) | src); } return 3; } static size_t -sub_r64_r64(char *buf, enum reg dest, enum reg src) +sub_r64_r64(struct data *text, enum reg dest, enum reg src) { - if (buf) { - *(buf++) = REX_W; - *(buf++) = 0x2b; - *(buf++) = (MOD_DIRECT << 6) | (dest << 3) | src; + uint8_t temp; + if (text) { + array_addlit(text, REX_W); + array_addlit(text, 0x2b); + array_addlit(text, (MOD_DIRECT << 6) | (dest << 3) | src); } return 3; } static size_t -sub_r64_imm(char *buf, enum reg dest, int32_t imm) +sub_r64_imm(struct data *text, enum reg dest, int32_t imm) { - if (buf) { - *(buf++) = REX_W; - *(buf++) = 0x81; - *(buf++) = (MOD_DIRECT << 6) | (5 << 3) | dest; - *(buf++) = imm & 0xFF; - *(buf++) = (imm >> 8) & 0xFF; - *(buf++) = (imm >> 16) & 0xFF; - *(buf++) = (imm >> 24) & 0xFF; + uint8_t temp; + if (text) { + array_addlit(text, REX_W); + array_addlit(text, 0x81); + array_addlit(text, (MOD_DIRECT << 6) | (5 << 3) | dest); + array_addlit(text, imm & 0xFF); + array_addlit(text, (imm >> 8) & 0xFF); + array_addlit(text, (imm >> 16) & 0xFF); + array_addlit(text, (imm >> 24) & 0xFF); } return 7; } static size_t -cmp_r64_r64(char *buf, enum reg reg1, enum reg reg2) +cmp_r64_r64(struct data *text, enum reg reg1, enum reg reg2) { - if (buf) { - *(buf++) = REX_W; - *(buf++) = 0x3b; - *(buf++) = (MOD_DIRECT << 6) | (reg1 << 3) | reg2; + uint8_t temp; + if (text) { + array_addlit(text, REX_W); + array_addlit(text, 0x3b); + array_addlit(text, (MOD_DIRECT << 6) | (reg1 << 3) | reg2); } return 3; } static size_t -jng(char *buf, int64_t offset) +jng(struct data *text, int64_t offset) { + uint8_t temp; if (-256 <= offset && offset <= 255) { int8_t i = offset; - if (buf) { - *(buf++) = 0x7E; - *(buf++) = i; + if (text) { + array_addlit(text, 0x7E); + array_addlit(text, i); } return 2; } else { @@ -469,13 +486,14 @@ jng(char *buf, int64_t offset) } static size_t -jg(char *buf, int64_t offset) +jg(struct data *text, int64_t offset) { + uint8_t temp; if (-256 <= offset && offset <= 255) { int8_t i = offset; - if (buf) { - *(buf++) = 0x7F; - *(buf++) = i; + if (text) { + array_addlit(text, 0x7F); + array_addlit(text, i); } return 2; } else { @@ -486,13 +504,14 @@ jg(char *buf, int64_t offset) } static size_t -jne(char *buf, int64_t offset) +jne(struct data *text, int64_t offset) { + uint8_t temp; if (-256 <= offset && offset <= 255) { int8_t i = offset; - if (buf) { - *(buf++) = 0x75; - *(buf++) = i; + if (text) { + array_addlit(text, 0x75); + array_addlit(text, i); } return 2; } else { @@ -503,13 +522,14 @@ jne(char *buf, int64_t offset) } static size_t -jmp(char *buf, int64_t offset) +jmp(struct data *text, int64_t offset) { + uint8_t temp; if (-256 <= offset && offset <= 255) { int8_t i = offset; - if (buf) { - *(buf++) = 0xEB; - *(buf++) = i; + if (text) { + array_addlit(text, 0xEB); + array_addlit(text, i); } return 2; } else { @@ -520,54 +540,58 @@ jmp(char *buf, int64_t offset) } static size_t -call(char *buf, int32_t offset) +call(struct data *text, int32_t offset) { - if (buf) { - *(buf++) = 0xE8; - *(buf++) = (uint32_t) offset & 0xff; - *(buf++) = ((uint32_t) offset >> 8) & 0xff; - *(buf++) = ((uint32_t) offset >> 16) & 0xff; - *(buf++) = ((uint32_t) offset >> 24) & 0xff; + uint8_t temp; + if (text) { + array_addlit(text, 0xE8); + array_addlit(text, (uint32_t) offset & 0xff); + array_addlit(text, ((uint32_t) offset >> 8) & 0xff); + array_addlit(text, ((uint32_t) offset >> 16) & 0xff); + array_addlit(text, ((uint32_t) offset >> 24) & 0xff); } return 5; } static size_t -ret(char *buf) +ret(struct data *text) { - if (buf) - *buf = 0xC3; + uint8_t temp; + if (text) + array_addlit(text, 0xC3); return 1; } static size_t -_pushpop_r64(char *buf, uint8_t ioff, enum reg reg) +_pushpop_r64(struct data *text, uint8_t ioff, enum reg reg) { - if (buf) { + uint8_t temp; + if (text) { if (reg >= 8) - *(buf++) = REX_B; + array_addlit(text, REX_B); - *buf = 0x50 + ioff + (reg & 7); + array_addlit(text, 0x50 + ioff + (reg & 7)); } return reg >= 8 ? 2 : 1; } static size_t -push_r64(char *buf, enum reg reg) +push_r64(struct data *text, enum reg reg) { - return _pushpop_r64(buf, 0, reg); + return _pushpop_r64(text, 0, reg); } static size_t -pop_r64(char *buf, enum reg reg) +pop_r64(struct data *text, enum reg reg) { - return _pushpop_r64(buf, 8, reg); + return _pushpop_r64(text, 8, reg); } -static size_t emitsyscall(char *buf, uint8_t paramcount); +static size_t emitsyscall(struct data *text, uint8_t paramcount); +static size_t emitproc(struct data *text, struct iproc *proc); const struct target x64_target = { .reserved = (1 << RSP) | (1 << RBP) | (1 << R12) | (1 << R13), @@ -578,40 +602,41 @@ const struct target x64_target = { #define NEXT ins++; assert(ins <= end); static size_t -emitsyscall(char *buf, uint8_t paramcount) +emitsyscall(struct data *text, uint8_t paramcount) { assert(paramcount < 8); size_t total = 0; - total += push_r64(buf ? buf + total : NULL, RBP); - total += mov_r64_r64(buf ? buf + total : NULL, RBP, RSP); + uint8_t temp; + total += push_r64(text, RBP); + total += mov_r64_r64(text, RBP, RSP); for (size_t i = 0; i < paramcount; i++) { - total += push_r64(buf ? buf + total : NULL, abi_arg[i]); - total += mov_disp8_r64_m64(buf ? buf + total : NULL, abi_arg[i], RBP, 8*i + 16); + total += push_r64(text, abi_arg[i]); + total += mov_disp8_r64_m64(text, abi_arg[i], RBP, 8*i + 16); } - if (buf) { - *(buf + total++) = 0x0f; - *(buf + total++) = 0x05; - } else { - total += 2; + if (text) { + array_addlit(text, 0x0f); + array_addlit(text, 0x05); } - total += mov_disp8_r64_m64(buf ? buf + total : NULL, RDI, RBP, 8*paramcount + 16); - total += mov_mr64_r64(buf ? buf + total : NULL, RDI, RAX); + total += 2; + + total += mov_disp8_r64_m64(text, RDI, RBP, 8*paramcount + 16); + total += mov_mr64_r64(text, RDI, RAX); for (size_t i = paramcount - 1; i < paramcount; i--) { - total += pop_r64(buf ? buf + total : NULL, abi_arg[i]); + total += pop_r64(text, abi_arg[i]); } - total += pop_r64(buf ? buf + total : NULL, RBP); - total += ret(buf ? buf + total : NULL); + total += pop_r64(text, RBP); + total += ret(text); return total; } size_t -emitblock(char *buf, struct iproc *proc, struct instr *start, struct instr *end, uint64_t end_label) +emitblock(struct data *text, struct iproc *proc, struct instr *start, struct instr *end, uint64_t end_label) { struct instr *ins = start ? start : proc->data; end = end ? end : &proc->data[proc->len]; @@ -624,8 +649,8 @@ emitblock(char *buf, struct iproc *proc, struct instr *start, struct instr *end, size_t total = 0; if (!start) { - total += push_r64(buf ? buf + total : NULL, RBP); - total += mov_r64_r64(buf ? buf + total : NULL, RBP, RSP); + total += push_r64(text, RBP); + total += mov_r64_r64(text, RBP, RSP); } while (ins < end) { @@ -640,13 +665,13 @@ emitblock(char *buf, struct iproc *proc, struct instr *start, struct instr *end, switch (ins->op) { // FIXME: we don't handle jumps backward yet case IR_JUMP: - total += jmp(buf ? buf + total : NULL, emitblock(NULL, proc, ins + 1, end, ins->id)); + total += jmp(text, emitblock(NULL, proc, ins + 1, end, ins->id)); NEXT; break; case IR_RETURN: - total += add_r64_imm(buf ? buf + total : NULL, RSP, localalloc); - total += pop_r64(buf ? buf + total : NULL, RBP); - total += ret(buf ? buf + total : NULL); + total += add_r64_imm(text, RSP, localalloc); + total += pop_r64(text, RBP); + total += ret(text); NEXT; break; case IR_SIZE: @@ -658,7 +683,7 @@ emitblock(char *buf, struct iproc *proc, struct instr *start, struct instr *end, src = proc->intervals.data[ins->id].reg; NEXT; assert(ins->op == IR_EXTRA); - total += mov_mr64_r64(buf ? buf + total : NULL, proc->intervals.data[ins->id].reg, src); + total += mov_mr64_r64(text, proc->intervals.data[ins->id].reg, src); NEXT; break; default: @@ -676,9 +701,9 @@ emitblock(char *buf, struct iproc *proc, struct instr *start, struct instr *end, switch (ins->op) { case IR_CEQ: - total += mov_r64_r64(buf ? buf + total : NULL, dest, proc->intervals.data[ins->id].reg); + total += mov_r64_r64(text, dest, proc->intervals.data[ins->id].reg); NEXT; - total += cmp_r64_r64(buf ? buf + total : NULL, dest, proc->intervals.data[ins->id].reg); + total += cmp_r64_r64(text, dest, proc->intervals.data[ins->id].reg); NEXT; if (ins->op == IR_CONDJUMP) { curi++; @@ -686,32 +711,32 @@ emitblock(char *buf, struct iproc *proc, struct instr *start, struct instr *end, NEXT; assert(ins->op == IR_EXTRA); if (ins->id == tmp) { - total += jne(buf ? buf + total : NULL, emitblock(NULL, proc, ins + 1, end, label)); + total += jne(text, emitblock(NULL, proc, ins + 1, end, label)); } NEXT; } break; case IR_ADD: - total += mov_r64_r64(buf ? buf + total : NULL, dest, proc->intervals.data[ins->id].reg); + total += mov_r64_r64(text, dest, proc->intervals.data[ins->id].reg); NEXT; - total += add_r64_r64(buf ? buf + total : NULL, dest, proc->intervals.data[ins->id].reg); + total += add_r64_r64(text, dest, proc->intervals.data[ins->id].reg); NEXT; break; case IR_IMM: - total += mov_r64_imm(buf ? buf + total : NULL, dest, ins->id); + total += mov_r64_imm(text, dest, ins->id); NEXT; break; case IR_IN: - total += mov_disp8_r64_m64(buf ? buf + total : NULL, dest, RBP, 8*ins->id + 16); + total += mov_disp8_r64_m64(text, dest, RBP, 8*ins->id + 16); NEXT; break; case IR_LOAD: - total += mov_r64_mr64(buf ? buf + total : NULL, dest, proc->intervals.data[ins->id].reg); + total += mov_r64_mr64(text, dest, proc->intervals.data[ins->id].reg); NEXT; break; case IR_ALLOC: - total += mov_r64_r64(buf ? buf + total : NULL, dest, RSP); - total += sub_r64_imm(buf ? buf + total : NULL, RSP, 8); // FIXME: hardcoding + total += mov_r64_r64(text, dest, RSP); + total += sub_r64_imm(text, RSP, 8); // FIXME: hardcoding localalloc += 8; NEXT; break; @@ -725,25 +750,25 @@ emitblock(char *buf, struct iproc *proc, struct instr *start, struct instr *end, for (int i = 0; i < 16; i++) { if (active & (1 << i)) { - total += push_r64(buf ? buf + total : NULL, i); + total += push_r64(text, i); } } NEXT; while (ins->op == IR_CALLARG) { count++; - total += push_r64(buf ? buf + total : NULL, proc->intervals.data[ins->id].reg); + total += push_r64(text, proc->intervals.data[ins->id].reg); NEXT; } // we assume call is constant width - this should probably change offset = -(proc->addr + total - toplevel.code.data[dest].addr + call(NULL, 0)); - total += call(buf ? buf + total : NULL, offset); + total += call(text, offset); // FIXME: this won't work with non-64-bit things - total += add_r64_imm(buf ? buf + total : NULL, RSP, 8*count); + total += add_r64_imm(text, RSP, 8*count); for (int i = 15; i >= 0; i--) { if (active & (1 << i)) { - total += pop_r64(buf ? buf + total : NULL, i); + total += pop_r64(text, i); } } break; @@ -768,7 +793,7 @@ done: // FIXME: use array_push size_t -emitproc(char *buf, struct iproc *proc) +emitproc(struct data *text, struct iproc *proc) { - return emitblock(buf, proc, NULL, NULL, 0); + return emitblock(text, proc, NULL, NULL, 0); } diff --git a/x64.h b/x64.h @@ -19,5 +19,3 @@ enum reg { extern char abi_arg[]; extern unsigned short used_reg; - -size_t emitproc(char *buf, struct iproc *proc);