mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	Working examples on windows.
Add some support for windows x64 ABI.
This commit is contained in:
		| @@ -20,11 +20,11 @@ | ||||
| @setlocal | ||||
|  | ||||
| @rem Example use asan | ||||
| @rem set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD /fsanitize=address /Zi | ||||
| @rem set JANET_LINK=link /nologo clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib | ||||
| @set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD /fsanitize=address /Zi /DEBUG | ||||
| @set JANET_LINK=link /nologo clang_rt.asan_dynamic-x86_64.lib clang_rt.asan_dynamic_runtime_thunk-x86_64.lib /DEBUG | ||||
|  | ||||
| @set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD | ||||
| @set JANET_LINK=link /nologo | ||||
| @rem set JANET_COMPILE=cl /nologo /Isrc\include /Isrc\conf /c /O2 /W3 /D_CRT_SECURE_NO_WARNINGS /MD | ||||
| @rem set JANET_LINK=link /nologo | ||||
|  | ||||
| @set JANET_LINK_STATIC=lib /nologo | ||||
|  | ||||
|   | ||||
| @@ -57,6 +57,7 @@ | ||||
|   (add-prim-type 'long 's64) | ||||
|   (add-prim-type 'pointer 'pointer) | ||||
|   (add-prim-type 'boolean 'boolean) | ||||
|   (add-prim-type 's16 's16) | ||||
|   (sysir/asm ctx into) | ||||
|   ctx) | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| janet.exe examples/sysir/samples.janet > temp.nasm | ||||
| nasm -fwin64 temp.nasm -l temp.lst -o temp.o | ||||
| link temp.o legacy_stdio_definitions.lib msvcrt.lib /out:temp.exe | ||||
| link /entry:Start /subsystem:windows kernel32.lib user32.lib temp.o /out:temp.exe | ||||
| temp.exe | ||||
|   | ||||
| @@ -32,19 +32,27 @@ | ||||
|      (return x))) | ||||
|  | ||||
| (def main-fn | ||||
|   '(defn WinMain:void [] | ||||
|   '(defn _start:void [] | ||||
|      #(syscall 1 1 "Hello, world!\n" 14) | ||||
|      (doloop 10 20) | ||||
|      (exit (the int 0)) | ||||
|      (return))) | ||||
|  | ||||
| (def winmain | ||||
|   '(defn Start:void [] | ||||
|      (MessageBoxExA (the pointer 0) "Hello, world!" "Test" 0 (the s16 0)) | ||||
|      (ExitProcess (the int 0)) | ||||
|      (return))) | ||||
|  | ||||
|  | ||||
| #### | ||||
|  | ||||
| #(compile1 square) | ||||
| (compile1 simple) | ||||
| (compile1 myprog) | ||||
| (compile1 doloop) | ||||
| (compile1 main-fn) | ||||
| #(compile1 simple) | ||||
| #(compile1 myprog) | ||||
| #(compile1 doloop) | ||||
| #(compile1 main-fn) | ||||
| (compile1 winmain) | ||||
| #(dump) | ||||
| #(dumpc) | ||||
| (dumpx64) | ||||
|   | ||||
| @@ -71,6 +71,7 @@ const char *prim_to_prim_name[] = { | ||||
| const char *janet_sysop_names[] = { | ||||
|     "link-name", /* JANET_SYSOP_LINK_NAME */ | ||||
|     "parameter-count", /* JANET_SYSOP_PARAMETER_COUNT */ | ||||
|     "calling-convention", /* JANET_SYSOP_CALLING_CONVENTION */ | ||||
|     "move", /* JANET_SYSOP_MOVE */ | ||||
|     "cast", /* JANET_SYSOP_CAST */ | ||||
|     "add", /* JANET_SYSOP_ADD */ | ||||
| @@ -158,6 +159,7 @@ static const JanetSysInstrName sys_op_names[] = { | ||||
|     {"branch-not", JANET_SYSOP_BRANCH_NOT}, | ||||
|     {"bxor", JANET_SYSOP_BXOR}, | ||||
|     {"call", JANET_SYSOP_CALL}, | ||||
|     {"calling-convention", JANET_SYSOP_CALLING_CONVENTION}, | ||||
|     {"cast", JANET_SYSOP_CAST}, | ||||
|     {"divide", JANET_SYSOP_DIVIDE}, | ||||
|     {"eq", JANET_SYSOP_EQ}, | ||||
| @@ -287,7 +289,7 @@ static uint32_t instr_read_type_operand(Janet x, JanetSysIR *ir, ReadOpMode rmod | ||||
|             return (uint32_t) n; | ||||
|         } else if (rmode == READ_TYPE_FORWARD_REF) { | ||||
|             uint32_t operand = linkage->type_def_count++; | ||||
|             janet_table_put(linkage->type_name_lookup, x, janet_wrap_number(-(int64_t)operand - 1)); | ||||
|             janet_table_put(linkage->type_name_lookup, x, janet_wrap_number(-(double)operand - 1.0)); | ||||
|             return operand; | ||||
|         } else if (rmode == READ_TYPE_DEFINITION) { | ||||
|             uint32_t operand = linkage->type_def_count++; | ||||
| @@ -370,6 +372,7 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction | ||||
|     JanetSysInstruction *ir = NULL; | ||||
|     JanetTable *labels = out->labels; | ||||
|     int found_parameter_count = 0; | ||||
|     int found_calling_convention = 0; | ||||
|  | ||||
|     /* Parse instructions */ | ||||
|     Janet x = janet_wrap_nil(); | ||||
| @@ -436,6 +439,14 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction | ||||
|                 found_parameter_count = 1; | ||||
|                 out->parameter_count = janet_getnat(tuple, 1); | ||||
|                 break; | ||||
|             case JANET_SYSOP_CALLING_CONVENTION: | ||||
|                 instr_assert_length(tuple, 2, opvalue); | ||||
|                 if (found_calling_convention) { | ||||
|                     janet_panic("duplicate calling-convention"); | ||||
|                 } | ||||
|                 found_calling_convention = 1; | ||||
|                 out->calling_convention = instr_read_cc(tuple[1]); | ||||
|                 break; | ||||
|             case JANET_SYSOP_ADD: | ||||
|             case JANET_SYSOP_SUBTRACT: | ||||
|             case JANET_SYSOP_MULTIPLY: | ||||
| @@ -1063,6 +1074,7 @@ static void janet_sysir_type_check(JanetSysIR *sysir) { | ||||
|             case JANET_SYSOP_ARG: | ||||
|             case JANET_SYSOP_LINK_NAME: | ||||
|             case JANET_SYSOP_PARAMETER_COUNT: | ||||
|             case JANET_SYSOP_CALLING_CONVENTION: | ||||
|             case JANET_SYSOP_JUMP: | ||||
|             case JANET_SYSOP_LABEL: | ||||
|                 break; | ||||
| @@ -1202,6 +1214,7 @@ static void janet_sys_ir_init(JanetSysIR *out, JanetView instructions, JanetSysI | ||||
|     ir.parameter_count = 0; | ||||
|     ir.link_name = NULL; | ||||
|     ir.error_ctx = janet_wrap_nil(); | ||||
|     ir.calling_convention = JANET_SYS_CC_DEFAULT; | ||||
|  | ||||
|     janet_sysir_init_instructions(&ir, instructions); | ||||
|  | ||||
| @@ -1384,6 +1397,7 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) { | ||||
|                 case JANET_SYSOP_ARG: | ||||
|                 case JANET_SYSOP_LINK_NAME: | ||||
|                 case JANET_SYSOP_PARAMETER_COUNT: | ||||
|                 case JANET_SYSOP_CALLING_CONVENTION: | ||||
|                     break; | ||||
|                 case JANET_SYSOP_LABEL: { | ||||
|                     janet_formatb(buffer, "\n_label_%u:\n", instruction.label.id); | ||||
|   | ||||
| @@ -102,6 +102,7 @@ typedef struct { | ||||
| typedef enum { | ||||
|     JANET_SYSOP_LINK_NAME, | ||||
|     JANET_SYSOP_PARAMETER_COUNT, | ||||
|     JANET_SYSOP_CALLING_CONVENTION, | ||||
|     JANET_SYSOP_MOVE, | ||||
|     JANET_SYSOP_CAST, | ||||
|     JANET_SYSOP_ADD, | ||||
| @@ -300,6 +301,7 @@ typedef struct { | ||||
|     JanetSysConstant *constants; | ||||
|     JanetTable *register_name_lookup; | ||||
|     JanetTable *labels; | ||||
|     JanetSysCallingConvention calling_convention; | ||||
|     Janet error_ctx; /* Temporary for holding error messages */ | ||||
| } JanetSysIR; | ||||
|  | ||||
|   | ||||
| @@ -91,11 +91,10 @@ typedef struct { | ||||
|     JanetSysTypeLayout *layouts; | ||||
|     JanetSysTypeLayout *ir_layouts; | ||||
|     uint32_t frame_size; | ||||
|     uint32_t restore_count; | ||||
|     uint32_t to_restore[128]; | ||||
|     JanetSysCallingConvention calling_convention; | ||||
|     JanetSysCallingConvention calling_convention; /* Store normalized calling convention of current IR */ | ||||
|     int32_t ir_index; | ||||
|     uint32_t occupied_registers; | ||||
|     uint32_t clobbered_registers; /* Restore these before returning */ | ||||
| } JanetSysx64Context; | ||||
|  | ||||
| /* Get the layout for types */ | ||||
| @@ -167,6 +166,8 @@ void assign_registers(JanetSysx64Context *ctx) { | ||||
|     /* TODO - avoid spills inside loops if possible i.e. not all spills are equal */ | ||||
|     /* TODO - move into sysir.c and allow reuse for multiple targets */ | ||||
|  | ||||
|     JanetSysCallingConvention cc = ctx->calling_convention; | ||||
|  | ||||
|     /* Make trivial assigments */ | ||||
|     uint32_t next_loc = 16; | ||||
|     ctx->regs = janet_smalloc(ctx->ir->register_count * sizeof(x64Reg)); | ||||
| @@ -179,19 +180,28 @@ void assign_registers(JanetSysx64Context *ctx) { | ||||
|         ctx->regs[i].kind = get_slot_regkind(ctx, i); | ||||
|         if (i < ctx->ir->parameter_count) { | ||||
|             /* Assign to rdi, rsi, etc. according to ABI */ | ||||
|             if (i == 0) ctx->regs[i].index = RDI; | ||||
|             if (i == 1) ctx->regs[i].index = RSI; | ||||
|             if (i == 2) ctx->regs[i].index = RDX; | ||||
|             if (i == 3) ctx->regs[i].index = RCX; | ||||
|             if (i == 4) ctx->regs[i].index = 8; | ||||
|             if (i == 5) ctx->regs[i].index = 9; | ||||
|             if (i >= 6) { | ||||
|                 janet_panic("nyi"); | ||||
|                 ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; | ||||
|             if (cc == JANET_SYS_CC_X64_SYSV) { | ||||
|                 if (i == 0) ctx->regs[i].index = RDI; | ||||
|                 if (i == 1) ctx->regs[i].index = RSI; | ||||
|                 if (i == 2) ctx->regs[i].index = RDX; | ||||
|                 if (i == 3) ctx->regs[i].index = RCX; | ||||
|                 if (i == 4) ctx->regs[i].index = 8; | ||||
|                 if (i == 5) ctx->regs[i].index = 9; | ||||
|                 if (i >= 6) { | ||||
|                     janet_panic("nyi parameter count > 6"); | ||||
|                     ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; | ||||
|                 } | ||||
|             } else if (cc == JANET_SYS_CC_X64_WINDOWS) { | ||||
|                 if (i == 0) ctx->regs[i].index = RCX; | ||||
|                 if (i == 1) ctx->regs[i].index = RDX; | ||||
|                 if (i == 2) ctx->regs[i].index = 8; | ||||
|                 if (i == 3) ctx->regs[i].index = 9; | ||||
|                 if (i >= 4) { | ||||
|                     ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER; | ||||
|                     ctx->regs[i].index = (i - 4) * 8 + 16; | ||||
|                 } | ||||
|             } else { | ||||
|                 ctx->regs[i].storage = JANET_SYSREG_REGISTER; | ||||
|                 assigned |= 1 << ctx->regs[i].index; | ||||
|                 occupied |= 1 << ctx->regs[i].index; | ||||
|                 janet_panic("cannot assign registers for calling convention"); | ||||
|             } | ||||
|         } else if (assigned < 0xFFFF) { | ||||
|             /* Assign to register */ | ||||
| @@ -216,19 +226,24 @@ void assign_registers(JanetSysx64Context *ctx) { | ||||
|     ctx->occupied_registers = occupied; | ||||
|  | ||||
|     /* Mark which registers need restoration before returning */ | ||||
|     ctx->restore_count = 0; | ||||
|     unsigned char seen[16] = {0}; | ||||
|     unsigned char tokeep[] = {3, 6, 7, 12, 13, 14, 15}; | ||||
|     for (uint32_t i = 0; i < ctx->ir->register_count; i++) { | ||||
|         x64Reg reg = ctx->regs[i]; | ||||
|         if (reg.storage != JANET_SYSREG_REGISTER) continue; | ||||
|         for (unsigned int j = 0; j < sizeof(tokeep); j++) { | ||||
|             if (!seen[j] && reg.index == tokeep[j]) { | ||||
|                 ctx->to_restore[ctx->restore_count++] = reg.index; | ||||
|                 seen[j] = 1; | ||||
|             } | ||||
|         } | ||||
|     uint32_t non_volatile_mask = 0; | ||||
|     if (cc == JANET_SYS_CC_X64_SYSV) { | ||||
|         non_volatile_mask = (1 << RBX) | ||||
|             | (1 << 12) | ||||
|             | (1 << 13) | ||||
|             | (1 << 14) | ||||
|             | (1 << 15); | ||||
|     } | ||||
|     if (cc == JANET_SYS_CC_X64_WINDOWS) { | ||||
|         non_volatile_mask = (1 << RBX) | ||||
|             | (RDI << 12) | ||||
|             | (RSI << 12) | ||||
|             | (1 << 12) | ||||
|             | (1 << 13) | ||||
|             | (1 << 14) | ||||
|             | (1 << 15); | ||||
|     } | ||||
|     ctx->clobbered_registers = assigned | non_volatile_mask; | ||||
| } | ||||
|  | ||||
| static int operand_isstack(JanetSysx64Context *ctx, uint32_t o) { | ||||
| @@ -372,10 +387,11 @@ static void sysemit_three_inst(JanetSysx64Context *ctx, const char *op, JanetSys | ||||
|  | ||||
| static void sysemit_ret(JanetSysx64Context *ctx, uint32_t arg, int has_return) { | ||||
|     if (has_return) sysemit_movreg(ctx, RAX, arg); | ||||
|     /* TODO - depends on current calling convention */ | ||||
|     for (uint32_t k = 0; k < ctx->restore_count; k++) { | ||||
|         /* Pop in reverse order */ | ||||
|         janet_formatb(ctx->buffer, "pop %s\n", register_names[ctx->to_restore[ctx->restore_count - k - 1]]); | ||||
|     /* 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]); | ||||
|         } | ||||
|     } | ||||
|     janet_formatb(ctx->buffer, "leave\n"); | ||||
|     janet_formatb(ctx->buffer, "ret\n"); | ||||
| @@ -404,7 +420,7 @@ static int sysemit_comp(JanetSysx64Context *ctx, uint32_t index, | ||||
|             nexti.branch.cond == instruction.three.dest) { | ||||
|         /* Combine compare and branch */ | ||||
|         int invert = nexti.opcode == JANET_SYSOP_BRANCH_NOT; | ||||
|         janet_formatb(ctx->buffer, "%s label_%d_%u\n", invert ? branch_invert : branch, ctx->ir_index, nexti.branch.to); | ||||
|         janet_formatb(ctx->buffer, "%s label_%d_%u\n", invert ? branch_invert : branch, ctx->ir_index, (uint64_t) nexti.branch.to); | ||||
|         /* Skip next branch IR instruction */ | ||||
|         return 1; | ||||
|     } else { | ||||
| @@ -438,6 +454,100 @@ static void sysemit_cast(JanetSysx64Context *ctx, JanetSysInstruction instructio | ||||
|     janet_formatb(ctx->buffer, "; cast nyi\n"); | ||||
| } | ||||
|  | ||||
| static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instruction, uint32_t *args, uint32_t argcount) { | ||||
|     /* Push first 6 arguments to particular registers */ | ||||
|     JanetSysIR *ir = ctx->ir; | ||||
|     JanetBuffer *buffer = ctx->buffer; | ||||
|     int save_rdi = argcount >= 1 || (ctx->occupied_registers & (1 << RDI)); | ||||
|     int save_rsi = argcount >= 2 || (ctx->occupied_registers & (1 << RSI)); | ||||
|     int save_rdx = argcount >= 3 || (ctx->occupied_registers & (1 << RDX)); | ||||
|     int save_rcx = argcount >= 4 || (ctx->occupied_registers & (1 << RCX)); | ||||
|     int save_r8 = argcount >= 5 || (ctx->occupied_registers & (1 << 8)); | ||||
|     int save_r9 = argcount >= 6 || (ctx->occupied_registers & (1 << 9)); | ||||
|     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_rsi && argcount >= 2) sysemit_mov_save(ctx, RSI, args[1]); | ||||
|     if (save_rsi && argcount < 2) sysemit_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_rcx && argcount >= 4) sysemit_mov_save(ctx, RCX, args[3]); | ||||
|     if (save_rcx && argcount < 4) sysemit_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_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); | ||||
|     for (int32_t argo = argcount - 1; argo >= 6; argo--) { | ||||
|         janet_panic("nyi push sysv args"); | ||||
|         janet_formatb(buffer, "push "); | ||||
|         sysemit_operand(ctx, args[argo], "\n"); | ||||
|     } | ||||
|     if (instruction.opcode == JANET_SYSOP_SYSCALL) { | ||||
|         sysemit_movreg(ctx, RAX, instruction.call.callee); | ||||
|         janet_formatb(buffer, "syscall\n"); | ||||
|     } else { | ||||
|         /* Save RAX to number of floating point args for varags - for now, always 0 :) */ | ||||
|         janet_formatb(buffer, "mov rax, 0\n"); | ||||
|         janet_formatb(buffer, "call "); | ||||
|         sysemit_operand(ctx, instruction.call.callee, "\n"); | ||||
|     } | ||||
|     if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movreg(ctx, RAX, instruction.call.dest); | ||||
|     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); | ||||
| } | ||||
|  | ||||
| static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction instruction, uint32_t *args, uint32_t argcount) { | ||||
|     /* Push first 6 arguments to particular registers */ | ||||
|     JanetSysIR *ir = ctx->ir; | ||||
|     JanetBuffer *buffer = ctx->buffer; | ||||
|     int save_rcx = argcount >= 1 || (ctx->occupied_registers & (1 << RCX)); | ||||
|     int save_rdx = argcount >= 2 || (ctx->occupied_registers & (1 << RDX)); | ||||
|     int save_r8 = argcount >= 3 || (ctx->occupied_registers & (1 << 8)); | ||||
|     int save_r9 = argcount >= 4 || (ctx->occupied_registers & (1 << 9)); | ||||
|     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_rdx && argcount >= 2) sysemit_mov_save(ctx, RDX, args[1]); | ||||
|     if (save_rdx && argcount < 2) sysemit_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_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); | ||||
|     for (uint32_t argo = 4; argo < argcount; argo++) { | ||||
|         janet_formatb(buffer, "push "); | ||||
|         sysemit_operand(ctx, args[argo], "\n"); | ||||
|     } | ||||
|     if (instruction.opcode == JANET_SYSOP_SYSCALL) { | ||||
|         sysemit_movreg(ctx, RAX, instruction.call.callee); | ||||
|         janet_formatb(buffer, "syscall\n"); | ||||
|     } else { | ||||
|         janet_formatb(buffer, "call "); | ||||
|         sysemit_operand(ctx, instruction.call.callee, "\n"); | ||||
|     } | ||||
|     if (argcount > 4) { | ||||
|         janet_formatb(buffer, "add rsp, %u\n", 8 * (argcount - 4)); | ||||
|     } | ||||
|     if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movreg(ctx, RAX, instruction.call.dest); | ||||
|     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); | ||||
| } | ||||
|  | ||||
| void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) { | ||||
|  | ||||
|     /* Partially setup context */ | ||||
| @@ -480,8 +590,13 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | ||||
|         if (ir->link_name == NULL) { | ||||
|             continue; | ||||
|         } | ||||
|         ctx.calling_convention = ir->calling_convention; | ||||
|         if (ctx.calling_convention == JANET_SYS_CC_DEFAULT) { | ||||
|             /* Pick default calling convention */ | ||||
|             ctx.calling_convention = JANET_SYS_CC_X64_WINDOWS; | ||||
|         } | ||||
|  | ||||
|         /* Setup conttext */ | ||||
|         /* Setup context */ | ||||
|         ctx.ir_layouts = janet_smalloc(ir->register_count * sizeof(JanetSysTypeLayout)); | ||||
|         for (uint32_t i = 0; i < ir->register_count; i++) { | ||||
|             ctx.ir_layouts[i] = ctx.layouts[ir->types[i]]; | ||||
| @@ -497,9 +612,10 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | ||||
|         } | ||||
|         janet_formatb(buffer, "push rbp\nmov rbp, rsp\nsub rsp, %u\n", ctx.frame_size); | ||||
|  | ||||
|         for (uint32_t k = 0; k < ctx.restore_count; k++) { | ||||
|             /* Pop in reverse order */ | ||||
|             janet_formatb(buffer, "push %s\n", register_names[ctx.to_restore[k]]); | ||||
|         for (uint32_t k = 0; k < 32; k++) { | ||||
|             if (ctx.clobbered_registers & (1u << k)) { | ||||
|                 janet_formatb(buffer, "push %s\n", register_names[k]); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* Function body */ | ||||
| @@ -593,64 +709,31 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | ||||
|                     break; | ||||
|                 case JANET_SYSOP_SYSCALL: | ||||
|                 case JANET_SYSOP_CALL: | ||||
|                     ; | ||||
|                     /* Push first 6 arguments to particular registers */ | ||||
|                     uint32_t argcount = 0; | ||||
|                     uint32_t *args = janet_sys_callargs(ir->instructions + j, &argcount); | ||||
|                     int save_rdi = argcount >= 1 || (ctx.occupied_registers & (1 << RDI)); | ||||
|                     int save_rsi = argcount >= 2 || (ctx.occupied_registers & (1 << RSI)); | ||||
|                     int save_rdx = argcount >= 3 || (ctx.occupied_registers & (1 << RDX)); | ||||
|                     int save_rcx = argcount >= 4 || (ctx.occupied_registers & (1 << RCX)); | ||||
|                     int save_r8 = argcount >= 5 || (ctx.occupied_registers & (1 << 8)); | ||||
|                     int save_r9 = argcount >= 6 || (ctx.occupied_registers & (1 << 9)); | ||||
|                     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_rsi && argcount >= 2) sysemit_mov_save(&ctx, RSI, args[1]); | ||||
|                     if (save_rsi && argcount < 2) sysemit_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_rcx && argcount >= 4) sysemit_mov_save(&ctx, RCX, args[3]); | ||||
|                     if (save_rcx && argcount < 4) sysemit_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_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); | ||||
|                     for (int32_t argo = argcount - 1; argo >= 5; argo--) { | ||||
|                         janet_panic("nyi"); | ||||
|                         janet_formatb(buffer, "push "); | ||||
|                         sysemit_operand(&ctx, args[argo], "\n"); | ||||
|                     { | ||||
|                         uint32_t argcount = 0; | ||||
|                         uint32_t *args = janet_sys_callargs(ir->instructions + j, &argcount); | ||||
|                         JanetSysCallingConvention cc = instruction.call.calling_convention; | ||||
|  | ||||
|                         /* Set default calling convention based on context */ | ||||
|                         if (cc == JANET_SYS_CC_DEFAULT) { | ||||
|                             cc = JANET_SYS_CC_X64_WINDOWS; | ||||
|                         } | ||||
|  | ||||
|                         if (cc == JANET_SYS_CC_X64_SYSV) { | ||||
|                             sysemit_sysv_call(&ctx, instruction, args, argcount); | ||||
|                         } else if (cc == JANET_SYS_CC_X64_WINDOWS) { | ||||
|                             sysemit_win64_call(&ctx, instruction, args, argcount); | ||||
|                         } | ||||
|                         janet_sfree(args); | ||||
|                         break; | ||||
|                     } | ||||
|                     janet_sfree(args); | ||||
|                     if (instruction.opcode == JANET_SYSOP_SYSCALL) { | ||||
|                         sysemit_movreg(&ctx, RAX, instruction.call.callee); | ||||
|                         janet_formatb(buffer, "syscall\n"); | ||||
|                     } else { | ||||
|                         /* Save RAX to number of floating point args for varags - for now, always 0 :) */ | ||||
|                         janet_formatb(buffer, "mov rax, 0\n"); | ||||
|                         janet_formatb(buffer, "call "); | ||||
|                         sysemit_operand(&ctx, instruction.call.callee, "\n"); | ||||
|                     } | ||||
|                     if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movreg(&ctx, RAX, instruction.call.dest); | ||||
|                     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); | ||||
|                     break; | ||||
|                     // On a comparison, if next instruction is branch that reads from dest, combine into a single op. | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     /* End section .text */ | ||||
|  | ||||
|     janet_formatb(buffer, "section .rodata\n\n"); | ||||
|     janet_formatb(buffer, "\nsection .rodata\n"); | ||||
|  | ||||
|     for (int32_t i = 0; i < linkage->ir_ordered->count; i++) { | ||||
|         JanetSysIR *ir = janet_unwrap_pointer(linkage->ir_ordered->data[i]); | ||||
| @@ -658,7 +741,7 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | ||||
|         for (uint32_t j = 0; j < ir->constant_count; j++) { | ||||
|             if (janet_checktype(ir->constants[j].value, JANET_STRING)) { | ||||
|                 JanetString str = janet_unwrap_string(ir->constants[j].value); | ||||
|                 janet_formatb(buffer, "\nCONST_%d_%u: db ", i, j); | ||||
|                 janet_formatb(buffer, "CONST_%d_%u: db ", i, j); | ||||
|                 /* Nasm syntax */ | ||||
|                 int in_string = 0; | ||||
|                 for (int32_t ci = 0; ci < janet_string_length(str); ci++) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose