1 /* $Id: ra_pack.c,v 1.8 1994/06/24 10:27:56 ceriel Exp $ */
3 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4 * See the copyright notice in the ACK home directory, in the file "Copyright".
6 /* R E G I S T E R A L L O C A T I O N
12 #include "../share/types.h"
13 #include "../share/debug.h"
14 #include "../share/def.h"
15 #include "../share/global.h"
16 #include "../share/lset.h"
17 #include "../share/cset.h"
18 #include "../share/alloc.h"
19 #include "../share/aux.h"
22 #include "ra_interv.h"
25 short regs_occupied[NRREGTYPES]; /* #occupied registers for reg_pointer,
28 #define reg_available(t) (regs_available[t] > regs_occupied[t])
34 for (t = 0; t < NRREGTYPES; t++) {
39 STATIC alloc_p make_dummy()
44 /* x->al_profits = 0; */
49 STATIC bool fits_in(a,b,cont_item)
53 /* See if allocation a can be assigned the same register as b.
54 * Both allocations should be of the same register-type.
55 * Note that there may be several other allocations (mates) assigned to
56 * the same register as b. A new candidate (i.e. 'a') is only
57 * allowed to join them if it is not the rival of any resident
62 if (a->al_regtype == b->al_regtype) {
63 while (b != (alloc_p) 0) {
64 if (Cis_elem(a->al_id,b->al_rivals)) break;
66 if (b != (alloc_p) 0 && a->al_item == b->al_item) {
71 return b == (alloc_p) 0;
75 STATIC alloc_p find_fitting_alloc(alloc,packed)
78 /* Try to find and already packed allocation that is assigned
79 * a register that may also be used for alloc.
80 * We prefer allocations that have the same item as alloc.
84 alloc_p cand = (alloc_p) 0;
87 for (x = packed->al_next; x != (alloc_p) 0; x = x->al_next) {
88 if (fits_in(alloc,x,&cont_item)) {
97 STATIC bool room_for(alloc,packed)
100 /* See if there is any register available for alloc */
102 return reg_available(alloc->al_regtype) ||
103 (find_fitting_alloc(alloc,packed) != (alloc_p) 0);
108 STATIC alloc_p best_alloc(unpacked,packed,time_opt)
109 alloc_p unpacked,packed;
110 bool time_opt; /* now unused */
112 /* Find the next best candidate */
114 register alloc_p x,best;
116 best = unpacked; /* dummy */
118 for (x = unpacked->al_next; x != (alloc_p) 0; x = x->al_next) {
119 if (x->al_profits > best->al_profits &&
120 room_for(x,packed)) {
124 return (best == unpacked ? (alloc_p) 0 : best);
130 STATIC alloc_p choose_location(alloc,packed,p)
131 alloc_p alloc,packed;
134 /* Decide in which register to put alloc */
139 fit = find_fitting_alloc(alloc,packed);
140 if (fit == (alloc_p) 0) {
141 /* Take a brand new register; allocate a dummy local for it */
142 alloc->al_regnr = regs_occupied[alloc->al_regtype]++;
143 dum = tmplocal(p,(offset) alloc->al_item->it_size);
144 alloc->al_dummy = dum;
146 alloc->al_regnr = fit->al_regnr;
147 alloc->al_dummy = fit->al_dummy;
154 STATIC update_lists(alloc,unpacked,packed,fit)
155 alloc_p alloc,unpacked,packed,fit;
157 /* 'alloc' has been granted a register; move it from the 'unpacked'
158 * list to the 'packed' list. Also remove any allocation from 'unpacked'
160 * 1. the same item as 'alloc' and
161 * 2. a timespan that overlaps the timespan of alloc.
164 register alloc_p x,q,next;
166 q = unpacked; /* dummy element at head of list */
167 for (x = unpacked->al_next; x != (alloc_p) 0; x = next) {
169 if (x->al_item == alloc->al_item &&
170 not_disjoint(x->al_timespan, alloc->al_timespan)) {
171 /* this code kills two birds with one stone;
172 * x is either an overlapping allocation or
175 q->al_next = x->al_next;
177 if (fit == (alloc_p) 0) {
178 x->al_next = packed->al_next;
181 x->al_mates = fit->al_mates;
183 x->al_next = (alloc_p) 0;
194 STATIC short cum_profits(alloc)
197 /* Add the profits of all allocations packed in the same
198 * register as alloc (i.e. alloc and all its 'mates').
204 for (m = alloc; m != (alloc_p) 0; m = m->al_mates) {
205 sum += m->al_profits;
212 STATIC alloc_p best_cumprofits(list,x_out,prev_out)
213 alloc_p list, *x_out, *prev_out;
215 /* Find the allocation with the best cummulative profits */
217 register alloc_p x,prev,best_prev;
221 for (x = list->al_next; x != (alloc_p) 0; x = x->al_next) {
222 cum = cum_profits(x);
230 *x_out = (alloc_p) 0;
232 *x_out = best_prev->al_next;
233 *prev_out = best_prev;
239 STATIC account_regsave(packed,unpacked)
240 alloc_p packed,unpacked;
242 /* After all packing has been done, we check for every allocated
243 * register whether it is really advantageous to use this
244 * register. It may be possible that the cost of saving
245 * and restoring the register are higher than the profits of all
246 * allocations packed in the register. If so, we simply remove
247 * all these allocations.
248 * The cost of saving/restoring one extra register may depend on
249 * the number of registers already saved.
252 alloc_p x,prev,checked;
254 short tot_cost = 0,diff;
257 checked = make_dummy();
259 best_cumprofits(packed,&x,&prev);
260 if (x == (alloc_p) 0) break;
261 regs_occupied[x->al_regtype]++;
262 regsave_cost(regs_occupied,&time,&space);
263 diff = add_timespace(time,space) - tot_cost;
264 if (diff < cum_profits(x)) {
266 prev->al_next = x->al_next;
267 x->al_next = checked->al_next;
268 checked->al_next = x;
274 /* Now every allocation in 'packed' does not pay off, so
275 * it is moved to unpacked, indicating it will not be assigned
278 for (x = unpacked; x->al_next != (alloc_p) 0; x = x->al_next);
279 x->al_next = packed->al_next;
280 packed->al_next = checked->al_next;
286 STATIC bool in_single_reg(item,packed)
290 /* See if item is allocated in only one register (i.e. not in
291 * several different registers during several parts of its lifetime.
294 register alloc_p x,m;
297 for (x = packed->al_next; x != (alloc_p) 0; x = x->al_next) {
298 for ( m = x; m != (alloc_p) 0; m = m->al_mates) {
299 if (m->al_item == item) {
300 if (seen) return FALSE;
311 STATIC alloc_p find_prev(alloc,list)
316 assert ( alloc != (alloc_p) 0);
317 for (x = list; x->al_next != alloc ; x = x->al_next)
318 assert(x != (alloc_p) 0);
323 /* If an item is always put in the same register during different loops,
324 * we try to put it in that register during the whole procedure.
325 * The profits of the whole-procedure allocation are updated to prevent
326 * account_regsave from rejecting it.
329 STATIC repl_allocs(new,old,packed)
330 alloc_p new,old,packed;
332 alloc_p x,next,prev,*p;
335 new->al_regnr = old->al_regnr;
336 new->al_dummy = old->al_dummy;
337 prev = find_prev(old,packed);
338 new->al_next = old->al_next;
339 old->al_next = (alloc_p) 0;
343 for (x = old; x != (alloc_p) 0; x = next) {
345 if (x->al_item == new->al_item) {
346 prof += x->al_profits;
353 new->al_profits = prof;
358 STATIC assemble_allocs(packed)
361 register alloc_p x,m,next;
365 for (x = packed->al_next; x != (alloc_p) 0; x = next) {
367 for ( m = x; m != (alloc_p) 0; m = m->al_mates) {
368 if (in_single_reg(m->al_item,packed) &&
369 (e = m->al_wholeproc) != (alloc_p) 0 &&
371 fits_in(e,x,&voidb)) {
372 repl_allocs(e,x,packed);
379 pack(alloclist,time_opt,packed_out,not_packed_out,p)
380 alloc_p alloclist, *packed_out,*not_packed_out;
384 /* This is the packing system. It decides which allations
385 * to grant a register.
386 * We use two lists: packed (for allocations that are assigned a
387 * register) and unpacked (allocations not yet assigned a register).
388 * The packed list is in fact '2-dimensional': the al_next field is
389 * used to link allations that are assigned different registers;
390 * the al_mates field links allocations that are assigned to
391 * the same registers (i.e. these allocations fit together).
395 alloc_p packed,unpacked,fit;
398 packed = make_dummy();
399 unpacked = make_dummy();
400 unpacked->al_next = alloclist;
401 while ((x = best_alloc(unpacked,packed,time_opt)) != (alloc_p) 0) {
402 fit = choose_location(x,packed,p);
403 update_lists(x,unpacked,packed,fit);
405 assemble_allocs(packed);
406 account_regsave(packed,unpacked);
407 /* remove allocations that don't pay off against register
408 * save/restore costs.
410 *packed_out = packed->al_next;
411 *not_packed_out = unpacked->al_next;