From 25b7c74089fcf91f9b2b7757433785217145cc8d Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Wed, 5 Jun 2024 17:50:11 -0500 Subject: [PATCH] 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. --- Makefile | 1 + examples/sysir/frontend.janet | 10 +++++++++ meson.build | 1 + src/core/sysir.c | 11 ++++++++++ src/core/sysir_x86.c | 40 +++++++++++++++++++++++++++++++---- 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8c341019..8202ec7d 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/examples/sysir/frontend.janet b/examples/sysir/frontend.janet index e8a96a2f..dfdde5d8 100644 --- a/examples/sysir/frontend.janet +++ b/examples/sysir/frontend.janet @@ -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) diff --git a/meson.build b/meson.build index 753173a1..5e7bc6d7 100644 --- a/meson.build +++ b/meson.build @@ -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', diff --git a/src/core/sysir.c b/src/core/sysir.c index d3c66fac..0db31a84 100644 --- a/src/core/sysir.c +++ b/src/core/sysir.c @@ -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); diff --git a/src/core/sysir_x86.c b/src/core/sysir_x86.c index a48fec5a..62aab717 100644 --- a/src/core/sysir_x86.c +++ b/src/core/sysir_x86.c @@ -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. }