+++ /dev/null
-
-/*---------------------------------------------------------------*/
-/*--- ---*/
-/*--- This file (host-generic/reg_alloc.c) is ---*/
-/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
-/*--- ---*/
-/*---------------------------------------------------------------*/
-
-/*
- This file is part of LibVEX, a library for dynamic binary
- instrumentation and translation.
-
- Copyright (C) 2004 OpenWorks, LLP.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; Version 2 dated June 1991 of the
- license.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
- for damages. See the GNU General Public License for more details.
-
- Neither the names of the U.S. Department of Energy nor the
- University of California nor the names of its contributors may be
- used to endorse or promote products derived from this software
- without prior written permission.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-*/
-
-#include "libvex_basictypes.h"
-#include "libvex.h"
-
-#include "main/vex_util.h"
-#include "host-generic/h_generic_regs.h"
-
-/* Set to 1 for lots of debugging output. */
-#define DEBUG_REGALLOC 0
-
-
-/* TODO 27 Oct 04:
-
- (Critical): Need a way to statically establish the vreg classes,
- else we can't allocate spill slots properly.
-
- Better consistency checking from what isMove tells us.
-
- We can possibly do V-V coalescing even when the src is spilled,
- providing we can arrange for the dst to have the same spill slot.
-
- Note that state[].hreg is the same as the available real regs.
-
- Check whether rreg preferencing has any beneficial effect.
-
- Remove preferencing fields in VRegInfo, if not used.
-
- Generally rationalise data structures. */
-
-
-/* Records information on virtual register live ranges. Computed once
- and remains unchanged after that. */
-typedef
- struct {
- /* Becomes live for the first time after this insn ... */
- Short live_after;
- /* Becomes dead for the last time before this insn ... */
- Short dead_before;
- /* The "home" spill slot, if needed. Never changes. */
- Short spill_offset;
- Short spill_size;
- /* What kind of register this is. */
- HRegClass reg_class;
- /* Preferencing info, if any. Currently unused. */
- /* Bool has_preference; */
- /* HReg preferred_rreg; */ /* if True, where I would like to be */
- }
- VRegInfo;
-
-
-/* Records information on real-register live ranges. Computed once
- and remains unchanged after that. */
-typedef
- struct {
- HReg rreg;
- /* Becomes live after this insn ... */
- Short live_after;
- /* Becomes dead before this insn ... */
- Short dead_before;
- }
- RRegInfo;
-
-
-/* An array of the following structs comprises the running state of
- the allocator. It indicates what the current disposition of each
- allocatable real register is. The array gets updated as the
- allocator processes instructions. */
-typedef
- struct {
- /* FIELDS WHICH DO NOT CHANGE */
- /* Which rreg is this for? */
- HReg rreg;
- /* Is this involved in any HLRs? (only an optimisation hint) */
- Bool has_hlrs;
- /* FIELDS WHICH DO CHANGE */
- /* What's it's current disposition? */
- enum { Free, /* available for use */
- Unavail, /* in a real-reg live range */
- Bound /* in use (holding value of some vreg) */
- }
- disp;
- /* If RRegBound, what vreg is it bound to? */
- HReg vreg;
- /* Used when .disp == Bound and we are looking for vregs to
- spill. */
- Bool is_spill_cand;
- }
- RRegState;
-
-
-
-/* Does this instruction mention a particular reg? */
-static Bool instrMentionsReg (
- void (*getRegUsage) (HRegUsage*, HInstr*),
- HInstr* instr,
- HReg r
-)
-{
- Int i;
- HRegUsage reg_usage;
- (*getRegUsage)(®_usage, instr);
- for (i = 0; i < reg_usage.n_used; i++)
- if (reg_usage.hreg[i] == r)
- return True;
- return False;
-}
-
-
-/* Search forward from some given point in the incoming instruction
- sequence. Point is to select a virtual register to spill, by
- finding the vreg which is mentioned as far ahead as possible, in
- the hope that this will minimise the number of consequent reloads.
-
- Only do the search for vregs which are Bound in the running state,
- and for which the .is_spill_cand field is set. This allows the
- caller to arbitrarily restrict the set of spill candidates to be
- considered.
-
- Returns an index into the state array indicating the (v,r) pair to
- spill, or -1 if none was found. */
-static
-Int findMostDistantlyMentionedVReg (
- void (*getRegUsage) (HRegUsage*, HInstr*),
- HInstrArray* instrs_in,
- Int search_from_instr,
- RRegState* state,
- Int n_state
-)
-{
- Int k, m;
- Int furthest_k = -1;
- Int furthest = -1;
- vassert(search_from_instr >= 0);
- for (k = 0; k < n_state; k++) {
- if (!state[k].is_spill_cand)
- continue;
- vassert(state[k].disp == Bound);
- for (m = search_from_instr; m < instrs_in->arr_used; m++) {
- if (instrMentionsReg(getRegUsage,
- instrs_in->arr[m], state[k].vreg))
- break;
- }
- if (m > furthest) {
- furthest = m;
- furthest_k = k;
- }
- }
- return furthest_k;
-}
-
-
-
-/* Double the size of the real-reg-info array, if needed. */
-static void ensureRRIspace ( RRegInfo** info, Int* size, Int used )
-{
- Int k;
- RRegInfo* arr2;
- if (used < *size) return;
- if (0)
- vex_printf("ensureRRISpace: %d -> %d\n", *size, 2 * *size);
- vassert(used == *size);
- arr2 = LibVEX_Alloc(2 * *size * sizeof(RRegInfo));
- for (k = 0; k < *size; k++)
- arr2[k] = (*info)[k];
- *size *= 2;
- *info = arr2;
-}
-
-
-/* A target-independent register allocator for Valgrind. Requires
- various functions which it uses to deal abstractly with
- instructions and registers, since it cannot have any
- target-specific knowledge.
-
- Returns a new list of instructions, which, as a result of the
- behaviour of mapRegs, will be in-place modifications of the
- original instructions.
-
- Requires that the incoming code has been generated using
- vreg numbers 0, 1 .. n_vregs-1. Appearance of a vreg outside
- that range is a checked run-time error.
-
- Takes an expandable array of pointers to unallocated insns.
- Returns an expandable array of pointers to allocated insns.
-*/
-HInstrArray* doRegisterAllocation_OLD (
-
- /* Incoming virtual-registerised code. */
- HInstrArray* instrs_in,
-
- /* An array listing all the real registers the allocator may use,
- in no particular order. */
- HReg* available_real_regs,
- Int n_available_real_regs,
-
- /* Return True iff the given insn is a reg-reg move, in which
- case also return the src and dst regs. */
- Bool (*isMove) (HInstr*, HReg*, HReg*),
-
- /* Get info about register usage in this insn. */
- void (*getRegUsage) (HRegUsage*, HInstr*),
-
- /* Apply a reg-reg mapping to an insn. */
- void (*mapRegs) (HRegRemap*, HInstr*),
-
- /* Return an insn to spill/restore a real reg to a spill slot
- byte offset. */
- HInstr* (*genSpill) ( HReg, Int ),
- HInstr* (*genReload) ( HReg, Int ),
- Int guest_sizeB,
-
- /* For debug printing only. */
- void (*ppInstr) ( HInstr* ),
- void (*ppReg) ( HReg )
-)
-{
-# define N_SPILL64S (LibVEX_N_SPILL_BYTES / 8)
-
- /* Iterators and temporaries. */
- Int ii, j, k, m, spillee, k_suboptimal;
- HReg rreg, vreg, vregS, vregD;
- HRegUsage reg_usage;
-
- /* Info on vregs and rregs. Computed once and remains
- unchanged. */
- VRegInfo* vreg_info;
- RRegInfo* rreg_info;
- Int rreg_info_size;
- Int rreg_info_used;
- Int n_vregs;
-
- /* Used when constructing vreg_info (for allocating stack
- slots). */
- Int ss_busy_until_before[N_SPILL64S];
-
- /* Used when constructing rreg_info. */
- Int* rreg_live_after;
- Int* rreg_dead_before;
-
- /* Running state of the core allocation algorithm. */
- RRegState* state;
- Int n_state;
-
- /* The vreg -> rreg map constructed and then applied to each
- instr. */
- HRegRemap remap;
-
- /* The output array of instructions. */
- HInstrArray* instrs_out;
-
- vassert(0 == LibVEX_N_SPILL_BYTES % 16);
- vassert(0 == guest_sizeB % 8);
-
- /* The live range numbers are signed shorts, and so limiting the
- number of insns to 10000 comfortably guards against them
- overflowing 32k. */
- vassert(instrs_in->arr_used <= 10000);
-
-# define INVALID_INSTRNO (-2)
-
-# define EMIT_INSTR(_instr) \
- do { \
- HInstr* _tmp = (_instr); \
- if (DEBUG_REGALLOC) { \
- vex_printf("** "); \
- (*ppInstr)(_tmp); \
- vex_printf("\n\n"); \
- } \
- addHInstr ( instrs_out, _tmp ); \
- } while (0)
-
-# define PRINT_STATE \
- do { \
- Int z; \
- for (z = 0; z < n_state; z++) { \
- vex_printf(" "); \
- (*ppReg)(state[z].rreg); \
- vex_printf("\t "); \
- switch (state[z].disp) { \
- case Free: vex_printf("Free\n"); break; \
- case Unavail: vex_printf("Unavail\n"); break; \
- case Bound: vex_printf("BoundTo "); \
- (*ppReg)(state[z].vreg); \
- vex_printf("\n"); break; \
- } \
- } \
- } while (0)
-
-
- /* --------- Stage 0: set up output array. --------- */
- instrs_out = newHInstrArray();
-
- /* ... and initialise running state. */
- /* n_state is no more than a short name for n_available_real_regs. */
- n_state = n_available_real_regs;
- state = LibVEX_Alloc(n_available_real_regs * sizeof(RRegState));
-
- for (j = 0; j < n_state; j++) {
- state[j].rreg = available_real_regs[j];
- state[j].has_hlrs = False;
- state[j].disp = Free;
- state[j].vreg = INVALID_HREG;
- state[j].is_spill_cand = False;
- }
-
- /* --------- Stage 1: compute vreg live ranges. --------- */
- /* --------- Stage 2: compute rreg live ranges. --------- */
-
- /* ------ start of SET UP TO COMPUTE VREG LIVE RANGES ------ */
-
- /* This is relatively simple, because (1) we only seek the complete
- end-to-end live range of each vreg, and are not interested in
- any holes in it, and (2) the vregs are conveniently numbered 0
- .. n_vregs-1, so we can just dump the results in a pre-allocated
- array. */
-
- n_vregs = instrs_in->n_vregs;
- vreg_info = NULL;
- if (n_vregs > 0)
- vreg_info = LibVEX_Alloc(sizeof(VRegInfo) * n_vregs);
-
- for (j = 0; j < n_vregs; j++) {
- vreg_info[j].live_after = INVALID_INSTRNO;
- vreg_info[j].dead_before = INVALID_INSTRNO;
- vreg_info[j].spill_offset = 0;
- vreg_info[j].spill_size = 0;
- vreg_info[j].reg_class = HRcINVALID;
- /* vreg_info[j].has_preference = False; */
- /* vreg_info[j].preferred_rreg = INVALID_HREG; */
- }
-
- /* ------ end of SET UP TO COMPUTE VREG LIVE RANGES ------ */
-
- /* ------ start of SET UP TO COMPUTE RREG LIVE RANGES ------ */
-
- /* This is more complex than Stage 1, because we need to compute
- exactly all the live ranges of all the allocatable real regs,
- and we don't know in advance how many there will be. */
-
- rreg_info_used = 0;
- rreg_info_size = 4;
- rreg_info = LibVEX_Alloc(rreg_info_size * sizeof(RRegInfo));
-
- /* We'll need to track live range start/end points seperately for
- each rreg. Sigh. */
- vassert(n_available_real_regs > 0);
- rreg_live_after = LibVEX_Alloc(n_available_real_regs * sizeof(Int));
- rreg_dead_before = LibVEX_Alloc(n_available_real_regs * sizeof(Int));
-
- for (j = 0; j < n_available_real_regs; j++) {
- rreg_live_after[j] =
- rreg_dead_before[j] = INVALID_INSTRNO;
- }
-
- /* ------ end of SET UP TO COMPUTE RREG LIVE RANGES ------ */
-
- /* ------ start of ITERATE OVER INSNS ------ */
-
- for (ii = 0; ii < instrs_in->arr_used; ii++) {
-
- (*getRegUsage)( ®_usage, instrs_in->arr[ii] );
-
-# if 0
- vex_printf("\n%d stage1: ", ii);
- (*ppInstr)(instrs_in->arr[ii]);
- vex_printf("\n");
- ppHRegUsage(®_usage);
-# endif
-
- /* ------ start of DEAL WITH VREG LIVE RANGES ------ */
-
- /* for each reg mentioned in the insn ... */
- for (j = 0; j < reg_usage.n_used; j++) {
-
- vreg = reg_usage.hreg[j];
- /* only interested in virtual registers right now. */
- if (!hregIsVirtual(vreg))
- continue;
- k = hregNumber(vreg);
- if (k < 0 || k >= n_vregs) {
- vex_printf("\n");
- (*ppInstr)(instrs_in->arr[ii]);
- vex_printf("\n");
- vex_printf("vreg %d, n_vregs %d\n", k, n_vregs);
- vpanic("doRegisterAllocation: out-of-range vreg");
- }
-
- /* Take the opportunity to note its regclass. We'll need
- that when allocating spill slots. */
- if (vreg_info[k].reg_class == HRcINVALID) {
- /* First mention of this vreg. */
- vreg_info[k].reg_class = hregClass(vreg);
- } else {
- /* Seen it before, so check for consistency. */
- vassert(vreg_info[k].reg_class == hregClass(vreg));
- }
-
- /* Now consider live ranges. */
- switch (reg_usage.mode[j]) {
- case HRmRead:
- if (vreg_info[k].live_after == INVALID_INSTRNO)
- vpanic("doRegisterAllocation: "
- "first event for vreg is Read");
- vreg_info[k].dead_before = ii + 1;
- break;
- case HRmWrite:
- if (vreg_info[k].live_after == INVALID_INSTRNO)
- vreg_info[k].live_after = ii;
- vreg_info[k].dead_before = ii + 1;
- break;
- case HRmModify:
- if (vreg_info[k].live_after == INVALID_INSTRNO)
- vpanic("doRegisterAllocation: "
- "first event for vreg is Modify");
- vreg_info[k].dead_before = ii + 1;
- break;
- default:
- vpanic("doRegisterAllocation(1)");
- } /* switch */
-
- } /* iterate over registers */
-
- /* ------ end of DEAL WITH VREG LIVE RANGES ------ */
-
- /* ------ start of DEAL WITH RREG LIVE RANGES ------ */
-
- /* for each reg mentioned in the insn ... */
- for (j = 0; j < reg_usage.n_used; j++) {
-
- /* Dummy initialisations of flush_la and flush_db to avoid
- possible bogus uninit-var warnings from gcc. */
- Int flush_la = INVALID_INSTRNO, flush_db = INVALID_INSTRNO;
- Bool flush;
-
- rreg = reg_usage.hreg[j];
-
- /* only interested in real registers right now. */
- if (hregIsVirtual(rreg))
- continue;
-
- /* Furthermore, we're not interested in this rreg unless it's
- one of the allocatable ones. For example, it could be a
- stack pointer register, or some other register beyond our
- control, in which case we should just ignore it. */
- for (k = 0; k < n_available_real_regs; k++)
- if (available_real_regs[k] == rreg)
- break;
- if (k == n_available_real_regs)
- continue; /* not found -- ignore. */
- flush = False;
- switch (reg_usage.mode[j]) {
- case HRmWrite:
- flush_la = rreg_live_after[k];
- flush_db = rreg_dead_before[k];
- if (flush_la != INVALID_INSTRNO
- && flush_db != INVALID_INSTRNO)
- flush = True;
- rreg_live_after[k] = ii;
- rreg_dead_before[k] = ii+1;
- break;
- case HRmRead:
- if (rreg_live_after[k] == INVALID_INSTRNO)
- vpanic("doRegisterAllocation: "
- "first event for rreg is Read");
- rreg_dead_before[k] = ii+1;
- break;
- case HRmModify:
- if (rreg_live_after[k] == INVALID_INSTRNO)
- vpanic("doRegisterAllocation: "
- "first event for rreg is Modify");
- rreg_dead_before[k] = ii+1;
- break;
- default:
- vpanic("doRegisterAllocation(2)");
- }
-
- if (flush) {
- vassert(flush_la != INVALID_INSTRNO);
- vassert(flush_db != INVALID_INSTRNO);
- ensureRRIspace(&rreg_info, &rreg_info_size, rreg_info_used);
- if (0)
- vex_printf("FLUSH 1 (%d,%d)\n", flush_la, flush_db);
- rreg_info[rreg_info_used].rreg = rreg;
- rreg_info[rreg_info_used].live_after = flush_la;
- rreg_info[rreg_info_used].dead_before = flush_db;
- rreg_info_used++;
- }
-
- } /* iterate over regs in the instr */
-
- /* ------ end of DEAL WITH RREG LIVE RANGES ------ */
-
- } /* iterate over insns */
-
- /* ------ end of ITERATE OVER INSNS ------ */
-
- /* ------ start of FINALISE RREG LIVE RANGES ------ */
-
- /* Now finish up any live ranges left over. */
- for (j = 0; j < n_available_real_regs; j++) {
-
-# if 0
- vex_printf("residual %d: %d %d\n", j, rreg_live_after[j],
- rreg_dead_before[j]);
-# endif
- vassert( (rreg_live_after[j] == INVALID_INSTRNO
- && rreg_dead_before[j] == INVALID_INSTRNO)
- ||
- (rreg_live_after[j] != INVALID_INSTRNO
- && rreg_dead_before[j] != INVALID_INSTRNO)
- );
-
- if (rreg_live_after[j] == INVALID_INSTRNO)
- continue;
-
- ensureRRIspace(&rreg_info, &rreg_info_size, rreg_info_used);
- if (0)
- vex_printf("FLUSH 2 (%d,%d)\n",
- rreg_live_after[j], rreg_dead_before[j]);
- rreg_info[rreg_info_used].rreg = available_real_regs[j];
- rreg_info[rreg_info_used].live_after = rreg_live_after[j];
- rreg_info[rreg_info_used].dead_before = rreg_dead_before[j];
- rreg_info_used++;
- }
-
- /* Compute summary hints for choosing real regs. If a real reg is
- involved in a hard live range, record that fact in the fixed
- part of the running state. Later, when offered a choice between
- rregs, it's better to choose one which is not marked as having
- any HLRs, since ones with HLRs may need to be spilled around
- their HLRs. Correctness of final assignment is unaffected by
- this mechanism -- it is an optimisation only. */
-
- for (j = 0; j < rreg_info_used; j++) {
- rreg = rreg_info[j].rreg;
- vassert(!hregIsVirtual(rreg));
- /* rreg is involved in a HLR. Record this info in the array, if
- there is space. */
- for (k = 0; k < n_state; k++)
- if (state[k].rreg == rreg)
- break;
- vassert(k < n_state); /* else rreg was not found in state?! */
- state[k].has_hlrs = True;
- }
- if (0) {
- for (j = 0; j < n_state; j++) {
- if (!state[j].has_hlrs)
- continue;
- ppReg(state[j].rreg);
- vex_printf(" hinted\n");
- }
- }
-
- /* ------ end of FINALISE RREG LIVE RANGES ------ */
-
-# if DEBUG_REGALLOC
- for (j = 0; j < n_vregs; j++) {
- vex_printf("vreg %d: la = %d, db = %d\n",
- j, vreg_info[j].live_after, vreg_info[j].dead_before );
- }
-# endif
-
-# if DEBUG_REGALLOC
- for (j = 0; j < rreg_info_used; j++) {
- (*ppReg)(rreg_info[j].rreg);
- vex_printf(" la = %d, db = %d\n",
- rreg_info[j].live_after, rreg_info[j].dead_before );
- }
-# endif
-
- /* --------- Stage 3: allocate spill slots. --------- */
-
- /* Each spill slot is 8 bytes long. For 128-bit vregs
- we'll have to allocate two spill slots. For now, tho,
- ignore the 128-bit problem.
-
- Do a rank-based allocation of vregs to spill slot numbers. We
- put as few values as possible in spill slows, but nevertheless
- need to have a spill slot available for all vregs, just in case.
- */
- /* max_ss_no = -1; */
-
- for (j = 0; j < N_SPILL64S; j++)
- ss_busy_until_before[j] = 0;
-
- for (j = 0; j < n_vregs; j++) {
-
- /* True iff this vreg is unused. In which case we also expect
- that the reg_class field for it has not been set. */
- if (vreg_info[j].live_after == INVALID_INSTRNO) {
- vassert(vreg_info[j].reg_class == HRcINVALID);
- continue;
- }
-
- /* Need to allocate two 64-bit spill slots for this. */
- if (vreg_info[j].reg_class == HRcVector128)
- vpanic("can't deal with spilling 128-bit values (yet)");
-
- /* Find the lowest-numbered spill slot which is available at the
- start point of this interval, and assign the interval to
- it. */
- for (k = 0; k < N_SPILL64S; k++)
- if (ss_busy_until_before[k] <= vreg_info[j].live_after)
- break;
- if (k == N_SPILL64S) {
- vpanic("LibVEX_N_SPILL_BYTES is too low. Increase and recompile.");
- }
- ss_busy_until_before[k] = vreg_info[j].dead_before;
-
- /* This reflects LibVEX's hard-wired knowledge of the baseBlock
- layout: the guest state, then an equal sized area following
- it for shadow state, and then the spill area. */
- vreg_info[j].spill_offset = guest_sizeB * 2 + k * 8;
-
- /* if (j > max_ss_no) */
- /* max_ss_no = j; */
- }
-
-# if 0
- vex_printf("\n\n");
- for (j = 0; j < n_vregs; j++)
- vex_printf("vreg %d --> spill offset %d\n",
- j, vreg_info[j].spill_offset);
-# endif
-
- /* --------- Stage 4: establish rreg preferences --------- */
-
- /* It may be advantageous to allocating certain vregs to specific
- rregs, as a way of avoiding reg-reg moves later. Here we
- establish which, if any, rreg each vreg would prefer to be in.
- Note that this constrains the allocator -- ideally we end up
- with as few as possible vregs expressing a preference. */
-
- /* For now, ignore this. It's only an optimisation, not needed for
- correctness. */
-
-
- /* --------- Stage 5: process instructions --------- */
-
- /* This is the main loop of the allocator. First, we need to
- correctly set up our running state, which tracks the status of
- each real register. */
-
- /* ------ BEGIN: Process each insn in turn. ------ */
-
- for (ii = 0; ii < instrs_in->arr_used; ii++) {
-
-# if DEBUG_REGALLOC
- vex_printf("\n====----====---- Insn %d ----====----====\n", ii);
- vex_printf("---- ");
- (*ppInstr)(instrs_in->arr[ii]);
- vex_printf("\n\nInitial state:\n");
- PRINT_STATE;
- vex_printf("\n");
-# endif
-
- /* ------ Sanity checks ------ */
-
- /* Sanity check 1: all rregs with a hard live range crossing
- this insn must be marked as unavailable in the running
- state. */
- for (j = 0; j < rreg_info_used; j++) {
- if (rreg_info[j].live_after < ii
- && ii < rreg_info[j].dead_before) {
- /* ii is the middle of a hard live range for some real reg.
- Check it's marked as such in the running state. */
-
-# if 0
- vex_printf("considering la %d .. db %d reg = ",
- rreg_info[j].live_after,
- rreg_info[j].dead_before);
- (*ppReg)(rreg_info[j].rreg);
- vex_printf("\n");
-# endif
-
- /* find the state entry for this rreg */
- for (k = 0; k < n_state; k++)
- if (state[k].rreg == rreg_info[j].rreg)
- break;
-
- /* and assert that this rreg is marked as unavailable */
- vassert(state[k].disp == Unavail);
- }
- }
-
- /* Sanity check 2: conversely, all rregs marked as unavailable in
- the running state must have a corresponding hard live range
- entry in the rreg_info array. */
- for (j = 0; j < n_available_real_regs; j++) {
- vassert(state[j].disp == Free
- || state[j].disp == Unavail
- || state[j].disp == Bound);
- if (state[j].disp != Unavail)
- continue;
- for (k = 0; k < rreg_info_used; k++)
- if (rreg_info[k].rreg == state[j].rreg
- && rreg_info[k].live_after < ii
- && ii < rreg_info[k].dead_before)
- break;
- /* If this vassertion fails, we couldn't find a corresponding
- HLR. */
- vassert(k < rreg_info_used);
- }
-
- /* Sanity check 3: No vreg is bound to more than one rreg. */
- for (j = 0; j < n_state; j++) {
- if (state[j].disp != Bound)
- continue;
- for (k = j+1; k < n_state; k++)
- if (state[k].disp == Bound)
- vassert(state[k].vreg != state[j].vreg);
- }
-
- /* Sanity check 4: all vreg-rreg bindings must bind registers of
- the same class. */
- for (j = 0; j < n_state; j++) {
- if (state[j].disp != Bound)
- continue;
- vassert(hregClass(state[j].rreg) == hregClass(state[j].vreg));
- vassert( hregIsVirtual(state[j].vreg));
- vassert(!hregIsVirtual(state[j].rreg));
- }
-
- /* ------ end of Sanity checks ------ */
-
- /* Do various optimisations pertaining to register coalescing
- and preferencing:
- MOV v <-> v coalescing (done here).
- MOV v <-> r coalescing (not yet, if ever)
- */
- /* If doing a reg-reg move between two vregs, and the src's live
- range ends here and the dst's live range starts here, bind
- the dst to the src's rreg, and that's all. */
- if ( (*isMove)( instrs_in->arr[ii], &vregS, &vregD ) ) {
- if (!hregIsVirtual(vregS)) goto cannot_coalesce;
- if (!hregIsVirtual(vregD)) goto cannot_coalesce;
- /* Check that *isMove is not telling us a bunch of lies ... */
- vassert(hregClass(vregS) == hregClass(vregD));
- k = hregNumber(vregS);
- m = hregNumber(vregD);
- vassert(k >= 0 && k < n_vregs);
- vassert(m >= 0 && m < n_vregs);
- if (vreg_info[k].dead_before != ii + 1) goto cannot_coalesce;
- if (vreg_info[m].live_after != ii) goto cannot_coalesce;
-# if DEBUG_REGALLOC
- vex_printf("COALESCE ");
- (*ppReg)(vregS);
- vex_printf(" -> ");
- (*ppReg)(vregD);
- vex_printf("\n\n");
-# endif
- /* Find the state entry for vregS. */
- for (m = 0; m < n_state; m++)
- if (state[m].disp == Bound && state[m].vreg == vregS)
- break;
- if (m == n_state)
- /* We failed to find a binding for vregS, which means it's
- currently not in a register. So we can't do the
- coalescing. Give up. */
- goto cannot_coalesce;
-
- /* Finally, we can do the coalescing. It's trivial -- merely
- claim vregS's register for vregD. */
- state[m].vreg = vregD;
- /* Don't bother to copy this insn, just move on to the post-
- insn actions to do with fixed regs. IOW, skip the main
- part of the insn processing entirely. */
- goto post_insn_actions;
- }
- cannot_coalesce:
-
- /* ------ Pre-instruction actions for fixed rreg uses ------ */
-
- /* Now we have to deal with rregs which are about to be made
- live by this instruction -- in other words, are entering into
- one of their live ranges. If any such rreg holds a vreg, we
- will have to free up the rreg. The simplest solution which
- is correct is to spill the rreg.
-
- Note we could do better:
- * Could move it into some other free rreg, if one is available
- * Don't bother to spill if the spill-slot value is known to
- be consistent.
- * If the associated vreg live range ends at this insn,
- no point in spilling or moving, since (in principle) the
- rreg will be free anyway after that.
-
- Simplest way to do this is to iterate over the collection
- of rreg live ranges.
- */
- for (j = 0; j < rreg_info_used; j++) {
- if (rreg_info[j].live_after == ii) {
- /* rreg_info[j].rreg needs to be freed up. Find
- the associated state entry. */
- /* Note, re rreg_info[j].live_after == ii. Real register
- live ranges are guaranteed to be well-formed in that
- they start with a write to the register -- Stage 2
- rejects any code not satisfying this. So the correct
- question to ask is whether rreg_info[j].live_after ==
- ii, that is, whether the reg becomes live after this
- insn -- rather than before it. */
-# if DEBUG_REGALLOC
- vex_printf("need to free up rreg: ");
- (*ppReg)(rreg_info[j].rreg);
- vex_printf("\n\n");
-# endif
- for (k = 0; k < n_state; k++)
- if (state[k].rreg == rreg_info[j].rreg)
- break;
- /* If this fails, we don't have an entry for this rreg.
- Which we should. */
- vassert(k < n_state);
- if (state[k].disp == Bound) {
- /* Yes, there is an associated vreg. Spill it if it's
- still live. */
- m = hregNumber(state[k].vreg);
- vassert(m >= 0 && m < n_vregs);
- if (vreg_info[m].dead_before > ii) {
- vassert(vreg_info[m].reg_class != HRcINVALID);
- EMIT_INSTR( (*genSpill)( state[k].rreg,
- vreg_info[m].spill_offset ) );
- }
- }
- state[k].disp = Unavail;
- state[k].vreg = INVALID_HREG;
- }
- }
-
-# if DEBUG_REGALLOC
- vex_printf("After pre-insn actions for fixed regs:\n");
- PRINT_STATE;
- vex_printf("\n");
-# endif
-
-
- /* ------ Deal with the current instruction. ------ */
-
- /* Finally we can begin the processing of this instruction
- itself. The aim is to free up enough rregs for this insn.
- This may generate spill stores since we may have to evict
- some vregs currently in rregs. Also generates spill loads.
- We also build up the final vreg->rreg mapping to be applied
- to the insn. */
-
- (*getRegUsage)( ®_usage, instrs_in->arr[ii] );
-
- initHRegRemap(&remap);
-
- /* for each reg mentioned in the insn ... */
- for (j = 0; j < reg_usage.n_used; j++) {
-
- vreg = reg_usage.hreg[j];
-
- /* only interested in virtual registers right now. */
- if (!hregIsVirtual(vreg))
- continue;
-
-# if 0
- vex_printf("considering "); (*ppReg)(vreg); vex_printf("\n");
-# endif
-
- /* Now we're trying to find a rreg for "vreg". First of all,
- if it already has an rreg assigned, we don't need to do
- anything more. Search the current state to find out. */
- for (k = 0; k < n_state; k++)
- if (state[k].vreg == vreg && state[k].disp == Bound)
- break;
- if (k < n_state) {
- addToHRegRemap(&remap, vreg, state[k].rreg);
- continue;
- }
-
- /* No luck. The next thing to do is see if there is a
- currently free rreg available, of the correct class. If
- so, bag it. NOTE, we could improve this by selecting an
- rreg for which the next live-range event is as far ahead
- as possible. */
- k_suboptimal = -1;
- for (k = 0; k < n_state; k++) {
- if (state[k].disp != Free
- || hregClass(state[k].rreg) != hregClass(vreg))
- continue;
- if (state[k].has_hlrs) {
- /* Well, at least we can use k_suboptimal if we really
- have to. Keep on looking for a better candidate. */
- k_suboptimal = k;
- } else {
- /* Found a preferable reg. Use it. */
- k_suboptimal = -1;
- break;
- }
- }
- if (k_suboptimal >= 0)
- k = k_suboptimal;
-
- if (k < n_state) {
- state[k].disp = Bound;
- state[k].vreg = vreg;
- addToHRegRemap(&remap, vreg, state[k].rreg);
- /* Generate a reload if needed. */
- if (reg_usage.mode[j] != HRmWrite) {
- m = hregNumber(vreg);
- vassert(m >= 0 && m < n_vregs);
- vassert(vreg_info[m].reg_class != HRcINVALID);
- EMIT_INSTR( (*genReload)( state[k].rreg,
- vreg_info[m].spill_offset ) );
- }
- continue;
- }
-
- /* There are no free rregs, but perhaps we can find one which
- is bound to a vreg which is now dead. If so, use that.
- Optimisation: prefer a rreg which is not marked as having
- any HLRs. */
- k_suboptimal = -1;
- for (k = 0; k < n_state; k++) {
- if (state[k].disp != Bound
- || hregClass(state[k].rreg) != hregClass(vreg))
- continue;
- m = hregNumber(state[k].vreg);
- vassert(m >= 0 && m < n_vregs);
- if (!(vreg_info[m].dead_before <= ii))
- continue;
- /* Ok, it's gone dead before the current insn. We can use
- it. If it's not marked as involved in any HLRs, use it
- with no further ado. */
- if (state[k].has_hlrs) {
- /* Well, at least we can use k_suboptimal if we really
- have to. Keep on looking for a better candidate. */
- k_suboptimal = k;
- } else {
- /* Found a preferable reg. Use it. */
- k_suboptimal = -1;
- break;
- }
- }
- if (k_suboptimal >= 0)
- k = k_suboptimal;
-
- if (k < n_state) {
- vassert(state[k].disp == Bound);
- state[k].vreg = vreg;
- addToHRegRemap(&remap, vreg, state[k].rreg);
- /* Generate a reload if needed. */
- if (reg_usage.mode[j] != HRmWrite) {
- m = hregNumber(vreg);
- vassert(m >= 0 && m < n_vregs);
- vassert(vreg_info[m].reg_class != HRcINVALID);
- EMIT_INSTR( (*genReload)( state[k].rreg,
- vreg_info[m].spill_offset ) );
- }
- continue;
- }
-
- /* Well, now we have no option but to spill a vreg. It's
- important to make a good choice of vreg to spill, and of
- course we need to be careful not to spill a vreg which is
- needed by this insn. */
-
- /* First, mark in the state, those rregs which are not spill
- candidates, due to holding a vreg mentioned by this
- instruction. Or being of the wrong class. */
- for (k = 0; k < n_state; k++) {
- state[k].is_spill_cand = False;
- if (state[k].disp != Bound)
- continue;
- if (hregClass(state[k].rreg) != hregClass(vreg))
- continue;
- state[k].is_spill_cand = True;
- for (m = 0; m < reg_usage.n_used; m++) {
- if (state[k].vreg == reg_usage.hreg[m]) {
- state[k].is_spill_cand = False;
- break;
- }
- }
- }
-
- /* We can choose to spill any rreg satisfying
- state[r].is_spill_cand (so to speak). Choose r so that
- the next use of its associated vreg is as far ahead as
- possible, in the hope that this will minimise the number
- of consequent reloads required. */
- spillee
- = findMostDistantlyMentionedVReg (
- getRegUsage, instrs_in, ii+1, state, n_state );
-
- if (spillee == -1) {
- /* Hmmmmm. There don't appear to be any spill candidates.
- We're hosed. */
- vex_printf("reg_alloc: can't find a register in class: ");
- ppHRegClass(hregClass(vreg));
- vex_printf("\n");
- vpanic("reg_alloc: can't create a free register.");
- }
-
- /* Right. So we're going to spill state[spillee]. */
- vassert(spillee >= 0 && spillee < n_state);
- vassert(state[spillee].disp == Bound);
- /* check it's the right class */
- vassert(hregClass(state[spillee].rreg) == hregClass(vreg));
- /* check we're not ejecting the vreg for which we are trying
- to free up a register. */
- vassert(state[spillee].vreg != vreg);
-
- m = hregNumber(state[spillee].vreg);
- vassert(m >= 0 && m < n_vregs);
-
- /* So here's the spill store. Assert that we're spilling a
- live vreg. */
- vassert(vreg_info[m].dead_before > ii);
- vassert(vreg_info[m].reg_class != HRcINVALID);
- EMIT_INSTR( (*genSpill)( state[spillee].rreg,
- vreg_info[m].spill_offset ) );
-
- /* Update the state to reflect the new assignment for this
- rreg. */
- state[spillee].vreg = vreg;
-
- /* Now, if this vreg is being read or modified (as opposed to
- written), we have to generate a reload for it. */
- if (reg_usage.mode[j] != HRmWrite) {
- m = hregNumber(vreg);
- vassert(m >= 0 && m < n_vregs);
- vassert(vreg_info[m].reg_class != HRcINVALID);
- EMIT_INSTR( (*genReload)( state[spillee].rreg,
- vreg_info[m].spill_offset ) );
-
- }
-
- /* So after much twisting and turning, we have vreg mapped to
- state[furthest_k].rreg. Note that in the map. */
- addToHRegRemap(&remap, vreg, state[spillee].rreg);
-
- } /* iterate over registers in this instruction. */
-
- /* We've finished clowning around with registers in this instruction.
- Three results:
- - the running state[] has been updated
- - a suitable vreg->rreg mapping for this instruction has been
- constructed
- - spill and reload instructions may have been emitted.
-
- The final step is to apply the mapping to the instruction,
- and emit that.
- */
-
- /* NOTE, DESTRUCTIVELY MODIFIES instrs_in->arr[ii]. */
- (*mapRegs)( &remap, instrs_in->arr[ii] );
- EMIT_INSTR( instrs_in->arr[ii] );
-
-# if DEBUG_REGALLOC
- vex_printf("After dealing with current insn:\n");
- PRINT_STATE;
- vex_printf("\n");
-# endif
-
- /* ------ Post-instruction actions for fixed rreg uses ------ */
-
- /* Now we need to check for rregs exiting fixed live ranges
- after this instruction, and if so mark them as free. */
- post_insn_actions:
- for (j = 0; j < rreg_info_used; j++) {
- if (rreg_info[j].dead_before == ii+1) {
- /* rreg_info[j].rreg is exiting a hard live range. Mark
- it as such in the main state array. */
- for (k = 0; k < n_state; k++)
- if (state[k].rreg == rreg_info[j].rreg)
- break;
- /* If this vassertion fails, we don't have an entry for
- this rreg. Which we should. */
- vassert(k < n_state);
- vassert(state[k].disp == Unavail);
- state[k].disp = Free;
- state[k].vreg = INVALID_HREG;
- }
- }
-
-# if DEBUG_REGALLOC
- vex_printf("After post-insn actions for fixed regs:\n");
- PRINT_STATE;
- vex_printf("\n");
-# endif
-
- } /* iterate over insns */
-
- /* ------ END: Process each insn in turn. ------ */
-
- /* free(state); */
- /* free(rreg_info); */
- /* if (vreg_info) free(vreg_info); */
-
- /* Paranoia */
- for (j = 0; j < n_state; j++)
- vassert(state[j].rreg == available_real_regs[j]);
-
- return instrs_out;
-
-# undef INVALID_INSTRNO
-# undef EMIT_INSTR
-# undef PRINT_STATE
-}
-
-
-
-/*---------------------------------------------------------------*/
-/*--- host-generic/reg_alloc.c ---*/
-/*---------------------------------------------------------------*/