Skip to content

Commit ee6d834

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 1611d23 commit ee6d834

File tree

3 files changed

+116
-41
lines changed

3 files changed

+116
-41
lines changed

src/defs.h

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

377380
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: 111 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. */
@@ -125,92 +185,98 @@ void load_var(basic_block_t *bb, var_t *var, int idx)
125185
ir->dest = idx;
126186
REGS[idx].var = var;
127187
REGS[idx].polluted = 0;
188+
vreg_map_to_phys(var, idx);
128189
}
129190

130191
int prepare_operand(basic_block_t *bb, var_t *var, int operand_0)
131192
{
193+
/* Check VReg mapping first for O(1) lookup */
194+
int phys_reg = vreg_get_phys(var);
195+
if (phys_reg >= 0 && phys_reg < REG_CNT && REGS[phys_reg].var == var)
196+
return phys_reg;
197+
132198
/* Force reload for address-taken variables (may be modified via pointer) */
133199
int i = find_in_regs(var);
134-
if (i > -1 && !var->address_taken)
200+
if (i > -1 && !var->address_taken) {
201+
vreg_map_to_phys(var, i);
135202
return i;
203+
}
136204

137205
for (i = 0; i < REG_CNT; i++) {
138206
if (!REGS[i].var) {
139207
load_var(bb, var, i);
208+
vreg_map_to_phys(var, i);
140209
return i;
141210
}
142211
}
143212

144-
for (i = 0; i < REG_CNT; i++) {
145-
if (i == operand_0)
146-
continue;
147-
if (check_live_out(bb, REGS[i].var)) {
148-
spill_var(bb, REGS[i].var, i);
149-
load_var(bb, var, i);
150-
return i;
213+
int spilled = find_best_spill(
214+
bb, bb->insn_list.tail ? bb->insn_list.tail->idx : 0, operand_0, -1);
215+
216+
if (spilled < 0) {
217+
for (i = 0; i < REG_CNT; i++) {
218+
if (i != operand_0 && REGS[i].var) {
219+
spilled = i;
220+
break;
221+
}
151222
}
152223
}
153224

154-
/* spill farthest local */
155-
int spilled = 0;
156-
for (i = 0; i < REG_CNT; i++) {
157-
if (!REGS[i].var)
158-
continue;
159-
if (REGS[i].var->consumed > REGS[spilled].var->consumed)
160-
spilled = i;
161-
}
225+
if (REGS[spilled].var)
226+
vreg_clear_phys(REGS[spilled].var);
162227

163228
spill_var(bb, REGS[spilled].var, spilled);
164229
load_var(bb, var, spilled);
230+
vreg_map_to_phys(var, spilled);
165231

166232
return spilled;
167233
}
168234

169235
int prepare_dest(basic_block_t *bb, var_t *var, int operand_0, int operand_1)
170236
{
237+
int phys_reg = vreg_get_phys(var);
238+
if (phys_reg >= 0 && phys_reg < REG_CNT && REGS[phys_reg].var == var) {
239+
REGS[phys_reg].polluted = 1;
240+
return phys_reg;
241+
}
242+
171243
int i = find_in_regs(var);
172244
if (i > -1) {
173245
REGS[i].polluted = 1;
246+
vreg_map_to_phys(var, i);
174247
return i;
175248
}
176249

177250
for (i = 0; i < REG_CNT; i++) {
178251
if (!REGS[i].var) {
179252
REGS[i].var = var;
180253
REGS[i].polluted = 1;
254+
vreg_map_to_phys(var, i);
181255
return i;
182256
}
183257
}
184258

185-
for (i = 0; i < REG_CNT; i++) {
186-
if (i == operand_0)
187-
continue;
188-
if (i == operand_1)
189-
continue;
190-
if (check_live_out(bb, REGS[i].var)) {
191-
spill_var(bb, REGS[i].var, i);
192-
REGS[i].var = var;
193-
REGS[i].polluted = 1;
194-
return i;
259+
int spilled =
260+
find_best_spill(bb, bb->insn_list.tail ? bb->insn_list.tail->idx : 0,
261+
operand_0, operand_1);
262+
263+
if (spilled < 0) {
264+
for (i = 0; i < REG_CNT; i++) {
265+
if (i != operand_0 && i != operand_1 && REGS[i].var) {
266+
spilled = i;
267+
break;
268+
}
195269
}
196270
}
197271

198-
/* spill farthest local */
199-
int spilled = 0;
200-
for (i = 0; i < REG_CNT; i++) {
201-
if (i == operand_0)
202-
continue;
203-
if (i == operand_1)
204-
continue;
205-
if (!REGS[i].var)
206-
continue;
207-
if (REGS[i].var->consumed > REGS[spilled].var->consumed)
208-
spilled = i;
272+
if (REGS[spilled].var) {
273+
vreg_clear_phys(REGS[spilled].var);
209274
}
210275

211276
spill_var(bb, REGS[spilled].var, spilled);
212277
REGS[spilled].var = var;
213278
REGS[spilled].polluted = 1;
279+
vreg_map_to_phys(var, spilled);
214280

215281
return spilled;
216282
}
@@ -247,11 +313,13 @@ void spill_live_out(basic_block_t *bb)
247313
if (!REGS[i].var)
248314
continue;
249315
if (!check_live_out(bb, REGS[i].var)) {
316+
vreg_clear_phys(REGS[i].var);
250317
REGS[i].var = NULL;
251318
REGS[i].polluted = 0;
252319
continue;
253320
}
254321
if (!var_check_killed(REGS[i].var, bb)) {
322+
vreg_clear_phys(REGS[i].var);
255323
REGS[i].var = NULL;
256324
REGS[i].polluted = 0;
257325
continue;
@@ -336,6 +404,7 @@ void reg_alloc(void)
336404
spill_var(GLOBAL_FUNC->bbs, global_insn->rd, dest);
337405
/* release the unused constant number in register manually */
338406
REGS[src0].polluted = 0;
407+
vreg_clear_phys(REGS[src0].var);
339408
REGS[src0].var = NULL;
340409
break;
341410
case OP_add: {
@@ -565,8 +634,10 @@ void reg_alloc(void)
565634
REGS[dest].polluted = 0;
566635
}
567636

568-
if (clear_reg)
637+
if (clear_reg) {
638+
vreg_clear_phys(REGS[src0].var);
569639
REGS[src0].var = NULL;
640+
}
570641

571642
break;
572643
case OP_read:

0 commit comments

Comments
 (0)