diff --git a/examples/sysir/samples.janet b/examples/sysir/samples.janet index 6b62bfc1..b236ea9e 100644 --- a/examples/sysir/samples.janet +++ b/examples/sysir/samples.janet @@ -57,11 +57,11 @@ (defsys test_arrays:myvec [a:myvec b:myvec] (return (+ a b))) -(defsys make_array:myvec [] +'(defsys make_array:myvec [] (def vec:myvec [0 0 0 0]) (return vec)) -(defsys make_mat:mymat [] +'(defsys make_mat:mymat [] (def mat:mymat [[1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]]) (return mat)) diff --git a/examples/sysir/x64.janet b/examples/sysir/x64.janet new file mode 100644 index 00000000..da77cbc9 --- /dev/null +++ b/examples/sysir/x64.janet @@ -0,0 +1,25 @@ +(use ./frontend) + +(defn-external printf:int [fmt:pointer x:int]) +(defn-external exit:void [x:int]) + +(defsys doloop [x:int y:int] + (var i:int x) + #(printf "i = %d\n" i) + (while (< i y) + (set i (+ 1 i)) + (printf "i = %d\n" i)) + (return x)) + +(defsys _start:void [] + (doloop 10 20) + (exit (the int 0)) + (return)) + +(defn main [& args] + (def [_ what] args) + (dump) + (eprint "MODE: " what) + (case what + "c" (dumpc) + "x64" (dumpx64))) diff --git a/src/core/sysir_x86.c b/src/core/sysir_x86.c index a95791b1..d91a5867 100644 --- a/src/core/sysir_x86.c +++ b/src/core/sysir_x86.c @@ -204,6 +204,8 @@ void assign_registers(JanetSysx64Context *ctx) { /* TODO check sizing and alignment */ ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; ctx->regs[i].index = (i - 6) * 8 + 16; + } else { + assigned |= 1 << (ctx->regs[i].index); } } else if (cc == JANET_SYS_CC_X64_WINDOWS) { if (i == 0) ctx->regs[i].index = RCX; @@ -214,6 +216,8 @@ void assign_registers(JanetSysx64Context *ctx) { /* TODO check sizing and alignment */ ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; ctx->regs[i].index = (i - 4) * 8 + 16; + } else { + assigned |= 1 << (ctx->regs[i].index); } } else { janet_panic("cannot assign registers for calling convention"); @@ -457,6 +461,51 @@ static int e_mov(JanetSysx64Context *ctx, uint32_t dest, uint32_t src) { } } +/* +push rbp +mov rbp, rsp +sub rsp, +*/ +static void e_fn_prefix(JanetSysx64Context *ctx, int32_t stack) { + if (stack >= 128) { + int a = stack & 0xFF; + int b = (stack >> 8) & 0xFF; + int c = (stack >> 16) & 0xFF; + int d = (stack >> 24) & 0xFF; + janet_formatb(ctx->buffer, "db 0x55, 0x48, 0x89, 0xe5, 0x48, 0x81, 0xec, 0x%.2X, 0x%.2X, 0x%2X, 0x%2X ; function prefix\n", a, b, c, d); + } else { + janet_formatb(ctx->buffer, "db 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x%.2X ; function prefix\n", stack); + } +} + +static void e_pushreg(JanetSysx64Context *ctx, uint32_t reg) { + assert(reg < 16); + if (reg >= 8) { + /* Use REX prefix */ + janet_formatb(ctx->buffer, "db 0x41, 0x%.2X ; push %s\n", 0x50 + (reg - 8), register_names[reg]); + } else { + janet_formatb(ctx->buffer, "db 0x%.2X ; push %s\n", 0x50 + reg, register_names[reg]); + } +} + +static void e_popreg(JanetSysx64Context *ctx, uint32_t reg) { + assert(reg < 16); + if (reg >= 8) { + /* Use REX prefix */ + janet_formatb(ctx->buffer, "db 0x41, 0x%.2X ; pop %s\n", 0x58 + (reg - 8), register_names[reg]); + } else { + janet_formatb(ctx->buffer, "db 0x%.2X ; pop %s\n", 0x58 + reg, register_names[reg]); + } +} + +/* +leave +ret +*/ +static void e_fn_suffix(JanetSysx64Context *ctx) { + janet_formatb(ctx->buffer, "db 0xc9, 0xc3 ; function suffix\n"); +} + /* Assembly emission */ static const char *sysemit_sizestr(x64RegKind kind) { @@ -715,7 +764,8 @@ static void sysemit_movfromreg(JanetSysx64Context *ctx, uint32_t dest, uint32_t } static void sysemit_pushreg(JanetSysx64Context *ctx, uint32_t dest_reg) { - janet_formatb(ctx->buffer, "push %s\n", register_names[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 */ @@ -725,7 +775,8 @@ static void sysemit_mov_save(JanetSysx64Context *ctx, uint32_t dest_reg, uint32_ } static void sysemit_popreg(JanetSysx64Context *ctx, uint32_t dest_reg) { - janet_formatb(ctx->buffer, "pop %s\n", register_names[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) { @@ -759,11 +810,13 @@ static void sysemit_ret(JanetSysx64Context *ctx, uint32_t arg, int has_return) { /* Pop in reverse order */ for (int32_t k = 31; k >= 0; k--) { if (ctx->clobbered_registers & (1u << k)) { - janet_formatb(ctx->buffer, "pop %s\n", register_names[k]); + e_popreg(ctx, k); + //janet_formatb(ctx->buffer, "pop %s\n", register_names[k]); } } - janet_formatb(ctx->buffer, "leave\n"); - janet_formatb(ctx->buffer, "ret\n"); + 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, @@ -908,8 +961,9 @@ static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction inst if (save_r10) sysemit_pushreg(ctx, 10); if (save_r11) sysemit_pushreg(ctx, 11); for (uint32_t argo = 4; argo < argcount; argo++) { - janet_formatb(buffer, "push "); - sysemit_operand(ctx, args[argo], "\n"); + e_pushreg(ctx, args[argo]); + //janet_formatb(buffer, "push "); + //sysemit_operand(ctx, args[argo], "\n"); } if (instruction.opcode == JANET_SYSOP_SYSCALL) { sysemit_movreg(ctx, RAX, instruction.call.callee); @@ -1000,11 +1054,13 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target } else { janet_formatb(buffer, "\n_section_%d:\n", i); } - janet_formatb(buffer, "push rbp\nmov rbp, rsp\nsub rsp, %u\n", ctx.frame_size); + 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)) { - janet_formatb(buffer, "push %s\n", register_names[k]); + e_pushreg(&ctx, k); + //janet_formatb(buffer, "push %s\n", register_names[k]); } } diff --git a/tools/x64.sh b/tools/x64.sh new file mode 100755 index 00000000..2cdca3d0 --- /dev/null +++ b/tools/x64.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +case "$2" in +c) + rm temp.bin temp.o temp.nasm + valgrind build/janet "$@" > temp.c + gcc -nostdlib temp.c -c temp.o + ;; +x64) + rm temp.bin temp.o temp.nasm + valgrind build/janet "$@" > temp.nasm + nasm -felf64 temp.nasm -l temp.lst -o temp.o + ;; +*) + echo "Unknown mode $2" + exit + ;; +esac + +ld -o temp.bin -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc temp.o +valgrind ./temp.bin