Skip to content

Commit df4d771

Browse files
committed
Add VReg abstraction for O(1) register lookups
This commit introduces a Virtual Register (VReg) abstraction layer to improve register allocation efficiency: - Add phys_reg field to var_t for direct physical register mapping - Optimize prepare_operand() and prepare_dest() with O(1) lookups - Eliminate redundant linear register searches
1 parent ee97fef commit df4d771

File tree

3 files changed

+115
-41
lines changed

3 files changed

+115
-41
lines changed

src/defs.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,10 @@ struct var {
370370
int consumed;
371371
bool is_ternary_ret;
372372
bool is_logical_ret;
373-
bool is_const; /* whether a constant representaion or not */
373+
bool is_const; /* whether a constant representaion or not */
374+
int vreg_id; /* Virtual register ID */
375+
int phys_reg; /* Physical register assignment (-1 if unassigned) */
376+
int vreg_flags; /* VReg flags */
374377
};
375378

376379
typedef struct {

src/parser.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ var_t *require_var(block_t *blk)
6363
var_t *var = arena_calloc(BLOCK_ARENA, 1, sizeof(var_t));
6464
var_list->elements[var_list->size++] = var;
6565
var->consumed = -1;
66+
var->phys_reg = -1;
6667
var->base = var;
6768
var->type = TY_int;
6869
return var;

src/reg-alloc.c

Lines changed: 110 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,28 @@
1212
* dead variable and does NOT wrtie it back to the stack.
1313
*/
1414

15-
#include <stdbool.h>
16-
1715
#include "defs.h"
1816
#include "globals.c"
1917

18+
void vreg_map_to_phys(var_t *var, int phys_reg)
19+
{
20+
if (var)
21+
var->phys_reg = phys_reg;
22+
}
23+
24+
int vreg_get_phys(var_t *var)
25+
{
26+
if (var)
27+
return var->phys_reg;
28+
return -1;
29+
}
30+
31+
void vreg_clear_phys(var_t *var)
32+
{
33+
if (var)
34+
var->phys_reg = -1;
35+
}
36+
2037
/* Aligns size to nearest multiple of 4, this meets ARMv7's alignment
2138
* requirement.
2239
*
@@ -45,6 +62,7 @@ void refresh(basic_block_t *bb, insn_t *insn)
4562
if (check_live_out(bb, REGS[i].var))
4663
continue;
4764
if (REGS[i].var->consumed < insn->idx) {
65+
vreg_clear_phys(REGS[i].var);
4866
REGS[i].var = NULL;
4967
REGS[i].polluted = 0;
5068
}
@@ -75,6 +93,46 @@ ph2_ir_t *bb_add_ph2_ir(basic_block_t *bb, opcode_t op)
7593
return n;
7694
}
7795

96+
int calculate_spill_cost(var_t *var, basic_block_t *bb, int current_idx)
97+
{
98+
if (check_live_out(bb, var))
99+
return 1000;
100+
101+
if (var->consumed > current_idx) {
102+
int distance = var->consumed - current_idx;
103+
if (distance < 10)
104+
return 100 - distance * 10;
105+
}
106+
107+
return 0;
108+
}
109+
110+
int find_best_spill(basic_block_t *bb,
111+
int current_idx,
112+
int avoid_reg1,
113+
int avoid_reg2)
114+
{
115+
int best_reg = -1;
116+
int min_cost = 99999;
117+
118+
for (int i = 0; i < REG_CNT; i++) {
119+
if (i == avoid_reg1 || i == avoid_reg2)
120+
continue;
121+
122+
if (!REGS[i].var)
123+
continue;
124+
125+
int cost = calculate_spill_cost(REGS[i].var, bb, current_idx);
126+
127+
if (cost < min_cost) {
128+
min_cost = cost;
129+
best_reg = i;
130+
}
131+
}
132+
133+
return best_reg;
134+
}
135+
78136
/* Priority of spilling:
79137
* - live_out variable
80138
* - farthest local variable
@@ -83,6 +141,7 @@ void spill_var(basic_block_t *bb, var_t *var, int idx)
83141
{
84142
if (!REGS[idx].polluted) {
85143
REGS[idx].var = NULL;
144+
vreg_clear_phys(var);
86145
return;
87146
}
88147

@@ -96,6 +155,7 @@ void spill_var(basic_block_t *bb, var_t *var, int idx)
96155
ir->src1 = var->offset;
97156
REGS[idx].var = NULL;
98157
REGS[idx].polluted = 0;
158+
vreg_clear_phys(var);
99159
}
100160

101161
/* Return the index of register for given variable. Otherwise, return -1. */
@@ -116,91 +176,96 @@ void load_var(basic_block_t *bb, var_t *var, int idx)
116176
ir->dest = idx;
117177
REGS[idx].var = var;
118178
REGS[idx].polluted = 0;
179+
vreg_map_to_phys(var, idx);
119180
}
120181

