mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 07:33:01 +00:00 
			
		
		
		
	More work on moving to machine code emission.
This commit is contained in:
		| @@ -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]); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose