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