From: Julian Seward Date: Mon, 22 Nov 2004 11:26:51 +0000 (+0000) Subject: rec_alloc.c is defunct; reg_alloc2.c replaced it a while back. X-Git-Tag: svn/VALGRIND_3_0_1^2~758 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d46357cb3be07bd0eaf8ecd69127feb106c8e52a;p=thirdparty%2Fvalgrind.git rec_alloc.c is defunct; reg_alloc2.c replaced it a while back. git-svn-id: svn://svn.valgrind.org/vex/trunk@576 --- diff --git a/VEX/Makefile b/VEX/Makefile index d4150e7d22..c3ea4bbabb 100644 --- a/VEX/Makefile +++ b/VEX/Makefile @@ -19,7 +19,6 @@ LIB_OBJS = priv/ir/irdefs.o \ priv/host-x86/hdefs.o \ priv/host-x86/isel.o \ priv/host-generic/h_generic_regs.o \ - priv/host-generic/reg_alloc.o \ priv/host-generic/reg_alloc2.o \ priv/guest-x86/ghelpers.o \ priv/guest-x86/toIR.o @@ -107,10 +106,6 @@ priv/host-generic/h_generic_regs.o: $(ALL_HEADERS) priv/host-generic/h_generic_r $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/h_generic_regs.o \ -c priv/host-generic/h_generic_regs.c -priv/host-generic/reg_alloc.o: $(ALL_HEADERS) priv/host-generic/reg_alloc.c - $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/reg_alloc.o \ - -c priv/host-generic/reg_alloc.c - priv/host-generic/reg_alloc2.o: $(ALL_HEADERS) priv/host-generic/reg_alloc2.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/host-generic/reg_alloc2.o \ -c priv/host-generic/reg_alloc2.c diff --git a/VEX/priv/host-generic/reg_alloc.c b/VEX/priv/host-generic/reg_alloc.c deleted file mode 100644 index 4831013226..0000000000 --- a/VEX/priv/host-generic/reg_alloc.c +++ /dev/null @@ -1,1141 +0,0 @@ - -/*---------------------------------------------------------------*/ -/*--- ---*/ -/*--- 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 ---*/ -/*---------------------------------------------------------------*/