📄 reg_alloc2.c
字号:
/*---------------------------------------------------------------*//*--- ---*//*--- This file (host-generic/reg_alloc2.c) is ---*//*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*//*--- ---*//*---------------------------------------------------------------*//* This file is part of LibVEX, a library for dynamic binary instrumentation and translation. Copyright (C) 2004-2005 OpenWorks LLP. All rights reserved. This library is made available under a dual licensing scheme. If you link LibVEX against other code all of which is itself licensed under the GNU General Public License, version 2 dated June 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL is missing, you can obtain a copy of the GPL v2 from the Free Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. For any other uses of LibVEX, you must first obtain a commercial license from OpenWorks LLP. Please contact info@open-works.co.uk for information about commercial licensing. This software is provided by OpenWorks LLP "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall OpenWorks LLP be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. 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.*/#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; } VRegLR;/* 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; } RRegLR;/* An array of the following structs (rreg_state) 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;/* The allocator also maintains a redundant array of indexes (vreg_state) from vreg numbers back to entries in rreg_state. It is redundant because iff vreg_state[i] == j then hregNumber(rreg_state[j].vreg) == i -- that is, the two entries point at each other. The purpose of this is to speed up activities which involve looking for a particular vreg: there is no need to scan the rreg_state looking for it, just index directly into vreg_state. The FAQ "does this vreg already have an associated rreg" is the main beneficiary. To indicate, in vreg_state[i], that a given vreg is not currently associated with any rreg, that entry can be set to INVALID_RREG_NO. Because the vreg_state entries are signed Shorts, the max number of vregs that can be handed by regalloc is 32767.*/#define INVALID_RREG_NO ((Short)(-1))#define IS_VALID_VREGNO(_zz) ((_zz) >= 0 && (_zz) < n_vregs)#define IS_VALID_RREGNO(_zz) ((_zz) >= 0 && (_zz) < n_rregs)/* 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. */staticInt 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 live-range array, if needed. */static void ensureRRLRspace ( RRegLR** info, Int* size, Int used ){ Int k; RRegLR* 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(RRegLR)); for (k = 0; k < *size; k++) arr2[k] = (*info)[k]; *size *= 2; *info = arr2;}/* A target-independent register allocator. 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 ( /* 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. */ Int n_vregs; VRegLR* vreg_lrs; /* [0 .. n_vregs-1] */ RRegLR* rreg_lrs; Int rreg_lrs_size; Int rreg_lrs_used; /* Used when constructing vreg_lrs (for allocating stack slots). */ Int ss_busy_until_before[N_SPILL64S]; /* Used when constructing rreg_lrs. */ Int* rreg_live_after; Int* rreg_dead_before; /* Running state of the core allocation algorithm. */ RRegState* rreg_state; /* [0 .. n_rregs-1] */ Int n_rregs; /* .. and the redundant backward map */ /* Each value is 0 .. n_rregs-1 or is INVALID_RREG_NO. This inplies n_rregs must be <= 32768. */ Short* vreg_state; /* [0 .. n_vregs-1] */ /* The vreg -> rreg map constructed and then applied to each instr. */ HRegRemap remap;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -