1
0
mirror of https://github.com/janet-lang/janet synced 2025-07-04 19:12:55 +00:00

Start removing NASM dependence.

Start setting up a test suite for sysir and work towards emitting jitted
x86 machine code.
This commit is contained in:
Calvin Rose 2025-05-04 20:20:11 -05:00
parent 3dd6e744de
commit 0066a5a304
14 changed files with 287 additions and 226 deletions

View File

@ -1,55 +0,0 @@
### typedef struct {float x; float y; float z;} Vec3;
###
### Vec3 addv(Vec3 a, Vec3 b) {
### Vec3 ret;
### ret.x = a.x + b.x;
### ret.y = a.y + b.y;
### ret.z = a.z + b.z;
### return ret;
### }
(def ir-asm
'((link-name "addv_with_err")
(parameter-count 2)
# Types
(type-prim Real f32)
(type-struct Vec3 Real Real Real)
(type-pointer PReal Real)
# Declarations
(bind position Vec3)
(bind velocity Vec3)
(bind next-position Vec3)
(bind dest Real)
(bind lhs Real)
(bind rhs Real)
(bind pdest PReal)
(bind plhs PReal)
(bind prhs PReal)
# Code (has type errors)
(fgetp pdest next-position 0)
(fgetp plhs position 0)
(fgetp prhs velocity 0)
(add dest plhs prhs)
(store pdest dest)
(fgetp pdest next-position 1)
(fgetp plhs position 1)
(fgetp prhs velocity 1)
(add dest lhs rhs)
(load lhs plhs)
(load rhs prhs)
(store pdest dest)
(fgetp pdest next-position 2)
(fgetp plhs position 2)
(fgetp prhs velocity 2)
(add dest plhs prhs)
(store pdest dest)
(return next-position)))
(def ctx (sysir/context))
(sysir/asm ctx ir-asm)
(print (sysir/to-c ctx))

View File

