#include #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); } } }