1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-18 06:34:48 +00:00

More work on x64 backend, especially branching.

Needs changes to IR to allow encoding immediates in all
instructions where possible. This makes the IR denser, means
we don't need `constant` and `callk`, and allows certain optimizations
like comparing to zero, using `inc` and `dec`, etc which are
specializations of more general instructions with constants.
This commit is contained in:
Calvin Rose 2024-06-08 13:20:34 -05:00
parent 3995fa86e2
commit af10c1d4b5
5 changed files with 275 additions and 91 deletions

View File

@ -367,5 +367,5 @@
#### ####
(compile1 myprog) (compile1 myprog)
#(dump) (dump)
(dumpx64) (dumpx64)

View File

@ -2226,8 +2226,8 @@
(defn thaw (defn thaw
`Thaw an object (make it mutable) and do a deep copy, making `Thaw an object (make it mutable) and do a deep copy, making
child value also mutable. Closures, fibers, and abstract child values also mutable. Closures, fibers, and abstract
types will not be recursively thawed, but all other types will` types will not be recursively thawed, but all other types will.`
[ds] [ds]
(case (type ds) (case (type ds)
:array (walk-ind thaw ds) :array (walk-ind thaw ds)

View File

@ -27,7 +27,7 @@
*/ */
/* TODO /* TODO
* [ ] named fields (for debugging mostly) * [ ] encode constants directly in 3 address codes - makes codegen easier
* [x] named registers and types * [x] named registers and types
* [x] better type errors (perhaps mostly for compiler debugging - full type system goes on top) * [x] better type errors (perhaps mostly for compiler debugging - full type system goes on top)
* [ ] x86/x64 machine code target * [ ] x86/x64 machine code target
@ -87,7 +87,7 @@ static const JanetPrimName prim_names[] = {
{"void", JANET_PRIM_VOID}, {"void", JANET_PRIM_VOID},
}; };
static const char *prim_to_prim_name[] = { const char *prim_to_prim_name[] = {
"u8", "u8",
"s8", "s8",
"u16", "u16",
@ -1757,6 +1757,9 @@ static int sysir_gcmark(void *p, size_t s) {
if (ir->link_name != NULL) { if (ir->link_name != NULL) {
janet_mark(janet_wrap_string(ir->link_name)); janet_mark(janet_wrap_string(ir->link_name));
} }
janet_mark(janet_wrap_table(ir->labels));
janet_mark(janet_wrap_table(ir->register_name_lookup));
janet_mark(janet_wrap_abstract(ir->linkage));
return 0; return 0;
} }

View File

@ -126,6 +126,11 @@ typedef struct {
uint32_t type; uint32_t type;
} JanetSysTypeField; } JanetSysTypeField;
/* Allow read arguments to be constants to allow
* encoding immediates. This makes codegen easier. */
#define JANET_SYS_MAX_OPERAND 0x7FFFFFFFU
#define JANET_SYS_CONSTANT_PREFIX 0x80000000U
typedef struct { typedef struct {
JanetSysOp opcode; JanetSysOp opcode;
union { union {
@ -251,10 +256,19 @@ typedef struct {
JANET_SYS_SPILL_BOTH JANET_SYS_SPILL_BOTH
} spills[3]; } spills[3];
uint32_t regs[3]; uint32_t regs[3];
uint32_t stack_offsets[3];
uint32_t stack_sizes[3];
} JanetSysSpill; } JanetSysSpill;
/* Delay alignment info for the most part to the lowering phase */
typedef struct {
uint32_t size;
uint32_t alignment;
} JanetSysTypeLayout;
/* Keep track of names for each instruction */ /* Keep track of names for each instruction */
extern const char *janet_sysop_names[]; extern const char *janet_sysop_names[];
extern const char *prim_to_prim_name[];
/* Lowering */ /* Lowering */
void janet_sys_ir_lower_to_ir(JanetSysIRLinkage *linkage, JanetArray *into); void janet_sys_ir_lower_to_ir(JanetSysIRLinkage *linkage, JanetArray *into);

View File

@ -25,17 +25,64 @@
#include <janet.h> #include <janet.h>
#include "sysir.h" #include "sysir.h"
#include "vector.h" #include "vector.h"
#include "util.h"
#endif #endif
/* static const char *register_names[] = {
* Wrap stuff up in a context struct "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
*/ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
};
static uint32_t v2reg(JanetTable *assignments, uint32_t var) { /* Get the layout for types */
return (uint32_t) janet_unwrap_number(janet_table_get(assignments, janet_wrap_number(var))); JanetSysTypeLayout get_x64layout(JanetSysTypeInfo info) {
JanetSysTypeLayout layout;
switch (info.prim) {
default:
layout.size = 1;
layout.alignment = 1;
break;
case JANET_PRIM_S8:
case JANET_PRIM_U8:
case JANET_PRIM_BOOLEAN:
layout.size = 1;
layout.alignment = 1;
break;
case JANET_PRIM_S16:
case JANET_PRIM_U16:
layout.size = 2;
layout.alignment = 2;
break;
case JANET_PRIM_S32:
case JANET_PRIM_U32:
layout.size = 4;
layout.alignment = 4;
break;
case JANET_PRIM_U64:
case JANET_PRIM_S64:
case JANET_PRIM_POINTER:
layout.size = 8;
layout.alignment = 8;
break;
case JANET_PRIM_F32:
case JANET_PRIM_F64:
layout.size = 8;
layout.alignment = 8;
break;
}
return layout;
} }
JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments, static uint32_t v2reg_dflt(JanetTable *assignments, uint32_t var, uint32_t dflt) {
Janet check = janet_table_get(assignments, janet_wrap_number(var));
if (janet_checktype(check, JANET_NUMBER)) {
return (uint32_t) janet_unwrap_number(check);
}
return dflt;
}
JanetSysSpill *assign_registers(JanetSysIR *ir,
JanetSysTypeLayout *layouts,
JanetTable *assignments,
uint32_t max_reg) { uint32_t max_reg) {
/* simplest register assignment algorithm - first n variables /* simplest register assignment algorithm - first n variables
@ -48,13 +95,19 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
for (uint32_t i = 0; i < ir->register_count; i++) { for (uint32_t i = 0; i < ir->register_count; i++) {
if (i < max_reg) { if (i < max_reg) {
janet_table_put(assignments, janet_wrap_number(i), janet_wrap_number(i)); janet_table_put(assignments, janet_wrap_number(i), janet_wrap_number(i));
} else {
janet_table_put(assignments, janet_wrap_number(i), janet_wrap_number(max_reg));
} }
} }
// TODO - keep track of where we spill to. Simple idea would be to assign each variable /* Assign all slots a stack location */
// a stack location. /* TODO - be smarter about this */
uint32_t *stack_locations = janet_smalloc(ir->register_count * sizeof(uint32_t));
uint32_t next_loc = 0;
for (uint32_t i = 0; i < ir->register_count; i++) {
JanetSysTypeLayout layout = layouts[i];
next_loc = (next_loc + layout.alignment - 1) / layout.alignment * layout.alignment;
stack_locations[i] = next_loc;
next_loc += layout.size;
}
/* Generate spills. Spills occur iff using the temporary register (max_reg) */ /* Generate spills. Spills occur iff using the temporary register (max_reg) */
JanetSysSpill *spills = NULL; JanetSysSpill *spills = NULL;
@ -89,20 +142,26 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
case JANET_SYSOP_GTE: case JANET_SYSOP_GTE:
case JANET_SYSOP_POINTER_ADD: case JANET_SYSOP_POINTER_ADD:
case JANET_SYSOP_POINTER_SUBTRACT: case JANET_SYSOP_POINTER_SUBTRACT:
rega = v2reg(assignments, instruction.three.dest); rega = v2reg_dflt(assignments, instruction.three.dest, max_reg);
regb = v2reg(assignments, instruction.three.lhs); regb = v2reg_dflt(assignments, instruction.three.lhs, max_reg + 1);
regc = v2reg(assignments, instruction.three.rhs); regc = v2reg_dflt(assignments, instruction.three.rhs, max_reg + 2);
if (rega == max_reg) { spill.regs[0] = rega;
spill.regs[1] = regb;
spill.regs[2] = regc;
if (rega >= max_reg) {
spill.spills[0] = JANET_SYS_SPILL_WRITE; spill.spills[0] = JANET_SYS_SPILL_WRITE;
spill.regs[0] = instruction.three.dest; spill.stack_offsets[0] = stack_locations[instruction.three.dest];
spill.stack_sizes[0] = layouts[instruction.three.dest].size;
} }
if (regb == max_reg) { if (regb >= max_reg) {
spill.spills[1] = JANET_SYS_SPILL_READ; spill.spills[1] = JANET_SYS_SPILL_READ;
spill.regs[1] = instruction.three.lhs; spill.stack_offsets[1] = stack_locations[instruction.three.lhs];
spill.stack_sizes[1] = layouts[instruction.three.lhs].size;
} }
if (regc == max_reg) { if (regc >= max_reg) {
spill.spills[2] = JANET_SYS_SPILL_READ; spill.spills[2] = JANET_SYS_SPILL_READ;
spill.regs[2] = instruction.three.rhs; spill.stack_offsets[2] = stack_locations[instruction.three.rhs];
spill.stack_sizes[2] = layouts[instruction.three.rhs].size;
} }
break; break;
@ -110,41 +169,51 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
case JANET_SYSOP_MOVE: case JANET_SYSOP_MOVE:
case JANET_SYSOP_CAST: case JANET_SYSOP_CAST:
case JANET_SYSOP_BNOT: case JANET_SYSOP_BNOT:
rega = v2reg(assignments, instruction.two.dest); rega = v2reg_dflt(assignments, instruction.two.dest, max_reg);
regb = v2reg(assignments, instruction.two.src); regb = v2reg_dflt(assignments, instruction.two.src, max_reg + 1);
if (rega == max_reg) { spill.regs[0] = rega;
spill.regs[1] = regb;
if (rega >= max_reg) {
spill.spills[0] = JANET_SYS_SPILL_WRITE; spill.spills[0] = JANET_SYS_SPILL_WRITE;
spill.regs[0] = instruction.two.dest; spill.stack_offsets[0] = stack_locations[instruction.two.dest];
spill.stack_sizes[0] = layouts[instruction.two.dest].size;
} }
if (regb == max_reg) { if (regb >= max_reg) {
spill.spills[1] = JANET_SYS_SPILL_READ; spill.spills[1] = JANET_SYS_SPILL_READ;
spill.regs[1] = instruction.two.src; spill.stack_offsets[1] = stack_locations[instruction.two.src];
spill.stack_sizes[1] = layouts[instruction.two.src].size;
} }
break; break;
/* branch COND */ /* branch COND */
case JANET_SYSOP_BRANCH: case JANET_SYSOP_BRANCH:
case JANET_SYSOP_BRANCH_NOT: case JANET_SYSOP_BRANCH_NOT:
rega = v2reg(assignments, instruction.branch.cond); rega = v2reg_dflt(assignments, instruction.branch.cond, max_reg);
if (rega == max_reg) { spill.regs[0] = rega;
if (rega >= max_reg) {
spill.spills[0] = JANET_SYS_SPILL_READ; spill.spills[0] = JANET_SYS_SPILL_READ;
spill.regs[0] = instruction.branch.cond; spill.stack_offsets[0] = stack_locations[instruction.branch.cond];
spill.stack_sizes[0] = layouts[instruction.branch.cond].size;
} }
break; break;
case JANET_SYSOP_CONSTANT: case JANET_SYSOP_CONSTANT:
rega = v2reg(assignments, instruction.constant.dest); rega = v2reg_dflt(assignments, instruction.constant.dest, max_reg);
if (rega == max_reg) { spill.regs[0] = rega;
if (rega >= max_reg) {
spill.spills[0] = JANET_SYS_SPILL_WRITE; spill.spills[0] = JANET_SYS_SPILL_WRITE;
spill.regs[0] = instruction.constant.dest; spill.stack_offsets[0] = stack_locations[instruction.constant.dest];
spill.stack_sizes[0] = layouts[instruction.constant.dest].size;
} }
break; break;
case JANET_SYSOP_RETURN: case JANET_SYSOP_RETURN:
rega = v2reg(assignments, instruction.one.src); rega = v2reg_dflt(assignments, instruction.one.src, max_reg);
if (rega == max_reg) { spill.regs[0] = rega;
if (rega >= max_reg) {
spill.spills[0] = JANET_SYS_SPILL_READ; spill.spills[0] = JANET_SYS_SPILL_READ;
spill.regs[0] = instruction.one.src; spill.stack_offsets[0] = stack_locations[instruction.one.src];
spill.stack_sizes[0] = layouts[instruction.one.src].size;
} }
break; break;
@ -152,10 +221,12 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
case JANET_SYSOP_ARG: case JANET_SYSOP_ARG:
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
uint32_t var = instruction.arg.args[j]; uint32_t var = instruction.arg.args[j];
rega = v2reg(assignments, var); rega = v2reg_dflt(assignments, var, 0);
if (rega == max_reg) { spill.regs[j] = rega;
if (rega >= max_reg) { /* Unused elements must be 0 */
spill.spills[j] = JANET_SYS_SPILL_READ; spill.spills[j] = JANET_SYS_SPILL_READ;
spill.regs[j] = var; spill.stack_offsets[j] = stack_locations[instruction.arg.args[j]];
spill.stack_sizes[j] = layouts[instruction.arg.args[j]].size;
} }
} }
break; break;
@ -163,46 +234,88 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
/* Variable arg */ /* Variable arg */
case JANET_SYSOP_CALL: case JANET_SYSOP_CALL:
case JANET_SYSOP_CALLK: case JANET_SYSOP_CALLK:
/* TODO */
break; break;
} }
janet_v_push(spills, spill); janet_v_push(spills, spill);
} }
janet_sfree(layouts);
janet_sfree(stack_locations);
return spills; return spills;
} }
static void do_spills(JanetBuffer *buffer, JanetSysSpill *spills, uint32_t index) { typedef struct {
uint32_t temps[3];
} JanetTempRegs;
static JanetTempRegs do_spills_read(JanetBuffer *buffer, JanetSysSpill *spills, uint32_t index) {
JanetSysSpill spill = spills[index];
JanetTempRegs temps;
for (int spi = 0; spi < 3; spi++) {
uint32_t reg = spill.regs[spi];
temps.temps[spi] = reg;
if (spill.spills[spi] == JANET_SYS_SPILL_READ || spill.spills[spi] == JANET_SYS_SPILL_BOTH) {
// emit load
uint32_t x = spill.stack_offsets[spi];
uint32_t s = spill.stack_sizes[spi];
janet_formatb(buffer, "load%u r%u from stack[%u] ; SPILL\n", s, reg, x);
}
}
return temps;
}
static void do_spills_write(JanetBuffer *buffer, JanetSysSpill *spills, uint32_t index) {
JanetSysSpill spill = spills[index]; JanetSysSpill spill = spills[index];
for (int spi = 0; spi < 3; spi++) { for (int spi = 0; spi < 3; spi++) {
if (spill.spills[spi] == JANET_SYS_SPILL_WRITE || spill.spills[spi] == JANET_SYS_SPILL_BOTH) { if (spill.spills[spi] == JANET_SYS_SPILL_WRITE || spill.spills[spi] == JANET_SYS_SPILL_BOTH) {
// emit store // emit store
uint32_t reg = spill.regs[spi]; uint32_t reg = spill.regs[spi];
void *x = (void *) 0x123456; uint32_t x = spill.stack_offsets[spi];
janet_formatb(buffer, "store r%u to %v ; SPILL\n", reg, janet_wrap_pointer(x)); uint32_t s = spill.stack_sizes[spi];
} janet_formatb(buffer, "store%u r%u to stack[%u] ; SPILL\n", s, reg, x);
if (spill.spills[spi] == JANET_SYS_SPILL_READ || spill.spills[spi] == JANET_SYS_SPILL_BOTH) {
// emit load
uint32_t reg = spill.regs[spi];
void *x = (void *) 0x123456;
janet_formatb(buffer, "load r%u from %v ; SPILL\n", reg, janet_wrap_pointer(x));
} }
} }
} }
void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) { void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
/* For now, emit assembly for nasm. Eventually an assembler for use with Janet would be good. */
JanetSysTypeLayout *all_layouts = janet_smalloc(linkage->type_def_count * sizeof(JanetSysTypeLayout));
for (uint32_t i = 0; i < linkage->type_def_count; i++) {
all_layouts[i] = get_x64layout(linkage->type_defs[i]);
}
/* Emit prelude */
janet_formatb(buffer, "bits 64\ndefault rel\n\n");
janet_formatb(buffer, "segment .text\n");
/* Do register allocation */ /* Do register allocation */
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]);
JanetTable *assignments = janet_table(0); JanetTable *assignments = janet_table(0);
/* 16 total 64 bit registers - 3 temp */ JanetTempRegs temps;
JanetSysSpill *spills = assign_registers(ir, assignments, 113); /* Get type layouts */
JanetSysTypeLayout *layouts = janet_smalloc(ir->register_count * sizeof(JanetSysTypeLayout));
for (uint32_t i = 0; i < ir->register_count; i++) {
layouts[i] = all_layouts[ir->types[i]];
}
JanetSysSpill *spills = assign_registers(ir, layouts, assignments, 13);
/* Allow combining compare + branch instructions more easily */
int skip_branch = 0;
/* Emit constant strings */
for (int32_t j = 0; j < ir->constant_count; j++) {
janet_formatb(buffer, ".CONST%u:\n .string %p\n", j, ir->constants[j]);
}
/* Emit prelude */ /* Emit prelude */
if (ir->link_name != NULL) { if (ir->link_name != NULL) {
janet_formatb(buffer, ".%s\n", ir->link_name); janet_formatb(buffer, "\n%s:\n", ir->link_name);
} else { } else {
janet_formatb(buffer, "._section_%d\n", i); janet_formatb(buffer, "\n_section_%d:\n", i);
} }
for (uint32_t j = 0; j < ir->instruction_count; j++) { for (uint32_t j = 0; j < ir->instruction_count; j++) {
JanetSysInstruction instruction = ir->instructions[j]; JanetSysInstruction instruction = ir->instructions[j];
@ -225,34 +338,34 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
case JANET_SYSOP_SUBTRACT: case JANET_SYSOP_SUBTRACT:
case JANET_SYSOP_MULTIPLY: case JANET_SYSOP_MULTIPLY:
case JANET_SYSOP_DIVIDE: case JANET_SYSOP_DIVIDE:
do_spills(buffer, spills, j); temps = do_spills_read(buffer, spills, j);
janet_formatb(buffer, "r%u = %s r%u, r%u\n", janet_formatb(buffer, "r%u = %s r%u, r%u\n",
v2reg(assignments, instruction.three.dest), temps.temps[0],
janet_sysop_names[instruction.opcode], janet_sysop_names[instruction.opcode],
v2reg(assignments, instruction.three.lhs), temps.temps[1],
v2reg(assignments, instruction.three.rhs)); temps.temps[2]);
do_spills_write(buffer, spills, j);
break; break;
case JANET_SYSOP_MOVE: case JANET_SYSOP_MOVE:
do_spills(buffer, spills, j); temps = do_spills_read(buffer, spills, j);
janet_formatb(buffer, "r%u = r%u\n", //janet_formatb(buffer, "r%u = r%u\n", temps.temps[0], temps.temps[1]);
v2reg(assignments, instruction.two.dest), janet_formatb(buffer, "mov %s, %s\n",
v2reg(assignments, instruction.two.src)); register_names[temps.temps[0]],
register_names[temps.temps[1]]);
do_spills_write(buffer, spills, j);
break; break;
case JANET_SYSOP_RETURN: case JANET_SYSOP_RETURN:
do_spills(buffer, spills, j); temps = do_spills_read(buffer, spills, j);
janet_formatb(buffer, "return r%u\n", //janet_formatb(buffer, "return r%u\n", temps.temps[0]);
v2reg(assignments, instruction.one.src)); janet_formatb(buffer, "leave\n mov %s, rax\nret\n", register_names[temps.temps[0]]);
break; break;
case JANET_SYSOP_CONSTANT: case JANET_SYSOP_CONSTANT:
do_spills(buffer, spills, j); temps = do_spills_read(buffer, spills, j);
janet_formatb(buffer, "r%u = constant $%v\n", janet_formatb(buffer, "r%u = constant $%v\n", temps.temps[0], ir->constants[instruction.constant.constant]);
v2reg(assignments, instruction.constant.dest), do_spills_write(buffer, spills, j);
ir->constants[instruction.constant.constant]);
break; break;
case JANET_SYSOP_LABEL: case JANET_SYSOP_LABEL:
do_spills(buffer, spills, j); janet_formatb(buffer, "label_%u:\n", instruction.label.id);
janet_formatb(buffer, "label_%u:\n",
v2reg(assignments, instruction.label.id));
break; break;
case JANET_SYSOP_EQ: case JANET_SYSOP_EQ:
case JANET_SYSOP_NEQ: case JANET_SYSOP_NEQ:
@ -260,19 +373,74 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
case JANET_SYSOP_LTE: case JANET_SYSOP_LTE:
case JANET_SYSOP_GT: case JANET_SYSOP_GT:
case JANET_SYSOP_GTE: case JANET_SYSOP_GTE:
do_spills(buffer, spills, j); temps = do_spills_read(buffer, spills, j);
janet_formatb(buffer, "r%u = %s r%u, r%u\n", JanetSysInstruction nexti = ir->instructions[j + 1];
v2reg(assignments, instruction.three.dest), /* Combine compare and branch into one instruction */
janet_sysop_names[instruction.opcode], /* TODO - handle when lhs or rhs is 0 */
v2reg(assignments, instruction.three.lhs), /* TODO - handle floats */
v2reg(assignments, instruction.three.rhs)); janet_formatb(buffer, "cmp %s, %s\n", register_names[temps.temps[1]], register_names[temps.temps[2]]);
if ((nexti.opcode == JANET_SYSOP_BRANCH ||
nexti.opcode == JANET_SYSOP_BRANCH_NOT)
&& nexti.branch.cond == instruction.three.dest) {
skip_branch = 1;
int invert = nexti.opcode == JANET_SYSOP_BRANCH_NOT;
if (instruction.opcode == JANET_SYSOP_EQ) {
janet_formatb(buffer, "%s label_%u\n", invert ? "jne" : "je", nexti.branch.to);
} else if (instruction.opcode == JANET_SYSOP_NEQ) {
janet_formatb(buffer, "%s label_%u\n", invert ? "je" : "jne", nexti.branch.to);
} else if (instruction.opcode == JANET_SYSOP_GT) {
janet_formatb(buffer, "%s label_%u\n", invert ? "jle" : "jg", nexti.branch.to);
} else if (instruction.opcode == JANET_SYSOP_GTE) {
janet_formatb(buffer, "%s label_%u\n", invert ? "jl" : "jge", nexti.branch.to);
} else if (instruction.opcode == JANET_SYSOP_LT) {
janet_formatb(buffer, "%s label_%u\n", invert ? "jge" : "jl", nexti.branch.to);
} else if (instruction.opcode == JANET_SYSOP_LTE) {
janet_formatb(buffer, "%s label_%u\n", invert ? "jg" : "jle", nexti.branch.to);
} else {
janet_panic("unreachable");
}
do_spills_write(buffer, spills, j);
break;
}
/* Fallback to set* instructions */
if (instruction.opcode == JANET_SYSOP_EQ) {
janet_formatb(buffer, "sete %s\n", register_names[temps.temps[0]]);
} else if (instruction.opcode == JANET_SYSOP_NEQ) {
janet_formatb(buffer, "setne %s\n", register_names[temps.temps[0]]);
} else if (instruction.opcode == JANET_SYSOP_GT) {
janet_formatb(buffer, "setg %s\n", register_names[temps.temps[0]]);
} else if (instruction.opcode == JANET_SYSOP_GTE) {
janet_formatb(buffer, "setge %s\n", register_names[temps.temps[0]]);
} else if (instruction.opcode == JANET_SYSOP_LT) {
janet_formatb(buffer, "setl %s\n", register_names[temps.temps[0]]);
} else if (instruction.opcode == JANET_SYSOP_LTE) {
janet_formatb(buffer, "setle %s\n", register_names[temps.temps[0]]);
} else {
janet_panic("unreachable");
}
do_spills_write(buffer, spills, j);
break; break;
case JANET_SYSOP_BRANCH: case JANET_SYSOP_BRANCH:
case JANET_SYSOP_BRANCH_NOT: case JANET_SYSOP_BRANCH_NOT:
do_spills(buffer, spills, j); ;
janet_formatb(buffer, "branch label_%u if r%u\n", if (skip_branch) {
instruction.branch.to, skip_branch = 0;
v2reg(assignments, instruction.branch.cond)); break;
}
temps = do_spills_read(buffer, spills, j);
if (instruction.opcode == JANET_SYSOP_BRANCH) {
janet_formatb(buffer, "jnz %s label_%u\n",
register_names[temps.temps[0]],
instruction.branch.to);
} else {
janet_formatb(buffer, "jz %s label_%u\n",
register_names[temps.temps[0]],
instruction.branch.to);
}
break;
case JANET_SYSOP_JUMP:
janet_formatb(buffer, "jmp label_%u\n",
instruction.jump.to);
break; break;
case JANET_SYSOP_CALLK: case JANET_SYSOP_CALLK:
case JANET_SYSOP_CALL: case JANET_SYSOP_CALL:
@ -284,15 +452,15 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
while (offset * 3 + sub_count >= (int32_t) instruction.call.arg_count) { while (offset * 3 + sub_count >= (int32_t) instruction.call.arg_count) {
sub_count--; sub_count--;
} }
JanetSysInstruction arg_instruction = ir->instructions[j + offset]; temps = do_spills_read(buffer, spills, j + offset);
do_spills(buffer, spills, j + offset);
for (int x = sub_count; x >= 0; x--) { for (int x = sub_count; x >= 0; x--) {
janet_formatb(buffer, "push r%u\n", v2reg(assignments, arg_instruction.arg.args[x])); janet_formatb(buffer, "push r%u\n", temps.temps[x]);
} }
} }
temps = do_spills_read(buffer, spills, j);
if (instruction.opcode == JANET_SYSOP_CALLK) { if (instruction.opcode == JANET_SYSOP_CALLK) {
if (instruction.callk.has_dest) { if (instruction.callk.has_dest) {
janet_formatb(buffer, "r%u = call %p\n", v2reg(assignments, instruction.callk.dest), janet_formatb(buffer, "r%u = call %p\n", temps.temps[0],
ir->constants[instruction.callk.constant]); ir->constants[instruction.callk.constant]);
} else { } else {
janet_formatb(buffer, "call %p\n", janet_formatb(buffer, "call %p\n",
@ -300,13 +468,12 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
} }
} else { } else {
if (instruction.call.has_dest) { if (instruction.call.has_dest) {
janet_formatb(buffer, "r%u = call r%u\n", v2reg(assignments, instruction.call.dest), janet_formatb(buffer, "r%u = call r%u\n", temps.temps[0], temps.temps[1]);
v2reg(assignments, instruction.call.callee));
} else { } else {
janet_formatb(buffer, "call r%u\n", janet_formatb(buffer, "call r%u\n", temps.temps[0]);
v2reg(assignments, instruction.call.callee));
} }
} }
do_spills_write(buffer, spills, j);
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.
} }