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

More work on register allocation and spilling.

Setup frontend.janet to show the basics of what is going on. Currently
emitting "fake" instructions just to hash out the idea.

One apparent issue is how we handle register spilling during variable
argument IR instructions (function calls). Arguments should come
_before_ the function call not after.
This commit is contained in:
Calvin Rose 2024-06-05 17:50:11 -05:00
parent 9e47cd94bd
commit 25b7c74089
5 changed files with 59 additions and 4 deletions

View File

@ -159,6 +159,7 @@ JANET_CORE_SOURCES=src/core/abstract.c \
src/core/struct.c \
src/core/symcache.c \
src/core/sysir.c \
src/core/sysir_x86.c \
src/core/table.c \
src/core/tuple.c \
src/core/util.c \

View File

@ -356,6 +356,16 @@
[]
(eprintf "%.99M\n" (sysir/to-ir ctx)))
(defn dumpx64
[]
(print (sysir/to-x64 ctx)))
(defn dumpc
[]
(print (sysir/to-c ctx)))
####
(compile1 myprog)
#(dump)
(dumpx64)

View File

@ -142,6 +142,7 @@ core_src = [
'src/core/struct.c',
'src/core/symcache.c',
'src/core/sysir.c',
'src/core/sysir_x86.c',
'src/core/table.c',
'src/core/tuple.c',
'src/core/util.c',

View File

@ -1839,12 +1839,23 @@ JANET_CORE_FN(cfun_sysir_toir,
return janet_wrap_array(array);
}
JANET_CORE_FN(cfun_sysir_tox64,
"(sysir/to-x64 context &opt buffer options)",
"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);
return janet_wrap_buffer(buffer);
}
void janet_lib_sysir(JanetTable *env) {
JanetRegExt cfuns[] = {
JANET_CORE_REG("sysir/context", cfun_sysir_context),
JANET_CORE_REG("sysir/asm", cfun_sysir_asm),
JANET_CORE_REG("sysir/to-c", cfun_sysir_toc),
JANET_CORE_REG("sysir/to-ir", cfun_sysir_toir),
JANET_CORE_REG("sysir/to-x64", cfun_sysir_tox64),
JANET_REG_END
};
janet_core_cfuns_ext(env, NULL, cfuns);

View File

@ -170,11 +170,17 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments,
void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
/* Do register allocation */
for (int32_t i = 0; i < janet_v_count(linkage->irs); i++) {
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);
JanetSysSpill *spills = assign_registers(ir, assignments, 15);
/* Emit prelude */
if (ir->link_name != NULL) {
janet_formatb(buffer, ".%s\n", ir->link_name);
} else {
janet_formatb(buffer, "._section_%d\n", i);
}
for (uint32_t j = 0; j < ir->instruction_count; j++) {
JanetSysInstruction instruction = ir->instructions[j];
JanetSysSpill spill = spills[j];
@ -183,21 +189,29 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
// emit load
uint32_t reg = spill.regs[spi];
void *x = (void *) 0x123456;
janet_formatb(buffer, "load r%u from %p\n", reg, x);
janet_formatb(buffer, "load r%u from %v ; SPILL\n", reg, janet_wrap_pointer(x));
}
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 %p\n", reg, x);
janet_formatb(buffer, "store r%u to %v ; SPILL\n", reg, janet_wrap_pointer(x));
}
}
switch (instruction.opcode) {
default:
janet_formatb(buffer, "; nyi: %s\n", janet_sysop_names[instruction.opcode]);
break;
case JANET_SYSOP_TYPE_PRIMITIVE:
case JANET_SYSOP_TYPE_UNION:
case JANET_SYSOP_TYPE_STRUCT:
case JANET_SYSOP_TYPE_BIND:
case JANET_SYSOP_TYPE_ARRAY:
case JANET_SYSOP_TYPE_POINTER:
/* Non synthesized instructions */
break;
case JANET_SYSOP_POINTER_ADD:
case JANET_SYSOP_POINTER_SUBTRACT:
break;
case JANET_SYSOP_ADD:
case JANET_SYSOP_SUBTRACT:
case JANET_SYSOP_MULTIPLY:
@ -208,6 +222,24 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
v2reg(assignments, instruction.three.lhs),
v2reg(assignments, instruction.three.rhs));
break;
case JANET_SYSOP_MOVE:
janet_formatb(buffer, "r%u = r%u\n",
v2reg(assignments, instruction.two.dest),
v2reg(assignments, instruction.two.src));
break;
case JANET_SYSOP_RETURN:
janet_formatb(buffer, "return r%u\n",
v2reg(assignments, instruction.one.src));
break;
case JANET_SYSOP_CONSTANT:
janet_formatb(buffer, "r%u = constant $%v\n",
v2reg(assignments, instruction.constant.dest),
ir->constants[instruction.constant.constant]);
break;
case JANET_SYSOP_LABEL:
janet_formatb(buffer, ":label_%u\n",
v2reg(assignments, instruction.label.id));
break;
// On a comparison, if next instruction is branch that reads from dest, combine into a single op.
}