aboutsummaryrefslogtreecommitdiff
path: root/to_assembly.c
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2018-01-05 23:42:24 +0100
committertomsmeding <tom.smeding@gmail.com>2018-01-05 23:42:24 +0100
commit3272b5d83d2e2167eed24748557df88bd66584ee (patch)
tree6b8f1574f6d6a44e11b74903516286f6249cb0b7 /to_assembly.c
parenta298cb75c4f586b83b304c7dc66cb555693ea1b8 (diff)
There's actually a chance that, correctly stringified, this will work
Diffstat (limited to 'to_assembly.c')
-rw-r--r--to_assembly.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/to_assembly.c b/to_assembly.c
new file mode 100644
index 0000000..ab5c845
--- /dev/null
+++ b/to_assembly.c
@@ -0,0 +1,71 @@
+#include <string.h>
+#include "to_assembly.h"
+
+
+static bool is_function_label(const char *lbl) {
+ return memcmp(lbl, "__", 2) != 0;
+}
+
+static void fix_everything(struct ir *ir, const int startidx, struct allocation *ral) {
+ int spillspace = 0;
+
+ for (int idx = startidx + 1; idx < ir->len; idx++) {
+ struct irins *ins = ir->inss[idx];
+
+ if (ins->type == INS_LBL && is_function_label(ins->name)) break;
+
+ if (ins->type == INS_CALLV) {
+ ins->type = INS_CALL;
+ ir_insert_before(ir, idx + 1, irins_make_01(INS_MOV, ins->r0, ref_reg(REG_A)));
+ idx--;
+ continue;
+ }
+ if (ins->type == INS_RETV) {
+ ir_insert_before(ir, idx, irins_make_01(INS_MOV, ref_reg(REG_A), ins->r1));
+ ins->type = INS_RET;
+ idx--;
+ continue;
+ }
+
+ bool haveref[3];
+ irins_which_refs(ins, haveref);
+ for (int ri = 0; ri < 3; ri++) {
+ struct ref *ref = &ins->three_refs[ri];
+ if (haveref[ri] && ref->type == REF_REG && ref->reg >= 0) {
+ if (ral->allocs[ref->reg].spill) {
+ *ref = ref_mem(REG_BP, spillspace + 1, REFREL_ZERO);
+ spillspace++;
+ } else {
+ ref->reg = ral->allocs[ref->reg].reg;
+ }
+ }
+ }
+ }
+
+ if (spillspace == 0) return;
+
+ ir_insert_before(ir, startidx + 1, irins_make_1(INS_PUSH, ref_reg(REG_BP)));
+ ir_insert_before(ir, startidx + 2, irins_make_01(INS_MOV, ref_reg(REG_BP), ref_reg(REG_SP)));
+ ir_insert_before(ir, startidx + 3,
+ irins_make_012(INS_SUB, ref_reg(REG_SP), ref_reg(REG_SP), ref_imm(spillspace)));
+
+ for (int idx = startidx + 1; idx < ir->len; idx++) {
+ struct irins *ins = ir->inss[idx];
+
+ if (ins->type == INS_LBL && is_function_label(ins->name)) break;
+
+ if (ins->type == INS_RET) {
+ ir_insert_before(ir, idx++, irins_make_01(INS_MOV, ref_reg(REG_SP), ref_reg(REG_BP)));
+ ir_insert_before(ir, idx++, irins_make_0(INS_POP, ref_reg(REG_BP)));
+ continue;
+ }
+ }
+}
+
+void to_assembly(struct ir *ir, struct allocation *ral) {
+ for (int idx = 0; idx < ir->len; idx++) {
+ if (ir->inss[idx]->type == INS_LBL && is_function_label(ir->inss[idx]->name)) {
+ fix_everything(ir, idx, ral);
+ }
+ }
+}