You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
|
1
(9) |
2
(6) |
3
|
|
4
|
5
(3) |
6
(2) |
7
|
8
(6) |
9
(7) |
10
(1) |
|
11
(1) |
12
(2) |
13
(5) |
14
(3) |
15
(2) |
16
(8) |
17
(1) |
|
18
|
19
|
20
(2) |
21
(2) |
22
|
23
(1) |
24
|
|
25
(2) |
26
(2) |
27
(1) |
28
|
29
(1) |
30
|
|
|
From: <sv...@va...> - 2017-06-14 15:10:19
|
Author: iraisr
Date: Wed Jun 14 16:10:08 2017
New Revision: 3395
Log:
Introduce RegAllocState in the VEX register allocator.
It contains all the data computed during its processing.
Modified:
branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c
Modified: branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c
==============================================================================
--- branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c (original)
+++ branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c Wed Jun 14 16:10:08 2017
@@ -44,6 +44,8 @@
/* Set to 1 for lots of debugging output. */
#define DEBUG_REGALLOC 0
+static void* local_memset ( void *destV, Int c, SizeT sz );
+
/* TODO 27 Oct 04:
@@ -122,6 +124,65 @@
}
RRegState;
+#define N_SPILL64S (LibVEX_N_SPILL_BYTES / 8)
+STATIC_ASSERT((LibVEX_N_SPILL_BYTES % LibVEX_GUEST_STATE_ALIGN) == 0);
+STATIC_ASSERT((N_SPILL64S % 2) == 0);
+
+/* Register allocator state. Keeps all vital information at one place. */
+typedef
+ struct {
+ /* Info on vregs. Computed once and remains unchanged. */
+ UInt n_vregs;
+ VRegLR* vreg_lrs; /* [0 .. n_vregs-1] */
+
+ /* Used when constructing vreg_lrs (for allocating spill slots). */
+ Short ss_busy_until_before[N_SPILL64S];
+
+ /* We keep two copies of the real-reg live range info, one sorted
+ by .live_after and the other by .dead_before. First the unsorted info
+ is created in the _la variant is copied into the _db variant. Once
+ that's done both of them are sorted. We also need two integer cursors
+ which record the next location in the two arrays to consider. */
+ RRegLR* rreg_lrs_la;
+ RRegLR* rreg_lrs_db;
+ UInt rreg_lrs_size;
+ UInt rreg_lrs_used;
+ Int rreg_lrs_la_next;
+ Int rreg_lrs_db_next;
+
+ /* Used when constructing rreg_lrs. */
+ Int* rreg_live_after;
+ Int* rreg_dead_before;
+
+ /* Running state of the core allocation algorithm. */
+ UInt n_rregs;
+ RRegState* rreg_state; /* [0 .. n_rregs-1] */
+
+ /* .. and the redundant backward map */
+ /* Each value is 0 .. n_rregs-1 or is INVALID_RREG_NO.
+ This implies n_rregs must be <= 32768. */
+ Short* vreg_state; /* [0 .. n_vregs-1] */
+ }
+ RegAllocState;
+
+typedef
+ struct _RegAllocChunk {
+ enum {
+ Chunk,
+ IfThenElse
+ } tag;
+ union {
+ struct {
+ RegAllocState** states;
+ UInt n_states;
+ } States;
+ struct {
+ struct _RegAllocChunk* fallThrough;
+ struct _RegAllocChunk* outOfLine;
+ } IfThenElse;
+ };
+ }
+ RegAllocChunk;
/* The allocator also maintains a redundant array of indexes
(vreg_state) from vreg numbers back to entries in rreg_state. It
@@ -142,9 +203,76 @@
#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)
+#define IS_VALID_VREGNO(_zz) ((_zz) >= 0 && (_zz) < state->n_vregs)
+#define IS_VALID_RREGNO(_zz) ((_zz) >= 0 && (_zz) < state->n_rregs)
+
+#define INVALID_INSTRNO (-2)
+
+static RegAllocState* create_RegAllocState(const RegAllocSettings* settings,
+ UInt n_vregs)
+{
+ RegAllocState* state = LibVEX_Alloc_inline(sizeof(RegAllocState));
+
+ state->n_vregs = n_vregs;
+ /* If this is not so, vreg_state entries will overflow. */
+ vassert(state->n_vregs < 32767);
+
+ /* n_rregs is no more than a short name for n_available_real_regs. */
+ state->n_rregs = settings->univ->allocable;
+ /* If this is not so, the universe we have is nonsensical. */
+ vassert(state->n_rregs > 0);
+ state->rreg_state = LibVEX_Alloc_inline(state->n_rregs * sizeof(RRegState));
+ state->vreg_state = LibVEX_Alloc_inline(state->n_vregs * sizeof(Short));
+
+ for (UInt j = 0; j < state->n_rregs; j++) {
+ state->rreg_state[j].has_hlrs = False;
+ state->rreg_state[j].disp = Free;
+ state->rreg_state[j].vreg = INVALID_HREG;
+ state->rreg_state[j].is_spill_cand = False;
+ state->rreg_state[j].eq_spill_slot = False;
+ }
+
+ /* Setup 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. */
+ state->vreg_lrs = NULL;
+ if (state->n_vregs > 0) {
+ state->vreg_lrs = LibVEX_Alloc_inline(sizeof(VRegLR) * state->n_vregs);
+ }
+ for (UInt j = 0; j < state->n_vregs; j++) {
+ state->vreg_lrs[j].live_after = INVALID_INSTRNO;
+ state->vreg_lrs[j].dead_before = INVALID_INSTRNO;
+ state->vreg_lrs[j].spill_offset = 0;
+ state->vreg_lrs[j].spill_size = 0;
+ state->vreg_lrs[j].reg_class = HRcINVALID;
+ }
+
+ local_memset(state->ss_busy_until_before, 0,
+ sizeof(state->ss_busy_until_before));
+
+ /* 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. */
+ state->rreg_lrs_used = 0;
+ state->rreg_lrs_size = 4;
+ state->rreg_lrs_la = LibVEX_Alloc_inline(state->rreg_lrs_size * sizeof(RRegLR));
+ state->rreg_lrs_db = NULL; /* we'll create this later */
+
+ /* We need to track live range start/end points seperately for each rreg. */
+ state->rreg_live_after = LibVEX_Alloc_inline(state->n_rregs * sizeof(Int));
+ state->rreg_dead_before = LibVEX_Alloc_inline(state->n_rregs * sizeof(Int));
+
+ for (UInt j = 0; j < state->n_rregs; j++) {
+ state->rreg_live_after[j] =
+ state->rreg_dead_before[j] = INVALID_INSTRNO;
+ }
+
+ for (UInt j = 0; j < state->n_vregs; j++)
+ state->vreg_state[j] = INVALID_RREG_NO;
+
+ return state;
+}
/* Search forward from some given point in the incoming instruction
sequence. Point is to select a virtual register to spill, by
@@ -212,7 +340,7 @@
UInt k;
RRegLR* arr2;
if (0)
- vex_printf("ensureRRISpace: %d -> %d\n", *size, 2 * *size);
+ vex_printf("ensureRRLRSpace: %d -> %d\n", *size, 2 * *size);
vassert(used == *size);
arr2 = LibVEX_Alloc_inline(2 * *size * sizeof(RRegLR));
for (k = 0; k < *size; k++)
@@ -295,7 +423,6 @@
return __builtin_ctzll(w64);
}
-
/* Vectorised memset, copied from Valgrind's m_libcbase.c. */
static void* local_memset ( void *destV, Int c, SizeT sz )
{
@@ -338,20 +465,20 @@
# undef IS_4_ALIGNED
}
-
-static inline void flush_rreg_lrs_la(
- RRegLR** rreg_lrs_la, UInt *rreg_lrs_size, UInt *rreg_lrs_used,
+/* Adds an entry into state->rreg_lrs_la. */
+static inline void add_into_rreg_lrs_la(RegAllocState* state,
HReg rreg, Int flush_la, Int flush_db, const HChar *debug_phase)
{
- ensureRRLRspace(rreg_lrs_la, rreg_lrs_size, *rreg_lrs_used);
+ ensureRRLRspace(&state->rreg_lrs_la, &state->rreg_lrs_size,
+ state->rreg_lrs_used);
if (0) {
vex_printf("%s (%d,%d)\n", debug_phase, flush_la, flush_db);
}
- (*rreg_lrs_la)[*rreg_lrs_used].rreg = rreg;
- (*rreg_lrs_la)[*rreg_lrs_used].live_after = toShort(flush_la);
- (*rreg_lrs_la)[*rreg_lrs_used].dead_before = toShort(flush_db);
- (*rreg_lrs_used)++;
+ state->rreg_lrs_la[state->rreg_lrs_used].rreg = rreg;
+ state->rreg_lrs_la[state->rreg_lrs_used].live_after = toShort(flush_la);
+ state->rreg_lrs_la[state->rreg_lrs_used].dead_before = toShort(flush_db);
+ state->rreg_lrs_used++;
}
/* A target-independent register allocator. Requires various
@@ -377,73 +504,30 @@
const RegAllocSettings* settings
)
{
-# define N_SPILL64S (LibVEX_N_SPILL_BYTES / 8)
-
const Bool eq_spill_opt = True;
- /* Info on vregs and rregs. Computed once and remains
- unchanged. */
- Int n_vregs;
- VRegLR* vreg_lrs; /* [0 .. n_vregs-1] */
-
- /* We keep two copies of the real-reg live range info, one sorted
- by .live_after and the other by .dead_before. First the
- unsorted info is created in the _la variant is copied into the
- _db variant. Once that's done both of them are sorted.
- We also need two integer cursors which record the next
- location in the two arrays to consider. */
- RRegLR* rreg_lrs_la;
- RRegLR* rreg_lrs_db;
- UInt rreg_lrs_size;
- UInt rreg_lrs_used;
- Int rreg_lrs_la_next;
- Int rreg_lrs_db_next;
+ /* The output array of instructions. */
+ HInstrSB* instrs_out;
+ HInstrVec *instrs_in = sb_in->insns;
- /* Info on register usage in the incoming instruction array.
+ /* Info on register usage in the incoming instruction vector.
Computed once and remains unchanged, more or less; updated
sometimes by the direct-reload optimisation. */
HRegUsage* reg_usage_arr; /* [0 .. instrs_in->insns_used-1] */
-
- /* Used when constructing vreg_lrs (for allocating stack
- slots). */
- Short 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 implies 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;
-
- /* The output array of instructions. */
- HInstrSB* instrs_out;
- HInstrVec *instrs_in = sb_in->insns;
+ reg_usage_arr
+ = LibVEX_Alloc_inline(sizeof(HRegUsage) * instrs_in->insns_used);
/* Sanity checks are expensive. They are only done periodically,
not at each insn processed. */
Bool do_sanity_check;
vassert(0 == (settings->guest_sizeB % LibVEX_GUEST_STATE_ALIGN));
- vassert(0 == (LibVEX_N_SPILL_BYTES % LibVEX_GUEST_STATE_ALIGN));
- vassert(0 == (N_SPILL64S % 2));
/* The live range numbers are signed shorts, and so limiting the
number of insns to 15000 comfortably guards against them
overflowing 32k. */
vassert(instrs_in->insns_used <= 15000);
-# define INVALID_INSTRNO (-2)
-
# define EMIT_INSTR(_instr) \
do { \
HInstr* _tmp = (_instr); \
@@ -455,120 +539,43 @@
addHInstr(instrs_out->insns, _tmp); \
} while (0)
-# define PRINT_STATE \
- do { \
- Int z, q; \
- for (z = 0; z < n_rregs; z++) { \
- vex_printf(" rreg_state[%2d] = ", z); \
- settings->ppReg(settings->univ->regs[z]); \
- vex_printf(" \t"); \
- switch (rreg_state[z].disp) { \
- case Free: vex_printf("Free\n"); break; \
- case Unavail: vex_printf("Unavail\n"); break; \
- case Bound: vex_printf("BoundTo "); \
- settings->ppReg(rreg_state[z].vreg); \
- vex_printf("\n"); break; \
- } \
- } \
- vex_printf("\n vreg_state[0 .. %d]:\n ", n_vregs-1); \
- q = 0; \
- for (z = 0; z < n_vregs; z++) { \
- if (vreg_state[z] == INVALID_RREG_NO) \
- continue; \
- vex_printf("[%d] -> %d ", z, vreg_state[z]); \
- q++; \
- if (q > 0 && (q % 6) == 0) \
- vex_printf("\n "); \
- } \
- vex_printf("\n"); \
+# define PRINT_STATE \
+ do { \
+ for (UInt z = 0; z < state->n_rregs; z++) { \
+ vex_printf(" rreg_state[%2d] = ", z); \
+ settings->ppReg(settings->univ->regs[z]); \
+ vex_printf(" \t"); \
+ switch (state->rreg_state[z].disp) { \
+ case Free: vex_printf("Free\n"); break; \
+ case Unavail: vex_printf("Unavail\n"); break; \
+ case Bound: vex_printf("BoundTo "); \
+ settings->ppReg(state->rreg_state[z].vreg); \
+ vex_printf("\n"); break; \
+ } \
+ } \
+ vex_printf("\n vreg_state[0 .. %d]:\n ", state->n_vregs-1); \
+ UInt q = 0; \
+ for (UInt z = 0; z < state->n_vregs; z++) { \
+ if (state->vreg_state[z] == INVALID_RREG_NO) \
+ continue; \
+ vex_printf("[%d] -> %d ", z, state->vreg_state[z]); \
+ q++; \
+ if (q > 0 && (q % 6) == 0) \
+ vex_printf("\n "); \
+ } \
+ vex_printf("\n"); \
} while (0)
/* --------- Stage 0: set up output array --------- */
- /* --------- and allocate/initialise running state. --------- */
instrs_out = newHInstrSB();
- /* ... and initialise running state. */
- /* n_rregs is no more than a short name for n_available_real_regs. */
- n_rregs = settings->univ->allocable;
- n_vregs = sb_in->n_vregs;
-
- /* If this is not so, vreg_state entries will overflow. */
- vassert(n_vregs < 32767);
-
- /* If this is not so, the universe we have is nonsensical. */
- vassert(n_rregs > 0);
-
- rreg_state = LibVEX_Alloc_inline(n_rregs * sizeof(RRegState));
- vreg_state = LibVEX_Alloc_inline(n_vregs * sizeof(Short));
-
- for (Int j = 0; j < n_rregs; j++) {
- rreg_state[j].has_hlrs = False;
- rreg_state[j].disp = Free;
- rreg_state[j].vreg = INVALID_HREG;
- rreg_state[j].is_spill_cand = False;
- rreg_state[j].eq_spill_slot = False;
- }
-
- for (Int j = 0; j < n_vregs; j++)
- vreg_state[j] = INVALID_RREG_NO;
-
+ RegAllocState* state = create_RegAllocState(settings, sb_in->n_vregs);
/* --------- 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. */
-
- vreg_lrs = NULL;
- if (n_vregs > 0)
- vreg_lrs = LibVEX_Alloc_inline(sizeof(VRegLR) * n_vregs);
-
- for (Int j = 0; j < n_vregs; j++) {
- vreg_lrs[j].live_after = INVALID_INSTRNO;
- vreg_lrs[j].dead_before = INVALID_INSTRNO;
- vreg_lrs[j].spill_offset = 0;
- vreg_lrs[j].spill_size = 0;
- vreg_lrs[j].reg_class = HRcINVALID;
- }
-
- /* An array to hold the reg-usage info for the incoming
- instructions. */
- reg_usage_arr
- = LibVEX_Alloc_inline(sizeof(HRegUsage) * instrs_in->insns_used);
-
- /* ------ 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_lrs_used = 0;
- rreg_lrs_size = 4;
- rreg_lrs_la = LibVEX_Alloc_inline(rreg_lrs_size * sizeof(RRegLR));
- rreg_lrs_db = NULL; /* we'll create this later */
-
- /* We'll need to track live range start/end points seperately for
- each rreg. Sigh. */
- vassert(n_rregs > 0);
- rreg_live_after = LibVEX_Alloc_inline(n_rregs * sizeof(Int));
- rreg_dead_before = LibVEX_Alloc_inline(n_rregs * sizeof(Int));
-
- for (Int j = 0; j < n_rregs; 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 (Int ii = 0; ii < instrs_in->insns_used; ii++) {
@@ -592,46 +599,46 @@
vassert(hregIsVirtual(vreg));
Int k = hregIndex(vreg);
- if (k < 0 || k >= n_vregs) {
+ if (k < 0 || k >= state->n_vregs) {
vex_printf("\n");
settings->ppInstr(instrs_in->insns[ii], settings->mode64);
vex_printf("\n");
- vex_printf("vreg %d, n_vregs %d\n", k, n_vregs);
+ vex_printf("vreg %d, n_vregs %d\n", k, state->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_lrs[k].reg_class == HRcINVALID) {
+ if (state->vreg_lrs[k].reg_class == HRcINVALID) {
/* First mention of this vreg. */
- vreg_lrs[k].reg_class = hregClass(vreg);
+ state->vreg_lrs[k].reg_class = hregClass(vreg);
} else {
/* Seen it before, so check for consistency. */
- vassert(vreg_lrs[k].reg_class == hregClass(vreg));
+ vassert(state->vreg_lrs[k].reg_class == hregClass(vreg));
}
/* Now consider live ranges. */
switch (reg_usage_arr[ii].vMode[j]) {
case HRmRead:
- if (vreg_lrs[k].live_after == INVALID_INSTRNO) {
+ if (state->vreg_lrs[k].live_after == INVALID_INSTRNO) {
vex_printf("\n\nOFFENDING VREG = %d\n", k);
vpanic("doRegisterAllocation: "
"first event for vreg is Read");
}
- vreg_lrs[k].dead_before = toShort(ii + 1);
+ state->vreg_lrs[k].dead_before = toShort(ii + 1);
break;
case HRmWrite:
- if (vreg_lrs[k].live_after == INVALID_INSTRNO)
- vreg_lrs[k].live_after = toShort(ii);
- vreg_lrs[k].dead_before = toShort(ii + 1);
+ if (state->vreg_lrs[k].live_after == INVALID_INSTRNO)
+ state->vreg_lrs[k].live_after = toShort(ii);
+ state->vreg_lrs[k].dead_before = toShort(ii + 1);
break;
case HRmModify:
- if (vreg_lrs[k].live_after == INVALID_INSTRNO) {
+ if (state->vreg_lrs[k].live_after == INVALID_INSTRNO) {
vex_printf("\n\nOFFENDING VREG = %d\n", k);
vpanic("doRegisterAllocation: "
"first event for vreg is Modify");
}
- vreg_lrs[k].dead_before = toShort(ii + 1);
+ state->vreg_lrs[k].dead_before = toShort(ii + 1);
break;
default:
vpanic("doRegisterAllocation(1)");
@@ -665,8 +672,8 @@
/* Don't bother to look at registers which are not available
to the allocator. We asserted above that n_rregs > 0, so
n_rregs-1 is safe. */
- if (rReg_maxIndex >= n_rregs)
- rReg_maxIndex = n_rregs-1;
+ if (rReg_maxIndex >= state->n_rregs)
+ rReg_maxIndex = state->n_rregs - 1;
}
/* for each allocator-available real reg mentioned in the insn ... */
@@ -690,14 +697,14 @@
Bool flush = False;
if (isW && !isR) {
- flush_la = rreg_live_after[j];
- flush_db = rreg_dead_before[j];
+ flush_la = state->rreg_live_after[j];
+ flush_db = state->rreg_dead_before[j];
if (flush_la != INVALID_INSTRNO && flush_db != INVALID_INSTRNO)
flush = True;
- rreg_live_after[j] = ii;
- rreg_dead_before[j] = ii+1;
+ state->rreg_live_after[j] = ii;
+ state->rreg_dead_before[j] = ii+1;
} else if (!isW && isR) {
- if (rreg_live_after[j] == INVALID_INSTRNO) {
+ if (state->rreg_live_after[j] == INVALID_INSTRNO) {
vex_printf("\nOFFENDING RREG = ");
settings->ppReg(settings->univ->regs[j]);
vex_printf("\n");
@@ -707,10 +714,10 @@
vpanic("doRegisterAllocation: "
"first event for rreg is Read");
}
- rreg_dead_before[j] = ii+1;
+ state->rreg_dead_before[j] = ii+1;
} else {
vassert(isR && isW);
- if (rreg_live_after[j] == INVALID_INSTRNO) {
+ if (state->rreg_live_after[j] == INVALID_INSTRNO) {
vex_printf("\nOFFENDING RREG = ");
settings->ppReg(settings->univ->regs[j]);
vex_printf("\n");
@@ -720,15 +727,14 @@
vpanic("doRegisterAllocation: "
"first event for rreg is Modify");
}
- rreg_dead_before[j] = ii+1;
+ state->rreg_dead_before[j] = ii+1;
}
if (flush) {
vassert(flush_la != INVALID_INSTRNO);
vassert(flush_db != INVALID_INSTRNO);
- flush_rreg_lrs_la(&rreg_lrs_la, &rreg_lrs_size, &rreg_lrs_used,
- settings->univ->regs[j], flush_la, flush_db,
- "FLUSH 1");
+ add_into_rreg_lrs_la(state, settings->univ->regs[j],
+ flush_la, flush_db, "FLUSH 1");
}
} /* iterate over rregs in the instr */
@@ -742,25 +748,25 @@
/* ------ start of FINALISE RREG LIVE RANGES ------ */
/* Now finish up any live ranges left over. */
- for (Int j = 0; j < n_rregs; j++) {
+ for (UInt j = 0; j < state->n_rregs; j++) {
if (0) {
- vex_printf("residual %d: %d %d\n", j, rreg_live_after[j],
- rreg_dead_before[j]);
+ vex_printf("residual %d: %d %d\n", j, state->rreg_live_after[j],
+ state->rreg_dead_before[j]);
}
- vassert( (rreg_live_after[j] == INVALID_INSTRNO
- && rreg_dead_before[j] == INVALID_INSTRNO)
+ vassert( (state->rreg_live_after[j] == INVALID_INSTRNO
+ && state->rreg_dead_before[j] == INVALID_INSTRNO)
||
- (rreg_live_after[j] != INVALID_INSTRNO
- && rreg_dead_before[j] != INVALID_INSTRNO)
+ (state->rreg_live_after[j] != INVALID_INSTRNO
+ && state->rreg_dead_before[j] != INVALID_INSTRNO)
);
- if (rreg_live_after[j] == INVALID_INSTRNO)
+ if (state->rreg_live_after[j] == INVALID_INSTRNO)
continue;
- flush_rreg_lrs_la(&rreg_lrs_la, &rreg_lrs_size, &rreg_lrs_used,
- settings->univ->regs[j], rreg_live_after[j],
- rreg_dead_before[j], "FLUSH 2");
+ add_into_rreg_lrs_la(state, settings->univ->regs[j],
+ state->rreg_live_after[j],
+ state->rreg_dead_before[j], "FLUSH 2");
}
/* Compute summary hints for choosing real regs. If a real reg is
@@ -771,18 +777,18 @@
their HLRs. Correctness of final assignment is unaffected by
this mechanism -- it is only an optimisation. */
- for (Int j = 0; j < rreg_lrs_used; j++) {
- HReg rreg = rreg_lrs_la[j].rreg;
+ for (UInt j = 0; j < state->rreg_lrs_used; j++) {
+ HReg rreg = state->rreg_lrs_la[j].rreg;
vassert(!hregIsVirtual(rreg));
/* rreg is involved in a HLR. Record this info in the array, if
there is space. */
UInt ix = hregIndex(rreg);
- vassert(ix < n_rregs);
- rreg_state[ix].has_hlrs = True;
+ vassert(ix < state->n_rregs);
+ state->rreg_state[ix].has_hlrs = True;
}
if (0) {
- for (Int j = 0; j < n_rregs; j++) {
- if (!rreg_state[j].has_hlrs)
+ for (UInt j = 0; j < state->n_rregs; j++) {
+ if (!state->rreg_state[j].has_hlrs)
continue;
settings->ppReg(settings->univ->regs[j]);
vex_printf(" hinted\n");
@@ -791,45 +797,50 @@
/* Finally, copy the _la variant into the _db variant and
sort both by their respective fields. */
- rreg_lrs_db = LibVEX_Alloc_inline(rreg_lrs_used * sizeof(RRegLR));
- for (Int j = 0; j < rreg_lrs_used; j++)
- rreg_lrs_db[j] = rreg_lrs_la[j];
-
- sortRRLRarray( rreg_lrs_la, rreg_lrs_used, True /* by .live_after*/ );
- sortRRLRarray( rreg_lrs_db, rreg_lrs_used, False/* by .dead_before*/ );
+ state->rreg_lrs_db = LibVEX_Alloc_inline(state->rreg_lrs_used * sizeof(RRegLR));
+ for (UInt j = 0; j < state->rreg_lrs_used; j++)
+ state->rreg_lrs_db[j] = state->rreg_lrs_la[j];
+
+ sortRRLRarray(state->rreg_lrs_la, state->rreg_lrs_used,
+ True /* by .live_after*/ );
+ sortRRLRarray(state->rreg_lrs_db, state->rreg_lrs_used,
+ False/* by .dead_before*/ );
/* And set up the cursors. */
- rreg_lrs_la_next = 0;
- rreg_lrs_db_next = 0;
+ state->rreg_lrs_la_next = 0;
+ state->rreg_lrs_db_next = 0;
- for (Int j = 1; j < rreg_lrs_used; j++) {
- vassert(rreg_lrs_la[j-1].live_after <= rreg_lrs_la[j].live_after);
- vassert(rreg_lrs_db[j-1].dead_before <= rreg_lrs_db[j].dead_before);
+ for (UInt j = 1; j < state->rreg_lrs_used; j++) {
+ vassert(state->rreg_lrs_la[j-1].live_after <= state->rreg_lrs_la[j].live_after);
+ vassert(state->rreg_lrs_db[j-1].dead_before <= state->rreg_lrs_db[j].dead_before);
}
/* ------ end of FINALISE RREG LIVE RANGES ------ */
if (DEBUG_REGALLOC) {
- for (Int j = 0; j < n_vregs; j++) {
+ for (UInt j = 0; j < state->n_vregs; j++) {
vex_printf("vreg %d: la = %d, db = %d\n",
- j, vreg_lrs[j].live_after, vreg_lrs[j].dead_before );
+ j, state->vreg_lrs[j].live_after,
+ state->vreg_lrs[j].dead_before);
}
}
if (DEBUG_REGALLOC) {
vex_printf("RRegLRs by LA:\n");
- for (Int j = 0; j < rreg_lrs_used; j++) {
+ for (UInt j = 0; j < state->rreg_lrs_used; j++) {
vex_printf(" ");
- settings->ppReg(rreg_lrs_la[j].rreg);
+ settings->ppReg(state->rreg_lrs_la[j].rreg);
vex_printf(" la = %d, db = %d\n",
- rreg_lrs_la[j].live_after, rreg_lrs_la[j].dead_before );
+ state->rreg_lrs_la[j].live_after,
+ state->rreg_lrs_la[j].dead_before );
}
vex_printf("RRegLRs by DB:\n");
- for (Int j = 0; j < rreg_lrs_used; j++) {
+ for (UInt j = 0; j < state->rreg_lrs_used; j++) {
vex_printf(" ");
- settings->ppReg(rreg_lrs_db[j].rreg);
+ settings->ppReg(state->rreg_lrs_db[j].rreg);
vex_printf(" la = %d, db = %d\n",
- rreg_lrs_db[j].live_after, rreg_lrs_db[j].dead_before );
+ state->rreg_lrs_db[j].live_after,
+ state->rreg_lrs_db[j].dead_before );
}
}
@@ -861,14 +872,12 @@
*/
/* Int max_ss_no = -1; */
- local_memset(ss_busy_until_before, 0, sizeof(ss_busy_until_before));
-
- for (Int j = 0; j < n_vregs; j++) {
+ for (UInt j = 0; j < state->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_lrs[j].live_after == INVALID_INSTRNO) {
- vassert(vreg_lrs[j].reg_class == HRcINVALID);
+ if (state->vreg_lrs[j].live_after == INVALID_INSTRNO) {
+ vassert(state->vreg_lrs[j].reg_class == HRcINVALID);
continue;
}
@@ -880,7 +889,7 @@
kept in sync with the size info on the definition of
HRegClass. */
Int ss_no = -1;
- switch (vreg_lrs[j].reg_class) {
+ switch (state->vreg_lrs[j].reg_class) {
case HRcVec128: case HRcFlt64:
/* Find two adjacent free slots in which between them
@@ -888,15 +897,17 @@
Since we are trying to find an even:odd pair, move
along in steps of 2 (slots). */
for (ss_no = 0; ss_no < N_SPILL64S-1; ss_no += 2)
- if (ss_busy_until_before[ss_no+0] <= vreg_lrs[j].live_after
- && ss_busy_until_before[ss_no+1] <= vreg_lrs[j].live_after)
+ if (state->ss_busy_until_before[ss_no+0]
+ <= state->vreg_lrs[j].live_after
+ && state->ss_busy_until_before[ss_no+1]
+ <= state->vreg_lrs[j].live_after)
break;
if (ss_no >= N_SPILL64S-1) {
vpanic("LibVEX_N_SPILL_BYTES is too low. "
"Increase and recompile.");
}
- ss_busy_until_before[ss_no+0] = vreg_lrs[j].dead_before;
- ss_busy_until_before[ss_no+1] = vreg_lrs[j].dead_before;
+ state->ss_busy_until_before[ss_no+0] = state->vreg_lrs[j].dead_before;
+ state->ss_busy_until_before[ss_no+1] = state->vreg_lrs[j].dead_before;
break;
default:
@@ -905,33 +916,35 @@
at the start point of this interval, and assign the
interval to it. */
for (ss_no = 0; ss_no < N_SPILL64S; ss_no++)
- if (ss_busy_until_before[ss_no] <= vreg_lrs[j].live_after)
+ if (state->ss_busy_until_before[ss_no]
+ <= state->vreg_lrs[j].live_after)
break;
if (ss_no == N_SPILL64S) {
vpanic("LibVEX_N_SPILL_BYTES is too low. "
"Increase and recompile.");
}
- ss_busy_until_before[ss_no] = vreg_lrs[j].dead_before;
+ state->ss_busy_until_before[ss_no] = state->vreg_lrs[j].dead_before;
break;
- } /* switch (vreg_lrs[j].reg_class) */
+ } /* switch (state->vreg_lrs[j].reg_class) */
/* This reflects LibVEX's hard-wired knowledge of the guest state
layout: the guest state itself, then two equal sized areas following
it for two sets of shadow state, and then the spill area. */
- vreg_lrs[j].spill_offset = toShort(settings->guest_sizeB * 3 + ss_no * 8);
+ state->vreg_lrs[j].spill_offset
+ = toShort(settings->guest_sizeB * 3 + ss_no * 8);
/* Independent check that we've made a sane choice of slot */
- sanity_check_spill_offset( &vreg_lrs[j] );
+ sanity_check_spill_offset(&state->vreg_lrs[j]);
/* if (j > max_ss_no) */
/* max_ss_no = j; */
}
if (0) {
vex_printf("\n\n");
- for (Int j = 0; j < n_vregs; j++)
+ for (UInt j = 0; j < state->n_vregs; j++)
vex_printf("vreg %d --> spill offset %d\n",
- j, vreg_lrs[j].spill_offset);
+ j, state->vreg_lrs[j].spill_offset);
}
/* --------- Stage 4: establish rreg preferences --------- */
@@ -985,24 +998,24 @@
/* Sanity check 1: all rregs with a hard live range crossing
this insn must be marked as unavailable in the running
state. */
- for (Int j = 0; j < rreg_lrs_used; j++) {
- if (rreg_lrs_la[j].live_after < ii
- && ii < rreg_lrs_la[j].dead_before) {
+ for (UInt j = 0; j < state->rreg_lrs_used; j++) {
+ if (state->rreg_lrs_la[j].live_after < ii
+ && ii < state->rreg_lrs_la[j].dead_before) {
/* ii is in the middle of a hard live range for some real
reg. Check it's marked as such in the running state. */
- HReg reg = rreg_lrs_la[j].rreg;
+ HReg reg = state->rreg_lrs_la[j].rreg;
if (0) {
vex_printf("considering la %d .. db %d reg = ",
- rreg_lrs_la[j].live_after,
- rreg_lrs_la[j].dead_before);
+ state->rreg_lrs_la[j].live_after,
+ state->rreg_lrs_la[j].dead_before);
settings->ppReg(reg);
vex_printf("\n");
}
/* assert that this rreg is marked as unavailable */
vassert(!hregIsVirtual(reg));
- vassert(rreg_state[hregIndex(reg)].disp == Unavail);
+ vassert(state->rreg_state[hregIndex(reg)].disp == Unavail);
}
}
@@ -1010,36 +1023,36 @@
unavailable in the running rreg_state must have a
corresponding hard live range entry in the rreg_lrs
array. */
- for (Int j = 0; j < n_rregs; j++) {
- vassert(rreg_state[j].disp == Bound
- || rreg_state[j].disp == Free
- || rreg_state[j].disp == Unavail);
- if (rreg_state[j].disp != Unavail)
+ for (UInt j = 0; j < state->n_rregs; j++) {
+ vassert(state->rreg_state[j].disp == Bound
+ || state->rreg_state[j].disp == Free
+ || state->rreg_state[j].disp == Unavail);
+ if (state->rreg_state[j].disp != Unavail)
continue;
Int k;
- for (k = 0; k < rreg_lrs_used; k++) {
- HReg reg = rreg_lrs_la[k].rreg;
+ for (k = 0; k < state->rreg_lrs_used; k++) {
+ HReg reg = state->rreg_lrs_la[k].rreg;
vassert(!hregIsVirtual(reg));
if (hregIndex(reg) == j
- && rreg_lrs_la[k].live_after < ii
- && ii < rreg_lrs_la[k].dead_before)
+ && state->rreg_lrs_la[k].live_after < ii
+ && ii < state->rreg_lrs_la[k].dead_before)
break;
}
/* If this vassertion fails, we couldn't find a
corresponding HLR. */
- vassert(k < rreg_lrs_used);
+ vassert(k < state->rreg_lrs_used);
}
/* Sanity check 3: all vreg-rreg bindings must bind registers
of the same class. */
- for (Int j = 0; j < n_rregs; j++) {
- if (rreg_state[j].disp != Bound) {
- vassert(rreg_state[j].eq_spill_slot == False);
+ for (UInt j = 0; j < state->n_rregs; j++) {
+ if (state->rreg_state[j].disp != Bound) {
+ vassert(state->rreg_state[j].eq_spill_slot == False);
continue;
}
vassert(hregClass(settings->univ->regs[j])
- == hregClass(rreg_state[j].vreg));
- vassert( hregIsVirtual(rreg_state[j].vreg));
+ == hregClass(state->rreg_state[j].vreg));
+ vassert( hregIsVirtual(state->rreg_state[j].vreg));
}
/* Sanity check 4: the vreg_state and rreg_state
@@ -1047,20 +1060,20 @@
rreg_state[j].vreg points at some vreg_state entry then
that vreg_state entry should point back at
rreg_state[j]. */
- for (Int j = 0; j < n_rregs; j++) {
- if (rreg_state[j].disp != Bound)
+ for (UInt j = 0; j < state->n_rregs; j++) {
+ if (state->rreg_state[j].disp != Bound)
continue;
- Int k = hregIndex(rreg_state[j].vreg);
+ Int k = hregIndex(state->rreg_state[j].vreg);
vassert(IS_VALID_VREGNO(k));
- vassert(vreg_state[k] == j);
+ vassert(state->vreg_state[k] == j);
}
- for (Int j = 0; j < n_vregs; j++) {
- Int k = vreg_state[j];
+ for (UInt j = 0; j < state->n_vregs; j++) {
+ Int k = state->vreg_state[j];
if (k == INVALID_RREG_NO)
continue;
vassert(IS_VALID_RREGNO(k));
- vassert(rreg_state[k].disp == Bound);
- vassert(hregIndex(rreg_state[k].vreg) == j);
+ vassert(state->rreg_state[k].disp == Bound);
+ vassert(hregIndex(state->rreg_state[k].vreg) == j);
}
} /* if (do_sanity_check) */
@@ -1086,8 +1099,8 @@
UInt m = hregIndex(vregD);
vassert(IS_VALID_VREGNO(k));
vassert(IS_VALID_VREGNO(m));
- if (vreg_lrs[k].dead_before != ii + 1) goto cannot_coalesce;
- if (vreg_lrs[m].live_after != ii) goto cannot_coalesce;
+ if (state->vreg_lrs[k].dead_before != ii + 1) goto cannot_coalesce;
+ if (state->vreg_lrs[m].live_after != ii) goto cannot_coalesce;
if (DEBUG_REGALLOC) {
vex_printf("COALESCE ");
settings->ppReg(vregS);
@@ -1096,7 +1109,7 @@
vex_printf("\n\n");
}
/* Find the state entry for vregS. */
- Int n = vreg_state[k]; /* k is the index of vregS */
+ Int n = state->vreg_state[k]; /* k is the index of vregS */
if (n == INVALID_RREG_NO) {
/* vregS is not currently in a real register. So we can't
do the coalescing. Give up. */
@@ -1106,15 +1119,15 @@
/* Finally, we can do the coalescing. It's trivial -- merely
claim vregS's register for vregD. */
- rreg_state[n].vreg = vregD;
+ state->rreg_state[n].vreg = vregD;
vassert(IS_VALID_VREGNO(hregIndex(vregD)));
vassert(IS_VALID_VREGNO(hregIndex(vregS)));
- vreg_state[hregIndex(vregD)] = toShort(n);
- vreg_state[hregIndex(vregS)] = INVALID_RREG_NO;
+ state->vreg_state[hregIndex(vregD)] = toShort(n);
+ state->vreg_state[hregIndex(vregS)] = INVALID_RREG_NO;
/* This rreg has become associated with a different vreg and
hence with a different spill slot. Play safe. */
- rreg_state[n].eq_spill_slot = False;
+ state->rreg_state[n].eq_spill_slot = False;
/* Move on to the next insn. We skip the post-insn stuff for
fixed registers, since this move should not interact with
@@ -1128,17 +1141,17 @@
/* Look for vregs whose live range has just ended, and
mark the associated rreg as free. */
- for (Int j = 0; j < n_rregs; j++) {
- if (rreg_state[j].disp != Bound)
+ for (UInt j = 0; j < state->n_rregs; j++) {
+ if (state->rreg_state[j].disp != Bound)
continue;
- UInt vregno = hregIndex(rreg_state[j].vreg);
+ UInt vregno = hregIndex(state->rreg_state[j].vreg);
vassert(IS_VALID_VREGNO(vregno));
- if (vreg_lrs[vregno].dead_before <= ii) {
- rreg_state[j].disp = Free;
- rreg_state[j].eq_spill_slot = False;
- Int m = hregIndex(rreg_state[j].vreg);
+ if (state->vreg_lrs[vregno].dead_before <= ii) {
+ state->rreg_state[j].disp = Free;
+ state->rreg_state[j].eq_spill_slot = False;
+ Int m = hregIndex(state->rreg_state[j].vreg);
vassert(IS_VALID_VREGNO(m));
- vreg_state[m] = INVALID_RREG_NO;
+ state->vreg_state[m] = INVALID_RREG_NO;
if (DEBUG_REGALLOC) {
vex_printf("free up ");
settings->ppReg(settings->univ->regs[j]);
@@ -1163,13 +1176,13 @@
(their .live_after field).
*/
while (True) {
- vassert(rreg_lrs_la_next >= 0);
- vassert(rreg_lrs_la_next <= rreg_lrs_used);
- if (rreg_lrs_la_next == rreg_lrs_used)
+ vassert(state->rreg_lrs_la_next >= 0);
+ vassert(state->rreg_lrs_la_next <= state->rreg_lrs_used);
+ if (state->rreg_lrs_la_next == state->rreg_lrs_used)
break; /* no more real reg live ranges to consider */
- if (ii < rreg_lrs_la[rreg_lrs_la_next].live_after)
+ if (ii < state->rreg_lrs_la[state->rreg_lrs_la_next].live_after)
break; /* next live range does not yet start */
- vassert(ii == rreg_lrs_la[rreg_lrs_la_next].live_after);
+ vassert(ii == state->rreg_lrs_la[state->rreg_lrs_la_next].live_after);
/* rreg_lrs_la[rreg_lrs_la_next].rreg needs to be freed up.
Find the associated rreg_state entry. */
/* Note, re ii == rreg_lrs_la[rreg_lrs_la_next].live_after.
@@ -1182,42 +1195,43 @@
than before it. */
if (DEBUG_REGALLOC) {
vex_printf("need to free up rreg: ");
- settings->ppReg(rreg_lrs_la[rreg_lrs_la_next].rreg);
+ settings->ppReg(state->rreg_lrs_la[state->rreg_lrs_la_next].rreg);
vex_printf("\n\n");
}
- Int k = hregIndex(rreg_lrs_la[rreg_lrs_la_next].rreg);
+ Int k = hregIndex(state->rreg_lrs_la[state->rreg_lrs_la_next].rreg);
/* If this fails, we don't have an entry for this rreg.
Which we should. */
vassert(IS_VALID_RREGNO(k));
- Int m = hregIndex(rreg_state[k].vreg);
- if (rreg_state[k].disp == Bound) {
+ Int m = hregIndex(state->rreg_state[k].vreg);
+ if (state->rreg_state[k].disp == Bound) {
/* Yes, there is an associated vreg. Spill it if it's
still live. */
vassert(IS_VALID_VREGNO(m));
- vreg_state[m] = INVALID_RREG_NO;
- if (vreg_lrs[m].dead_before > ii) {
- vassert(vreg_lrs[m].reg_class != HRcINVALID);
- if ((!eq_spill_opt) || !rreg_state[k].eq_spill_slot) {
+ state->vreg_state[m] = INVALID_RREG_NO;
+ if (state->vreg_lrs[m].dead_before > ii) {
+ vassert(state->vreg_lrs[m].reg_class != HRcINVALID);
+ if ((!eq_spill_opt) || !state->rreg_state[k].eq_spill_slot) {
HInstr* spill1 = NULL;
HInstr* spill2 = NULL;
settings->genSpill(&spill1, &spill2, settings->univ->regs[k],
- vreg_lrs[m].spill_offset, settings->mode64);
+ state->vreg_lrs[m].spill_offset,
+ settings->mode64);
vassert(spill1 || spill2); /* can't both be NULL */
if (spill1)
EMIT_INSTR(spill1);
if (spill2)
EMIT_INSTR(spill2);
}
- rreg_state[k].eq_spill_slot = True;
+ state->rreg_state[k].eq_spill_slot = True;
}
}
- rreg_state[k].disp = Unavail;
- rreg_state[k].vreg = INVALID_HREG;
- rreg_state[k].eq_spill_slot = False;
+ state->rreg_state[k].disp = Unavail;
+ state->rreg_state[k].vreg = INVALID_HREG;
+ state->rreg_state[k].eq_spill_slot = False;
/* check for further rregs entering HLRs at this point */
- rreg_lrs_la_next++;
+ state->rreg_lrs_la_next++;
}
if (DEBUG_REGALLOC) {
@@ -1235,6 +1249,8 @@
We also build up the final vreg->rreg mapping to be applied
to the insn. */
+ /* The vreg -> rreg map constructed and then applied to each instr. */
+ HRegRemap remap;
initHRegRemap(&remap);
/* ------------ BEGIN directReload optimisation ----------- */
@@ -1264,13 +1280,13 @@
nreads++;
Int m = hregIndex(vreg);
vassert(IS_VALID_VREGNO(m));
- Int k = vreg_state[m];
+ Int k = state->vreg_state[m];
if (!IS_VALID_RREGNO(k)) {
/* ok, it is spilled. Now, is this its last use? */
- vassert(vreg_lrs[m].dead_before >= ii+1);
- if (vreg_lrs[m].dead_before == ii+1
+ vassert(state->vreg_lrs[m].dead_before >= ii+1);
+ if (state->vreg_lrs[m].dead_before == ii+1
&& hregIsInvalid(cand)) {
- spilloff = vreg_lrs[m].spill_offset;
+ spilloff = state->vreg_lrs[m].spill_offset;
cand = vreg;
}
}
@@ -1324,14 +1340,14 @@
anything more. Inspect the current state to find out. */
Int m = hregIndex(vreg);
vassert(IS_VALID_VREGNO(m));
- Int n = vreg_state[m];
+ Int n = state->vreg_state[m];
if (IS_VALID_RREGNO(n)) {
- vassert(rreg_state[n].disp == Bound);
+ vassert(state->rreg_state[n].disp == Bound);
addToHRegRemap(&remap, vreg, settings->univ->regs[n]);
/* If this rreg is written or modified, mark it as different
from any spill slot value. */
if (reg_usage_arr[ii].vMode[j] != HRmRead)
- rreg_state[n].eq_spill_slot = False;
+ state->rreg_state[n].eq_spill_slot = False;
continue;
} else {
vassert(n == INVALID_RREG_NO);
@@ -1344,11 +1360,11 @@
as possible. */
Int k_suboptimal = -1;
Int k;
- for (k = 0; k < n_rregs; k++) {
- if (rreg_state[k].disp != Free
+ for (k = 0; k < state->n_rregs; k++) {
+ if (state->rreg_state[k].disp != Free
|| hregClass(settings->univ->regs[k]) != hregClass(vreg))
continue;
- if (rreg_state[k].has_hlrs) {
+ if (state->rreg_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;
@@ -1361,12 +1377,12 @@
if (k_suboptimal >= 0)
k = k_suboptimal;
- if (k < n_rregs) {
- rreg_state[k].disp = Bound;
- rreg_state[k].vreg = vreg;
+ if (k < state->n_rregs) {
+ state->rreg_state[k].disp = Bound;
+ state->rreg_state[k].vreg = vreg;
Int p = hregIndex(vreg);
vassert(IS_VALID_VREGNO(p));
- vreg_state[p] = toShort(k);
+ state->vreg_state[p] = toShort(k);
addToHRegRemap(&remap, vreg, settings->univ->regs[k]);
/* Generate a reload if needed. This only creates needed
reloads because the live range builder for vregs will
@@ -1375,11 +1391,12 @@
the first reference for this vreg, and so a reload is
indeed needed. */
if (reg_usage_arr[ii].vMode[j] != HRmWrite) {
- vassert(vreg_lrs[p].reg_class != HRcINVALID);
+ vassert(state->vreg_lrs[p].reg_class != HRcINVALID);
HInstr* reload1 = NULL;
HInstr* reload2 = NULL;
settings->genReload(&reload1, &reload2, settings->univ->regs[k],
- vreg_lrs[p].spill_offset, settings->mode64);
+ state->vreg_lrs[p].spill_offset,
+ settings->mode64);
vassert(reload1 || reload2); /* can't both be NULL */
if (reload1)
EMIT_INSTR(reload1);
@@ -1389,13 +1406,13 @@
If it's merely read we can claim it now equals the
spill slot, but not so if it is modified. */
if (reg_usage_arr[ii].vMode[j] == HRmRead) {
- rreg_state[k].eq_spill_slot = True;
+ state->rreg_state[k].eq_spill_slot = True;
} else {
vassert(reg_usage_arr[ii].vMode[j] == HRmModify);
- rreg_state[k].eq_spill_slot = False;
+ state->rreg_state[k].eq_spill_slot = False;
}
} else {
- rreg_state[k].eq_spill_slot = False;
+ state->rreg_state[k].eq_spill_slot = False;
}
continue;
@@ -1409,18 +1426,19 @@
/* First, mark in the rreg_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_rregs; k++) {
- rreg_state[k].is_spill_cand = False;
- if (rreg_state[k].disp != Bound)
+ for (k = 0; k < state->n_rregs; k++) {
+ state->rreg_state[k].is_spill_cand = False;
+ if (state->rreg_state[k].disp != Bound)
continue;
if (hregClass(settings->univ->regs[k]) != hregClass(vreg))
continue;
- rreg_state[k].is_spill_cand = True;
+ state->rreg_state[k].is_spill_cand = True;
/* Note, the following loop visits only the virtual regs
mentioned by the instruction. */
for (m = 0; m < reg_usage_arr[ii].n_vRegs; m++) {
- if (sameHReg(rreg_state[k].vreg, reg_usage_arr[ii].vRegs[m])) {
- rreg_state[k].is_spill_cand = False;
+ if (sameHReg(state->rreg_state[k].vreg,
+ reg_usage_arr[ii].vRegs[m])) {
+ state->rreg_state[k].is_spill_cand = False;
break;
}
}
@@ -1433,7 +1451,8 @@
of consequent reloads required. */
Int spillee
= findMostDistantlyMentionedVReg (
- reg_usage_arr, ii+1, instrs_in->insns_used, rreg_state, n_rregs );
+ reg_usage_arr, ii+1, instrs_in->insns_used, state->rreg_state,
+ state->n_rregs);
if (spillee == -1) {
/* Hmmmmm. There don't appear to be any spill candidates.
@@ -1446,25 +1465,26 @@
/* Right. So we're going to spill rreg_state[spillee]. */
vassert(IS_VALID_RREGNO(spillee));
- vassert(rreg_state[spillee].disp == Bound);
+ vassert(state->rreg_state[spillee].disp == Bound);
/* check it's the right class */
vassert(hregClass(settings->univ->regs[spillee]) == hregClass(vreg));
/* check we're not ejecting the vreg for which we are trying
to free up a register. */
- vassert(! sameHReg(rreg_state[spillee].vreg, vreg));
+ vassert(! sameHReg(state->rreg_state[spillee].vreg, vreg));
- m = hregIndex(rreg_state[spillee].vreg);
+ m = hregIndex(state->rreg_state[spillee].vreg);
vassert(IS_VALID_VREGNO(m));
/* So here's the spill store. Assert that we're spilling a
live vreg. */
- vassert(vreg_lrs[m].dead_before > ii);
- vassert(vreg_lrs[m].reg_class != HRcINVALID);
- if ((!eq_spill_opt) || !rreg_state[spillee].eq_spill_slot) {
+ vassert(state->vreg_lrs[m].dead_before > ii);
+ vassert(state->vreg_lrs[m].reg_class != HRcINVALID);
+ if ((!eq_spill_opt) || !state->rreg_state[spillee].eq_spill_slot) {
HInstr* spill1 = NULL;
HInstr* spill2 = NULL;
settings->genSpill(&spill1, &spill2, settings->univ->regs[spillee],
- vreg_lrs[m].spill_offset, settings->mode64);
+ state->vreg_lrs[m].spill_offset,
+ settings->mode64);
vassert(spill1 || spill2); /* can't both be NULL */
if (spill1)
EMIT_INSTR(spill1);
@@ -1474,24 +1494,25 @@
/* Update the rreg_state to reflect the new assignment for this
rreg. */
- rreg_state[spillee].vreg = vreg;
- vreg_state[m] = INVALID_RREG_NO;
+ state->rreg_state[spillee].vreg = vreg;
+ state->vreg_state[m] = INVALID_RREG_NO;
- rreg_state[spillee].eq_spill_slot = False; /* be safe */
+ state->rreg_state[spillee].eq_spill_slot = False; /* be safe */
m = hregIndex(vreg);
vassert(IS_VALID_VREGNO(m));
- vreg_state[m] = toShort(spillee);
+ state->vreg_state[m] = toShort(spillee);
/* Now, if this vreg is being read or modified (as opposed to
written), we have to generate a reload for it. */
if (reg_usage_arr[ii].vMode[j] != HRmWrite) {
- vassert(vreg_lrs[m].reg_class != HRcINVALID);
+ vassert(state->vreg_lrs[m].reg_class != HRcINVALID);
HInstr* reload1 = NULL;
HInstr* reload2 = NULL;
settings->genReload(&reload1, &reload2,
settings->univ->regs[spillee],
- vreg_lrs[m].spill_offset, settings->mode64);
+ state->vreg_lrs[m].spill_offset,
+ settings->mode64);
vassert(reload1 || reload2); /* can't both be NULL */
if (reload1)
EMIT_INSTR(reload1);
@@ -1501,10 +1522,10 @@
If it's merely read we can claim it now equals the
spill slot, but not so if it is modified. */
if (reg_usage_arr[ii].vMode[j] == HRmRead) {
- rreg_state[spillee].eq_spill_slot = True;
+ state->rreg_state[spillee].eq_spill_slot = True;
} else {
vassert(reg_usage_arr[ii].vMode[j] == HRmModify);
- rreg_state[spillee].eq_spill_slot = False;
+ state->rreg_state[spillee].eq_spill_slot = False;
}
}
@@ -1540,26 +1561,26 @@
/* Now we need to check for rregs exiting fixed live ranges
after this instruction, and if so mark them as free. */
while (True) {
- vassert(rreg_lrs_db_next >= 0);
- vassert(rreg_lrs_db_next <= rreg_lrs_used);
- if (rreg_lrs_db_next == rreg_lrs_used)
+ vassert(state->rreg_lrs_db_next >= 0);
+ vassert(state->rreg_lrs_db_next <= state->rreg_lrs_used);
+ if (state->rreg_lrs_db_next == state->rreg_lrs_used)
break; /* no more real reg live ranges to consider */
- if (ii+1 < rreg_lrs_db[rreg_lrs_db_next].dead_before)
+ if (ii+1 < state->rreg_lrs_db[state->rreg_lrs_db_next].dead_before)
break; /* next live range does not yet start */
- vassert(ii+1 == rreg_lrs_db[rreg_lrs_db_next].dead_before);
+ vassert(ii+1 == state->rreg_lrs_db[state->rreg_lrs_db_next].dead_before);
/* rreg_lrs_db[[rreg_lrs_db_next].rreg is exiting a hard live
range. Mark it as such in the main rreg_state array. */
- HReg reg = rreg_lrs_db[rreg_lrs_db_next].rreg;
+ HReg reg = state->rreg_lrs_db[state->rreg_lrs_db_next].rreg;
vassert(!hregIsVirtual(reg));
Int k = hregIndex(reg);
vassert(IS_VALID_RREGNO(k));
- vassert(rreg_state[k].disp == Unavail);
- rreg_state[k].disp = Free;
- rreg_state[k].vreg = INVALID_HREG;
- rreg_state[k].eq_spill_slot = False;
+ vassert(state->rreg_state[k].disp == Unavail);
+ state->rreg_state[k].disp = Free;
+ state->rreg_state[k].vreg = INVALID_HREG;
+ state->rreg_state[k].eq_spill_slot = False;
/* check for further rregs leaving HLRs at this point */
- rreg_lrs_db_next++;
+ state->rreg_lrs_db_next++;
}
if (DEBUG_REGALLOC) {
@@ -1572,13 +1593,9 @@
/* ------ END: Process each insn in turn. ------ */
- /* free(rreg_state); */
- /* free(rreg_lrs); */
- /* if (vreg_lrs) free(vreg_lrs); */
-
/* Paranoia */
- vassert(rreg_lrs_la_next == rreg_lrs_used);
- vassert(rreg_lrs_db_next == rreg_lrs_used);
+ vassert(state->rreg_lrs_la_next == state->rreg_lrs_used);
+ vassert(state->rreg_lrs_db_next == state->rreg_lrs_used);
return instrs_out;
|
|
From: <sv...@va...> - 2017-06-14 06:10:29
|
Author: iraisr
Date: Wed Jun 14 07:10:18 2017
New Revision: 3394
Log:
Small obvious fixes.
Modified:
branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c
Modified: branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c
==============================================================================
--- branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c (original)
+++ branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c Wed Jun 14 07:10:18 2017
@@ -418,7 +418,7 @@
/* .. and the redundant backward map */
/* Each value is 0 .. n_rregs-1 or is INVALID_RREG_NO.
- This inplies n_rregs must be <= 32768. */
+ This implies n_rregs must be <= 32768. */
Short* vreg_state; /* [0 .. n_vregs-1] */
/* The vreg -> rreg map constructed and then applied to each
@@ -541,7 +541,7 @@
/* An array to hold the reg-usage info for the incoming
instructions. */
reg_usage_arr
- = LibVEX_Alloc_inline(sizeof(HRegUsage) * instrs_in->insns_used-1);
+ = LibVEX_Alloc_inline(sizeof(HRegUsage) * instrs_in->insns_used);
/* ------ end of SET UP TO COMPUTE VREG LIVE RANGES ------ */
@@ -671,7 +671,7 @@
/* for each allocator-available real reg mentioned in the insn ... */
/* Note. We are allocating only over the real regs available to
- the allocator. Others, eg the stack or baseblock pointers,
+ the allocator. Others, eg the stack or guest state pointers,
are unavailable to allocation and so we never visit them.
Hence the iteration is cut off at n_rregs-1, since n_rregs ==
univ->allocable. */
@@ -916,8 +916,8 @@
} /* switch (vreg_lrs[j].reg_class) */
- /* This reflects LibVEX's hard-wired knowledge of the baseBlock
- layout: the guest state, then two equal sized areas following
+ /* This reflects LibVEX's hard-wired knowledge of the guest state
+ layout: the guest state itself, then two equal sized areas following
it for two sets of shadow state, and then the spill area. */
vreg_lrs[j].spill_offset = toShort(settings->guest_sizeB * 3 + ss_no * 8);
|
|
From: <sv...@va...> - 2017-06-14 04:03:35
|
Author: iraisr
Date: Wed Jun 14 05:03:21 2017
New Revision: 3393
Log:
Revert VEX register allocator back to the original state from r3389.
The current approach (work on small chunks in isolation) will not work.
Modified:
branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c
Modified: branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c
==============================================================================
--- branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c (original)
+++ branches/VEX_JIT_HACKS/priv/host_generic_reg_alloc2.c Wed Jun 14 05:03:21 2017
@@ -142,8 +142,8 @@
#define INVALID_RREG_NO ((Short)(-1))
-#define IS_VALID_VREGNO(_zz) ((_zz) >= 0 && (_zz) < state->n_vregs)
-#define IS_VALID_RREGNO(_zz) ((_zz) >= 0 && (_zz) < state->n_rregs)
+#define IS_VALID_VREGNO(_zz) ((_zz) >= 0 && (_zz) < n_vregs)
+#define IS_VALID_RREGNO(_zz) ((_zz) >= 0 && (_zz) < n_rregs)
/* Search forward from some given point in the incoming instruction
@@ -338,73 +338,10 @@
# undef IS_4_ALIGNED
}
-#define N_SPILL64S (LibVEX_N_SPILL_BYTES / 8)
-STATIC_ASSERT((LibVEX_N_SPILL_BYTES % LibVEX_GUEST_STATE_ALIGN) == 0);
-STATIC_ASSERT((N_SPILL64S % 2) == 0);
-
-/* Register allocator state. Keeps all vital information at one place. */
-typedef
- struct {
- /* Info on vregs. Computed once and remains unchanged. */
- UInt n_vregs;
- VRegLR* vreg_lrs; /* [0 .. n_vregs-1] */
-
- /* Running state of the core allocation algorithm. */
- RRegState* rreg_state; /* [0 .. n_rregs-1] */
- UInt n_rregs;
-
- /* .. and the redundant backward map */
- /* Each value is 0 .. n_rregs-1 or is INVALID_RREG_NO.
- This implies n_rregs must be <= 32768. */
- Short* vreg_state; /* [0 .. n_vregs-1] */
- }
- RegAllocState;
-
-
-#define INVALID_INSTRNO (-2)
-
-static void initRegAllocState(
- RegAllocState* state,
- const RegAllocSettings* settings,
- UInt n_vregs)
-{
- state->n_vregs = n_vregs;
-
- state->vreg_lrs = NULL;
- if (state->n_vregs > 0)
- state->vreg_lrs = LibVEX_Alloc_inline(sizeof(VRegLR) * state->n_vregs);
- for (UInt j = 0; j < state->n_vregs; j++) {
- state->vreg_lrs[j].live_after = INVALID_INSTRNO;
- state->vreg_lrs[j].dead_before = INVALID_INSTRNO;
- state->vreg_lrs[j].spill_offset = 0;
- state->vreg_lrs[j].spill_size = 0;
- state->vreg_lrs[j].reg_class = HRcINVALID;
- }
-
- /* n_rregs is no more than a short name for n_available_real_regs. */
- state->n_rregs = settings->univ->allocable;
- /* If this is not so, the universe we have is nonsensical. */
- vassert(state->n_rregs > 0);
-
- /* Initialise running state. */
- state->rreg_state = LibVEX_Alloc_inline(state->n_rregs * sizeof(RRegState));
-
- for (UInt j = 0; j < state->n_rregs; j++) {
- state->rreg_state[j].has_hlrs = False;
- state->rreg_state[j].disp = Free;
- state->rreg_state[j].vreg = INVALID_HREG;
- state->rreg_state[j].is_spill_cand = False;
- state->rreg_state[j].eq_spill_slot = False;
- }
-
- state->vreg_state = LibVEX_Alloc_inline(state->n_vregs * sizeof(Short));
- for (UInt j = 0; j < state->n_vregs; j++)
- state->vreg_state[j] = INVALID_RREG_NO;
-}
static inline void flush_rreg_lrs_la(
- RRegLR** rreg_lrs_la, UInt *rreg_lrs_size, UInt *rreg_lrs_used,
- HReg rreg, Int flush_la, Int flush_db, const HChar *debug_phase)
+ RRegLR** rreg_lrs_la, UInt *rreg_lrs_size, UInt *rreg_lrs_used,
+ HReg rreg, Int flush_la, Int flush_db, const HChar *debug_phase)
{
ensureRRLRspace(rreg_lrs_la, rreg_lrs_size, *rreg_lrs_used);
if (0) {
@@ -417,34 +354,38 @@
(*rreg_lrs_used)++;
}
-/* Register allocator for a chunk of instructions in an HInstrVec.
+/* 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.
- Takes a chunk of unallocated insns present in HInstrVec, delimited
- by 'ii_start' .. 'ii_start + ii_length' (exclusive).
-
- Emits the allocated insns into insns_out.
-*/
-static void regAlloc_HInstrVecChunk (
- /* Incoming virtual-registerised code. */
- HInstrVec* instrs_in,
+ Returns a new list of instructions, which, as a result of the
+ behaviour of mapRegs, will be in-place modifications of the
+ original instructions.
- UInt ii_start,
- UInt ii_length,
+ 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.
- /* Register allocator state. */
- RegAllocState* state,
+ Takes an expandable array of pointers to unallocated insns.
+ Returns an expandable array of pointers to allocated insns.
+*/
+HInstrSB* doRegisterAllocation (
+ /* Incoming virtual-registerised code. */
+ HInstrSB* sb_in,
/* Register allocator settings. */
- const RegAllocSettings* settings,
-
- /* Outgoing code with real registers. */
- HInstrVec* instrs_out
+ const RegAllocSettings* settings
)
{
- vassert(ii_start + ii_length <= instrs_in->insns_used);
+# define N_SPILL64S (LibVEX_N_SPILL_BYTES / 8)
const Bool eq_spill_opt = True;
+ /* Info on vregs and rregs. Computed once and remains
+ unchanged. */
+ Int n_vregs;
+ VRegLR* vreg_lrs; /* [0 .. n_vregs-1] */
+
/* We keep two copies of the real-reg live range info, one sorted
by .live_after and the other by .dead_before. First the
unsorted info is created in the _la variant is copied into the
@@ -461,7 +402,7 @@
/* Info on register usage in the incoming instruction array.
Computed once and remains unchanged, more or less; updated
sometimes by the direct-reload optimisation. */
- HRegUsage* reg_usage_arr; /* [0 .. ii_length - 1] */
+ HRegUsage* reg_usage_arr; /* [0 .. instrs_in->insns_used-1] */
/* Used when constructing vreg_lrs (for allocating stack
slots). */
@@ -471,14 +412,37 @@
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;
+
+ /* The output array of instructions. */
+ HInstrSB* instrs_out;
+ HInstrVec *instrs_in = sb_in->insns;
+
/* Sanity checks are expensive. They are only done periodically,
not at each insn processed. */
Bool do_sanity_check;
+ vassert(0 == (settings->guest_sizeB % LibVEX_GUEST_STATE_ALIGN));
+ vassert(0 == (LibVEX_N_SPILL_BYTES % LibVEX_GUEST_STATE_ALIGN));
+ vassert(0 == (N_SPILL64S % 2));
+
/* The live range numbers are signed shorts, and so limiting the
number of insns to 15000 comfortably guards against them
overflowing 32k. */
- vassert(ii_length <= 15000);
+ vassert(instrs_in->insns_used <= 15000);
+
+# define INVALID_INSTRNO (-2)
# define EMIT_INSTR(_instr) \
do { \
@@ -488,38 +452,69 @@
settings->ppInstr(_tmp, settings->mode64); \
vex_printf("\n\n"); \
} \
- addHInstr(instrs_out, _tmp); \
+ addHInstr(instrs_out->insns, _tmp); \
} while (0)
-# define PRINT_STATE \
- do { \
- Int z, q; \
- for (z = 0; z < state->n_rregs; z++) { \
- vex_printf(" rreg_state[%2d] = ", z); \
- settings->ppReg(settings->univ->regs[z]); \
- vex_printf(" \t"); \
- switch (state->rreg_state[z].disp) { \
- case Free: vex_printf("Free\n"); break; \
- case Unavail: vex_printf("Unavail\n"); break; \
- case Bound: vex_printf("BoundTo "); \
- settings->ppReg(state->rreg_state[z].vreg); \
- vex_printf("\n"); break; \
- } \
- } \
- vex_printf("\n vreg_state[0 .. %d]:\n ", state->n_vregs-1); \
- q = 0; \
- for (z = 0; z < state->n_vregs; z++) { \
- if (state->vreg_state[z] == INVALID_RREG_NO) \
- continue; \
- vex_printf("[%d] -> %d ", z, state->vreg_state[z]); \
- q++; \
- if (q > 0 && (q % 6) == 0) \
- vex_printf("\n "); \
- } \
- vex_printf("\n"); \
+# define PRINT_STATE \
+ do { \
+ Int z, q; \
+ for (z = 0; z < n_rregs; z++) { \
+ vex_printf(" rreg_state[%2d] = ", z); \
+ settings->ppReg(settings->univ->regs[z]); \
+ vex_printf(" \t"); \
+ switch (rreg_state[z].disp) { \
+ case Free: vex_printf("Free\n"); break; \
+ case Unavail: vex_printf("Unavail\n"); break; \
+ case Bound: vex_printf("BoundTo "); \
+ settings->ppReg(rreg_state[z].vreg); \
+ vex_printf("\n"); break; \
+ } \
+ } \
+ vex_printf("\n vreg_state[0 .. %d]:\n ", n_vregs-1); \
+ q = 0; \
+ for (z = 0; z < n_vregs; z++) { \
+ if (vreg_state[z] == INVALID_RREG_NO) \
+ continue; \
+ vex_printf("[%d] -> %d ", z, vreg_state[z]); \
+ q++; \
+ if (q > 0 && (q % 6) == 0) \
+ vex_printf("\n "); \
+ } \
+ vex_printf("\n"); \
} while (0)
+ /* --------- Stage 0: set up output array --------- */
+ /* --------- and allocate/initialise running state. --------- */
+
+ instrs_out = newHInstrSB();
+
+ /* ... and initialise running state. */
+ /* n_rregs is no more than a short name for n_available_real_regs. */
+ n_rregs = settings->univ->allocable;
+ n_vregs = sb_in->n_vregs;
+
+ /* If this is not so, vreg_state entries will overflow. */
+ vassert(n_vregs < 32767);
+
+ /* If this is not so, the universe we have is nonsensical. */
+ vassert(n_rregs > 0);
+
+ rreg_state = LibVEX_Alloc_inline(n_rregs * sizeof(RRegState));
+ vreg_state = LibVEX_Alloc_inline(n_vregs * sizeof(Short));
+
+ for (Int j = 0; j < n_rregs; j++) {
+ rreg_state[j].has_hlrs = False;
+ rreg_state[j].disp = Free;
+ rreg_state[j].vreg = INVALID_HREG;
+ rreg_state[j].is_spill_cand = False;
+ rreg_state[j].eq_spill_slot = False;
+ }
+
+ for (Int j = 0; j < n_vregs; j++)
+ vreg_state[j] = INVALID_RREG_NO;
+
+
/* --------- Stage 1: compute vreg live ranges. --------- */
/* --------- Stage 2: compute rreg live ranges. --------- */
@@ -531,9 +526,22 @@
0 .. n_vregs-1, so we can just dump the results
in a pre-allocated array. */
+ vreg_lrs = NULL;
+ if (n_vregs > 0)
+ vreg_lrs = LibVEX_Alloc_inline(sizeof(VRegLR) * n_vregs);
+
+ for (Int j = 0; j < n_vregs; j++) {
+ vreg_lrs[j].live_after = INVALID_INSTRNO;
+ vreg_lrs[j].dead_before = INVALID_INSTRNO;
+ vreg_lrs[j].spill_offset = 0;
+ vreg_lrs[j].spill_size = 0;
+ vreg_lrs[j].reg_class = HRcINVALID;
+ }
+
/* An array to hold the reg-usage info for the incoming
instructions. */
- reg_usage_arr = LibVEX_Alloc_inline(sizeof(HRegUsage) * ii_length);
+ reg_usage_arr
+ = LibVEX_Alloc_inline(sizeof(HRegUsage) * instrs_in->insns_used-1);
/* ------ end of SET UP TO COMPUTE VREG LIVE RANGES ------ */
@@ -550,10 +558,11 @@
/* We'll need to track live range start/end points seperately for
each rreg. Sigh. */
- rreg_live_after = LibVEX_Alloc_inline(state->n_rregs * sizeof(Int));
- rreg_dead_before = LibVEX_Alloc_inline(state->n_rregs * sizeof(Int));
+ vassert(n_rregs > 0);
+ rreg_live_after = LibVEX_Alloc_inline(n_rregs * sizeof(Int));
+ rreg_dead_before = LibVEX_Alloc_inline(n_rregs * sizeof(Int));
- for (UInt j = 0; j < state->n_rregs; j++) {
+ for (Int j = 0; j < n_rregs; j++) {
rreg_live_after[j] =
rreg_dead_before[j] = INVALID_INSTRNO;
}
@@ -562,14 +571,14 @@
/* ------ start of ITERATE OVER INSNS ------ */
- for (UInt ii = 0; ii < ii_length; ii++) {
- const HInstr* instr_in = instrs_in->insns[ii_start + ii];
+ for (Int ii = 0; ii < instrs_in->insns_used; ii++) {
- settings->getRegUsage(®_usage_arr[ii], instr_in, settings->mode64);
+ settings->getRegUsage(®_usage_arr[ii], instrs_in->insns[ii],
+ settings->mode64);
if (0) {
vex_printf("\n%d stage1: ", ii);
- settings->ppInstr(instr_in, settings->mode64);
+ settings->ppInstr(instrs_in->insns[ii], settings->mode64);
vex_printf("\n");
ppHRegUsage(settings->univ, ®_usage_arr[ii]);
}
@@ -583,46 +592,46 @@
vassert(hregIsVirtual(vreg));
Int k = hregIndex(vreg);
- if (k < 0 || k >= state->n_vregs) {
+ if (k < 0 || k >= n_vregs) {
vex_printf("\n");
- settings->ppInstr(instr_in, settings->mode64);
+ settings->ppInstr(instrs_in->insns[ii], settings->mode64);
vex_printf("\n");
- vex_printf("vreg %d, n_vregs %d\n", k, state->n_vregs);
+ 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 (state->vreg_lrs[k].reg_class == HRcINVALID) {
+ if (vreg_lrs[k].reg_class == HRcINVALID) {
/* First mention of this vreg. */
- state->vreg_lrs[k].reg_class = hregClass(vreg);
+ vreg_lrs[k].reg_class = hregClass(vreg);
} else {
/* Seen it before, so check for consistency. */
- vassert(state->vreg_lrs[k].reg_class == hregClass(vreg));
+ vassert(vreg_lrs[k].reg_class == hregClass(vreg));
}
/* Now consider live ranges. */
switch (reg_usage_arr[ii].vMode[j]) {
case HRmRead:
- if (state->vreg_lrs[k].live_after == INVALID_INSTRNO) {
+ if (vreg_lrs[k].live_after == INVALID_INSTRNO) {
vex_printf("\n\nOFFENDING VREG = %d\n", k);
vpanic("doRegisterAllocation: "
"first event for vreg is Read");
}
- state->vreg_lrs[k].dead_before = toShort(ii + 1);
+ vreg_lrs[k].dead_before = toShort(ii + 1);
break;
case HRmWrite:
- if (state->vreg_lrs[k].live_after == INVALID_INSTRNO)
- state->vreg_lrs[k].live_after = toShort(ii);
- state->vreg_lrs[k].dead_before = toShort(ii + 1);
+ if (vreg_lrs[k].live_after == INVALID_INSTRNO)
+ vreg_lrs[k].live_after = toShort(ii);
+ vreg_lrs[k].dead_before = toShort(ii + 1);
break;
case HRmModify:
- if (state->vreg_lrs[k].live_after == INVALID_INSTRNO) {
+ if (vreg_lrs[k].live_after == INVALID_INSTRNO) {
vex_printf("\n\nOFFENDING VREG = %d\n", k);
vpanic("doRegisterAllocation: "
"first event for vreg is Modify");
}
- state->vreg_lrs[k].dead_before = toShort(ii + 1);
+ vreg_lrs[k].dead_before = toShort(ii + 1);
break;
default:
vpanic("doRegisterAllocation(1)");
@@ -656,8 +665,8 @@
/* Don't bother to look at registers which are not available
to the allocator. We asserted above that n_rregs > 0, so
n_rregs-1 is safe. */
- if (rReg_maxIndex >= state->n_rregs)
- rReg_maxIndex = state->n_rregs - 1;
+ if (rReg_maxIndex >= n_rregs)
+ rReg_maxIndex = n_rregs-1;
}
/* for each allocator-available real reg mentioned in the insn ... */
@@ -693,7 +702,7 @@
settings->ppReg(settings->univ->regs[j]);
vex_printf("\n");
vex_printf("\nOFFENDING instr = ");
- settings->ppInstr(instr_in, settings->mode64);
+ settings->ppInstr(instrs_in->insns[ii], settings->mode64);
vex_printf("\n");
vpanic("doRegisterAllocation: "
"first event for rreg is Read");
@@ -706,7 +715,7 @@
settings->ppReg(settings->univ->regs[j]);
vex_printf("\n");
vex_printf("\nOFFENDING instr = ");
- settings->ppInstr(instr_in, settings->mode64);
+ settings->ppInstr(instrs_in->insns[ii], settings->mode64);
vex_printf("\n");
vpanic("doRegisterAllocation: "
"first event for rreg is Modify");
@@ -733,7 +742,7 @@
/* ------ start of FINALISE RREG LIVE RANGES ------ */
/* Now finish up any live ranges left over. */
- for (UInt j = 0; j < state->n_rregs; j++) {
+ for (Int j = 0; j < n_rregs; j++) {
if (0) {
vex_printf("residual %d: %d %d\n", j, rreg_live_after[j],
@@ -768,12 +777,12 @@
/* rreg is involved in a HLR. Record this info in the array, if
there is space. */
UInt ix = hregIndex(rreg);
- vassert(ix < state->n_rregs);
- state->rreg_state[ix].has_hlrs = True;
+ vassert(ix < n_rregs);
+ rreg_state[ix].has_hlrs = True;
}
if (0) {
- for (UInt j = 0; j < state->n_rregs; j++) {
- if (!state->rreg_state[j].has_hlrs)
+ for (Int j = 0; j < n_rregs; j++) {
+ if (!rreg_state[j].has_hlrs)
continue;
settings->ppReg(settings->univ->regs[j]);
vex_printf(" hinted\n");
@@ -801,9 +810,9 @@
/* ------ end of FINALISE RREG LIVE RANGES ------ */
if (DEBUG_REGALLOC) {
- for (Int j = 0; j < state->n_vregs; j++) {
- vex_printf("vreg %d: la = %d, db = %d\n", j,
- state->vreg_lrs[j].live_after, state->vreg_lrs[j].dead_before);
+ for (Int j = 0; j < n_vregs; j++) {
+ vex_printf("vreg %d: la = %d, db = %d\n",
+ j, vreg_lrs[j].live_after, vreg_lrs[j].dead_before );
}
}
@@ -854,12 +863,12 @@
local_memset(ss_busy_until_before, 0, sizeof(ss_busy_until_before));
- for (Int j = 0; j < state->n_vregs; j++) {
+ for (Int 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 (state->vreg_lrs[j].live_after == INVALID_INSTRNO) {
- vassert(state->vreg_lrs[j].reg_class == HRcINVALID);
+ if (vreg_lrs[j].live_after == INVALID_INSTRNO) {
+ vassert(vreg_lrs[j].reg_class == HRcINVALID);
continue;
}
@@ -871,7 +880,7 @@
kept in sync with the size info on the definition of
HRegClass. */
Int ss_no = -1;
- switch (state->vreg_lrs[j].reg_class) {
+ switch (vreg_lrs[j].reg_class) {
case HRcVec128: case HRcFlt64:
/* Find two adjacent free slots in which between them
@@ -879,15 +888,15 @@
Since we are trying to find an even:odd pair, move
along in steps of 2 (slots). */
for (ss_no = 0; ss_no < N_SPILL64S-1; ss_no += 2)
- if (ss_busy_until_before[ss_no+0] <= state->vreg_lrs[j].live_after
- && ss_busy_until_before[ss_no+1] <= state->vreg_lrs[j].live_after)
+ if (ss_busy_until_before[ss_no+0] <= vreg_lrs[j].live_after
+ && ss_busy_until_before[ss_no+1] <= vreg_lrs[j].live_after)
break;
if (ss_no >= N_SPILL64S-1) {
vpanic("LibVEX_N_SPILL_BYTES is too low. "
"Increase and recompile.");
}
- ss_busy_until_before[ss_no+0] = state->vreg_lrs[j].dead_before;
- ss_busy_until_before[ss_no+1] = state->vreg_lrs[j].dead_before;
+ ss_busy_until_before[ss_no+0] = vreg_lrs[j].dead_before;
+ ss_busy_until_before[ss_no+1] = vreg_lrs[j].dead_before;
break;
default:
@@ -896,34 +905,33 @@
at the start point of this interval, and assign the
interval to it. */
for (ss_no = 0; ss_no < N_SPILL64S; ss_no++)
- if (ss_busy_until_before[ss_no] <= state->vreg_lrs[j].live_after)
+ if (ss_busy_until_before[ss_no] <= vreg_lrs[j].live_after)
break;
if (ss_no == N_SPILL64S) {
vpanic("LibVEX_N_SPILL_BYTES is too low. "
"Increase and recompile.");
}
- ss_busy_until_before[ss_no] = state->vreg_lrs[j].dead_before;
+ ss_busy_until_before[ss_no] = vreg_lrs[j].dead_before;
break;
- } /* switch (state->vreg_lrs[j].reg_class) */
+ } /* switch (vreg_lrs[j].reg_class) */
/* This reflects LibVEX's hard-wired knowledge of the baseBlock
layout: the guest state, then two equal sized areas following
it for two sets of shadow state, and then the spill area. */
- state->vreg_lrs[j].spill_offset
- = toShort(settings->guest_sizeB * 3 + ss_no * 8);
+ vreg_lrs[j].spill_offset = toShort(settings->guest_sizeB * 3 + ss_no * 8);
/* Independent check that we've made a sane choice of slot */
- sanity_check_spill_offset(&state->vreg_lrs[j]);
+ sanity_check_spill_offset( &vreg_lrs[j] );
/* if (j > max_ss_no) */
/* max_ss_no = j; */
}
if (0) {
vex_printf("\n\n");
- for (Int j = 0; j < state->n_vregs; j++)
+ for (Int j = 0; j < n_vregs; j++)
vex_printf("vreg %d --> spill offset %d\n",
- j, state->vreg_lrs[j].spill_offset);
+ j, vreg_lrs[j].spill_offset);
}
/* --------- Stage 4: establish rreg preferences --------- */
@@ -949,13 +957,12 @@
/* ------ BEGIN: Process each insn in turn. ------ */
- for (UInt ii = 0; ii < ii_length; ii++) {
- HInstr* instr_in = instrs_in->insns[ii_start + ii];
+ for (Int ii = 0; ii < instrs_in->insns_used; ii++) {
if (DEBUG_REGALLOC) {
vex_printf("\n====----====---- Insn %d ----====----====\n", ii);
vex_printf("---- ");
- settings->ppInstr(instr_in, settings->mode64);
+ settings->ppInstr(instrs_in->insns[ii], settings->mode64);
vex_printf("\n\nInitial state:\n");
PRINT_STATE;
vex_printf("\n");
@@ -968,9 +975,8 @@
instruction. */
do_sanity_check
= toBool(
- /* TODO-JIT: Sanity checks unconditionally enabled. */
- True /* Set to True for sanity checking of all insns. */
- || ii == ii_length - 1
+ False /* Set to True for sanity checking of all insns. */
+ || ii == instrs_in->insns_used-1
|| (ii > 0 && (ii % 17) == 0)
);
@@ -996,7 +1002,7 @@
/* assert that this rreg is marked as unavailable */
vassert(!hregIsVirtual(reg));
- vassert(state->rreg_state[hregIndex(reg)].disp == Unavail);
+ vassert(rreg_state[hregIndex(reg)].disp == Unavail);
}
}
@@ -1004,11 +1010,11 @@
unavailable in the running rreg_state must have a
corresponding hard live range entry in the rreg_lrs
array. */
- for (UInt j = 0; j < state->n_rregs; j++) {
- vassert(state->rreg_state[j].disp == Bound
- || state->rreg_state[j].disp == Free
- || state->rreg_state[j].disp == Unavail);
- if (state->rreg_state[j].disp != Unavail)
+ for (Int j = 0; j < n_rregs; j++) {
+ vassert(rreg_state[j].disp == Bound
+ || rreg_state[j].disp == Free
+ || rreg_state[j].disp == Unavail);
+ if (rreg_state[j].disp != Unavail)
continue;
Int k;
for (k = 0; k < rreg_lrs_used; k++) {
@@ -1026,14 +1032,14 @@
/* Sanity check 3: all vreg-rreg bindings must bind registers
of the same class. */
- for (UInt j = 0; j < state->n_rregs; j++) {
- if (state->rreg_state[j].disp != Bound) {
- vassert(state->rreg_state[j].eq_spill_slot == False);
+ for (Int j = 0; j < n_rregs; j++) {
+ if (rreg_state[j].disp != Bound) {
+ vassert(rreg_state[j].eq_spill_slot == False);
continue;
}
vassert(hregClass(settings->univ->regs[j])
- == hregClass(state->rreg_state[j].vreg));
- vassert( hregIsVirtual(state->rreg_state[j].vreg));
+ == hregClass(rreg_state[j].vreg));
+ vassert( hregIsVirtual(rreg_state[j].vreg));
}
/* Sanity check 4: the vreg_state and rreg_state
@@ -1041,20 +1047,20 @@
rreg_state[j].vreg points at some vreg_state entry then
that vreg_state entry should point back at
rreg_state[j]. */
- for (UInt j = 0; j < state->n_rregs; j++) {
- if (state->rreg_state[j].disp != Bound)
+ for (Int j = 0; j < n_rregs; j++) {
+ if (rreg_state[j].disp != Bound)
continue;
- Int k = hregIndex(state->rreg_state[j].vreg);
+ Int k = hregIndex(rreg_state[j].vreg);
vassert(IS_VALID_VREGNO(k));
- vassert(state->vreg_state[k] == j);
+ vassert(vreg_state[k] == j);
}
- for (Int j = 0; j < state->n_vregs; j++) {
- Int k = state->vreg_state[j];
+ for (Int j = 0; j < n_vregs; j++) {
+ Int k = vreg_state[j];
if (k == INVALID_RREG_NO)
continue;
vassert(IS_VALID_RREGNO(k));
- vassert(state->rreg_state[k].disp == Bound);
- vassert(hregIndex(state->rreg_state[k].vreg) == j);
+ vassert(rreg_state[k].disp == Bound);
+ vassert(hregIndex(rreg_state[k].vreg) == j);
}
} /* if (do_sanity_check) */
@@ -1071,7 +1077,7 @@
the dst to the src's rreg, and that's all. */
HReg vregS = INVALID_HREG;
HReg vregD = INVALID_HREG;
- if (settings->isMove(instr_in, &vregS, &vregD)) {
+ if (settings->isMove(instrs_in->insns[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 ... */
@@ -1080,8 +1086,8 @@
UInt m = hregIndex(vregD);
vassert(IS_VALID_VREGNO(k));
vassert(IS_VALID_VREGNO(m));
- if (state->vreg_lrs[k].dead_before != ii + 1) goto cannot_coalesce;
- if (state->vreg_lrs[m].live_after != ii) goto cannot_coalesce;
+ if (vreg_lrs[k].dead_before != ii + 1) goto cannot_coalesce;
+ if (vreg_lrs[m].live_after != ii) goto cannot_coalesce;
if (DEBUG_REGALLOC) {
vex_printf("COALESCE ");
settings->ppReg(vregS);
@@ -1090,7 +1096,7 @@
vex_printf("\n\n");
}
/* Find the state entry for vregS. */
- Int n = state->vreg_state[k]; /* k is the index of vregS */
+ Int n = vreg_state[k]; /* k is the index of vregS */
if (n == INVALID_RREG_NO) {
/* vregS is not currently in a real register. So we can't
do the coalescing. Give up. */
@@ -1100,15 +1106,15 @@
/* Finally, we can do the coalescing. It's trivial -- merely
claim vregS's register for vregD. */
- state->rreg_state[n].vreg = vregD;
+ rreg_state[n].vreg = vregD;
vassert(IS_VALID_VREGNO(hregIndex(vregD)));
vassert(IS_VALID_VREGNO(hregIndex(vregS)));
- state->vreg_state[hregIndex(vregD)] = toShort(n);
- state->vreg_state[hregIndex(vregS)] = INVALID_RREG_NO;
+ vreg_state[hregIndex(vregD)] = toShort(n);
+ vreg_state[hregIndex(vregS)] = INVALID_RREG_NO;
/* This rreg has become associated with a different vreg and
hence with a different spill slot. Play safe. */
- state->rreg_state[n].eq_spill_slot = False;
+ rreg_state[n].eq_spill_slot = False;
/* Move on to the next insn. We skip the post-insn stuff for
fixed registers, since this move should not interact with
@@ -1122,17 +1128,17 @@
/* Look for vregs whose live range has just ended, and
mark the associated rreg as free. */
- for (UInt j = 0; j < state->n_rregs; j++) {
- if (state->rreg_state[j].disp != Bound)
+ for (Int j = 0; j < n_rregs; j++) {
+ if (rreg_state[j].disp != Bound)
continue;
- UInt vregno = hregIndex(state->rreg_state[j].vreg);
+ UInt vregno = hregIndex(rreg_state[j].vreg);
vassert(IS_VALID_VREGNO(vregno));
- if (state->vreg_lrs[vregno].dead_before <= ii) {
- state->rreg_state[j].disp = Free;
- state->rreg_state[j].eq_spill_slot = False;
- Int m = hregIndex(state->rreg_state[j].vreg);
+ if (vreg_lrs[vregno].dead_before <= ii) {
+ rreg_state[j].disp = Free;
+ rreg_state[j].eq_spill_slot = False;
+ Int m = hregIndex(rreg_state[j].vreg);
vassert(IS_VALID_VREGNO(m));
- state->vreg_state[m] = INVALID_RREG_NO;
+ vreg_state[m] = INVALID_RREG_NO;
if (DEBUG_REGALLOC) {
vex_printf("free up ");
settings->ppReg(settings->univ->regs[j]);
@@ -1184,32 +1190,31 @@
/* If this fails, we don't have an entry for this rreg.
Which we should. */
vassert(IS_VALID_RREGNO(k));
- Int m = hregIndex(state->rreg_state[k].vreg);
- if (state->rreg_state[k].disp == Bound) {
+ Int m = hregIndex(rreg_state[k].vreg);
+ if (rreg_state[k].disp == Bound) {
/* Yes, there is an associated vreg. Spill it if it's
still live. */
vassert(IS_VALID_VREGNO(m));
- state->vreg_state[m] = INVALID_RREG_NO;
- if (state->vreg_lrs[m].dead_before > ii) {
- vassert(state->vreg_lrs[m].reg_class != HRcINVALID);
- if ((!eq_spill_opt) || !state->rreg_state[k].eq_spill_slot) {
+ vreg_state[m] = INVALID_RREG_NO;
+ if (vreg_lrs[m].dead_before > ii) {
+ vassert(vreg_lrs[m].reg_class != HRcINVALID);
+ if ((!eq_spill_opt) || !rreg_state[k].eq_spill_slot) {
HInstr* spill1 = NULL;
HInstr* spill2 = NULL;
settings->genSpill(&spill1, &spill2, settings->univ->regs[k],
- state->vreg_lrs[m].spill_offset,
- settings->mode64);
+ vreg_lrs[m].spill_offset, settings->mode64);
vassert(spill1 || spill2); /* can't both be NULL */
if (spill1)
EMIT_INSTR(spill1);
if (spill2)
EMIT_INSTR(spill2);
}
- state->rreg_state[k].eq_spill_slot = True;
+ rreg_state[k].eq_spill_slot = True;
}
}
- state->rreg_state[k].disp = Unavail;
- state->rreg_state[k].vreg = INVALID_HREG;
- state->rreg_state[k].eq_spill_slot = False;
+ rreg_state[k].disp = Unavail;
+ rreg_state[k].vreg = INVALID_HREG;
+ rreg_state[k].eq_spill_slot = False;
/* check for further rregs entering HLRs at this point */
rreg_lrs_la_next++;
@@ -1230,8 +1235,6 @@
We also build up the final vreg->rreg mapping to be applied
to the insn. */
- /* The vreg -> rreg map constructed and then applied to each instr. */
- HRegRemap remap;
initHRegRemap(&remap);
/* ------------ BEGIN directReload optimisation ----------- */
@@ -1241,9 +1244,10 @@
can convert the instruction into one that reads directly from
the spill slot. This is clearly only possible for x86 and
amd64 targets, since ppc and arm are load-store
- architectures. If successful, replace instrs_in->insns[ii_start + ii]
- with this new instruction, and recompute its reg usage, so that
- the change is invisible to the standard-case handling that follows. */
+ architectures. If successful, replace instrs_in->arr[ii]
+ with this new instruction, and recompute its reg usage, so
+ that the change is invisible to the standard-case handling
+ that follows. */
if (settings->directReload != NULL && reg_usage_arr[ii].n_vRegs <= 2) {
Bool debug_direct_reload = False;
@@ -1260,13 +1264,13 @@
nreads++;
Int m = hregIndex(vreg);
vassert(IS_VALID_VREGNO(m));
- Int k = state->vreg_state[m];
+ Int k = vreg_state[m];
if (!IS_VALID_RREGNO(k)) {
/* ok, it is spilled. Now, is this its last use? */
- vassert(state->vreg_lrs[m].dead_before >= ii+1);
- if (state->vreg_lrs[m].dead_before == ii+1
+ vassert(vreg_lrs[m].dead_before >= ii+1);
+ if (vreg_lrs[m].dead_before == ii+1
&& hregIsInvalid(cand)) {
- spilloff = state->vreg_lrs[m].spill_offset;
+ spilloff = vreg_lrs[m].spill_offset;
cand = vreg;
}
}
@@ -1279,17 +1283,17 @@
vassert(! sameHReg(reg_usage_arr[ii].vRegs[0],
reg_usage_arr[ii].vRegs[1]));
- reloaded = settings->directReload(instr_in, cand, spilloff);
+ reloaded = settings->directReload(instrs_in->insns[ii], cand,
+ spilloff);
if (debug_direct_reload && !reloaded) {
vex_printf("[%3d] ", spilloff); ppHReg(cand); vex_printf(" ");
- settings->ppInstr(instr_in, settings->mode64);
+ settings->ppInstr(instrs_in->insns[ii], settings->mode64);
}
if (reloaded) {
/* Update info about the insn, so it looks as if it had
been in this form all along. */
- instr_in = reloaded;
- instrs_in->insns[ii_start + ii] = reloaded;
- settings->getRegUsage(®_usage_arr[ii], instr_in,
+ instrs_in->insns[ii] = reloaded;
+ settings->getRegUsage(®_usage_arr[ii], instrs_in->insns[ii],
settings->mode64);
if (debug_direct_reload && !reloaded) {
vex_printf(" --> ");
@@ -1320,14 +1324,14 @@
anything more. Inspect the current state to find out. */
Int m = hregIndex(vreg);
vassert(IS_VALID_VREGNO(m));
- Int n = state->vreg_state[m];
+ Int n = vreg_state[m];
if (IS_VALID_RREGNO(n)) {
- vassert(state->rreg_state[n].disp == Bound);
+ vassert(rreg_state[n].disp == Bound);
addToHRegRemap(&remap, vreg, settings->univ->regs[n]);
/* If this rreg is written or modified, mark it as different
from any spill slot value. */
if (reg_usage_arr[ii].vMode[j] != HRmRead)
- state->rreg_state[n].eq_spill_slot = False;
+ rreg_state[n].eq_spill_slot = False;
continue;
} else {
vassert(n == INVALID_RREG_NO);
@@ -1340,11 +1344,11 @@
as possible. */
Int k_suboptimal = -1;
Int k;
- for (k = 0; k < state->n_rregs; k++) {
- if (state->rreg_state[k].disp != Free
+ for (k = 0; k < n_rregs; k++) {
+ if (rreg_state[k].disp != Free
|| hregClass(settings->univ->regs[k]) != hregClass(vreg))
continue;
- if (state->rreg_state[k].has_hlrs) {
+ if (rreg_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;
@@ -1357,12 +1361,12 @@
if (k_suboptimal >= 0)
k = k_suboptimal;
- if (k < state->n_rregs) {
- state->rreg_state[k].disp = Bound;
- state->rreg_state[k].vreg = vreg;
+ if (k < n_rregs) {
+ rreg_state[k].disp = Bound;
+ rreg_state[k].vreg = vreg;
Int p = hregIndex(vreg);
vassert(IS_VALID_VREGNO(p));
- state->vreg_state[p] = toShort(k);
+ vreg_state[p] = toShort(k);
addToHRegRemap(&remap, vreg, settings->univ->regs[k]);
/* Generate a reload if needed. This only creates needed
reloads because the live range builder for vregs will
@@ -1371,12 +1375,11 @@
the first reference for this vreg, and so a reload is
indeed needed. */
if (reg_usage_arr[ii].vMode[j] != HRmWrite) {
- vassert(state->vreg_lrs[p].reg_class != HRcINVALID);
+ vassert(vreg_lrs[p].reg_class != HRcINVALID);
HInstr* reload1 = NULL;
HInstr* reload2 = NULL;
settings->genReload(&reload1, &reload2, settings->univ->regs[k],
- state->vreg_lrs[p].spill_offset,
- settings->mode64);
+ vreg_lrs[p].spill_offset, settings->mode64);
vassert(reload1 || reload2); /* can't both be NULL */
if (reload1)
EMIT_INSTR(reload1);
@@ -1386,13 +1389,13 @@
If it's merely read we can claim it now equals the
spill slot, but not so if it is modified. */
if (reg_usage_arr[ii].vMode[j] == HRmRead) {
- state->rreg_state[k].eq_spill_slot = True;
+ rreg_state[k].eq_spill_slot = True;
} else {
vassert(reg_usage_arr[ii].vMode[j] == HRmModify);
- state->rreg_state[k].eq_spill_slot = False;
+ rreg_state[k].eq_spill_slot = False;
}
} else {
- state->rreg_state[k].eq_spill_slot = False;
+ rreg_state[k].eq_spill_slot = False;
}
continue;
@@ -1406,19 +1409,18 @@
/* First, mark in the rreg_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 < state->n_rregs; k++) {
- state->rreg_state[k].is_spill_cand = False;
- if (state->rreg_state[k].disp != Bound)
+ for (k = 0; k < n_rregs; k++) {
+ rreg_state[k].is_spill_cand = False;
+ if (rreg_state[k].disp != Bound)
continue;
if (hregClass(settings->univ->regs[k]) != hregClass(vreg))
continue;
- state->rreg_state[k].is_spill_cand = True;
+ rreg_state[k].is_spill_cand = True;
/* Note, the following loop visits only the virtual regs
mentioned by the instruction. */
for (m = 0; m < reg_usage_arr[ii].n_vRegs; m++) {
- if (sameHReg(state->rreg_state[k].vreg,
- reg_usage_arr[ii].vRegs[m])) {
- state->rreg_state[k].is_spill_cand = False;
+ if (sameHReg(rreg_state[k].vreg, reg_usage_arr[ii].vRegs[m])) {
+ rreg_state[k].is_spill_cand = False;
break;
}
}
@@ -1430,8 +1432,8 @@
possible, in the hope that this will minimise the number
of consequent reloads required. */
Int spillee
- = findMostDistantlyMentionedVReg(reg_usage_arr, ii+1, ii_length,
- state->rreg_state, state->n_rregs);
+ = findMostDistantlyMentionedVReg (
+ reg_usage_arr, ii+1, instrs_in->insns_used, rreg_state, n_rregs );
if (spillee == -1) {
/* Hmmmmm. There don't appear to be any spill candidates.
@@ -1444,26 +1446,25 @@
/* Right. So we're going to spill rreg_state[spillee]. */
vassert(IS_VALID_RREGNO(spillee));
- vassert(state->rreg_state[spillee].disp == Bound);
+ vassert(rreg_state[spillee].disp == Bound);
/* check it's the right class */
vassert(hregClass(settings->univ->regs[spillee]) == hregClass(vreg));
/* check we're not ejecting the vreg for which we are trying
to free up a register. */
- vassert(! sameHReg(state->rreg_state[spillee].vreg, vreg));
+ vassert(! sameHReg(rreg_state[spillee].vreg, vreg));
- m = hregIndex(state->rreg_state[spillee].vreg);
+ m = hregIndex(rreg_state[spillee].vreg);
vassert(IS_VALID_VREGNO(m));
/* So here's the spill store. Assert that we're spilling a
live vreg. */
- vassert(state->vreg_lrs[m].dead_before > ii);
- vassert(state->vreg_lrs[m].reg_class != HRcINVALID);
- if ((!eq_spill_opt) || !state->rreg_state[spillee].eq_spill_slot) {
+ vassert(vreg_lrs[m].dead_before > ii);
+ vassert(vreg_lrs[m].reg_class != HRcINVALID);
+ if ((!eq_spill_opt) || !rreg_state[spillee].eq_spill_slot) {
HInstr* spill1 = NULL;
HInstr* spill2 = NULL;
settings->genSpill(&spill1, &spill2, settings->univ->regs[spillee],
- state->vreg_lrs[m].spill_offset,
- settings->mode64);
+ vreg_lrs[m].spill_offset, settings->mode64);
vassert(spill1 || spill2); /* can't both be NULL */
if (spill1)
EMIT_INSTR(spill1);
@@ -1473,25 +1474,24 @@
/* Update the rreg_state to reflect the new assignment for this
rreg. */
- state->rreg_state[spillee].vreg = vreg;
- state->vreg_state[m] = INVALID_RREG_NO;
+ rreg_state[spillee].vreg = vreg;
+ vreg_state[m] = INVALID_RREG_NO;
- state->rreg_state[spillee].eq_spill_slot = False; /* be safe */
+ rreg_state[spillee].eq_spill_slot = False; /* be safe */
m = hregIndex(vreg);
vassert(IS_VALID_VREGNO(m));
- state->vreg_state[m] = toShort(spillee);
+ vreg_state[m] = toShort(spillee);
/* Now, if this vreg is being read or modified (as opposed to
written), we have to generate a reload for it. */
if (reg_usage_arr[ii].vMode[j] != HRmWrite) {
- vassert(state->vreg_lrs[m].reg_class != HRcINVALID);
+ vassert(vreg_lrs[m].reg_class != HRcINVALID);
HInstr* reload1 = NULL;
HInstr* reload2 = NULL;
settings->genReload(&reload1, &reload2,
settings->univ->regs[spillee],
- state->vreg_lrs[m].spill_offset,
- settings->mode64);
+ vreg_lrs[m].spill_offset, settings->mode64);
vassert(reload1 || reload2); /* can't both be NULL */
if (reload1)
EMIT_INSTR(reload1);
@@ -1501,10 +1501,10 @@
If it's merely read we can claim it now equals the
spill slot, but not so if it is modified. */
if (reg_usage_arr[ii].vMode[j] == HRmRead) {
- state->rreg_state[spillee].eq_spill_slot = True;
+ rreg_state[spillee].eq_spill_slot = True;
} else {
vassert(reg_usage_arr[ii].vMode[j] == HRmModify);
- state->rreg_state[spillee].eq_spill_slot = False;
+ rreg_state[spillee].eq_spill_slot = False;
}
}
@@ -1525,9 +1525,9 @@
and emit that.
*/
- /* NOTE, DESTRUCTIVELY MODIFIES instrs_in->insns[ii_start + ii]. */
- settings->mapRegs(&remap, instr_in, settings->mode64);
- EMIT_INSTR(instr_in);
+ /* NOTE, DESTRUCTIVELY MODIFIES instrs_in->insns[ii]. */
+ settings->mapRegs(&remap, instrs_in->insns[ii], settings->mode64);
+ EMIT_INSTR(instrs_in->insns[ii]);
if (DEBUG_REGALLOC) {
vex_printf("After dealing with current insn:\n");
@@ -1553,10 +1553,10 @@
vassert(!hregIsVirtual(reg));
Int k = hregIndex(reg);
vassert(IS_VALID_RREGNO(k));
- vassert(state->rreg_state[k].disp == Unavail);
- state->rreg_state[k].disp = Free;
- state->rreg_state[k].vreg = INVALID_HREG;
- state->rreg_state[k].eq_spill_slot = False;
+ vassert(rreg_state[k].disp == Unavail);
+ rreg_state[k].disp = Free;
+ rreg_state[k].vreg = INVALID_HREG;
+ rreg_state[k].eq_spill_slot = False;
/* check for further rregs leaving HLRs at this point */
rreg_lrs_db_next++;
@@ -1572,83 +1572,22 @@
/* ------ END: Process each insn in turn. ------ */
- /* free(state->rreg_state); */
+ /* free(rreg_state); */
/* free(rreg_lrs); */
- /* if (state->vreg_lrs) free(state->vreg_lrs); */
+ /* if (vreg_lrs) free(vreg_lrs); */
/* Paranoia */
vassert(rreg_lrs_la_next == rreg_lrs_used);
vassert(rreg_lrs_db_next == rreg_lrs_used);
+ return instrs_out;
+
# undef INVALID_INSTRNO
# undef EMIT_INSTR
# undef PRINT_STATE
}
-static void doRegisterAllocation_HInstrVec(
- HInstrVec* insns_in, UInt n_vregs, const RegAllocSettings* settings,
- HInstrVec* insns_out)
-{
- UInt ii_start = 0, ii = 0;
-
- RegAllocState state;
- initRegAllocState(&state, settings, n_vregs);
-
- for ( ; ii < insns_in->insns_used; ii++) {
- HInstrIfThenElse* hite = settings->isIfThenElse(insns_in->insns[ii]);
-
- if (UNLIKELY(hite != NULL)) {
- vpanic("HInstrIfThenElse not supported yet in reg alloc");
- // Pass the previous insn chunk to regAlloc_HInstrVecChunk
- // Save the snapshot of the register allocator state
- // Work on fallThrough
- // Work on outOfLine
- // Merge the states and emit HInstrIfThenElse
- }
- }
-
- if (ii - ii_start > 0) {
- regAlloc_HInstrVecChunk(insns_in, ii_start, ii - ii_start, &state,
- settings, insns_out);
- }
-}
-
-/* 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.
- They are all stashed in 'settings'.
- 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 HInstrSB with unallocated insns.
- Returns an HInstrSB with allocated insns.
-*/
-HInstrSB* doRegisterAllocation(
- /* Incoming virtual-registerised code. */
- HInstrSB* sb_in,
-
- /* Register allocator settings. */
- const RegAllocSettings* settings
-)
-{
- vassert((settings->guest_sizeB % LibVEX_GUEST_STATE_ALIGN) == 0);
-
- /* If this is not so, vreg_state entries will overflow. */
- vassert(sb_in->n_vregs < 32767);
-
- HInstrSB* sb_out = newHInstrSB();
-
- doRegisterAllocation_HInstrVec(sb_in->insns, sb_in->n_vregs, settings,
- sb_out->insns);
-
- return sb_out;
-}
/*---------------------------------------------------------------*/
/*--- host_reg_alloc2.c ---*/
|