12
12
* dead variable and does NOT wrtie it back to the stack.
13
13
*/
14
14
15
- #include <stdbool.h>
16
-
17
15
#include "defs.h"
18
16
#include "globals.c"
19
17
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
+
20
37
/* Aligns size to nearest multiple of 4, this meets ARMv7's alignment
21
38
* requirement.
22
39
*
@@ -45,6 +62,7 @@ void refresh(basic_block_t *bb, insn_t *insn)
45
62
if (check_live_out (bb , REGS [i ].var ))
46
63
continue ;
47
64
if (REGS [i ].var -> consumed < insn -> idx ) {
65
+ vreg_clear_phys (REGS [i ].var );
48
66
REGS [i ].var = NULL ;
49
67
REGS [i ].polluted = 0 ;
50
68
}
@@ -75,6 +93,46 @@ ph2_ir_t *bb_add_ph2_ir(basic_block_t *bb, opcode_t op)
75
93
return n ;
76
94
}
77
95
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
+
78
136
/* Priority of spilling:
79
137
* - live_out variable
80
138
* - farthest local variable
@@ -83,6 +141,7 @@ void spill_var(basic_block_t *bb, var_t *var, int idx)
83
141
{
84
142
if (!REGS [idx ].polluted ) {
85
143
REGS [idx ].var = NULL ;
144
+ vreg_clear_phys (var );
86
145
return ;
87
146
}
88
147
@@ -96,6 +155,7 @@ void spill_var(basic_block_t *bb, var_t *var, int idx)
96
155
ir -> src1 = var -> offset ;
97
156
REGS [idx ].var = NULL ;
98
157
REGS [idx ].polluted = 0 ;
158
+ vreg_clear_phys (var );
99
159
}
100
160
101
161
/* 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)
125
185
ir -> dest = idx ;
126
186
REGS [idx ].var = var ;
127
187
REGS [idx ].polluted = 0 ;
188
+ vreg_map_to_phys (var , idx );
128
189
}
129
190
130
191
int prepare_operand (basic_block_t * bb , var_t * var , int operand_0 )
131
192
{
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
+
132
198
/* Force reload for address-taken variables (may be modified via pointer) */
133
199
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 );
135
202
return i ;
203
+ }
136
204
137
205
for (i = 0 ; i < REG_CNT ; i ++ ) {
138
206
if (!REGS [i ].var ) {
139
207
load_var (bb , var , i );
208
+ vreg_map_to_phys (var , i );
140
209
return i ;
141
210
}
142
211
}
143
212
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
+ }
151
222
}
152
223
}
153
224
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 );
162
227
163
228
spill_var (bb , REGS [spilled ].var , spilled );
164
229
load_var (bb , var , spilled );
230
+ vreg_map_to_phys (var , spilled );
165
231
166
232
return spilled ;
167
233
}
168
234
169
235
int prepare_dest (basic_block_t * bb , var_t * var , int operand_0 , int operand_1 )
170
236
{
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
+
171
243
int i = find_in_regs (var );
172
244
if (i > -1 ) {
173
245
REGS [i ].polluted = 1 ;
246
+ vreg_map_to_phys (var , i );
174
247
return i ;
175
248
}
176
249
177
250
for (i = 0 ; i < REG_CNT ; i ++ ) {
178
251
if (!REGS [i ].var ) {
179
252
REGS [i ].var = var ;
180
253
REGS [i ].polluted = 1 ;
254
+ vreg_map_to_phys (var , i );
181
255
return i ;
182
256
}
183
257
}
184
258
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
+ }
195
269
}
196
270
}
197
271
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 );
209
274
}
210
275
211
276
spill_var (bb , REGS [spilled ].var , spilled );
212
277
REGS [spilled ].var = var ;
213
278
REGS [spilled ].polluted = 1 ;
279
+ vreg_map_to_phys (var , spilled );
214
280
215
281
return spilled ;
216
282
}
@@ -247,11 +313,13 @@ void spill_live_out(basic_block_t *bb)
247
313
if (!REGS [i ].var )
248
314
continue ;
249
315
if (!check_live_out (bb , REGS [i ].var )) {
316
+ vreg_clear_phys (REGS [i ].var );
250
317
REGS [i ].var = NULL ;
251
318
REGS [i ].polluted = 0 ;
252
319
continue ;
253
320
}
254
321
if (!var_check_killed (REGS [i ].var , bb )) {
322
+ vreg_clear_phys (REGS [i ].var );
255
323
REGS [i ].var = NULL ;
256
324
REGS [i ].polluted = 0 ;
257
325
continue ;
@@ -336,6 +404,7 @@ void reg_alloc(void)
336
404
spill_var (GLOBAL_FUNC -> bbs , global_insn -> rd , dest );
337
405
/* release the unused constant number in register manually */
338
406
REGS [src0 ].polluted = 0 ;
407
+ vreg_clear_phys (REGS [src0 ].var );
339
408
REGS [src0 ].var = NULL ;
340
409
break ;
341
410
case OP_add : {
@@ -565,8 +634,10 @@ void reg_alloc(void)
565
634
REGS [dest ].polluted = 0 ;
566
635
}
567
636
568
- if (clear_reg )
637
+ if (clear_reg ) {
638
+ vreg_clear_phys (REGS [src0 ].var );
569
639
REGS [src0 ].var = NULL ;
640
+ }
570
641
571
642
break ;
572
643
case OP_read :
0 commit comments