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