@ -52,31 +52,6 @@
#define REX_X 0x42
#define REX_B 0x41
static const char *register_names[] = {
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
};
static const char *register_names_32[] = {
"eax", "ecx", "edx", "ebx", "rsp", "rbp", "esi", "edi",
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
};
static const char *register_names_16[] = {
"ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
};
static const char *register_names_8[] = {
"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"
};
static const char *register_names_xmm[] = {
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
};
typedef enum {
JANET_SYSREG_8,
JANET_SYSREG_16,
@ -103,6 +78,9 @@ typedef struct {
JanetSysIRLinkage *linkage;
JanetSysIR *ir;
JanetBuffer *buffer;
JanetBuffer *constant_data; /* A buffer of constants for RIP-relative addressing to point to */
uint32_t *v_rip_indicies; /* An array of pointers of all emitted addresses to patch at end. */
JanetTable *constant_to_data; /* Table mapping constants to index into v_constant_data (dedupe constants) */
x64Reg *regs; /* Map IR virtual registers to hardware register or stack offset */
JanetSysTypeLayout *layouts;
JanetSysTypeLayout *ir_layouts;
@ -317,6 +295,30 @@ static int operand_isreg(JanetSysx64Context *ctx, uint32_t o, uint32_t regindex)
return reg.index == regindex;
}
/* Visit a constant and return the index into the constant data buffer. */
static uint32_t janet_x64_constant(JanetSysx64Context *ctx, uint32_t const_index) {
Janet key = janet_wrap_number((double) const_index);
Janet check = janet_table_get(ctx->constant_to_data, key);
if (janet_checktype(check, JANET_NUMBER)) {
/* Constant has been seen before */
return (uint32_t) janet_unwrap_integer(check);
}
JanetSysConstant jsc = ctx->ir->constants[const_index];
JanetSysTypeInfo tinfo = ctx->linkage->type_defs[jsc.type];
/* TODO - check type and alignment for data types beyond pointers such as large struct and other immediates */
uint32_t index = ctx->constant_data->count;
switch (janet_type(jsc.value)) {
default:
janet_assert(0, "cannot emit constant");
break;
case JANET_STRING:
janet_assert(tinfo.prim == JANET_PRIM_POINTER, "expected pointer type for string constant");
janet_buffer_push_string(ctx->constant_data, janet_unwrap_string(jsc.value));
break;
}
return index;
}
/*
* Machine code emission
*/
@ -330,7 +332,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_formatb(C->buffer, "0x%.2X,", c.data & 0xFF);
janet_buffer_push_u8(C->buffer, c.data & 0xFF);
c.data = c.data >> 8;
}
}
@ -347,22 +349,17 @@ static void i_combine(JanetSysx64Context *C,
assert(mod_reg_rm.bytes < 3);
assert(scaled_index.bytes < 2);
assert(opcode < 512);
janet_buffer_push_cstring(C->buffer, "db ");
i_chunk(C, prefix);
if (opcode >= 256) {
janet_formatb(C->buffer, "0x%.2X,", 0x0Fu);
janet_buffer_push_u8(C->buffer, 0x0Fu);
opcode -= 256;
}
janet_formatb(C->buffer, "0x%.2X,", opcode);
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);
if (msg) {
janet_formatb(C->buffer, "; %s\n", msg);
} else {
janet_buffer_push_cstring(C->buffer, "\n");
}
(void) msg;
}
typedef enum {
@ -380,16 +377,19 @@ static void e_mov_ext(JanetSysx64Context *ctx, x64Reg d, x64Reg s, MoveMode mm,
/* src is a constant */
if (s.storage == JANET_SYSREG_CONSTANT) {
//uint32_t disp = janet_x64_constant(ctx, s.index);
if (d.index >= 8) rex |= REX_R;
if (d.kind >= JANET_SYSREG_64) rex |= REX_W;
Janet c = ctx->ir->constants[s.index].value;
int32_t imm = 0;
uint64_t imm64 = 0;
int is64 = 0;
//int isRipRel = 0;
InstrChunk dispchunk = empty_chunk;
if (janet_checktype(c, JANET_STRING)) {
is64 = 1;
imm64 = (uint64_t) janet_unwrap_pointer(c);
imm64 = (uint64_t) janet_unwrap_pointer(c);// janet_x64_constant(ctx, s.index);
//isRipRel = 1;
} else if (s.kind >= JANET_SYSREG_64) {
is64 = 1;
imm64 = janet_unwrap_u64(c);
@ -407,7 +407,7 @@ static void e_mov_ext(JanetSysx64Context *ctx, x64Reg d, x64Reg s, MoveMode mm,
}
/* encode movabsq */
rex |= REX_W;
imm64 = 0xDEADBEEFCAFEBABEULL;
// imm64 = 0xDEADBEEFCAFEBABEULL;
opcode = 0xB8;
opcode += (d.index & 7);
if (d.index >= 8) rex |= REX_R;
@ -496,7 +496,6 @@ static void e_mov_ext(JanetSysx64Context *ctx, x64Reg d, x64Reg s, MoveMode mm,
if (!rex) prefix.bytes = 0;
InstrChunk modregrm = {1, mod_rm};
i_combine(ctx, prefix, opcode, modregrm, empty_chunk, dispchunk, empty_chunk, msg);
//janet_formatb(ctx->buffer, ";mov %s <- %s, mode=%d, %s\n", register_names[d.index], register_names[s.index], mm, sizestr);
}
static void e_mov(JanetSysx64Context *ctx, uint32_t dest, uint32_t src, const char *msg) {
@ -516,9 +515,11 @@ static void e_fn_prefix(JanetSysx64Context *ctx, int32_t stack) {
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);
uint8_t bytes[] = {0x55, 0x48, 0x89, 0xe5, 0x48, 0x81, 0xec, a, b, c, d};
janet_buffer_push_bytes(ctx->buffer, bytes, sizeof(bytes));
} else {
janet_formatb(ctx->buffer, "db 0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, 0x%.2X ; function prefix\n", stack);
uint8_t bytes[] = {0x55, 0x48, 0x89, 0xe5, 0x48, 0x83, 0xec, stack};
janet_buffer_push_bytes(ctx->buffer, bytes, sizeof(bytes));
}
}
@ -526,9 +527,11 @@ 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]);
uint8_t bytes[] = {0x41, 0x50 + (reg - 8)};
janet_buffer_push_bytes(ctx->buffer, bytes, sizeof(bytes));
} else {
janet_formatb(ctx->buffer, "db 0x%.2X ; push %s\n", 0x50 + reg, register_names[reg]);
uint8_t bytes[] = {0x50 + reg};
janet_buffer_push_bytes(ctx->buffer, bytes, sizeof(bytes));
}
}
@ -536,15 +539,18 @@ 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]);
uint8_t bytes[] = {0x41, 0x58 + (reg - 8)};
janet_buffer_push_bytes(ctx->buffer, bytes, sizeof(bytes));
} else {
janet_formatb(ctx->buffer, "db 0x%.2X ; pop %s\n", 0x58 + reg, register_names[reg]);
uint8_t bytes[] = {0x58 + reg};
janet_buffer_push_bytes(ctx->buffer, bytes, sizeof(bytes));
}
}
static void e_fn_suffix(JanetSysx64Context *ctx) {
/* leave, ret */
janet_formatb(ctx->buffer, "db 0xc9, 0xc3 ; function suffix\n");
uint8_t bytes[] = {0xc9, 0xc3};
janet_buffer_push_bytes(ctx->buffer, bytes, sizeof(bytes));
}
/* Assembly emission */
@ -557,47 +563,18 @@ static x64Reg mk_tmpreg(JanetSysx64Context *ctx, uint32_t src) {
return tempreg;
}
static void sysemit_reg(JanetSysx64Context *ctx, x64Reg reg, const char *after) {
const char *sizestr = sysemit_sizestr_reg(reg);
if (reg.storage == JANET_SYSREG_STACK) {
// TODO - use LEA for parameters larger than a qword
janet_formatb(ctx->buffer, "%s [rbp-%u]", sizestr, reg.index);
} else if (reg.storage == JANET_SYSREG_STACK_PARAMETER) {
// TODO - use LEA for parameters larger than a qword
janet_formatb(ctx->buffer, "%s [rbp+%u]", sizestr, reg.index);
} else if (reg.kind == JANET_SYSREG_64) {
janet_formatb(ctx->buffer, "%s", register_names[reg.index]);
} else if (reg.kind == JANET_SYSREG_32) {
janet_formatb(ctx->buffer, "%s", register_names_32[reg.index]);
} else if (reg.kind == JANET_SYSREG_16) {
janet_formatb(ctx->buffer, "%s", register_names_16[reg.index]);
} else if (reg.kind == JANET_SYSREG_8) {
janet_formatb(ctx->buffer, "%s", register_names_8[reg.index]);
} else {
janet_formatb(ctx->buffer, "%s", register_names_xmm[reg.index]);
}
if (after) janet_buffer_push_cstring(ctx->buffer, after);
static void sysemit_movreg(JanetSysx64Context *ctx, uint32_t regdest, uint32_t src) {
if (operand_isreg(ctx, src, regdest)) return;
x64Reg tempreg = mk_tmpreg(ctx, src);
tempreg.index = regdest;
e_mov_ext(ctx, tempreg, to_reg(ctx, src), MOV_FLAT, "sysemit_movreg");
}
static void sysemit_operand(JanetSysx64Context *ctx, uint32_t o, const char *after) {
if (o <= JANET_SYS_MAX_OPERAND) {
sysemit_reg(ctx, ctx->regs[o], NULL);
} else {
/* Constant */
uint32_t index = o - JANET_SYS_CONSTANT_PREFIX;
Janet c = ctx->ir->constants[index].value;
// TODO - do this properly
if (janet_checktype(c, JANET_STRING)) {
janet_formatb(ctx->buffer, "CONST_%d_%u", ctx->ir_index, index);
} else {
// TODO - do this properly too.
// Also figure out how to load large constants to a temporary register
// In x64, only move to register is allowed to take a 64 bit immediate, so
// our methodology here changes based on what kind of operand we need.
janet_formatb(ctx->buffer, "%V", c);
}
}
if (after) janet_buffer_push_cstring(ctx->buffer, after);
static void sysemit_movfromreg(JanetSysx64Context *ctx, uint32_t dest, uint32_t srcreg) {
if (operand_isreg(ctx, dest, srcreg)) return;
x64Reg tempreg = mk_tmpreg(ctx, dest);
tempreg.index = srcreg;
e_mov_ext(ctx, ctx->regs[dest], tempreg, MOV_FLAT, "move from specific register");
}
/* A = A op B */
@ -607,14 +584,16 @@ static void sysemit_binop(JanetSysx64Context *ctx, const char *op, uint32_t dest
x64Reg tempreg = mk_tmpreg(ctx, dest);
x64Reg srcreg = ctx->regs[src];
e_mov_ext(ctx, tempreg, srcreg, MOV_FLAT, "mem -> RAX temp");
janet_formatb(ctx->buffer, "%s ", op);
sysemit_operand(ctx, dest, ", ");
sysemit_reg(ctx, tempreg, "\n");
} else {
janet_formatb(ctx->buffer, "%s ", op);
sysemit_operand(ctx, dest, ", ");
sysemit_operand(ctx, src, "\n");
}
}
janet_formatb(ctx->buffer, "%s ", op);
//sysemit_operand(ctx, dest, ", ");
//sysemit_operand(ctx, src, "\n");
}
/* Dest = LHS op RHS */
static void sysemit_threeop(JanetSysx64Context *ctx, const char *op, uint32_t dest, uint32_t lhs, uint32_t rhs) {
e_mov(ctx, dest, lhs, op);
sysemit_binop(ctx, op, dest, rhs);
}
/* dest = src[0] */
@ -684,52 +663,15 @@ static void sysemit_store(JanetSysx64Context *ctx, uint32_t dest, uint32_t src)
}
}
static void sysemit_movreg(JanetSysx64Context *ctx, uint32_t regdest, uint32_t src) {
if (operand_isreg(ctx, src, regdest)) return;
x64Reg tempreg = mk_tmpreg(ctx, src);
tempreg.index = regdest;
e_mov_ext(ctx, tempreg, to_reg(ctx, src), MOV_FLAT, "sysemit_movreg");
}
static void sysemit_movfromreg(JanetSysx64Context *ctx, uint32_t dest, uint32_t srcreg) {
if (operand_isreg(ctx, dest, srcreg)) return;
x64Reg tempreg = mk_tmpreg(ctx, dest);
tempreg.index = srcreg;
e_mov_ext(ctx, ctx->regs[dest], tempreg, MOV_FLAT, "move from specific register");
}
/* Move a value to a register, and save the contents of the old register on the stack */
static void sysemit_mov_save(JanetSysx64Context *ctx, uint32_t regdest, uint32_t src) {
e_pushreg(ctx, regdest);
if (operand_isreg(ctx, src, regdest)) return;
x64Reg tempreg = mk_tmpreg(ctx, src);
tempreg.index = regdest;
janet_formatb(ctx->buffer, "; mov save %s <- %u\n", register_names[regdest], src);
e_mov_ext(ctx, tempreg, to_reg(ctx, src), MOV_FLAT, "mov save");
}
static void sysemit_threeop(JanetSysx64Context *ctx, const char *op, uint32_t dest, uint32_t lhs, uint32_t rhs) {
e_mov(ctx, dest, lhs, op);
sysemit_binop(ctx, op, dest, rhs);
}
static void sysemit_threeop_nodeststack(JanetSysx64Context *ctx, const char *op, uint32_t dest, uint32_t lhs,
uint32_t rhs) {
if (operand_isstack(ctx, dest)) {
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, ", ");
sysemit_operand(ctx, lhs, "\n");
sysemit_movfromreg(ctx, dest, RAX);
} else {
sysemit_threeop(ctx, op, dest, lhs, rhs);
}
}
static void sysemit_three_inst(JanetSysx64Context *ctx, const char *op, JanetSysInstruction instruction) {
sysemit_threeop(ctx, op, instruction.three.dest, instruction.three.lhs, instruction.three.rhs);
}
@ -778,7 +720,7 @@ static int sysemit_comp(JanetSysx64Context *ctx, uint32_t index,
/* Zero the upper bits */
sysemit_binop(ctx, "xor", instruction.three.dest, instruction.three.dest);
}
janet_formatb(ctx->buffer, "%s %s\n", set, register_names_8[instruction.three.dest]);
//janet_formatb(ctx->buffer, "%s %s\n", set, register_names_8[instruction.three.dest]);
return 0;
}
}
@ -846,7 +788,7 @@ static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instr
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");
//sysemit_operand(ctx, args[argo], "\n");
}
if (instruction.opcode == JANET_SYSOP_SYSCALL) {
sysemit_movreg(ctx, RAX, instruction.call.callee);
@ -855,7 +797,7 @@ static void sysemit_sysv_call(JanetSysx64Context *ctx, JanetSysInstruction instr
/* Save RAX to number of floating point args for varags - for now, always 0 :) */
janet_formatb(buffer, "db 0x48, 0x31, 0xc0 ; xor rax, rax\n");
janet_formatb(buffer, "call ");
sysemit_operand(ctx, instruction.call.callee, "\n");
//sysemit_operand(ctx, instruction.call.callee, "\n");
}
if (save_r11) e_popreg(ctx, 11);
if (save_r10) e_popreg(ctx, 10);
@ -895,7 +837,7 @@ static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction inst
janet_formatb(buffer, "syscall\n");
} else {
janet_formatb(buffer, "call ");
sysemit_operand(ctx, instruction.call.callee, "\n");
//sysemit_operand(ctx, instruction.call.callee, "\n");
}
if (argcount > 4) {
janet_formatb(buffer, "add rsp, %u\n", 8 * (argcount - 4));
@ -909,12 +851,42 @@ static void sysemit_win64_call(JanetSysx64Context *ctx, JanetSysInstruction inst
if (instruction.call.flags & JANET_SYS_CALLFLAG_HAS_DEST) sysemit_movfromreg(ctx, instruction.call.dest, RAX);
}
static void emit_nasm_string(JanetBuffer *buffer, const uint8_t *str, int32_t len) {
/* Nasm syntax */
int in_string = 0;
for (int32_t ci = 0; ci < len; ci++) {
int c = str[ci];
if (c < 32) {
if (in_string) {
janet_formatb(buffer, "\", %d", c);
} else {
janet_formatb(buffer, ci ? ", %d" : "%d", c);
}
in_string = 0;
} else {
if (!in_string) {
janet_buffer_push_cstring(buffer, ci ? ", \"" : "\"");
}
janet_buffer_push_u8(buffer, c);
in_string = 1;
}
}
if (!in_string) {
janet_buffer_push_cstring(buffer, ", 0\n");
} else {
janet_buffer_push_cstring(buffer, "\", 0\n");
}
}
void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target, JanetBuffer *buffer) {
/* Partially setup context */
JanetSysx64Context ctx;
ctx.linkage = linkage;
ctx.buffer = buffer;
ctx.constant_data = janet_buffer(0);
ctx.v_rip_indicies = NULL;
ctx.constant_to_data = janet_table(0);
ctx.layouts = janet_smalloc(linkage->type_def_count * sizeof(JanetSysTypeLayout));
for (uint32_t i = 0; i < linkage->type_def_count; i++) {
ctx.layouts[i] = get_x64layout(linkage->type_defs[i]);
@ -1018,7 +990,7 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target
sysemit_three_inst(&ctx, "sub", instruction);
break;
case JANET_SYSOP_MULTIPLY:
sysemit_threeop_nodeststack(&ctx, "imul", instruction.three.dest,
sysemit_threeop(&ctx, "imul", instruction.three.dest,
instruction.three.lhs, instruction.three.rhs);
break;
case JANET_SYSOP_DIVIDE:
@ -1073,7 +1045,7 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target
case JANET_SYSOP_BRANCH_NOT:
janet_formatb(buffer, "test ");
// TODO - ensure branch condition is not a const
sysemit_operand(&ctx, instruction.branch.cond, ", 0\n");
//sysemit_operand(&ctx, instruction.branch.cond, ", 0\n");
janet_formatb(buffer,
"%s label_%d_%u\n",
instruction.opcode == JANET_SYSOP_BRANCH ? "jnz" : "jz",
@ -1103,39 +1075,20 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetSysTarget target
}
/* End section .text */
/* rodata */
janet_formatb(buffer, "\nsection .rodata\n");
janet_formatb(buffer, "CONST_DATA: db ");
emit_nasm_string(buffer, ctx.constant_data->data, ctx.constant_data->count);
/* old rodata */
for (int32_t i = 0; i < linkage->ir_ordered->count; i++) {
JanetSysIR *ir = janet_unwrap_pointer(linkage->ir_ordered->data[i]);
/* Emit constant strings */
for (uint32_t j = 0; j < ir->constant_count; j++) {
if (janet_checktype(ir->constants[j].value, JANET_STRING)) {
janet_formatb(buffer, "CONST_%d_%d: db ", i, j);
JanetString str = janet_unwrap_string(ir->constants[j].value);
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++) {
int c = str[ci];
if (c < 32) {
if (in_string) {
janet_formatb(buffer, "\", %d", c);
} else {
janet_formatb(buffer, ci ? ", %d" : "%d", c);
}
in_string = 0;
} else {
if (!in_string) {
janet_buffer_push_cstring(buffer, ci ? ", \"" : "\"");
}
janet_buffer_push_u8(buffer, c);
in_string = 1;
}
}
if (!in_string) {
janet_buffer_push_cstring(buffer, ", 0\n");
} else {
janet_buffer_push_cstring(buffer, "\", 0\n");
}
emit_nasm_string(buffer, str, janet_string_length(str));
}
}
}

View File

@ -27,7 +27,7 @@
(if x
(when is-verbose (eprintf "\e[32m✔\e[0m %s: %s: %v" line-info (describe e) x))
(do
(eprintf "\e[31m✘\e[0m %s: %s: %v" line-info (describe e) x) (eflush)))
(eprintf "\e[31m✘\e[0m %s: %s: %v" line-info (string e) x) (eflush)))
x)
(defn skip-asserts

View File

@ -24,4 +24,27 @@
(use ../examples/sysir/frontend)
(assert true) # smoke test
(def janet (dyn *executable*))
(def run (filter next (string/split " " (os/getenv "SUBRUN" ""))))
(defn do-expect-directory
"Iterate a directory, evaluating all scripts in the directory. Assert that the captured output of the script
is as expected according to a matching .expect file."
[dir]
(each path (sorted (os/dir dir))
(when (string/has-suffix? ".janet" path)
(def fullpath (string dir "/" path))
(def proc (os/spawn [;run janet fullpath] :p {:out :pipe :err :out}))
(def buff @"")
(var ret-code nil)
(ev/gather
(while (ev/read (proc :out) 4096 buff))
(set ret-code (os/proc-wait proc)))
(def expect-file (string dir "/" path ".expect"))
(def expected-out (slurp expect-file))
(assert (= (string/trim expected-out) (string/trim buff))
(string "\nfile: " fullpath "\nexpected:\n======\n" expected-out "\n======\ngot:\n======\n" buff "\n======\n")))))
(do-expect-directory "test/sysir")
(end-suite)

View File

@ -25,4 +25,4 @@
(sysir/asm ctx types-asm)
(sysir/asm ctx add-asm)
(sysir/asm ctx sub-asm)
(print (sysir/to-c ctx))
(printf "%.99j" (sysir/to-ir ctx))

View File

@ -0,0 +1 @@
@[@[(type-prim Double f64) (type-array BigVec Double 100)] @[(parameter-count 0)] @[(link-name "add_vector") (parameter-count 2) (type-bind 0 BigVec) (type-bind 1 BigVec) (type-bind 2 BigVec) (add 2 0 1) (return 2)] @[(link-name "sub_vector") (parameter-count 2) (type-bind 0 BigVec) (type-bind 1 BigVec) (type-bind 2 BigVec) (subtract 2 0 1) (return 2)]]

View File

@ -16,8 +16,7 @@
(def ctx (sysir/context))
(sysir/asm ctx ir-asm)
(print (sysir/to-c ctx))
(printf "%.99M" (sysir/to-ir ctx))
(print (sysir/scalarize ctx))
(printf "%.99M" (sysir/to-ir ctx))
(printf "%j" (sysir/to-ir ctx))
(sysir/scalarize ctx)
(printf "%j" (sysir/to-ir ctx))
(print (sysir/to-c ctx))

View File

@ -0,0 +1,66 @@
@[@[(type-prim Double f64) (type-array BigVec Double 100) (type-pointer BigVecP BigVec)] @[(link-name "add_vectorp") (parameter-count 2) (type-bind 0 BigVecP) (type-bind 1 BigVecP) (type-bind 2 BigVecP) (add 2 0 1) (return 2)]]
@[@[(type-prim Double f64) (type-array BigVec Double 100) (type-pointer BigVecP BigVec)] @[(link-name "add_vectorp") (parameter-count 2) (type-bind 0 BigVecP) (type-bind 1 BigVecP) (type-bind 2 BigVecP) (type-bind 3 U32Index) (type-bind 5 PointerTo) (type-bind 6 PointerTo) (type-bind 7 PointerTo) (type-bind 4 Boolean) (load 3 [U32Index 0]) (label 7) (gte 4 3 [U32Index 0]) (branch 4 21) (apgetp 5 0 3) (apgetp 6 1 3) (apgetp 7 2 3) (add 7 5 6) (add 3 3 [U32Index 1]) (jump 7) (label 21) (return 2)]]
#include <stddef.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/syscall.h>
#define _t0 void
#line 6
typedef double _t1;
#line 7
typedef struct { _t1 els[100]; } _t2;
#line 8
typedef _t2 *_t3;
_t3 add_vectorp(_t3 _r0, _t3 _r1)
{
_t3 _r2;
_t4 _r3;
_t5 _r4;
_t6 _r5;
_t6 _r6;
_t6 _r7;
#line 6
#line 7
#line 8
#line 11
#line 12
#line 13
#line 14
#line 14
#line 14
#line 14
#line 14
#line 14
_r3 = *(0);
#line 14
_label_0:
#line 14
_r4 = _r3 > 0;
#line 14
if (_r4) goto _label_1;
#line 14
_r5 = &(_r0->els[_r3]);
#line 14
_r6 = &(_r1->els[_r3]);
#line 14
_r7 = &(_r2->els[_r3]);
#line 14
_r7 = _r5 + _r6;
#line 14
_r3 = _r3 + 1;
#line 14
goto _label_0;
#line 14
_label_1:
#line 15
return _r2;
}

View File

@ -5,7 +5,7 @@
(type-prim Int s32)
(type-prim Double f64)
(type-struct MyPair 0 1)
(type-pointer PInt 0)
(type-pointer PInt Int)
(type-array DoubleArray 1 1024)
# Declarations
@ -18,14 +18,14 @@
(bind 6 MyPair)
# Code
(constant 0 10)
(constant 0 21)
(move 0 (Int 10))
(move 0 (Int 21))
:location
(add 2 1 0)
(constant 3 1.77)
(call 3 sin 3)
(move 3 (Double 1.77))
(call :default 3 (PInt sin) 3)
(cast bob 2)
(call :default bob test_function)
(call :default bob (PInt test_function))
(add 5 bob 3)
(jump :location)
(return 5)))

