aboutsummaryrefslogtreecommitdiff
path: root/to_assembly.c
blob: ab5c845e5e8d0b4b68945fad97a55dfde01ca8fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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);
		}
	}
}