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:
parent
3995fa86e2
commit
af10c1d4b5
@ -367,5 +367,5 @@
|
||||
####
|
||||
|
||||
(compile1 myprog)
|
||||
#(dump)
|
||||
(dump)
|
||||
(dumpx64)
|
||||
|
@ -2226,8 +2226,8 @@
|
||||
|
||||
(defn thaw
|
||||
`Thaw an object (make it mutable) and do a deep copy, making
|
||||
child value also mutable. Closures, fibers, and abstract
|
||||
types will not be recursively thawed, but all other types will`
|
||||
child values also mutable. Closures, fibers, and abstract
|
||||
types will not be recursively thawed, but all other types will.`
|
||||
[ds]
|
||||
(case (type ds)
|
||||
:array (walk-ind thaw ds)
|
||||
|
@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
* [ ] named fields (for debugging mostly)
|
||||
* [ ] encode constants directly in 3 address codes - makes codegen easier
|
||||
* [x] named registers and types
|
||||
* [x] better type errors (perhaps mostly for compiler debugging - full type system goes on top)
|
||||
* [ ] x86/x64 machine code target
|
||||
@ -87,7 +87,7 @@ static const JanetPrimName prim_names[] = {
|
||||
{"void", JANET_PRIM_VOID},
|
||||
};
|
||||
|
||||
static const char *prim_to_prim_name[] = {
|
||||
const char *prim_to_prim_name[] = {
|
||||
"u8",
|
||||
"s8",
|
||||
"u16",
|
||||
@ -1757,6 +1757,9 @@ static int sysir_gcmark(void *p, size_t s) {
|
||||
if (ir->link_name != NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -126,6 +126,11 @@ typedef struct {
|
||||
uint32_t type;
|
||||
} 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 {
|
||||
JanetSysOp opcode;
|
||||
union {
|
||||
@ -251,10 +256,19 @@ typedef struct {
|
||||
JANET_SYS_SPILL_BOTH
|
||||
} spills[3];
|
||||
uint32_t regs[3];
|
||||
uint32_t stack_offsets[3];
|
||||
uint32_t stack_sizes[3];
|
||||
} 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 */
|
||||
extern const char *janet_sysop_names[];
|
||||
extern const char *prim_to_prim_name[];
|
||||
|
||||
/* Lowering */
|
||||
void janet_sys_ir_lower_to_ir(JanetSysIRLinkage *linkage, JanetArray *into);
|
||||
|
@ -25,17 +25,64 @@
|
||||
#include <janet.h>
|
||||
#include "sysir.h"
|
||||
#include "vector.h"
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Wrap stuff up in a context struct
|
||||
*/
|
||||
static const char *register_names[] = {
|
||||
"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) {
|
||||
return (uint32_t) janet_unwrap_number(janet_table_get(assignments, janet_wrap_number(var)));
|
||||
/* Get the layout for types */
|
||||
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) {
|
||||
|
||||
/* 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++) {
|
||||
if (i < max_reg) {
|
||||
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
|
||||
// a stack location.
|
||||
/* Assign all slots 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) */
|
||||
JanetSysSpill *spills = NULL;
|
||||
@ -89,20 +142,26 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
|
||||
case JANET_SYSOP_GTE:
|
||||
case JANET_SYSOP_POINTER_ADD:
|
||||
case JANET_SYSOP_POINTER_SUBTRACT:
|
||||
rega = v2reg(assignments, instruction.three.dest);
|
||||
regb = v2reg(assignments, instruction.three.lhs);
|
||||
regc = v2reg(assignments, instruction.three.rhs);
|
||||
if (rega == max_reg) {
|
||||
rega = v2reg_dflt(assignments, instruction.three.dest, max_reg);
|
||||
regb = v2reg_dflt(assignments, instruction.three.lhs, max_reg + 1);
|
||||
regc = v2reg_dflt(assignments, instruction.three.rhs, max_reg + 2);
|
||||
spill.regs[0] = rega;
|
||||
spill.regs[1] = regb;
|
||||
spill.regs[2] = regc;
|
||||
if (rega >= max_reg) {
|
||||
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.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.regs[2] = instruction.three.rhs;
|
||||
spill.stack_offsets[2] = stack_locations[instruction.three.rhs];
|
||||
spill.stack_sizes[2] = layouts[instruction.three.rhs].size;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -110,41 +169,51 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
|
||||
case JANET_SYSOP_MOVE:
|
||||
case JANET_SYSOP_CAST:
|
||||
case JANET_SYSOP_BNOT:
|
||||
rega = v2reg(assignments, instruction.two.dest);
|
||||
regb = v2reg(assignments, instruction.two.src);
|
||||
if (rega == max_reg) {
|
||||
rega = v2reg_dflt(assignments, instruction.two.dest, max_reg);
|
||||
regb = v2reg_dflt(assignments, instruction.two.src, max_reg + 1);
|
||||
spill.regs[0] = rega;
|
||||
spill.regs[1] = regb;
|
||||
if (rega >= max_reg) {
|
||||
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.regs[1] = instruction.two.src;
|
||||
spill.stack_offsets[1] = stack_locations[instruction.two.src];
|
||||
spill.stack_sizes[1] = layouts[instruction.two.src].size;
|
||||
}
|
||||
break;
|
||||
|
||||
/* branch COND */
|
||||
case JANET_SYSOP_BRANCH:
|
||||
case JANET_SYSOP_BRANCH_NOT:
|
||||
rega = v2reg(assignments, instruction.branch.cond);
|
||||
if (rega == max_reg) {
|
||||
rega = v2reg_dflt(assignments, instruction.branch.cond, max_reg);
|
||||
spill.regs[0] = rega;
|
||||
if (rega >= max_reg) {
|
||||
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;
|
||||
|
||||
case JANET_SYSOP_CONSTANT:
|
||||
rega = v2reg(assignments, instruction.constant.dest);
|
||||
if (rega == max_reg) {
|
||||
rega = v2reg_dflt(assignments, instruction.constant.dest, max_reg);
|
||||
spill.regs[0] = rega;
|
||||
if (rega >= max_reg) {
|
||||
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;
|
||||
|
||||
case JANET_SYSOP_RETURN:
|
||||
rega = v2reg(assignments, instruction.one.src);
|
||||
if (rega == max_reg) {
|
||||
rega = v2reg_dflt(assignments, instruction.one.src, max_reg);
|
||||
spill.regs[0] = rega;
|
||||
if (rega >= max_reg) {
|
||||
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;
|
||||
|
||||
@ -152,10 +221,12 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
|
||||
case JANET_SYSOP_ARG:
|
||||
for (int j = 0; j < 3; j++) {
|
||||
uint32_t var = instruction.arg.args[j];
|
||||
rega = v2reg(assignments, var);
|
||||
if (rega == max_reg) {
|
||||
rega = v2reg_dflt(assignments, var, 0);
|
||||
spill.regs[j] = rega;
|
||||
if (rega >= max_reg) { /* Unused elements must be 0 */
|
||||
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;
|
||||
@ -163,46 +234,88 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
|
||||
/* Variable arg */
|
||||
case JANET_SYSOP_CALL:
|
||||
case JANET_SYSOP_CALLK:
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
janet_v_push(spills, spill);
|
||||
}
|
||||
|
||||
janet_sfree(layouts);
|
||||
janet_sfree(stack_locations);
|
||||
|
||||
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];
|
||||
for (int spi = 0; spi < 3; spi++) {
|
||||
if (spill.spills[spi] == JANET_SYS_SPILL_WRITE || spill.spills[spi] == JANET_SYS_SPILL_BOTH) {
|
||||
// emit store
|
||||
uint32_t reg = spill.regs[spi];
|
||||
void *x = (void *) 0x123456;
|
||||
janet_formatb(buffer, "store r%u to %v ; SPILL\n", reg, janet_wrap_pointer(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));
|
||||
uint32_t x = spill.stack_offsets[spi];
|
||||
uint32_t s = spill.stack_sizes[spi];
|
||||
janet_formatb(buffer, "store%u r%u to stack[%u] ; SPILL\n", s, reg, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
for (int32_t i = 0; i < linkage->ir_ordered->count; i++) {
|
||||
JanetSysIR *ir = janet_unwrap_pointer(linkage->ir_ordered->data[i]);
|
||||
JanetTable *assignments = janet_table(0);
|
||||
/* 16 total 64 bit registers - 3 temp */
|
||||
JanetSysSpill *spills = assign_registers(ir, assignments, 113);
|
||||
JanetTempRegs temps;
|
||||
/* 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 */
|
||||
if (ir->link_name != NULL) {
|
||||
janet_formatb(buffer, ".%s\n", ir->link_name);
|
||||
janet_formatb(buffer, "\n%s:\n", ir->link_name);
|
||||
} 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++) {
|
||||
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_MULTIPLY:
|
||||
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",
|
||||
v2reg(assignments, instruction.three.dest),
|
||||
temps.temps[0],
|
||||
janet_sysop_names[instruction.opcode],
|
||||
v2reg(assignments, instruction.three.lhs),
|
||||
v2reg(assignments, instruction.three.rhs));
|
||||
temps.temps[1],
|
||||
temps.temps[2]);
|
||||
do_spills_write(buffer, spills, j);
|
||||
break;
|
||||
case JANET_SYSOP_MOVE:
|
||||
do_spills(buffer, spills, j);
|
||||
janet_formatb(buffer, "r%u = r%u\n",
|
||||
v2reg(assignments, instruction.two.dest),
|
||||
v2reg(assignments, instruction.two.src));
|
||||
temps = do_spills_read(buffer, spills, j);
|
||||
//janet_formatb(buffer, "r%u = r%u\n", temps.temps[0], temps.temps[1]);
|
||||
janet_formatb(buffer, "mov %s, %s\n",
|
||||
register_names[temps.temps[0]],
|
||||
register_names[temps.temps[1]]);
|
||||
do_spills_write(buffer, spills, j);
|
||||
break;
|
||||
case JANET_SYSOP_RETURN:
|
||||
do_spills(buffer, spills, j);
|
||||
janet_formatb(buffer, "return r%u\n",
|
||||
v2reg(assignments, instruction.one.src));
|
||||
temps = do_spills_read(buffer, spills, j);
|
||||
//janet_formatb(buffer, "return r%u\n", temps.temps[0]);
|
||||
janet_formatb(buffer, "leave\n mov %s, rax\nret\n", register_names[temps.temps[0]]);
|
||||
break;
|
||||
case JANET_SYSOP_CONSTANT:
|
||||
do_spills(buffer, spills, j);
|
||||
janet_formatb(buffer, "r%u = constant $%v\n",
|
||||
v2reg(assignments, instruction.constant.dest),
|
||||
ir->constants[instruction.constant.constant]);
|
||||
temps = do_spills_read(buffer, spills, j);
|
||||
janet_formatb(buffer, "r%u = constant $%v\n", temps.temps[0], ir->constants[instruction.constant.constant]);
|
||||
do_spills_write(buffer, spills, j);
|
||||
break;
|
||||
case JANET_SYSOP_LABEL:
|
||||
do_spills(buffer, spills, j);
|
||||
janet_formatb(buffer, "label_%u:\n",
|
||||
v2reg(assignments, instruction.label.id));
|
||||
janet_formatb(buffer, "label_%u:\n", instruction.label.id);
|
||||
break;
|
||||
case JANET_SYSOP_EQ:
|
||||
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_GT:
|
||||
case JANET_SYSOP_GTE:
|
||||
do_spills(buffer, spills, j);
|
||||
janet_formatb(buffer, "r%u = %s r%u, r%u\n",
|
||||
v2reg(assignments, instruction.three.dest),
|
||||
janet_sysop_names[instruction.opcode],
|
||||
v2reg(assignments, instruction.three.lhs),
|
||||
v2reg(assignments, instruction.three.rhs));
|
||||
temps = do_spills_read(buffer, spills, j);
|
||||
JanetSysInstruction nexti = ir->instructions[j + 1];
|
||||
/* Combine compare and branch into one instruction */
|
||||
/* TODO - handle when lhs or rhs is 0 */
|
||||
/* TODO - handle floats */
|
||||
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;
|
||||
case JANET_SYSOP_BRANCH:
|
||||
case JANET_SYSOP_BRANCH_NOT:
|
||||
do_spills(buffer, spills, j);
|
||||
janet_formatb(buffer, "branch label_%u if r%u\n",
|
||||
instruction.branch.to,
|
||||
v2reg(assignments, instruction.branch.cond));
|
||||
;
|
||||
if (skip_branch) {
|
||||
skip_branch = 0;
|
||||
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;
|
||||
case JANET_SYSOP_CALLK:
|
||||
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) {
|
||||
sub_count--;
|
||||
}
|
||||
JanetSysInstruction arg_instruction = ir->instructions[j + offset];
|
||||
do_spills(buffer, spills, j + offset);
|
||||
temps = do_spills_read(buffer, spills, j + offset);
|
||||
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.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]);
|
||||
} else {
|
||||
janet_formatb(buffer, "call %p\n",
|
||||
@ -300,13 +468,12 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
|
||||
}
|
||||
} else {
|
||||
if (instruction.call.has_dest) {
|
||||
janet_formatb(buffer, "r%u = call r%u\n", v2reg(assignments, instruction.call.dest),
|
||||
v2reg(assignments, instruction.call.callee));
|
||||
janet_formatb(buffer, "r%u = call r%u\n", temps.temps[0], temps.temps[1]);
|
||||
} else {
|
||||
janet_formatb(buffer, "call r%u\n",
|
||||
v2reg(assignments, instruction.call.callee));
|
||||
janet_formatb(buffer, "call r%u\n", temps.temps[0]);
|
||||
}
|
||||
}
|
||||
do_spills_write(buffer, spills, j);
|
||||
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