View File

@ -0,0 +1,71 @@
#include <stddef.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/syscall.h>
#define _t0 void
#line 5
typedef int32_t _t1;
#line 6
typedef double _t2;
#line 7
typedef struct {
_t0 _f0;
_t1 _f1;
} _t3;
#line 8
typedef _t1 *_t4;
#line 9
typedef struct { _t1 els[1024]; } _t5;
_t2 test_function()
{
_t1 _r0;
_t1 _r1;
_t1 _r2;
_t2 _r3;
_t2 _r4;
_t2 _r5;
_t3 _r6;
#line 5
#line 6
#line 7
#line 7
#line 8
#line 9
#line 12
#line 13
#line 14
#line 15
#line 16
#line 17
#line 18
#line 21
_r0 = 10;
#line 22
_r0 = 21;
_label_0:
#line 24
_r2 = _r1 + _r0;
#line 25
_r3 = 1.77;
#line 26
_r3 = sin(_r3);
#line 26
#line 27
_r4 = (_t2) _r2;
#line 28
_r4 = test_function();
#line 29
_r5 = _r4 + _r3;
#line 30
goto _label_0;
#line 31
return _r5;
}

View File

@ -0,0 +1 @@
nope

1
test/sysir/smoke.janet Normal file
View File

@ -0,0 +1 @@
(print "hello")

View File

@ -0,0 +1 @@
hello