mirror of
https://github.com/janet-lang/janet
synced 2025-01-07 22:20:26 +00:00
x64 allow dynamically switching between windows and sysv target.
This commit is contained in:
parent
e5765b26d4
commit
b6fb7ae69c
2
Makefile
2
Makefile
@ -51,7 +51,7 @@ SONAME_SETTER=-Wl,-soname,
|
||||
HOSTCC?=$(CC)
|
||||
HOSTAR?=$(AR)
|
||||
# Symbols are (optionally) removed later, keep -g as default!
|
||||
CFLAGS?=-O2 -g
|
||||
CFLAGS?=-O0 -g
|
||||
LDFLAGS?=-rdynamic
|
||||
LIBJANET_LDFLAGS?=$(LD_FLAGS)
|
||||
RUN:=$(RUN)
|
||||
|
@ -1,4 +1,4 @@
|
||||
janet.exe examples/sysir/samples.janet > temp.nasm
|
||||
janet.exe examples/sysir/windows_samples.janet > temp.nasm
|
||||
nasm -fwin64 temp.nasm -l temp.lst -o temp.o
|
||||
link /entry:Start /subsystem:windows kernel32.lib user32.lib temp.o /out:temp.exe
|
||||
temp.exe
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
build/janet examples/sysir/samples.janet > temp.nasm
|
||||
valgrind build/janet examples/sysir/samples.janet > temp.nasm
|
||||
nasm -felf64 temp.nasm -l temp.lst -o temp.o
|
||||
ld -o temp.bin -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc temp.o
|
||||
valgrind ./temp.bin
|
||||
|
@ -38,24 +38,13 @@
|
||||
(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 winmain)
|
||||
(compile1 square)
|
||||
(compile1 simple)
|
||||
(compile1 myprog)
|
||||
(compile1 doloop)
|
||||
(compile1 main-fn)
|
||||
#(dump)
|
||||
#(dumpc)
|
||||
(dumpx64)
|
||||
|
||||
# Run with
|
||||
# janet examples/sysir/scratch.janet > temp.nasm && nasm -felf64 temp.nasm -l temp.lst && ld temp.o && ./a.out
|
||||
|
14
examples/sysir/windows_samples.janet
Normal file
14
examples/sysir/windows_samples.janet
Normal file
@ -0,0 +1,14 @@
|
||||
(use ./frontend)
|
||||
|
||||
(def winmain
|
||||
'(defn Start:void []
|
||||
(MessageBoxExA (the pointer 0) "Hello, world!" "Test" 0 (the s16 0))
|
||||
(ExitProcess (the int 0))
|
||||
(return)))
|
||||
|
||||
####
|
||||
|
||||
(compile1 winmain)
|
||||
#(dump)
|
||||
#(dumpc)
|
||||
(dumpx64)
|
@ -1879,12 +1879,26 @@ JANET_CORE_FN(cfun_sysir_toir,
|
||||
}
|
||||
|
||||
JANET_CORE_FN(cfun_sysir_tox64,
|
||||
"(sysir/to-x64 context &opt buffer options)",
|
||||
"(sysir/to-x64 context &opt buffer target)",
|
||||
"Lower IR to x64 machine code.") {
|
||||
janet_arity(argc, 1, 3);
|
||||
JanetSysIRLinkage *ir = janet_getabstract(argv, 0, &janet_sysir_context_type);
|
||||
JanetBuffer *buffer = janet_optbuffer(argv, argc, 1, 0);
|
||||
janet_sys_ir_lower_to_x64(ir, buffer);
|
||||
JanetSysTarget target;
|
||||
if (argc < 3 || janet_checktype(argv[2], JANET_NIL) || janet_keyeq(argv[2], "native")) {
|
||||
#ifdef JANET_WINDOWS
|
||||
target = JANET_SYS_TARGET_X64_WINDOWS;
|
||||
#else
|
||||
target = JANET_SYS_TARGET_X64_LINUX;
|
||||
#endif
|
||||
} else if (janet_keyeq(argv[1], "windows")) {
|
||||
target = JANET_SYS_TARGET_X64_WINDOWS;
|
||||
} else if (janet_keyeq(argv[1], "linux")) {
|
||||
target = JANET_SYS_TARGET_X64_LINUX;
|
||||
} else {
|
||||
janet_panicf("unknown target %v", argv[1]);
|
||||
}
|
||||
janet_sys_ir_lower_to_x64(ir, target, buffer);
|
||||
return janet_wrap_buffer(buffer);
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,11 @@ typedef enum {
|
||||
JANET_SYS_CC_X64_WINDOWS,
|
||||
} JanetSysCallingConvention;
|
||||
|
||||
typedef enum {
|
||||
JANET_SYS_TARGET_X64_WINDOWS, /* 64 bit, modern windows */
|
||||
JANET_SYS_TARGET_X64_LINUX, /* x64 linux with recent kernel */
|
||||
} JanetSysTarget;
|
||||
|
||||
typedef struct {
|
||||
JanetSysOp opcode;
|
||||
union {
|
||||
@ -328,6 +333,6 @@ uint32_t *janet_sys_callargs(JanetSysInstruction *instr, uint32_t *count);
|
||||
void janet_sys_ir_lower_to_ir(JanetSysIRLinkage *linkage, JanetArray *into);
|
||||
void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer);
|
||||
|
||||
void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer);
|
||||
void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target, JanetBuffer *buffer);
|
||||
|
||||
#endif
|
||||
|
@ -180,6 +180,7 @@ 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 */
|
||||
ctx->regs[i].storage = JANET_SYSREG_REGISTER;
|
||||
if (cc == JANET_SYS_CC_X64_SYSV) {
|
||||
if (i == 0) ctx->regs[i].index = RDI;
|
||||
if (i == 1) ctx->regs[i].index = RSI;
|
||||
@ -188,8 +189,9 @@ void assign_registers(JanetSysx64Context *ctx) {
|
||||
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");
|
||||
/* TODO check sizing and alignment */
|
||||
ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER;
|
||||
ctx->regs[i].index = (i - 6) * 8 + 16;
|
||||
}
|
||||
} else if (cc == JANET_SYS_CC_X64_WINDOWS) {
|
||||
if (i == 0) ctx->regs[i].index = RCX;
|
||||
@ -197,6 +199,7 @@ void assign_registers(JanetSysx64Context *ctx) {
|
||||
if (i == 2) ctx->regs[i].index = 8;
|
||||
if (i == 3) ctx->regs[i].index = 9;
|
||||
if (i >= 4) {
|
||||
/* TODO check sizing and alignment */
|
||||
ctx->regs[i].storage = JANET_SYSREG_STACK_PARAMETER;
|
||||
ctx->regs[i].index = (i - 4) * 8 + 16;
|
||||
}
|
||||
@ -222,28 +225,29 @@ void assign_registers(JanetSysx64Context *ctx) {
|
||||
}
|
||||
|
||||
next_loc = (next_loc + 15) / 16 * 16;
|
||||
ctx->frame_size = next_loc + 16;
|
||||
ctx->frame_size = next_loc;
|
||||
ctx->occupied_registers = occupied;
|
||||
|
||||
/* Mark which registers need restoration before returning */
|
||||
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);
|
||||
| (1 << 12)
|
||||
| (1 << 13)
|
||||
| (1 << 14)
|
||||
| (1 << 15);
|
||||
}
|
||||
if (cc == JANET_SYS_CC_X64_WINDOWS) {
|
||||
ctx->frame_size += 16; /* For shadow stack */
|
||||
non_volatile_mask = (1 << RBX)
|
||||
| (RDI << 12)
|
||||
| (RSI << 12)
|
||||
| (1 << 12)
|
||||
| (1 << 13)
|
||||
| (1 << 14)
|
||||
| (1 << 15);
|
||||
| (RDI << 12)
|
||||
| (RSI << 12)
|
||||
| (1 << 12)
|
||||
| (1 << 13)
|
||||
| (1 << 14)
|
||||
| (1 << 15);
|
||||
}
|
||||
ctx->clobbered_registers = assigned | non_volatile_mask;
|
||||
ctx->clobbered_registers = assigned & non_volatile_mask;
|
||||
}
|
||||
|
||||
static int operand_isstack(JanetSysx64Context *ctx, uint32_t o) {
|
||||
@ -330,6 +334,7 @@ static void sysemit_movreg(JanetSysx64Context *ctx, uint32_t regdest, uint32_t s
|
||||
if (operand_isreg(ctx, src, regdest)) return;
|
||||
x64Reg tempreg;
|
||||
tempreg.kind = get_slot_regkind(ctx, src);
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.index = regdest;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
@ -340,6 +345,7 @@ static void sysemit_movfromreg(JanetSysx64Context *ctx, uint32_t dest, uint32_t
|
||||
if (operand_isreg(ctx, dest, srcreg)) return;
|
||||
x64Reg tempreg;
|
||||
tempreg.kind = get_slot_regkind(ctx, dest);
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.index = srcreg;
|
||||
janet_formatb(ctx->buffer, "mov ");
|
||||
sysemit_operand(ctx, dest, ", ");
|
||||
@ -371,6 +377,7 @@ static void sysemit_threeop_nodeststack(JanetSysx64Context *ctx, const char *op,
|
||||
sysemit_movreg(ctx, RAX, lhs);
|
||||
x64Reg tempreg;
|
||||
tempreg.kind = get_slot_regkind(ctx, dest);
|
||||
tempreg.storage = JANET_SYSREG_REGISTER;
|
||||
tempreg.index = RAX;
|
||||
janet_formatb(ctx->buffer, "%s ", op);
|
||||
sysemit_reg(ctx, tempreg, ", ");
|
||||
@ -456,7 +463,6 @@ static void sysemit_cast(JanetSysx64Context *ctx, JanetSysInstruction instructio
|
||||
|
||||
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));
|
||||
@ -507,7 +513,6 @@ static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instr
|
||||
|
||||
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));
|
||||
@ -548,7 +553,7 @@ static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction inst
|
||||
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, JanetSysTarget target, JanetBuffer *buffer) {
|
||||
|
||||
/* Partially setup context */
|
||||
JanetSysx64Context ctx;
|
||||
@ -581,19 +586,27 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
janet_formatb(buffer, "section .text\n");
|
||||
janet_formatb(buffer, "\nsection .text\n");
|
||||
|
||||
/* Do register allocation */
|
||||
/* For Top level IR group, emit a function body or other data */
|
||||
for (int32_t i = 0; i < linkage->ir_ordered->count; i++) {
|
||||
JanetSysIR *ir = janet_unwrap_pointer(linkage->ir_ordered->data[i]);
|
||||
ctx.ir_index = i;
|
||||
if (ir->link_name == NULL) {
|
||||
/* Unnamed IR sections contain just type definitions and can be discarded during lowering. */
|
||||
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;
|
||||
switch (target) {
|
||||
default:
|
||||
ctx.calling_convention = JANET_SYS_CC_X64_SYSV;
|
||||
break;
|
||||
case JANET_SYS_TARGET_X64_WINDOWS:
|
||||
ctx.calling_convention = JANET_SYS_CC_X64_WINDOWS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup context */
|
||||
@ -708,25 +721,20 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
|
||||
janet_formatb(buffer, "jmp label_%d_%u\n", i, instruction.jump.to);
|
||||
break;
|
||||
case JANET_SYSOP_SYSCALL:
|
||||
case JANET_SYSOP_CALL:
|
||||
{
|
||||
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;
|
||||
case JANET_SYSOP_CALL: {
|
||||
uint32_t argcount = 0;
|
||||
uint32_t *args = janet_sys_callargs(ir->instructions + j, &argcount);
|
||||
JanetSysCallingConvention cc = instruction.call.calling_convention;
|
||||
// TODO better way of chosing default calling convention
|
||||
if (cc == JANET_SYS_CC_DEFAULT) cc = ctx.calling_convention;
|
||||
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;
|
||||
}
|
||||
// On a comparison, if next instruction is branch that reads from dest, combine into a single op.
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user