mirror of
https://github.com/janet-lang/janet
synced 2025-05-03 07:54:14 +00:00
More work on moving to machine code emission.
This commit is contained in:
parent
c677c72a73
commit
871f8ebf4e
@ -14,12 +14,6 @@
|
||||
(defpointer p16 u16)
|
||||
(defpointer cursor p32)
|
||||
|
||||
# Linux syscalls
|
||||
# (defn-syscall brk:p32 12 [amount:uint])
|
||||
# (defn-syscall exit:void 60 [code:int])
|
||||
# (defn-syscall write:void 1 [fd:int data:p32 size:uint])
|
||||
# (defn-syscall write_string 1 [fd:int data:pointer size:uint])
|
||||
|
||||
# External
|
||||
(defn-external write:void [fd:int mem:pointer size:uint])
|
||||
(defn-external exit:void [x:int])
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
(defsys doloop [x:int y:int]
|
||||
(var i:int x)
|
||||
#(printf "i = %d\n" i)
|
||||
(printf "initial i = %d\n" i)
|
||||
(while (< i y)
|
||||
(set i (+ 1 i))
|
||||
(printf "i = %d\n" i))
|
||||
|
@ -1650,7 +1650,7 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
|
||||
#define EMITBINOP_NOSUGAR(OP) emit_binop(ir, buffer, tempbuf, instruction, OP, 0)
|
||||
|
||||
/* Prelude */
|
||||
janet_formatb(buffer, "#include <stddef.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <sys/syscall.h>\n#define _t0 void\n\n");
|
||||
janet_formatb(buffer, "#include <stddef.h>\n#include <unistd.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <sys/syscall.h>\n#define _t0 void\n\n");
|
||||
|
||||
/* Emit type defs */
|
||||
for (uint32_t j = 0; j < (uint32_t) linkage->ir_ordered->count; j++) {
|
||||
|
@ -167,7 +167,6 @@ static x64RegKind get_slot_regkind(JanetSysx64Context *ctx, uint32_t o) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void assign_registers(JanetSysx64Context *ctx) {
|
||||
|
||||
/* simplest register assignment algorithm - first n variables
|
||||
@ -223,6 +222,7 @@ void assign_registers(JanetSysx64Context *ctx) {
|
||||
janet_panic("cannot assign registers for calling convention");
|
||||
}
|
||||
} else if (assigned < 0xFFFF) {
|
||||
//} else if (assigned < 1) {
|
||||
/* Assign to register */
|
||||
uint32_t to = 0;
|
||||
while ((1 << to) & assigned) to++;
|
||||
@ -283,7 +283,6 @@ static int operand_isreg(JanetSysx64Context *ctx, uint32_t o, uint32_t regindex)
|
||||
* Machine code emission
|
||||
*/
|
||||
|
||||
/* One piece of a x86 instruction */
|
||||
typedef struct {
|
||||
int bytes;
|
||||
uint64_t data;
|
||||
@ -293,7 +292,7 @@ static const InstrChunk empty_chunk = { 0, 0 };
|
||||
|
||||
static void i_chunk(JanetSysx64Context *C, InstrChunk c) {
|
||||
for (int i = 0; i < c.bytes; i++) {
|
||||
janet_buffer_push_u8(C->buffer, c.data & 0xFF);
|
||||
janet_formatb(C->buffer, "0x%.2X,", c.data & 0xFF);
|
||||
c.data = c.data >> 8;
|
||||
}
|
||||
}
|
||||
@ -305,160 +304,138 @@ static void i_combine(JanetSysx64Context *C,
|
||||
InstrChunk mod_reg_rm,
|
||||
InstrChunk scaled_index,
|
||||
InstrChunk displacement,
|
||||
InstrChunk immediate) {
|
||||
assert(mod_reg_rm.bytes < 3);
|
||||
assert(scaled_index.bytes < 2);
|
||||
assert(opcode < 512);
|
||||
int len_total = prefix.bytes + mod_reg_rm.bytes + scaled_index.bytes + displacement.bytes + immediate.bytes;
|
||||
if (opcode >= 256) len_total++;
|
||||
janet_buffer_extra(C->buffer, len_total);
|
||||
int32_t final_len = C->buffer->count + len_total;
|
||||
i_chunk(C, prefix);
|
||||
if (opcode >= 256) {
|
||||
janet_buffer_push_u8(C->buffer, 0x0Fu);
|
||||
opcode -= 256;
|
||||
}
|
||||
janet_buffer_push_u8(C->buffer, opcode);
|
||||
i_chunk(C, mod_reg_rm);
|
||||
i_chunk(C, scaled_index);
|
||||
i_chunk(C, displacement);
|
||||
i_chunk(C, immediate);
|
||||
assert(C->buffer->count == final_len);
|
||||
}
|
||||
|
||||
static void debug_chunk(JanetSysx64Context *C, InstrChunk c) {
|
||||
for (int i = 0; i < c.bytes; i++) {
|
||||
janet_formatb(C->buffer, "0x%.2X,", c.data & 0xFF);
|
||||
c.data = c.data >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit one x86_64 instruction given all of the individual components */
|
||||
static void debug_combine(JanetSysx64Context *C,
|
||||
InstrChunk prefix,
|
||||
uint16_t opcode,
|
||||
InstrChunk mod_reg_rm,
|
||||
InstrChunk scaled_index,
|
||||
InstrChunk displacement,
|
||||
InstrChunk immediate) {
|
||||
InstrChunk immediate,
|
||||
const char *msg) {
|
||||
assert(mod_reg_rm.bytes < 3);
|
||||
assert(scaled_index.bytes < 2);
|
||||
assert(opcode < 512);
|
||||
janet_buffer_push_cstring(C->buffer, "db ");
|
||||
debug_chunk(C, prefix);
|
||||
i_chunk(C, prefix);
|
||||
if (opcode >= 256) {
|
||||
janet_formatb(C->buffer, "0x%.2X,", 0x0Fu);
|
||||
opcode -= 256;
|
||||
}
|
||||
janet_formatb(C->buffer, "0x%.2X,", opcode);
|
||||
debug_chunk(C, mod_reg_rm);
|
||||
debug_chunk(C, scaled_index);
|
||||
debug_chunk(C, displacement);
|
||||
debug_chunk(C, immediate);
|
||||
janet_buffer_push_cstring(C->buffer, " ; ");
|
||||
i_chunk(C, mod_reg_rm);
|
||||
i_chunk(C, scaled_index);
|
||||
i_chunk(C, displacement);
|
||||
i_chunk(C, immediate);
|
||||
if (msg) {
|
||||
janet_formatb(C->buffer, "; %s\n", msg);
|
||||
} else {
|
||||
janet_buffer_push_cstring(C->buffer, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void e_mov_to_reg(JanetSysx64Context *ctx, x64Reg d, x64Reg s, int deref, const char *msg) {
|
||||
uint8_t rex = 0;
|
||||
uint8_t mod_rm = 0;
|
||||
uint16_t opcode = 0;
|
||||
int flip = 0;
|
||||
InstrChunk dispchunk = empty_chunk;
|
||||
if (s.storage != JANET_SYSREG_REGISTER && d.storage != JANET_SYSREG_REGISTER) {
|
||||
/* mem -> RAX -> mem */
|
||||
x64Reg rax_tmp = { s.kind, JANET_SYSREG_REGISTER, RAX };
|
||||
e_mov_to_reg(ctx, rax_tmp, s, 0, "mem -> RAX (mov to reg)");
|
||||
e_mov_to_reg(ctx, d, rax_tmp, 0, msg);
|
||||
return;
|
||||
}
|
||||
if (deref == 2 || s.storage != JANET_SYSREG_REGISTER) {
|
||||
x64Reg t = d; d = s; s = t; /* swap */
|
||||
flip = 1;
|
||||
}
|
||||
assert(s.storage == JANET_SYSREG_REGISTER);
|
||||
opcode = 0x88;
|
||||
mod_rm |= (uint8_t) (s.index & 7) << 3;
|
||||
if (s.index >= 8) rex |= REX_R;
|
||||
if (s.kind >= JANET_SYSREG_64) rex |= REX_W;
|
||||
if (d.storage == JANET_SYSREG_REGISTER) {
|
||||
if (d.index >= 8) rex |= REX_B;
|
||||
if (!deref) { /* if deref, mod = 00 */
|
||||
mod_rm |= 0xC0u; /* reg, reg mode */
|
||||
}
|
||||
mod_rm |= (uint8_t) (d.index & 7);
|
||||
} else {
|
||||
assert(!deref);
|
||||
/* d is memory */
|
||||
int32_t disp = (d.storage == JANET_SYSREG_STACK_PARAMETER) ? ((int32_t) d.index) : -((int32_t) d.index);
|
||||
if (disp >= -128 && disp <= 127) {
|
||||
dispchunk.bytes = 1;
|
||||
dispchunk.data = (uint64_t) disp;
|
||||
mod_rm |= 0x45; /* 8 bit displacement */
|
||||
} else {
|
||||
dispchunk.bytes = 4;
|
||||
dispchunk.data = (uint64_t) disp;
|
||||
mod_rm |= 0x85; /* 32 bit displacement */
|
||||
}
|
||||
}
|
||||
if (s.kind != JANET_SYSREG_8) opcode++;
|
||||
if (flip) opcode += 2;
|
||||
InstrChunk prefix = {1, rex};
|
||||
if (!rex) prefix.bytes = 0;
|
||||
InstrChunk modregrm = {1, mod_rm};
|
||||
i_combine(ctx, prefix, opcode, modregrm, empty_chunk, dispchunk, empty_chunk, msg);
|
||||
}
|
||||
|
||||
/* Return 1 if actually emitted, 0 if falling back to textual assembly */
|
||||
static int e_mov(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) {
|
||||
static void e_mov(JanetSysx64Context *ctx, uint32_t dest, uint32_t src, const char *msg) {
|
||||
assert(dest <= JANET_SYS_MAX_OPERAND);
|
||||
x64Reg d = ctx->regs[dest];
|
||||
x64RegKind sk = get_slot_regkind(ctx, src);
|
||||
uint8_t rex = 0;
|
||||
uint8_t mod_rm = 0;
|
||||
uint16_t opcode;
|
||||
int32_t disp = 0;
|
||||
int has_disp = 0;
|
||||
if (sk >= JANET_SYSREG_64) rex |= REX_W;
|
||||
if (src <= JANET_SYS_MAX_OPERAND) {
|
||||
/* src is not a constant */
|
||||
x64Reg s = ctx->regs[src];
|
||||
opcode = 0;
|
||||
if (s.storage == JANET_SYSREG_REGISTER) {
|
||||
opcode = 0x88;
|
||||
mod_rm |= (uint8_t) (s.index & 7) << 3;
|
||||
if (s.index >= 8) rex |= REX_R;
|
||||
if (d.storage == JANET_SYSREG_REGISTER) {
|
||||
mod_rm |= 0xC0u; /* reg, reg mode */
|
||||
mod_rm |= (uint8_t) (d.index & 7);
|
||||
if (d.index >= 8) rex |= REX_B;
|
||||
} else {
|
||||
/* d is memory */
|
||||
has_disp = 1;
|
||||
mod_rm |= 0x80; /* 32 bit displacement */
|
||||
mod_rm |= 42; /* reg, BP + disp */
|
||||
disp = (d.storage == JANET_SYSREG_STACK_PARAMETER) ? ((int32_t) d.index) : -((int32_t) d.index);
|
||||
}
|
||||
} else if (d.storage == JANET_SYSREG_REGISTER) {
|
||||
opcode = 0x8A;
|
||||
mod_rm |= (d.index & 7) << 3;
|
||||
if (d.index >= 8) rex |= REX_R;
|
||||
/* s is memory */
|
||||
has_disp = 1;
|
||||
mod_rm |= 0x80; /* 32 bit displacement */
|
||||
mod_rm |= 42; /* reg, BP + disp */
|
||||
disp = (s.storage == JANET_SYSREG_STACK_PARAMETER) ? ((int32_t) s.index) : -((int32_t) s.index);
|
||||
e_mov_to_reg(ctx, d, s, 0, msg);
|
||||
return;
|
||||
}
|
||||
/* src is a constant */
|
||||
if (d.index >= 8) rex |= REX_R;
|
||||
if (d.kind >= JANET_SYSREG_64) rex |= REX_W;
|
||||
Janet c = ctx->ir->constants[src - JANET_SYS_CONSTANT_PREFIX].value;
|
||||
int32_t imm = 0;
|
||||
if (janet_checktype(c, JANET_STRING)) {
|
||||
janet_formatb(ctx->buffer, "; nyi - immediate pointer - %s\n", msg);
|
||||
return;
|
||||
} else if (sk >= JANET_SYSREG_64) {
|
||||
janet_formatb(ctx->buffer, "; nyi - immediate 64 bit value - %s\n", msg);
|
||||
return;
|
||||
} else {
|
||||
if (janet_checktype(c, JANET_BOOLEAN)) {
|
||||
imm = janet_truthy(c) ? -1 : 0;
|
||||
} else {
|
||||
/* mem -> mem, we need to use a temporary register */
|
||||
/* mem -> RAX -> mem */
|
||||
janet_formatb(ctx->buffer, "; mem -> RAX -> mem NYI\n");
|
||||
return 0;
|
||||
imm = janet_unwrap_integer(c);
|
||||
}
|
||||
}
|
||||
InstrChunk dispchunk = empty_chunk;
|
||||
if (d.storage == JANET_SYSREG_REGISTER) {
|
||||
/* This aint right */
|
||||
opcode = 0xB0;
|
||||
opcode += (d.index & 7) << 3;
|
||||
rex |= REX_B;
|
||||
if (d.index >= 8) rex |= REX_R;
|
||||
if (sk != JANET_SYSREG_8) opcode += 8;
|
||||
} else {
|
||||
/* This aint right */
|
||||
opcode = 0xC6;
|
||||
int32_t disp = (d.storage == JANET_SYSREG_STACK_PARAMETER) ? ((int32_t) d.index) : -((int32_t) d.index);
|
||||
if (disp >= -128 && disp <= 127) {
|
||||
dispchunk.bytes = 1;
|
||||
dispchunk.data = (uint64_t) disp;
|
||||
mod_rm |= 0x45; /* 8 bit displacement */
|
||||
} else {
|
||||
dispchunk.bytes = 4;
|
||||
dispchunk.data = (uint64_t) disp;
|
||||
mod_rm |= 0x85; /* 32 bit displacement */
|
||||
}
|
||||
if (sk != JANET_SYSREG_8) opcode++;
|
||||
// TODO - make a little nicer - no need for InstrChunks, we could probably just pass the bytes directly. */
|
||||
InstrChunk prefix = {1, rex};
|
||||
if (!rex) prefix.bytes = 0;
|
||||
InstrChunk modregrm = {1, mod_rm};
|
||||
InstrChunk dispchunk = empty_chunk;
|
||||
if (has_disp) {
|
||||
dispchunk.bytes = 4;
|
||||
dispchunk.data = (uint64_t) disp;
|
||||
}
|
||||
debug_combine(ctx, prefix, opcode, modregrm, empty_chunk, dispchunk, empty_chunk);
|
||||
return 1;
|
||||
} else {
|
||||
/* src is a constant */
|
||||
Janet c = ctx->ir->constants[src - JANET_SYS_CONSTANT_PREFIX].value;
|
||||
int32_t imm = 0;
|
||||
if (janet_checktype(c, JANET_STRING)) {
|
||||
janet_formatb(ctx->buffer, "; nyi - immediate pointer\n");
|
||||
return 0;
|
||||
} else if (sk >= JANET_SYSREG_64) {
|
||||
janet_formatb(ctx->buffer, "; nyi - immediate 64 bit value\n");
|
||||
return 0;
|
||||
} else {
|
||||
if (janet_checktype(c, JANET_BOOLEAN)) {
|
||||
imm = janet_truthy(c);
|
||||
} else {
|
||||
imm = janet_unwrap_integer(c);
|
||||
}
|
||||
}
|
||||
if (d.storage == JANET_SYSREG_REGISTER) {
|
||||
opcode = 0xB0;
|
||||
mod_rm |= 0xC0u; /* reg, reg mode */
|
||||
mod_rm |= (d.index & 7) << 3;
|
||||
if (d.index >= 8) rex |= REX_R;
|
||||
if (sk != JANET_SYSREG_8) opcode = 0xB8;
|
||||
} else {
|
||||
opcode = 0xC6;
|
||||
has_disp = 1;
|
||||
mod_rm |= 0x80; /* 32 bit displacement */
|
||||
mod_rm |= 42; /* reg, BP + disp */
|
||||
disp = (d.storage == JANET_SYSREG_STACK_PARAMETER) ? ((int32_t) d.index) : -((int32_t) d.index);
|
||||
}
|
||||
InstrChunk prefix = {1, rex};
|
||||
if (!rex) prefix.bytes = 0;
|
||||
InstrChunk modregrm = {1, mod_rm};
|
||||
InstrChunk dispchunk = empty_chunk;
|
||||
InstrChunk immchunk = {4, imm};
|
||||
if (has_disp) {
|
||||
dispchunk.bytes = 4;
|
||||
dispchunk.data = (uint64_t) disp;
|
||||
}
|
||||
//debug_combine(ctx, prefix, opcode, modregrm, empty_chunk, dispchunk, immchunk);
|
||||
//return 1;
|
||||
janet_formatb(ctx->buffer, "; nyi - immediates\n");
|
||||
return 0;
|
||||
}
|
||||
InstrChunk prefix = {1, rex};
|
||||
if (!rex) prefix.bytes = 0;
|
||||
InstrChunk immchunk = {4, imm};
|
||||
InstrChunk modregrm = {mod_rm ? 1 : 0, mod_rm};
|
||||
i_combine(ctx, prefix, opcode, modregrm, empty_chunk, dispchunk, immchunk, msg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -508,6 +485,14 @@ static void e_fn_suffix(JanetSysx64Context *ctx) {
|
||||
|
||||
/* Assembly emission */
|
||||
|
||||
static x64Reg mk_tmpreg(JanetSysx64Context *ctx, uint32_t src) {
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, src);
|
||||
tempreg.index = RAX;
|
||||
return tempreg;
|
||||
}
|
||||
|
||||
static const char *sysemit_sizestr(x64RegKind kind) {
|
||||
switch (kind) {
|
||||
case JANET_SYSREG_8:
|
||||
@ -578,13 +563,9 @@ static void sysemit_operand(JanetSysx64Context *ctx, uint32_t o, const char *aft
|
||||
static void sysemit_binop(JanetSysx64Context *ctx, const char *op, uint32_t dest, uint32_t src) {
|
||||
if (operand_isstack(ctx, dest) && operand_isstack(ctx, src)) {
|
||||
/* Use a temporary register for src */
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, dest);
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
sysemit_operand(ctx, src, "\n");
|
||||
x64Reg tempreg = mk_tmpreg(ctx, dest);
|
||||
x64Reg srcreg = ctx->regs[src];
|
||||
e_mov_to_reg(ctx, tempreg, srcreg, 0, "mem -> RAX temp");
|
||||
janet_formatb(ctx->buffer, "%s ", op);
|
||||
sysemit_operand(ctx, dest, ", ");
|
||||
sysemit_reg(ctx, tempreg, "\n");
|
||||
@ -597,71 +578,68 @@ static void sysemit_binop(JanetSysx64Context *ctx, const char *op, uint32_t dest
|
||||
|
||||
/* dest = src[0] */
|
||||
static void sysemit_load(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) {
|
||||
/* This seems verbose... */
|
||||
int src_is_stack = operand_isstack(ctx, src);
|
||||
int dest_is_stack = operand_isstack(ctx, dest);
|
||||
x64Reg d = ctx->regs[dest];
|
||||
x64Reg s = ctx->regs[src];
|
||||
if (!src_is_stack && !dest_is_stack) {
|
||||
/* Simplest case */
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_operand(ctx, dest, ", [");
|
||||
sysemit_operand(ctx, src, "]\n");
|
||||
e_mov_to_reg(ctx, d, s, 2, "dest = src[0] (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_operand(ctx, dest, ", [");
|
||||
//sysemit_operand(ctx, src, "]\n");
|
||||
} else if (src_is_stack && dest_is_stack) {
|
||||
/* Most complicated case. */
|
||||
/* RAX = src */
|
||||
/* RAX = RAX[0] */
|
||||
/* dest = RAX */
|
||||
/* Copy src to temp reg first */
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, src);
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
sysemit_operand(ctx, src, "\n");
|
||||
x64Reg tempreg = mk_tmpreg(ctx, src);
|
||||
e_mov_to_reg(ctx, tempreg, s, 0, "RAX = src (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg, ", ");
|
||||
//sysemit_operand(ctx, src, "\n");
|
||||
/* Now to load to second tempreg */
|
||||
x64Reg tempreg2;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg2.kind = get_slot_regkind(ctx, dest);
|
||||
tempreg2.index = RAX; /* We can reuse RAX */
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg2, ", [");
|
||||
sysemit_reg(ctx, tempreg, "]\n");
|
||||
x64Reg tempreg2 = mk_tmpreg(ctx, dest);
|
||||
e_mov_to_reg(ctx, tempreg2, tempreg, 2, "RAX = RAX[0] (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg2, ", [");
|
||||
//sysemit_reg(ctx, tempreg, "]\n");
|
||||
/* Finally, move tempreg2 to dest */
|
||||
/* Now move tempreg to dest */
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_operand(ctx, dest, ", ");
|
||||
sysemit_reg(ctx, tempreg2, "\n");
|
||||
e_mov_to_reg(ctx, d, tempreg2, 0, "dest = RAX (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_operand(ctx, dest, ", ");
|
||||
//sysemit_reg(ctx, tempreg2, "\n");
|
||||
} else if (src_is_stack) {
|
||||
/* RAX = src */
|
||||
/* dest = RAX[0] */
|
||||
/* Copy src to temp reg first */
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, src);
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
sysemit_operand(ctx, src, "\n");
|
||||
x64Reg tempreg = mk_tmpreg(ctx, src);
|
||||
e_mov_to_reg(ctx, tempreg, s, 0, "RAX = src (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg, ", ");
|
||||
//sysemit_operand(ctx, src, "\n");
|
||||
/* Now do load to dest */
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_operand(ctx, dest, ", [");
|
||||
sysemit_reg(ctx, tempreg, "]\n");
|
||||
e_mov_to_reg(ctx, d, tempreg, 2, "dest = RAX[0] (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_operand(ctx, dest, ", [");
|
||||
//sysemit_reg(ctx, tempreg, "]\n");
|
||||
} else { /* dest_is_stack */
|
||||
/* RAX = src[0] */
|
||||
/* dest = RAX */
|
||||
/* Copy temp reg to dest after */
|
||||
/* Load to tempreg first */
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, src);
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", [");
|
||||
sysemit_operand(ctx, src, "]\n");
|
||||
x64Reg tempreg = mk_tmpreg(ctx, src);
|
||||
e_mov_to_reg(ctx, tempreg, s, 2, "RAX = src[0] (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg, ", [");
|
||||
//sysemit_operand(ctx, src, "]\n");
|
||||
/* Now move tempreg to dest */
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_operand(ctx, dest, ", ");
|
||||
sysemit_reg(ctx, tempreg, "\n");
|
||||
e_mov_to_reg(ctx, d, tempreg, 0, "dest = RAX (load)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_operand(ctx, dest, ", ");
|
||||
//sysemit_reg(ctx, tempreg, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -670,75 +648,73 @@ static void sysemit_store(JanetSysx64Context *ctx, uint32_t dest, uint32_t src)
|
||||
/* This seems verbose... */
|
||||
int src_is_stack = operand_isstack(ctx, src);
|
||||
int dest_is_stack = operand_isstack(ctx, dest);
|
||||
x64Reg d = ctx->regs[dest];
|
||||
x64Reg s = ctx->regs[src];
|
||||
const char *store_size = sysemit_sizestr_slot(ctx, src);
|
||||
if (!src_is_stack && !dest_is_stack) {
|
||||
/* Simplest case */
|
||||
janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
sysemit_operand(ctx, dest, "], ");
|
||||
sysemit_operand(ctx, src, "\n");
|
||||
e_mov_to_reg(ctx, d, s, 1, "dest[0] = src (store)");
|
||||
//janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
//sysemit_operand(ctx, dest, "], ");
|
||||
//sysemit_operand(ctx, src, "\n");
|
||||
} else if (src_is_stack && dest_is_stack) {
|
||||
/* Most complicated case. */
|
||||
/* dest = RAX */
|
||||
/* src = RBX */
|
||||
/* RAX = RBX[0] */
|
||||
/* RAX = dest */
|
||||
/* RBX = src */
|
||||
/* RAX[0] = RBX */
|
||||
/* Copy dest to temp reg first */
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, dest);
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
sysemit_operand(ctx, dest, "\n");
|
||||
/* Now to load to second tempreg */
|
||||
x64Reg tempreg2;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg2.kind = get_slot_regkind(ctx, dest);
|
||||
x64Reg tempreg = mk_tmpreg(ctx, dest);
|
||||
x64Reg tempreg2 = mk_tmpreg(ctx, dest);
|
||||
tempreg2.index = RBX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg2, ", ");
|
||||
sysemit_operand(ctx, src, "\n");
|
||||
e_mov_to_reg(ctx, tempreg, d, 0, "RAX = dest (store)");
|
||||
e_mov_to_reg(ctx, tempreg2, s, 0, "RBX = src (store)");
|
||||
e_mov_to_reg(ctx, tempreg, tempreg2, 1, "RAX[0] = RBX (store)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg, ", ");
|
||||
//sysemit_operand(ctx, dest, "\n");
|
||||
/* Now to load to second tempreg */
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg2, ", ");
|
||||
//sysemit_operand(ctx, src, "\n");
|
||||
/* Finally, move tempreg2 to dest */
|
||||
janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
sysemit_reg(ctx, tempreg, "], ");
|
||||
sysemit_reg(ctx, tempreg2, "\n");
|
||||
//janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
//sysemit_reg(ctx, tempreg, "], ");
|
||||
//sysemit_reg(ctx, tempreg2, "\n");
|
||||
} else if (src_is_stack) {
|
||||
/* Copy src to temp reg first */
|
||||
/* RAX = src */
|
||||
/* dest[0] = RAX */
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, src);
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
sysemit_operand(ctx, src, "\n");
|
||||
x64Reg tempreg = mk_tmpreg(ctx, src);
|
||||
e_mov_to_reg(ctx, tempreg, s, 0, "RAX = src (store)");
|
||||
e_mov_to_reg(ctx, d, tempreg, 1, "dest[0] = RAX (store)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg, ", ");
|
||||
//sysemit_operand(ctx, src, "\n");
|
||||
/* Now do load to dest */
|
||||
janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
sysemit_operand(ctx, dest, "], ");
|
||||
sysemit_reg(ctx, tempreg, "\n");
|
||||
//janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
//sysemit_operand(ctx, dest, "], ");
|
||||
//sysemit_reg(ctx, tempreg, "\n");
|
||||
} else { /* dest_is_stack */
|
||||
/* Copy temp reg to dest after */
|
||||
/* RAX = dest */
|
||||
/* RAX[0] = src */
|
||||
/* Load to tempreg first */
|
||||
x64Reg tempreg;
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.kind = get_slot_regkind(ctx, dest);
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
sysemit_operand(ctx, dest, "\n");
|
||||
janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
sysemit_reg(ctx, tempreg, "], ");
|
||||
sysemit_operand(ctx, src, "\n");
|
||||
x64Reg tempreg = mk_tmpreg(ctx, dest);
|
||||
e_mov_to_reg(ctx, tempreg, d, 0, "RAX = dest (store)");
|
||||
e_mov_to_reg(ctx, tempreg, s, 1, "RAX[0] = src (store)");
|
||||
//janet_formatb(ctx->buffer, "mov ");
|
||||
//sysemit_reg(ctx, tempreg, ", ");
|
||||
//sysemit_operand(ctx, dest, "\n");
|
||||
//janet_formatb(ctx->buffer, "mov %s [", store_size);
|
||||
//sysemit_reg(ctx, tempreg, "], ");
|
||||
//sysemit_operand(ctx, src, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* dest = src */
|
||||
static void sysemit_mov(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) {
|
||||
if (dest == src) return;
|
||||
e_mov(ctx, dest, src);
|
||||
sysemit_binop(ctx, "mov", dest, src);
|
||||
e_mov(ctx, dest, src, "sysemit_mov");
|
||||
}
|
||||
|
||||
static void sysemit_movreg(JanetSysx64Context *ctx, uint32_t regdest, uint32_t src) {
|
||||
@ -755,30 +731,20 @@ static void sysemit_movreg(JanetSysx64Context *ctx, uint32_t regdest, uint32_t s
|
||||
static void sysemit_movfromreg(JanetSysx64Context *ctx, uint32_t dest, uint32_t srcreg) {
|
||||
if (operand_isreg(ctx, dest, srcreg)) return;
|
||||
x64Reg tempreg;
|
||||
tempreg.index = srcreg;
|
||||
tempreg.kind = get_slot_regkind(ctx, dest);
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.index = srcreg;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_operand(ctx, dest, ", ");
|
||||
sysemit_reg(ctx, tempreg, "\n");
|
||||
}
|
||||
|
||||
static void sysemit_pushreg(JanetSysx64Context *ctx, uint32_t dest_reg) {
|
||||
e_pushreg(ctx, dest_reg);
|
||||
//janet_formatb(ctx->buffer, "push %s\n", register_names[dest_reg]);
|
||||
}
|
||||
|
||||
/* Move a value to a register, and save the contents of the old register on fhe stack */
|
||||
static void sysemit_mov_save(JanetSysx64Context *ctx, uint32_t dest_reg, uint32_t src) {
|
||||
sysemit_pushreg(ctx, dest_reg);
|
||||
e_pushreg(ctx, dest_reg);
|
||||
sysemit_movreg(ctx, dest_reg, src);
|
||||
}
|
||||
|
||||
static void sysemit_popreg(JanetSysx64Context *ctx, uint32_t dest_reg) {
|
||||
e_popreg(ctx, dest_reg);
|
||||
//janet_formatb(ctx->buffer, "pop %s\n", register_names[dest_reg]);
|
||||
}
|
||||
|
||||
static void sysemit_threeop(JanetSysx64Context *ctx, const char *op, uint32_t dest, uint32_t lhs, uint32_t rhs) {
|
||||
sysemit_mov(ctx, dest, lhs);
|
||||
sysemit_binop(ctx, op, dest, rhs);
|
||||
@ -811,12 +777,9 @@ static void sysemit_ret(JanetSysx64Context *ctx, uint32_t arg, int has_return) {
|
||||
for (int32_t k = 31; k >= 0; k--) {
|
||||
if (ctx->clobbered_registers & (1u << k)) {
|
||||
e_popreg(ctx, k);
|
||||
//janet_formatb(ctx->buffer, "pop %s\n", register_names[k]);
|
||||
}
|
||||
}
|
||||
e_fn_suffix(ctx);
|
||||
//janet_formatb(ctx->buffer, "leave\n");
|
||||
//janet_formatb(ctx->buffer, "ret\n");
|
||||
}
|
||||
|
||||
static int sysemit_comp(JanetSysx64Context *ctx, uint32_t index,
|
||||
@ -903,19 +866,19 @@ static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instr
|
||||
int save_r10 = ctx->occupied_registers & (1 << 10);
|
||||
int save_r11 = ctx->occupied_registers & (1 << 11);
|
||||
if (save_rdi && argcount >= 1) sysemit_mov_save(ctx, RDI, args[0]);
|
||||
if (save_rdi && argcount < 1) sysemit_pushreg(ctx, RDI);
|
||||
if (save_rdi && argcount < 1) e_pushreg(ctx, RDI);
|
||||
if (save_rsi && argcount >= 2) sysemit_mov_save(ctx, RSI, args[1]);
|
||||
if (save_rsi && argcount < 2) sysemit_pushreg(ctx, RSI);
|
||||
if (save_rsi && argcount < 2) e_pushreg(ctx, RSI);
|
||||
if (save_rdx && argcount >= 3) sysemit_mov_save(ctx, RDX, args[2]);
|
||||
if (save_rdx && argcount < 3) sysemit_pushreg(ctx, RDX);
|
||||
if (save_rdx && argcount < 3) e_pushreg(ctx, RDX);
|
||||
if (save_rcx && argcount >= 4) sysemit_mov_save(ctx, RCX, args[3]);
|
||||
if (save_rcx && argcount < 4) sysemit_pushreg(ctx, RCX);
|
||||
if (save_rcx && argcount < 4) e_pushreg(ctx, RCX);
|
||||
if (save_r8 && argcount >= 5) sysemit_mov_save(ctx, 8, args[4]);
|
||||
if (save_r8 && argcount < 5) sysemit_pushreg(ctx, 8);
|
||||
if (save_r8 && argcount < 5) e_pushreg(ctx, 8);
|
||||
if (save_r9 && argcount >= 6) sysemit_mov_save(ctx, 9, args[5]);
|
||||
if (save_r9 && argcount < 6) sysemit_pushreg(ctx, 9);
|
||||
if (save_r10) sysemit_pushreg(ctx, 10);
|
||||
if (save_r11) sysemit_pushreg(ctx, 11);
|
||||
if (save_r9 && argcount < 6) e_pushreg(ctx, 9);
|
||||
if (save_r10) e_pushreg(ctx, 10);
|
||||
if (save_r11) e_pushreg(ctx, 11);
|
||||
for (int32_t argo = argcount - 1; argo >= 6; argo--) {
|
||||
janet_panic("nyi push sysv args");
|
||||
janet_formatb(buffer, "push ");
|
||||
@ -930,14 +893,14 @@ static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instr
|
||||
janet_formatb(buffer, "call ");
|
||||
sysemit_operand(ctx, instruction.call.callee, "\n");
|
||||
}
|
||||
if (save_r11) sysemit_popreg(ctx, 11);
|
||||
if (save_r10) sysemit_popreg(ctx, 10);
|
||||
if (save_r9) sysemit_popreg(ctx, 9);
|
||||
if (save_r8) sysemit_popreg(ctx, 8);
|
||||
if (save_rcx) sysemit_popreg(ctx, RCX);
|
||||
if (save_rdx) sysemit_popreg(ctx, RDX);
|
||||
if (save_rsi) sysemit_popreg(ctx, RSI);
|
||||
if (save_rdi) sysemit_popreg(ctx, RDI);
|
||||
if (save_r11) e_popreg(ctx, 11);
|
||||
if (save_r10) e_popreg(ctx, 10);
|
||||
if (save_r9) e_popreg(ctx, 9);
|
||||
if (save_r8) e_popreg(ctx, 8);
|
||||
if (save_rcx) e_popreg(ctx, RCX);
|
||||
if (save_rdx) e_popreg(ctx, RDX);
|
||||
if (save_rsi) e_popreg(ctx, RSI);
|
||||
if (save_rdi) e_popreg(ctx, RDI);
|
||||
if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movfromreg(ctx, instruction.call.dest, RAX);
|
||||
}
|
||||
|
||||
@ -951,15 +914,15 @@ static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction inst
|
||||
int save_r10 = ctx->occupied_registers & (1 << 10);
|
||||
int save_r11 = ctx->occupied_registers & (1 << 11);
|
||||
if (save_rcx && argcount >= 1) sysemit_mov_save(ctx, RCX, args[0]);
|
||||
if (save_rcx && argcount < 1) sysemit_pushreg(ctx, RCX);
|
||||
if (save_rcx && argcount < 1) e_pushreg(ctx, RCX);
|
||||
if (save_rdx && argcount >= 2) sysemit_mov_save(ctx, RDX, args[1]);
|
||||
if (save_rdx && argcount < 2) sysemit_pushreg(ctx, RDX);
|
||||
if (save_rdx && argcount < 2) e_pushreg(ctx, RDX);
|
||||
if (save_r8 && argcount >= 3) sysemit_mov_save(ctx, 8, args[2]);
|
||||
if (save_r8 && argcount < 3) sysemit_pushreg(ctx, 8);
|
||||
if (save_r8 && argcount < 3) e_pushreg(ctx, 8);
|
||||
if (save_r9 && argcount >= 4) sysemit_mov_save(ctx, 9, args[3]);
|
||||
if (save_r9 && argcount < 4) sysemit_pushreg(ctx, 9);
|
||||
if (save_r10) sysemit_pushreg(ctx, 10);
|
||||
if (save_r11) sysemit_pushreg(ctx, 11);
|
||||
if (save_r9 && argcount < 4) e_pushreg(ctx, 9);
|
||||
if (save_r10) e_pushreg(ctx, 10);
|
||||
if (save_r11) e_pushreg(ctx, 11);
|
||||
for (uint32_t argo = 4; argo < argcount; argo++) {
|
||||
e_pushreg(ctx, args[argo]);
|
||||
//janet_formatb(buffer, "push ");
|
||||
@ -975,12 +938,12 @@ static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction inst
|
||||
if (argcount > 4) {
|
||||
janet_formatb(buffer, "add rsp, %u\n", 8 * (argcount - 4));
|
||||
}
|
||||
if (save_r11) sysemit_popreg(ctx, 11);
|
||||
if (save_r10) sysemit_popreg(ctx, 10);
|
||||
if (save_r9) sysemit_popreg(ctx, 9);
|
||||
if (save_r8) sysemit_popreg(ctx, 8);
|
||||
if (save_rdx) sysemit_popreg(ctx, RDX);
|
||||
if (save_rcx) sysemit_popreg(ctx, RCX);
|
||||
if (save_r11) e_popreg(ctx, 11);
|
||||
if (save_r10) e_popreg(ctx, 10);
|
||||
if (save_r9) e_popreg(ctx, 9);
|
||||
if (save_r8) e_popreg(ctx, 8);
|
||||
if (save_rdx) e_popreg(ctx, RDX);
|
||||
if (save_rcx) e_popreg(ctx, RCX);
|
||||
if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movfromreg(ctx, instruction.call.dest, RAX);
|
||||
}
|
||||
|
||||
@ -1055,12 +1018,10 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target
|
||||
janet_formatb(buffer, "\n_section_%d:\n", i);
|
||||
}
|
||||
e_fn_prefix(&ctx, ctx.frame_size);
|
||||
//janet_formatb(buffer, "push rbp\nmov rbp, rsp\nsub rsp, %u\n", ctx.frame_size);
|
||||
|
||||
for (uint32_t k = 0; k < 32; k++) {
|
||||
if (ctx.clobbered_registers & (1u << k)) {
|
||||
e_pushreg(&ctx, k);
|
||||
//janet_formatb(buffer, "push %s\n", register_names[k]);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user