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/struct.c \
src/core/symcache.c \ src/core/symcache.c \
src/core/sysir.c \ src/core/sysir.c \
src/core/sysir_x86.c \
src/core/table.c \ src/core/table.c \
src/core/tuple.c \ src/core/tuple.c \
src/core/util.c \ src/core/util.c \

View File

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

View File

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

View File

@ -1839,12 +1839,23 @@ JANET_CORE_FN(cfun_sysir_toir,
return janet_wrap_array(array); 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) { void janet_lib_sysir(JanetTable *env) {
JanetRegExt cfuns[] = { JanetRegExt cfuns[] = {
JANET_CORE_REG("sysir/context", cfun_sysir_context), JANET_CORE_REG("sysir/context", cfun_sysir_context),
JANET_CORE_REG("sysir/asm", cfun_sysir_asm), JANET_CORE_REG("sysir/asm", cfun_sysir_asm),
JANET_CORE_REG("sysir/to-c", cfun_sysir_toc), JANET_CORE_REG("sysir/to-c", cfun_sysir_toc),
JANET_CORE_REG("sysir/to-ir", cfun_sysir_toir), JANET_CORE_REG("sysir/to-ir", cfun_sysir_toir),
JANET_CORE_REG("sysir/to-x64", cfun_sysir_tox64),
JANET_REG_END JANET_REG_END
}; };
janet_core_cfuns_ext(env, NULL, cfuns); 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) { void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
/* Do register allocation */ /* 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]); JanetSysIR *ir = janet_unwrap_pointer(linkage->ir_ordered->data[i]);
JanetTable *assignments = janet_table(0); JanetTable *assignments = janet_table(0);
JanetSysSpill *spills = assign_registers(ir, assignments, 15); 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++) { for (uint32_t j = 0; j < ir->instruction_count; j++) {
JanetSysInstruction instruction = ir->instructions[j]; JanetSysInstruction instruction = ir->instructions[j];
JanetSysSpill spill = spills[j]; JanetSysSpill spill = spills[j];
@ -183,21 +189,29 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer)
// emit load // emit load
uint32_t reg = spill.regs[spi]; uint32_t reg = spill.regs[spi];
void *x = (void *) 0x123456; 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) { 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; 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) { switch (instruction.opcode) {
default: 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; break;
case JANET_SYSOP_POINTER_ADD: case JANET_SYSOP_POINTER_ADD:
case JANET_SYSOP_POINTER_SUBTRACT: case JANET_SYSOP_POINTER_SUBTRACT:
break;
case JANET_SYSOP_ADD: case JANET_SYSOP_ADD:
case JANET_SYSOP_SUBTRACT: case JANET_SYSOP_SUBTRACT:
case JANET_SYSOP_MULTIPLY: 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.lhs),
v2reg(assignments, instruction.three.rhs)); v2reg(assignments, instruction.three.rhs));
break; 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. // On a comparison, if next instruction is branch that reads from dest, combine into a single op.
} }