sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 1 | |
| 2 | /*---------------------------------------------------------------*/ |
| 3 | /*--- ---*/ |
| 4 | /*--- This file (reg_alloc.c) is ---*/ |
| 5 | /*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ |
| 6 | /*--- ---*/ |
| 7 | /*---------------------------------------------------------------*/ |
| 8 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 9 | #include <stdio.h> |
| 10 | #include <malloc.h> |
| 11 | |
| 12 | #include "basictypes.h" |
| 13 | #include "host_regs.h" |
| 14 | |
| 15 | |
| 16 | /* How many 64-bit sized spill slots do we have? */ |
| 17 | #define N_SPILL64S 16 |
| 18 | |
| 19 | |
sewardj | 968396e | 2004-07-03 14:50:33 +0000 | [diff] [blame^] | 20 | /* TODO (critical) |
| 21 | - Need a way to statically establish the vreg classes, |
| 22 | else we can't allocate spill slots properly. |
| 23 | - Better consistency checking from what isMove tells us. |
| 24 | */ |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 25 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 26 | |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 27 | /* Records information on virtual register live ranges. Computed once |
| 28 | and remains unchanged after that. */ |
| 29 | typedef |
| 30 | struct { |
| 31 | /* Becomes live for the first time after this insn ... */ |
| 32 | Int live_after; |
| 33 | /* Becomes dead for the last time before this insn ... */ |
| 34 | Int dead_before; |
| 35 | /* The "home" spill slot, if needed. Never changes. */ |
| 36 | Int spill_offset; |
| 37 | Int spill_size; |
| 38 | /* Preferencing info, if any. */ |
| 39 | Bool has_preference; |
| 40 | HReg preferred_rreg; /* if True, where I would like to be */ |
| 41 | } |
| 42 | VRegInfo; |
| 43 | |
| 44 | |
| 45 | /* Records information on real-register live ranges. Computed once |
| 46 | and remains unchanged after that. */ |
| 47 | typedef |
| 48 | struct { |
| 49 | HReg rreg; |
| 50 | /* Becomes live after this insn ... */ |
| 51 | Int live_after; |
| 52 | /* Becomes dead before this insn ... */ |
| 53 | Int dead_before; |
| 54 | } |
| 55 | RRegInfo; |
| 56 | |
| 57 | |
| 58 | /* An array of the following structs comprises the running state of |
| 59 | the allocator. It indicates what the current disposition of each |
| 60 | allocatable real register is. The array gets updated as the |
| 61 | allocator processes instructions. */ |
| 62 | typedef |
| 63 | struct { |
| 64 | /* Which rreg is this for? */ |
| 65 | HReg rreg; |
| 66 | /* What's it's current disposition? */ |
| 67 | enum { Free, /* available for use */ |
| 68 | Unavail, /* in a real-reg live range */ |
| 69 | Bound /* in use (holding value of some vreg) */ |
| 70 | } |
| 71 | disp; |
| 72 | /* If RRegBound, what vreg is it bound to? */ |
| 73 | HReg vreg; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 74 | /* Used when .disp == Bound and we are looking for vregs to |
| 75 | spill. */ |
| 76 | Bool is_spill_cand; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 77 | } |
| 78 | RRegState; |
| 79 | |
| 80 | |
| 81 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 82 | /* Does this instruction mention a particular reg? */ |
| 83 | static Bool instrMentionsReg ( |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 84 | void (*getRegUsage) (HRegUsage*, HInstr*), |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 85 | HInstr* instr, |
| 86 | HReg r |
| 87 | ) |
| 88 | { |
| 89 | Int i; |
| 90 | HRegUsage reg_usage; |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 91 | (*getRegUsage)(®_usage, instr); |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 92 | for (i = 0; i < reg_usage.n_used; i++) |
| 93 | if (reg_usage.hreg[i] == r) |
| 94 | return True; |
| 95 | return False; |
| 96 | } |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 97 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 98 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 99 | /* Search forward from some given point in the incoming instruction |
| 100 | sequence. Point is to select a virtual register to spill, by |
| 101 | finding the vreg which is mentioned as far ahead as possible, in |
| 102 | the hope that this will minimise the number of consequent reloads. |
| 103 | |
| 104 | Only do the search for vregs which are Bound in the running state, |
| 105 | and for which the .mark field is set. This allows the caller to |
| 106 | arbitrarily restrict the set of spill candidates to be considered. |
| 107 | |
| 108 | Returns an index into the state array indicating the (v,r) pair to |
| 109 | spill, or -1 if none was found. */ |
| 110 | static |
| 111 | Int findMostDistantlyMentionedVReg ( |
| 112 | void (*getRegUsage) (HRegUsage*, HInstr*), |
| 113 | HInstrArray* instrs_in, |
| 114 | Int search_from_instr, |
| 115 | RRegState* state, |
| 116 | Int n_state |
| 117 | ) |
| 118 | { |
| 119 | Int k, m; |
| 120 | Int furthest_k = -1; |
| 121 | Int furthest = -1; |
| 122 | assert(search_from_instr >= 0); |
| 123 | for (k = 0; k < n_state; k++) { |
| 124 | if (!state[k].is_spill_cand) |
| 125 | continue; |
| 126 | assert(state[k].disp == Bound); |
| 127 | for (m = search_from_instr; m < instrs_in->arr_used; m++) { |
| 128 | if (instrMentionsReg(getRegUsage, |
| 129 | instrs_in->arr[m], state[k].vreg)) |
| 130 | break; |
| 131 | } |
| 132 | if (m > furthest) { |
| 133 | furthest = m; |
| 134 | furthest_k = k; |
| 135 | } |
| 136 | } |
| 137 | return furthest_k; |
| 138 | } |
| 139 | |
| 140 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 141 | /* A target-independent register allocator for Valgrind. Requires |
| 142 | various functions which it uses to deal abstractly with |
| 143 | instructions and registers, since it cannot have any |
| 144 | target-specific knowledge. |
| 145 | |
| 146 | Returns a new list of instructions, which, as a result of the |
| 147 | behaviour of mapRegs, will be in-place modifications of the |
| 148 | original instructions. |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 149 | |
| 150 | Requires that the incoming code has been generated using |
| 151 | vreg numbers 0, 1 .. n_vregs-1. Appearance of a vreg outside |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 152 | that range is a checked run-time error. |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 153 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 154 | Takes an expandable array of pointers to unallocated insns. |
| 155 | Returns an expandable array of pointers to allocated insns. |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 156 | */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 157 | HInstrArray* doRegisterAllocation ( |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 158 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 159 | /* Incoming virtual-registerised code. */ |
| 160 | HInstrArray* instrs_in, |
| 161 | Int n_vregs, |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 162 | |
| 163 | /* An array listing all the real registers the allocator may use, |
| 164 | in no particular order. */ |
| 165 | HReg* available_real_regs, |
| 166 | Int n_available_real_regs, |
| 167 | |
| 168 | /* Return True iff the given insn is a reg-reg move, in which |
| 169 | case also return the src and dst regs. */ |
| 170 | Bool (*isMove) (HInstr*, HReg*, HReg*), |
| 171 | |
| 172 | /* Get info about register usage in this insn. */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 173 | void (*getRegUsage) (HRegUsage*, HInstr*), |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 174 | |
| 175 | /* Apply a reg-reg mapping to an insn. */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 176 | void (*mapRegs) (HRegRemap*, HInstr*), |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 177 | |
| 178 | /* Return an insn to spill/restore a real reg to a spill slot |
| 179 | offset. */ |
| 180 | HInstr* (*genSpill) ( HReg, Int ), |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 181 | HInstr* (*genReload) ( HReg, Int ) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 182 | ) |
| 183 | { |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 184 | /* Iterators and temporaries. */ |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 185 | Int ii, j, k, m, spillee; |
sewardj | 968396e | 2004-07-03 14:50:33 +0000 | [diff] [blame^] | 186 | HReg rreg, vreg, vregS, vregD; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 187 | HRegUsage reg_usage; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 188 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 189 | /* Info on vregs and rregs. Computed once and remains |
| 190 | unchanged. */ |
| 191 | VRegInfo* vreg_info; |
| 192 | RRegInfo* rreg_info; |
| 193 | Int rreg_info_size; |
| 194 | Int rreg_info_used; |
| 195 | |
| 196 | /* Used when constructing vreg_info (for allocating stack |
| 197 | slots). */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 198 | Int ss_busy_until_before[N_SPILL64S]; |
| 199 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 200 | /* Used when constructing rreg_info. */ |
| 201 | Int* rreg_live_after; |
| 202 | Int* rreg_dead_before; |
| 203 | |
| 204 | /* Running state of the core allocation algorithm. */ |
| 205 | RRegState* state; |
| 206 | Int n_state; |
| 207 | |
| 208 | /* The vreg -> rreg map constructed and then applied to each |
| 209 | instr. */ |
| 210 | HRegRemap remap; |
| 211 | |
| 212 | /* The output array of instructions. */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 213 | HInstrArray* instrs_out; |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 214 | |
| 215 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 216 | # define INVALID_INSTRNO (-2) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 217 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 218 | # define EMIT_INSTR(_instr) \ |
| 219 | do { \ |
| 220 | HInstr* _tmp = (_instr); \ |
| 221 | if (1) { \ |
| 222 | fprintf(stdout, "** "); \ |
| 223 | ppX86Instr(stdout, _tmp); \ |
| 224 | fprintf(stdout, "\n"); \ |
| 225 | } \ |
| 226 | addHInstr ( instrs_out, _tmp ); \ |
| 227 | } while (0) |
| 228 | |
| 229 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 230 | /* --------- Stage 0: set up output array. --------- */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 231 | instrs_out = newHInstrArray(); |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 232 | |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 233 | |
| 234 | /* --------- Stage 1: compute vreg live ranges. --------- */ |
| 235 | |
| 236 | /* This is relatively simple, because (1) we only seek the complete |
| 237 | end-to-end live range of each vreg, and are not interested in |
| 238 | any holes in it, and (2) the vregs are conveniently numbered 0 |
| 239 | .. n_vregs-1, so we can just dump the results in a pre-allocated |
| 240 | array. */ |
| 241 | |
| 242 | vreg_info = NULL; |
| 243 | if (n_vregs > 0) |
| 244 | vreg_info = malloc(sizeof(VRegInfo) * n_vregs); |
| 245 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 246 | for (j = 0; j < n_vregs; j++) { |
| 247 | vreg_info[j].live_after = INVALID_INSTRNO; |
| 248 | vreg_info[j].dead_before = INVALID_INSTRNO; |
| 249 | vreg_info[j].spill_offset = 0; |
| 250 | vreg_info[j].spill_size = 0; |
| 251 | vreg_info[j].has_preference = False; |
| 252 | vreg_info[j].preferred_rreg = INVALID_HREG; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 253 | } |
| 254 | |
| 255 | /* for each insn ... */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 256 | for (ii = 0; ii < instrs_in->arr_used; ii++) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 257 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 258 | (*getRegUsage)( ®_usage, instrs_in->arr[ii] ); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 259 | |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 260 | fprintf(stdout, "\n%d stage1: ", ii); |
| 261 | ppX86Instr(stdout, instrs_in->arr[ii]); |
| 262 | fprintf(stdout, "\n"); |
| 263 | ppHRegUsage(stdout, ®_usage); |
| 264 | |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 265 | /* for each reg mentioned in the insn ... */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 266 | for (j = 0; j < reg_usage.n_used; j++) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 267 | |
| 268 | /* only interested in virtual registers right now. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 269 | if (!hregIsVirtual(reg_usage.hreg[j])) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 270 | continue; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 271 | k = hregNumber(reg_usage.hreg[j]); |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 272 | if (k < 0 || k >= n_vregs) |
| 273 | panic("doRegisterAllocation: out-of-range vreg"); |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 274 | switch (reg_usage.mode[j]) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 275 | case HRmRead: |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 276 | if (vreg_info[k].live_after == INVALID_INSTRNO) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 277 | panic("doRegisterAllocation: " |
| 278 | "first event for vreg is Read"); |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 279 | vreg_info[k].dead_before = ii; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 280 | break; |
| 281 | case HRmWrite: |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 282 | if (vreg_info[k].live_after == INVALID_INSTRNO) |
| 283 | vreg_info[k].live_after = ii; |
| 284 | vreg_info[k].dead_before = ii + 1; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 285 | break; |
| 286 | case HRmModify: |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 287 | if (vreg_info[k].live_after == INVALID_INSTRNO) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 288 | panic("doRegisterAllocation: " |
| 289 | "first event for vreg is Modify"); |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 290 | vreg_info[k].dead_before = ii + 1; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 291 | break; |
| 292 | default: |
| 293 | panic("doRegisterAllocation(1)"); |
| 294 | } /* switch */ |
| 295 | |
| 296 | } /* iterate over registers */ |
| 297 | |
| 298 | } /* iterate over insns */ |
| 299 | |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 300 | for (j = 0; j < n_vregs; j++) { |
| 301 | fprintf(stdout, "vreg %d: la = %d, db = %d\n", |
| 302 | j, vreg_info[j].live_after, vreg_info[j].dead_before ); |
| 303 | } |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 304 | |
| 305 | /* --------- Stage 2: compute rreg live ranges. --------- */ |
| 306 | |
| 307 | /* This is more complex than Stage 1, because we need to compute |
| 308 | exactly all the live ranges of all the allocatable real regs, |
| 309 | and we don't know in advance how many there will be. */ |
| 310 | |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 311 | rreg_info_used = 0; |
| 312 | rreg_info_size = 4; |
| 313 | rreg_info = malloc(rreg_info_size * sizeof(RRegInfo)); |
| 314 | |
| 315 | /* We'll need to track live range start/end points seperately for |
| 316 | each rreg. Sigh. */ |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 317 | assert(n_available_real_regs > 0); |
| 318 | rreg_live_after = malloc(n_available_real_regs * sizeof(Int)); |
| 319 | rreg_dead_before = malloc(n_available_real_regs * sizeof(Int)); |
| 320 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 321 | for (j = 0; j < n_available_real_regs; j++) |
| 322 | rreg_live_after[j] = |
| 323 | rreg_dead_before[j] = INVALID_INSTRNO; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 324 | |
| 325 | /* for each insn ... */ |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 326 | for (ii = 0; ii < instrs_in->arr_used; ii++) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 327 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 328 | (*getRegUsage)( ®_usage, instrs_in->arr[ii] ); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 329 | |
| 330 | /* for each reg mentioned in the insn ... */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 331 | for (j = 0; j < reg_usage.n_used; j++) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 332 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 333 | /* Dummy initialisations of flush_la and flush_db to avoid |
| 334 | possible bogus uninit-var warnings from gcc. */ |
| 335 | Int flush_la = INVALID_INSTRNO, flush_db = INVALID_INSTRNO; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 336 | Bool flush; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 337 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 338 | rreg = reg_usage.hreg[j]; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 339 | |
| 340 | /* only interested in real registers right now. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 341 | if (hregIsVirtual(rreg)) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 342 | continue; |
| 343 | |
| 344 | /* Furthermore, we're not interested in this rreg unless it's |
| 345 | one of the allocatable ones. For example, it could be a |
| 346 | stack pointer register, or some other register beyond our |
| 347 | control, in which case we should just ignore it. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 348 | for (k = 0; k < n_available_real_regs; k++) |
| 349 | if (available_real_regs[k] == rreg) |
| 350 | break; |
| 351 | if (k == n_available_real_regs) |
| 352 | continue; /* not found -- ignore. */ |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 353 | flush = False; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 354 | switch (reg_usage.mode[j]) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 355 | case HRmWrite: |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 356 | flush_la = rreg_live_after[k]; |
| 357 | flush_db = rreg_dead_before[k]; |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 358 | if (flush_la != INVALID_INSTRNO |
| 359 | && flush_db != INVALID_INSTRNO) |
| 360 | flush = True; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 361 | rreg_live_after[k] = ii; |
| 362 | rreg_dead_before[k] = ii+1; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 363 | break; |
| 364 | case HRmRead: |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 365 | if (rreg_live_after[k] == INVALID_INSTRNO) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 366 | panic("doRegisterAllocation: " |
| 367 | "first event for rreg is Read"); |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 368 | rreg_dead_before[k] = ii; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 369 | break; |
| 370 | case HRmModify: |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 371 | if (rreg_live_after[k] == INVALID_INSTRNO) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 372 | panic("doRegisterAllocation: " |
| 373 | "first event for rreg is Modify"); |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 374 | rreg_dead_before[k] = ii+1; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 375 | break; |
| 376 | default: |
| 377 | panic("doRegisterAllocation(2)"); |
| 378 | } |
| 379 | |
| 380 | if (flush) { |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 381 | assert(flush_la != INVALID_INSTRNO); |
| 382 | assert(flush_db != INVALID_INSTRNO); |
| 383 | printf("FLUSH 1 (%d,%d)\n", flush_la, flush_db); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 384 | if (rreg_info_used == rreg_info_size) { |
| 385 | panic("make rreg info array bigger(1)"); |
| 386 | } |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 387 | rreg_info[rreg_info_used].rreg = rreg; |
| 388 | rreg_info[rreg_info_used].live_after = flush_la; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 389 | rreg_info[rreg_info_used].dead_before = flush_db; |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 390 | rreg_info_used++; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 391 | } |
| 392 | |
| 393 | } /* iterate over regs in the instr */ |
| 394 | |
| 395 | } /* iterate over instrs */ |
| 396 | |
| 397 | /* Now finish up any live ranges left over. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 398 | for (j = 0; j < n_available_real_regs; j++) { |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 399 | |
| 400 | # if 0 |
| 401 | printf("residual %d: %d %d\n", j, rreg_live_after[j], |
| 402 | rreg_dead_before[j]); |
| 403 | # endif |
| 404 | assert( (rreg_live_after[j] == INVALID_INSTRNO |
| 405 | && rreg_dead_before[j] == INVALID_INSTRNO) |
| 406 | || |
| 407 | (rreg_live_after[j] != INVALID_INSTRNO |
| 408 | && rreg_dead_before[j] != INVALID_INSTRNO) |
| 409 | ); |
| 410 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 411 | if (rreg_live_after[j] == INVALID_INSTRNO) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 412 | continue; |
| 413 | if (rreg_info_used == rreg_info_size) { |
| 414 | panic("make rreg info array bigger(2)"); |
| 415 | } |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 416 | rreg_info[rreg_info_used].rreg = available_real_regs[j]; |
| 417 | rreg_info[rreg_info_used].live_after = rreg_live_after[j]; |
| 418 | rreg_info[rreg_info_used].dead_before = rreg_dead_before[j]; |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 419 | rreg_info_used++; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 420 | } |
| 421 | |
| 422 | free(rreg_live_after); |
| 423 | free(rreg_dead_before); |
| 424 | |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 425 | # if 1 |
| 426 | for (j = 0; j < rreg_info_used; j++) { |
| 427 | ppHReg(stdout, rreg_info[j].rreg); |
| 428 | fprintf(stdout, " la = %d, db = %d\n", |
| 429 | rreg_info[j].live_after, rreg_info[j].dead_before ); |
| 430 | } |
| 431 | # endif |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 432 | |
| 433 | /* --------- Stage 3: allocate spill slots. --------- */ |
| 434 | |
| 435 | /* Each spill slot is 8 bytes long. For 128-bit vregs |
| 436 | we'll have to allocate two spill slots. For now, tho, |
| 437 | ignore the 128-bit problem. |
| 438 | |
| 439 | Do a rank-based allocation of vregs to spill slot numbers. We |
| 440 | put as few values as possible in spill slows, but nevertheless |
| 441 | need to have a spill slot available for all vregs, just in case. |
| 442 | */ |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 443 | /* max_ss_no = -1; */ |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 444 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 445 | for (j = 0; j < N_SPILL64S; j++) |
| 446 | ss_busy_until_before[j] = 0; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 447 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 448 | for (j = 0; j < n_vregs; j++) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 449 | |
| 450 | /* True iff this vreg is unused. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 451 | if (vreg_info[j].live_after == INVALID_INSTRNO) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 452 | continue; |
| 453 | |
| 454 | /* Find the lowest-numbered spill slot which is available at the |
| 455 | start point of this interval, and assign the interval to |
| 456 | it. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 457 | for (k = 0; k < N_SPILL64S; k++) |
| 458 | if (ss_busy_until_before[k] <= vreg_info[j].live_after) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 459 | break; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 460 | if (k == N_SPILL64S) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 461 | panic("N_SPILL64S is too low"); |
| 462 | } |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 463 | ss_busy_until_before[k] = vreg_info[j].dead_before; |
| 464 | vreg_info[j].spill_offset = k * 8; |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 465 | /* if (j > max_ss_no) */ |
| 466 | /* max_ss_no = j; */ |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 467 | } |
| 468 | |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 469 | fprintf(stdout, "\n\n"); |
| 470 | for (j = 0; j < n_vregs; j++) |
| 471 | fprintf(stdout, "vreg %d --> spill offset %d\n", |
| 472 | j, vreg_info[j].spill_offset); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 473 | |
| 474 | /* --------- Stage 4: establish rreg preferences --------- */ |
| 475 | |
| 476 | /* It may be advantageous to allocating certain vregs to specific |
| 477 | rregs, as a way of avoiding reg-reg moves later. Here we |
| 478 | establish which, if any, rreg each vreg would prefer to be in. |
| 479 | Note that this constrains the allocator -- ideally we end up |
| 480 | with as few as possible vregs expressing a preference. */ |
| 481 | |
| 482 | /* For now, ignore this. It's only an optimisation, not needed for |
| 483 | correctness. */ |
| 484 | |
| 485 | |
| 486 | /* --------- Stage 5: process instructions --------- */ |
| 487 | |
| 488 | /* This is the main loop of the allocator. First, we need to |
| 489 | correctly set up our running state, which tracks the status of |
| 490 | each real register. */ |
| 491 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 492 | /* n_state is no more than a short name for n_available_real_regs. */ |
| 493 | n_state = n_available_real_regs; |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 494 | state = malloc(n_available_real_regs * sizeof(RRegState)); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 495 | |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 496 | for (j = 0; j < n_state; j++) { |
| 497 | state[j].rreg = available_real_regs[j]; |
| 498 | state[j].disp = Free; |
| 499 | state[j].vreg = INVALID_HREG; |
| 500 | state[j].is_spill_cand = False; |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 501 | } |
| 502 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 503 | /* ------ BEGIN: Process each insn in turn. ------ */ |
| 504 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 505 | for (ii = 0; ii < instrs_in->arr_used; ii++) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 506 | |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 507 | fprintf(stdout, "\n-----------\n%d ", ii); |
| 508 | ppX86Instr(stdout, instrs_in->arr[ii]); |
| 509 | fprintf(stdout, "\n"); |
| 510 | for (j = 0; j < n_state; j++) { |
| 511 | ppHReg(stdout, state[j].rreg); |
| 512 | fprintf(stdout, "\t "); |
| 513 | switch (state[j].disp) { |
| 514 | case Free: fprintf(stdout, "Free\n"); break; |
| 515 | case Unavail: fprintf(stdout, "Unavail\n"); break; |
| 516 | case Bound: fprintf(stdout, "BoundTo "); |
| 517 | ppHReg(stdout, state[j].vreg); |
| 518 | fprintf(stdout, "\n"); break; |
| 519 | } |
| 520 | } |
| 521 | fprintf(stdout, "\n"); |
| 522 | |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 523 | /* ------ Sanity checks ------ */ |
| 524 | |
| 525 | /* Sanity check 1: all rregs with a hard live range crossing |
| 526 | this insn must be marked as unavailable in the running |
| 527 | state. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 528 | for (j = 0; j < rreg_info_used; j++) { |
| 529 | if (rreg_info[j].live_after < ii |
| 530 | && ii < rreg_info[j].dead_before) { |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 531 | /* ii is the middle of a hard live range for some real reg. |
| 532 | Check it's marked as such in the running state. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 533 | assert(state[rreg_info[j].rreg].disp == Unavail); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 534 | } |
| 535 | } |
| 536 | |
| 537 | /* Sanity check 2: conversely, all rregs marked as unavailable in |
| 538 | the running state must have a corresponding hard live range |
| 539 | entry in the rreg_info array. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 540 | for (j = 0; j < n_available_real_regs; j++) { |
| 541 | assert(state[j].disp == Free |
| 542 | || state[j].disp == Unavail |
| 543 | || state[j].disp == Bound); |
| 544 | if (state[j].disp != Unavail) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 545 | continue; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 546 | for (k = 0; k < rreg_info_used; k++) |
| 547 | if (rreg_info[k].rreg == state[j].rreg |
| 548 | && rreg_info[k].live_after < ii |
| 549 | && ii < rreg_info[k].dead_before) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 550 | break; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 551 | /* If this assertion fails, we couldn't find a correspond |
| 552 | HLR. */ |
| 553 | assert(k < rreg_info_used); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 554 | } |
| 555 | |
| 556 | /* Sanity check 3: No vreg is bound to more than one rreg. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 557 | for (j = 0; j < n_state; j++) { |
| 558 | if (state[j].disp != Bound) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 559 | continue; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 560 | for (k = j+1; k < n_state; k++) |
| 561 | if (state[k].disp == Bound) |
| 562 | assert(state[k].vreg != state[j].vreg); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 563 | } |
| 564 | |
| 565 | /* Sanity check 4: all vreg-rreg bindings must bind registers of |
| 566 | the same class. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 567 | for (j = 0; j < n_state; j++) { |
| 568 | if (state[j].disp != Bound) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 569 | continue; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 570 | assert(hregClass(state[j].rreg) == hregClass(state[j].vreg)); |
| 571 | assert( hregIsVirtual(state[j].vreg)); |
| 572 | assert(!hregIsVirtual(state[j].rreg)); |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 573 | } |
| 574 | |
| 575 | /* ------ end of Sanity checks ------ */ |
| 576 | |
| 577 | /* Do various optimisations pertaining to register coalescing |
| 578 | and preferencing: |
sewardj | 968396e | 2004-07-03 14:50:33 +0000 | [diff] [blame^] | 579 | MOV v <-> v coalescing (done here). |
| 580 | MOV v <-> r coalescing (not yet, if ever) |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 581 | */ |
sewardj | 968396e | 2004-07-03 14:50:33 +0000 | [diff] [blame^] | 582 | /* If doing a reg-reg move between two vregs, and the src's live |
| 583 | range ends here and the dst's live range starts here, bind |
| 584 | the dst to the src's rreg, and that's all. */ |
| 585 | if ( (*isMove)( instrs_in->arr[ii], &vregS, &vregD ) ) { |
| 586 | if (!hregIsVirtual(vregS)) goto cannot_coalesce; |
| 587 | if (!hregIsVirtual(vregD)) goto cannot_coalesce; |
| 588 | /* Check that *isMove is not telling us a bunch of lies ... */ |
| 589 | assert(hregClass(vregS) == hregClass(vregD)); |
| 590 | k = hregNumber(vregS); |
| 591 | m = hregNumber(vregD); |
| 592 | assert(k >= 0 && k < n_vregs); |
| 593 | assert(m >= 0 && m < n_vregs); |
| 594 | if (vreg_info[k].dead_before != ii) goto cannot_coalesce; |
| 595 | if (vreg_info[m].live_after != ii) goto cannot_coalesce; |
| 596 | printf("COALESCE "); |
| 597 | ppHReg(stdout, vregS); |
| 598 | printf(" -> "); |
| 599 | ppHReg(stdout, vregD); |
| 600 | printf("\n"); |
| 601 | |
| 602 | /* Ok, we can do it. Find the state entry for vregS. */ |
| 603 | for (m = 0; m < n_state; m++) |
| 604 | if (state[m].disp == Bound && state[m].vreg == vregS) |
| 605 | break; |
| 606 | /* If this fails, we have no binding for vregS, which |
| 607 | cannot be correct. */ |
| 608 | assert(m < n_state); |
| 609 | /* Claim it for vregD. */ |
| 610 | state[m].vreg = vregD; |
| 611 | /* Don't bother to copy this insn, just move on to the next |
| 612 | insn. */ |
| 613 | continue; |
| 614 | } |
| 615 | cannot_coalesce: |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 616 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 617 | /* ------ Pre-instruction actions for fixed rreg uses ------ */ |
sewardj | 8149744 | 2004-07-02 17:30:07 +0000 | [diff] [blame] | 618 | |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 619 | /* Now we have to deal with rregs which are about to be made |
| 620 | live by this instruction -- in other words, are entering into |
| 621 | one of their live ranges. If any such rreg holds a vreg, we |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 622 | will have to free up the rreg. The simplest solution which |
| 623 | is correct is to spill the rreg. |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 624 | |
| 625 | Note we could do better: |
| 626 | * Could move it into some other free rreg, if one is available |
| 627 | * Don't bother to spill if the spill-slot value is known to |
| 628 | be consistent. |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 629 | * If the associated vreg live range ends at this insn, |
| 630 | no point in spilling or moving, since (in principle) the |
| 631 | rreg will be free anyway after that. |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 632 | |
| 633 | Simplest way to do this is to iterate over the collection |
| 634 | of rreg live ranges. |
| 635 | */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 636 | for (j = 0; j < rreg_info_used; j++) { |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 637 | if (rreg_info[j].live_after == ii) { |
| 638 | /* rreg_info[j].rreg needs to be freed up. Find |
| 639 | the associated state entry. */ |
| 640 | printf("need to free up rreg: "); |
| 641 | ppHReg(stdout, rreg_info[j].rreg); |
| 642 | printf("\n"); |
| 643 | for (k = 0; k < n_state; k++) |
| 644 | if (state[k].rreg == rreg_info[j].rreg) |
| 645 | break; |
| 646 | /* If this fails, we don't have an entry for this rreg. |
| 647 | Which we should. */ |
| 648 | assert(k < n_state); |
| 649 | if (state[k].disp == Bound) { |
| 650 | /* Yes, there is an associated vreg. Spill it if it's |
| 651 | still live. */ |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 652 | m = hregNumber(state[k].vreg); |
| 653 | assert(m >= 0 && m < n_vregs); |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 654 | if (vreg_info[m].dead_before > ii) |
| 655 | EMIT_INSTR( (*genSpill)( state[k].rreg, |
| 656 | vreg_info[m].spill_offset ) ); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 657 | } |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 658 | state[k].disp = Unavail; |
| 659 | state[k].vreg = INVALID_HREG; |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 660 | } |
| 661 | } |
| 662 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 663 | /* ------ Deal with the current instruction. ------ */ |
| 664 | |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 665 | /* Finally we can begin the processing of this instruction |
| 666 | itself. The aim is to free up enough rregs for this insn. |
| 667 | This may generate spill stores since we may have to evict |
| 668 | some vregs currently in rregs. Also generates spill loads. |
| 669 | We also build up the final vreg->rreg mapping to be applied |
| 670 | to the insn. */ |
| 671 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 672 | (*getRegUsage)( ®_usage, instrs_in->arr[ii] ); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 673 | |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 674 | initHRegRemap(&remap); |
| 675 | |
| 676 | /* for each reg mentioned in the insn ... */ |
| 677 | for (j = 0; j < reg_usage.n_used; j++) { |
| 678 | |
| 679 | vreg = reg_usage.hreg[j]; |
| 680 | |
| 681 | /* only interested in virtual registers right now. */ |
| 682 | if (!hregIsVirtual(vreg)) |
| 683 | continue; |
| 684 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 685 | printf("considering "); ppHReg(stdout, vreg); printf("\n"); |
| 686 | |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 687 | /* Now we're trying to find a rreg for "vreg". First of all, |
| 688 | if it already has an rreg assigned, we don't need to do |
| 689 | anything more. Search the current state to find out. */ |
| 690 | for (k = 0; k < n_state; k++) |
| 691 | if (state[k].vreg == vreg && state[k].disp == Bound) |
| 692 | break; |
| 693 | if (k < n_state) { |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 694 | addToHRegRemap(&remap, vreg, state[k].rreg); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 695 | continue; |
| 696 | } |
| 697 | |
| 698 | /* No luck. The next thing to do is see if there is a |
| 699 | currently free rreg available, of the correct class. If |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 700 | so, bag it. NOTE, we could improve this by selecting an |
| 701 | rreg for which the next live-range event is as far ahead |
| 702 | as possible. */ |
| 703 | for (k = 0; k < n_state; k++) { |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 704 | if (state[k].disp == Free |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 705 | && hregClass(state[k].rreg) == hregClass(vreg)) |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 706 | break; |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 707 | } |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 708 | if (k < n_state) { |
| 709 | state[k].disp = Bound; |
| 710 | state[k].vreg = vreg; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 711 | addToHRegRemap(&remap, vreg, state[k].rreg); |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 712 | /* Generate a reload if needed. */ |
| 713 | if (reg_usage.mode[j] != HRmWrite) { |
| 714 | m = hregNumber(vreg); |
| 715 | assert(m >= 0 && m < n_vregs); |
| 716 | EMIT_INSTR( (*genReload)( state[k].rreg, |
| 717 | vreg_info[m].spill_offset ) ); |
| 718 | } |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 719 | continue; |
| 720 | } |
| 721 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 722 | /* There are no free rregs, but perhaps we can find one which |
| 723 | is bound to a vreg which is now dead. If so, use that. |
| 724 | NOTE, we could improve this by selecting an rreg for which |
| 725 | the next live-range event is as far ahead as possible. */ |
| 726 | for (k = 0; k < n_state; k++) { |
| 727 | if (state[k].disp == Bound |
| 728 | && hregClass(state[k].rreg) == hregClass(vreg)) { |
| 729 | m = hregNumber(state[k].vreg); |
| 730 | assert(m >= 0 && m < n_vregs); |
| 731 | if (vreg_info[m].dead_before <= ii) { |
| 732 | /* Ok, it's gone dead before this insn. We can use |
| 733 | it. */ |
| 734 | break; |
| 735 | } |
| 736 | } |
| 737 | } |
| 738 | if (k < n_state) { |
| 739 | assert(state[k].disp == Bound); |
| 740 | state[k].vreg = vreg; |
| 741 | addToHRegRemap(&remap, vreg, state[k].rreg); |
| 742 | /* Generate a reload if needed. */ |
| 743 | if (reg_usage.mode[j] != HRmWrite) { |
| 744 | m = hregNumber(vreg); |
| 745 | assert(m >= 0 && m < n_vregs); |
| 746 | EMIT_INSTR( (*genReload)( state[k].rreg, |
| 747 | vreg_info[m].spill_offset ) ); |
| 748 | } |
| 749 | continue; |
| 750 | } |
| 751 | |
| 752 | /* Well, now we have no option but to spill a vreg. It's |
| 753 | important to make a good choice of vreg to spill, and of |
| 754 | course we need to be careful not to spill a vreg which is |
| 755 | needed by this insn. */ |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 756 | |
| 757 | /* First, mark in the state, those rregs which are not spill |
| 758 | candidates, due to holding a vreg mentioned by this |
| 759 | instruction. Or being of the wrong class. */ |
| 760 | for (k = 0; k < n_state; k++) { |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 761 | state[k].is_spill_cand = False; |
| 762 | if (state[k].disp != Bound) |
| 763 | continue; |
| 764 | if (hregClass(state[k].rreg) != hregClass(vreg)) |
| 765 | continue; |
| 766 | state[k].is_spill_cand = True; |
| 767 | for (m = 0; m < reg_usage.n_used; m++) { |
| 768 | if (state[k].vreg == reg_usage.hreg[m]) { |
| 769 | state[k].is_spill_cand = False; |
| 770 | break; |
| 771 | } |
| 772 | } |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 773 | } |
| 774 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 775 | /* We can choose to spill any rreg satisfying |
| 776 | state[r].is_spill_cand (so to speak). Choose r so that |
| 777 | the next use of its associated vreg is as far ahead as |
| 778 | possible, in the hope that this will minimise the number |
| 779 | of consequent reloads required. */ |
| 780 | spillee |
| 781 | = findMostDistantlyMentionedVReg ( |
| 782 | getRegUsage, instrs_in, ii+1, state, n_state ); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 783 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 784 | if (spillee == -1) { |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 785 | /* Hmmmmm. There don't appear to be any spill candidates. |
| 786 | We're hosed. */ |
| 787 | fprintf(stderr, "reg_alloc: can't find a register in class: "); |
| 788 | ppHRegClass(stderr, hregClass(vreg)); |
| 789 | fprintf(stderr, "\n"); |
| 790 | panic("reg_alloc: can't create a free register."); |
| 791 | } |
| 792 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 793 | /* Right. So we're going to spill state[spillee]. */ |
| 794 | assert(spillee >= 0 && spillee < n_state); |
| 795 | assert(state[spillee].disp == Bound); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 796 | /* check it's the right class */ |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 797 | assert(hregClass(state[spillee].rreg) == hregClass(vreg)); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 798 | /* check we're not ejecting the vreg for which we are trying |
| 799 | to free up a register. */ |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 800 | assert(state[spillee].vreg != vreg); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 801 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 802 | m = hregNumber(state[spillee].vreg); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 803 | assert(m >= 0 && m < n_vregs); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 804 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 805 | /* So here's the spill store. Assert that we're spilling a |
| 806 | live vreg. */ |
| 807 | assert(vreg_info[m].dead_before > ii); |
| 808 | EMIT_INSTR( (*genSpill)( state[spillee].rreg, |
| 809 | vreg_info[m].spill_offset ) ); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 810 | |
| 811 | /* Update the state to reflect the new assignment for this |
| 812 | rreg. */ |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 813 | state[spillee].vreg = vreg; |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 814 | |
| 815 | /* Now, if this vreg is being read or modified (as opposed to |
| 816 | written), we have to generate a reload for it. */ |
| 817 | if (reg_usage.mode[j] != HRmWrite) { |
| 818 | m = hregNumber(vreg); |
| 819 | assert(m >= 0 && m < n_vregs); |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 820 | EMIT_INSTR( (*genReload)( state[spillee].rreg, |
| 821 | vreg_info[m].spill_offset ) ); |
| 822 | |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 823 | } |
| 824 | |
| 825 | /* So after much twisting and turning, we have vreg mapped to |
| 826 | state[furthest_k].rreg. Note that in the map. */ |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 827 | addToHRegRemap(&remap, vreg, state[spillee].rreg); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 828 | |
| 829 | } /* iterate over registers in this instruction. */ |
| 830 | |
| 831 | /* We've finished clowning around with registers in this instruction. |
| 832 | Three results: |
| 833 | - the running state[] has been updated |
| 834 | - a suitable vreg->rreg mapping for this instruction has been |
| 835 | constructed |
| 836 | - spill and reload instructions may have been emitted. |
| 837 | |
| 838 | The final step is to apply the mapping to the instruction, |
| 839 | and emit that. |
| 840 | */ |
| 841 | |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 842 | /* NOTE, DESTRUCTIVELY MODIFIES instrs_in->arr[ii]. */ |
| 843 | (*mapRegs)( &remap, instrs_in->arr[ii] ); |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 844 | EMIT_INSTR( instrs_in->arr[ii] ); |
| 845 | |
| 846 | /* ------ Post-instruction actions for fixed rreg uses ------ */ |
| 847 | |
| 848 | /* Now we need to check for rregs exiting fixed live ranges |
| 849 | after this instruction, and if so mark them as free. */ |
| 850 | |
| 851 | for (j = 0; j < rreg_info_used; j++) { |
| 852 | if (rreg_info[j].dead_before == ii+1) { |
| 853 | /* rreg_info[j].rreg is exiting a hard live range. Mark |
| 854 | it as such in the main state array. */ |
| 855 | for (k = 0; k < n_state; k++) |
| 856 | if (state[k].rreg == rreg_info[j].rreg) |
| 857 | break; |
| 858 | /* If this assertion fails, we don't have an entry for |
| 859 | this rreg. Which we should. */ |
| 860 | assert(k < n_state); |
| 861 | assert(state[k].disp == Unavail); |
| 862 | state[k].disp = Free; |
| 863 | state[k].vreg = INVALID_HREG; |
| 864 | } |
| 865 | } |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 866 | |
| 867 | } /* iterate over insns */ |
| 868 | |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 869 | /* ------ END: Process each insn in turn. ------ */ |
| 870 | |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 871 | free(state); |
sewardj | 62c4142 | 2004-07-01 21:00:22 +0000 | [diff] [blame] | 872 | free(rreg_info); |
| 873 | if (vreg_info) free(vreg_info); |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 874 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 875 | return instrs_out; |
sewardj | af5a522 | 2004-07-01 23:14:42 +0000 | [diff] [blame] | 876 | |
sewardj | b3d4ce7 | 2004-07-02 07:09:23 +0000 | [diff] [blame] | 877 | # undef INVALID_INSTRNO |
| 878 | # undef EMIT_INSTR |
sewardj | 73b58bc | 2004-07-01 18:30:56 +0000 | [diff] [blame] | 879 | } |
| 880 | |
| 881 | |
| 882 | |
| 883 | /*---------------------------------------------------------------*/ |
| 884 | /*--- reg_alloc.c ---*/ |
| 885 | /*---------------------------------------------------------------*/ |