121182
int prepare_operand(basic_block_t *bb, var_t *var, int operand_0)
122183
{
184+
int phys_reg = vreg_get_phys(var);
185+
if (phys_reg >= 0 && phys_reg < REG_CNT && REGS[phys_reg].var == var)
186+
return phys_reg;
187+
123188
int i = find_in_regs(var);
124-
if (i > -1)
189+
if (i > -1) {
190+
vreg_map_to_phys(var, i);
125191
return i;
192+
}
126193

127194
for (i = 0; i < REG_CNT; i++) {
128195
if (!REGS[i].var) {
129196
load_var(bb, var, i);
197+
vreg_map_to_phys(var, i);
130198
return i;
131199
}
132200
}
133201

134-
for (i = 0; i < REG_CNT; i++) {
135-
if (i == operand_0)
136-
continue;
137-
if (check_live_out(bb, REGS[i].var)) {
138-
spill_var(bb, REGS[i].var, i);
139-
load_var(bb, var, i);
140-
return i;
202+
int spilled = find_best_spill(
203+
bb, bb->insn_list.tail ? bb->insn_list.tail->idx : 0, operand_0, -1);
204+
205+
if (spilled < 0) {
206+
for (i = 0; i < REG_CNT; i++) {
207+
if (i != operand_0 && REGS[i].var) {
208+
spilled = i;
209+
break;
210+
}
141211
}
142212
}
143213

144-
/* spill farthest local */
145-
int spilled = 0;
146-
for (i = 0; i < REG_CNT; i++) {
147-
if (!REGS[i].var)
148-
continue;
149-
if (REGS[i].var->consumed > REGS[spilled].var->consumed)
150-
spilled = i;
151-
}
214+
if (REGS[spilled].var)
215+
vreg_clear_phys(REGS[spilled].var);
152216

153217
spill_var(bb, REGS[spilled].var, spilled);
154218
load_var(bb, var, spilled);
219+
vreg_map_to_phys(var, spilled);
155220

156221
return spilled;
157222
}
158223

159224
int prepare_dest(basic_block_t *bb, var_t *var, int operand_0, int operand_1)
160225
{
226+
int phys_reg = vreg_get_phys(var);
227+
if (phys_reg >= 0 && phys_reg < REG_CNT && REGS[phys_reg].var == var) {
228+
REGS[phys_reg].polluted = 1;
229+
return phys_reg;
230+
}
231+
161232
int i = find_in_regs(var);
162233
if (i > -1) {
163234
REGS[i].polluted = 1;
235+
vreg_map_to_phys(var, i);
164236
return i;
165237
}
166238

167239
for (i = 0; i < REG_CNT; i++) {
168240
if (!REGS[i].var) {
169241
REGS[i].var = var;
170242
REGS[i].polluted = 1;
243+
vreg_map_to_phys(var, i);
171244
return i;
172245
}
173246
}
174247

175-
for (i = 0; i < REG_CNT; i++) {
176-
if (i == operand_0)
177-
continue;
178-
if (i == operand_1)
179-
continue;
180-
if (check_live_out(bb, REGS[i].var)) {
181-
spill_var(bb, REGS[i].var, i);
182-
REGS[i].var = var;
183-
REGS[i].polluted = 1;
184-
return i;
248+
int spilled =
249+
find_best_spill(bb, bb->insn_list.tail ? bb->insn_list.tail->idx : 0,
250+
operand_0, operand_1);
251+
252+
if (spilled < 0) {
253+
for (i = 0; i < REG_CNT; i++) {
254+
if (i != operand_0 && i != operand_1 && REGS[i].var) {
255+
spilled = i;
256+
break;
257+
}
185258
}
186259
}
187260

188-
/* spill farthest local */
189-
int spilled = 0;
190-
for (i = 0; i < REG_CNT; i++) {
191-
if (i == operand_0)
192-
continue;
193-
if (i == operand_1)
194-
continue;
195-
if (!REGS[i].var)
196-
continue;
197-
if (REGS[i].var->consumed > REGS[spilled].var->consumed)
198-
spilled = i;
261+
if (REGS[spilled].var) {
262+
vreg_clear_phys(REGS[spilled].var);
199263
}
200264

201265
spill_var(bb, REGS[spilled].var, spilled);
202266
REGS[spilled].var = var;
203267
REGS[spilled].polluted = 1;
268+
vreg_map_to_phys(var, spilled);
204269

205270
return spilled;
206271
}
@@ -227,11 +292,13 @@ void spill_live_out(basic_block_t *bb)
227292
if (!REGS[i].var)
228293
continue;
229294
if (!check_live_out(bb, REGS[i].var)) {
295+
vreg_clear_phys(REGS[i].var);
230296
REGS[i].var = NULL;
231297
REGS[i].polluted = 0;
232298
continue;
233299
}
234300
if (!var_check_killed(REGS[i].var, bb)) {
301+
vreg_clear_phys(REGS[i].var);
235302
REGS[i].var = NULL;
236303
REGS[i].polluted = 0;
237304
continue;
@@ -316,6 +383,7 @@ void reg_alloc(void)
316383
spill_var(GLOBAL_FUNC->bbs, global_insn->rd, dest);
317384
/* release the unused constant number in register manually */
318385
REGS[src0].polluted = 0;
386+
vreg_clear_phys(REGS[src0].var);
319387
REGS[src0].var = NULL;
320388
break;
321389
case OP_add: {
@@ -539,8 +607,10 @@ void reg_alloc(void)
539607
REGS[dest].polluted = 0;
540608
}
541609

542-
if (clear_reg)
610+
if (clear_reg) {
611+
vreg_clear_phys(REGS[src0].var);
543612
REGS[src0].var = NULL;
613+
}
544614

545615
break;
546616
case OP_read:

0 commit comments

Comments
 (0)