-
Notifications
You must be signed in to change notification settings - Fork 2
/
codegen.c
117 lines (98 loc) · 3.24 KB
/
codegen.c
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "codegen.h"
#include "list.h"
#include "x86_64_codegen.h"
void _lruBump(struct codegen *cg, struct variable *var);
void codegen_init(struct codegen *cg, size_t registerCount) {
*cg = (struct codegen){};
dbuffer_init(&cg->buffer);
cg->registerCount = registerCount;
LIST_INIT(&cg->lruVariables);
cg->registerStatus = dzmalloc(sizeof(void *) * cg->registerCount);
}
void codegen_pushBlock(struct codegen *cg, label_t *label) {
label_setOffset(label, cg->buffer.usage);
}
void codegen_popBlock(struct codegen *cg) {
// spill dirty registers.
for (int i = 0; i < cg->registerCount; i++) {
struct variable *var = cg->registerStatus[i];
if (var == NULL)
continue;
variable_store(cg, cg->registerStatus[i]);
}
}
struct variable *codegen_newVarReg(struct codegen *cg, int reg) {
struct variable *var = nnew(struct variable);
var->reg = reg;
var->stackPos = -1; // no stack pos.
cg->registerStatus[reg] = var;
list_add(&cg->lruVariables, &var->list);
return var;
}
struct variable *codegen_newVar(struct codegen *cg) {
int reg = codegen_allocateReg(cg);
return codegen_newVarReg(cg, reg);
}
struct variable *codegen_newTmp(struct codegen *cg) {
struct variable *var = nnew(struct variable);
var->isTmp = 1;
var->reg = -1; // no reg.
var->stackPos = -1; // no stack pos.
}
void codegen_initFunction(struct codegen *cg, int argCount,
struct variable **vars) {
// TODO: Set arguments here !!
// setup variables here.
for (int i = 0; i < argCount; i++)
vars[i] = arch_initFunctionArg(cg, i);
}
// Backup the variable but keep it's registers.
/*
void variable_backup(struct codegen *cg, struct variable *var) {
if (var->stackPos < 0)
var->stackPos = ++cg->frameSize;
arch_spill(cg, var);
}
*/
void variable_store(struct codegen *cg, struct variable *var) {
// Allocate a new slot.
if (var->stackPos < 0)
var->stackPos = ++cg->frameSize;
// Remove from the lru list.
arch_spill(cg, var);
list_deattach(&var->list);
cg->registerStatus[var->reg] = NULL;
var->reg = -1;
}
int codegen_allocateReg(struct codegen *cg) {
for (int i = 0; i < cg->registerCount; i++) {
// Found a free register.
if (cg->registerStatus[i] == NULL)
return i;
}
// Free a register.
assert(cg->lruVariables.next != NULL && "invalid state");
struct variable *var =
containerof(cg->lruVariables.next, struct variable, list);
int reg = var->reg;
variable_store(cg, var);
return reg;
}
void _lruBump(struct codegen *cg, struct variable *var) {
list_deattach(&var->list);
list_add(&cg->lruVariables, &var->list);
}
// Get or allocate a register for a variable.
// The register allocator might free the register that this variable lives on
// at any time. This needs to be called every time variable is used.
int variable_ref(struct codegen *cg, struct variable *var) {
if (var->reg >= 0) {
_lruBump(cg, var);
return var->reg;
}
int result = var->reg = codegen_allocateReg(cg);
cg->registerStatus[result] = var;
arch_loadReg(cg, var);
list_add(&cg->lruVariables, &var->list);
return result;
}