reg numbers to allocnos and vice versa.
max_allocno gets the number of allocnos in use.
- 2. Allocate a max_allocno by max_allocno conflict bit matrix and
- clear it. This is called "conflict".
+ 2. Allocate a max_allocno by max_allocno compressed triangular conflict
+ bit matrix (a triangular bit matrix with portions removed for which we
+ can guarantee there are no conflicts, example: two local pseudos that
+ live in different basic blocks) and clear it. This is called "conflict".
+ Note that for triangular bit matrices, there are two possible equations
+ for computing the bit number for two allocnos: LOW and HIGH (LOW < HIGH):
+
+ 1) BITNUM = f(HIGH) + LOW, where
+ f(HIGH) = (HIGH * (HIGH - 1)) / 2
+
+ 2) BITNUM = f(LOW) + HIGH, where
+ f(LOW) = LOW * (max_allocno - LOW) + (LOW * (LOW - 1)) / 2 - LOW - 1
+
+ We use the second (and less common) equation as this gives us better
+ cache locality for local allocnos that are live within the same basic
+ block. Also note that f(HIGH) and f(LOW) can be precalculated for all
+ values of HIGH and LOW, so all that is necessary to compute the bit
+ number for two allocnos LOW and HIGH is a load followed by an addition.
Allocate a max_allocno by FIRST_PSEUDO_REGISTER conflict matrix for
conflicts between allocnos and explicit hard register use (which
includes use of pseudo-registers allocated by local_alloc). This
is the hard_reg_conflicts inside each allocno.
- 3. For each basic block
- walk forward through the block, recording which
- pseudo-registers and which hardware registers are live.
- Build the conflict matrix between the pseudo-registers
- and another of pseudo-registers versus hardware registers.
- Also record the preferred hardware registers
- for each pseudo-register.
+ 3. For each basic block, walk backward through the block, recording
+ which pseudo-registers and which hardware registers are live.
+ Build the conflict matrix between the pseudo-registers and another of
+ pseudo-registers versus hardware registers.
+
+ 4. For each basic block, walk backward through the block, recording
+ the preferred hardware registers for each pseudo-register.
- 4. Sort a table of the allocnos into order of
- desirability of the variables.
+ 5. Sort a table of the allocnos into order of desirability of the variables.
- 5. Allocate the variables in that order; each if possible into
+ 6. Allocate the variables in that order; each if possible into
a preferred register, else into another register. */
\f
/* A vector of the integers from 0 to max_allocno-1,
static int *allocno_order;
-/* Two macros to test or store 1 in an element of `conflicts'. */
-
-#define CONFLICTP(I, J) \
- (conflicts[(I) * allocno_row_words + (unsigned) (J) / HOST_BITS_PER_WIDE_INT] \
- & ((HOST_WIDE_INT) 1 << ((unsigned) (J) % HOST_BITS_PER_WIDE_INT)))
-
/* Set of registers that global-alloc isn't supposed to use. */
static HARD_REG_SET no_global_alloc_regs;
#define SET_REGBIT(TABLE, I, J) SET_HARD_REG_BIT (allocno[I].TABLE, J)
-/* This is turned off because it doesn't work right for DImode.
- (And it is only used for DImode, so the other cases are worthless.)
- The problem is that it isn't true that there is NO possibility of conflict;
- only that there is no conflict if the two pseudos get the exact same regs.
- If they were allocated with a partial overlap, there would be a conflict.
- We can't safely turn off the conflict unless we have another way to
- prevent the partial overlap.
-
- Idea: change hard_reg_conflicts so that instead of recording which
- hard regs the allocno may not overlap, it records where the allocno
- may not start. Change both where it is used and where it is updated.
- Then there is a way to record that (reg:DI 108) may start at 10
- but not at 9 or 11. There is still the question of how to record
- this semi-conflict between two pseudos. */
-#if 0
-/* Reg pairs for which conflict after the current insn
- is inhibited by a REG_NO_CONFLICT note.
- If the table gets full, we ignore any other notes--that is conservative. */
-#define NUM_NO_CONFLICT_PAIRS 4
-/* Number of pairs in use in this insn. */
-int n_no_conflict_pairs;
-static struct { int allocno1, allocno2;}
- no_conflict_pairs[NUM_NO_CONFLICT_PAIRS];
-#endif /* 0 */
-
/* Return true if *LOC contains an asm. */
static int
rtx insn;
FOR_BB_INSNS_REVERSE (bb, insn)
{
- struct df_ref **def_rec;
+ df_ref *def_rec;
if (insn_contains_asm (insn))
for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
{
- struct df_ref *def = *def_rec;
+ df_ref def = *def_rec;
unsigned int dregno = DF_REF_REGNO (def);
if (dregno < FIRST_PSEUDO_REGISTER)
{
/* All registers that can be eliminated. */
-static HARD_REG_SET eliminable_regset;
+HARD_REG_SET eliminable_regset;
+static int regno_compare (const void *, const void *);
static int allocno_compare (const void *, const void *);
-static void mirror_conflicts (void);
static void expand_preferences (void);
static void prune_preferences (void);
static void set_preferences (void);
static void find_reg (int, HARD_REG_SET, int, int, int);
static void dump_conflicts (FILE *);
-static void build_insn_chain (void);
\f
/* Look through the list of eliminable registers. Set ELIM_SET to the
This will normally be called with ELIM_SET as the file static
variable eliminable_regset, and NO_GLOBAL_SET as the file static
- variable NO_GLOBAL_ALLOC_REGS. */
+ variable NO_GLOBAL_ALLOC_REGS.
+
+ It also initializes global flag frame_pointer_needed. */
static void
compute_regsets (HARD_REG_SET *elim_set,
/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
Unlike regs_ever_live, elements of this array corresponding to
eliminable regs like the frame pointer are set if an asm sets them. */
- char *regs_asm_clobbered = alloca (FIRST_PSEUDO_REGISTER * sizeof (char));
+ char *regs_asm_clobbered = XALLOCAVEC (char, FIRST_PSEUDO_REGISTER);
#ifdef ELIMINABLE_REGS
static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
size_t i;
#endif
+
+ /* FIXME: If EXIT_IGNORE_STACK is set, we will not save and restore
+ sp for alloca. So we can't eliminate the frame pointer in that
+ case. At some point, we should improve this by emitting the
+ sp-adjusting insns for this case. */
int need_fp
= (! flag_omit_frame_pointer
- || (current_function_calls_alloca && EXIT_IGNORE_STACK)
+ || (cfun->calls_alloca && EXIT_IGNORE_STACK)
+ || crtl->accesses_prior_frames
+ || crtl->stack_realign_needed
|| FRAME_POINTER_REQUIRED);
+ frame_pointer_needed = need_fp;
+
max_regno = max_reg_num ();
compact_blocks ();
{
bool cannot_elim
= (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
- || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp));
+ || (eliminables[i].to == STACK_POINTER_REGNUM
+ && need_fp
+ && (! SUPPORTS_STACK_ALIGNMENT
+ || ! stack_realign_fp)));
if (!regs_asm_clobbered[eliminables[i].from])
{
{
int retval;
size_t i;
+ int max_blk;
+ int *num_allocnos_per_blk;
compute_regsets (&eliminable_regset, &no_global_alloc_regs);
reg_allocno = XNEWVEC (int, max_regno);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- reg_allocno[i] = -1;
-
+ /* Initially fill the reg_allocno array with regno's... */
+ max_blk = 0;
max_allocno = 0;
for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
/* Note that reg_live_length[i] < 0 indicates a "constant" reg
if (REG_N_REFS (i) != 0 && REG_LIVE_LENGTH (i) != -1
/* Don't allocate pseudos that cross calls,
if this function receives a nonlocal goto. */
- && (! current_function_has_nonlocal_label
+ && (! cfun->has_nonlocal_label
|| REG_N_CALLS_CROSSED (i) == 0))
{
- reg_allocno[i] = max_allocno++;
+ int blk = regno_basic_block (i);
+ reg_allocno[max_allocno++] = i;
+ if (blk > max_blk)
+ max_blk = blk;
gcc_assert (REG_LIVE_LENGTH (i));
}
- else
- reg_allocno[i] = -1;
allocno = XCNEWVEC (struct allocno, max_allocno);
+ partial_bitnum = XNEWVEC (HOST_WIDE_INT, max_allocno);
+ num_allocnos_per_blk = XCNEWVEC (int, max_blk + 1);
- for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
- if (reg_allocno[i] >= 0)
- {
- int num = reg_allocno[i];
- allocno[num].reg = i;
- allocno[num].size = PSEUDO_REGNO_SIZE (i);
- allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
- allocno[num].throwing_calls_crossed
- += REG_N_THROWING_CALLS_CROSSED (i);
- allocno[num].n_refs += REG_N_REFS (i);
- allocno[num].freq += REG_FREQ (i);
- if (allocno[num].live_length < REG_LIVE_LENGTH (i))
- allocno[num].live_length = REG_LIVE_LENGTH (i);
- }
+ /* ...so we can sort them in the order we want them to receive
+ their allocnos. */
+ qsort (reg_allocno, max_allocno, sizeof (int), regno_compare);
+
+ for (i = 0; i < (size_t) max_allocno; i++)
+ {
+ int regno = reg_allocno[i];
+ int blk = regno_basic_block (regno);
+ num_allocnos_per_blk[blk]++;
+ allocno[i].reg = regno;
+ allocno[i].size = PSEUDO_REGNO_SIZE (regno);
+ allocno[i].calls_crossed += REG_N_CALLS_CROSSED (regno);
+ allocno[i].freq_calls_crossed += REG_FREQ_CALLS_CROSSED (regno);
+ allocno[i].throwing_calls_crossed
+ += REG_N_THROWING_CALLS_CROSSED (regno);
+ allocno[i].n_refs += REG_N_REFS (regno);
+ allocno[i].freq += REG_FREQ (regno);
+ if (allocno[i].live_length < REG_LIVE_LENGTH (regno))
+ allocno[i].live_length = REG_LIVE_LENGTH (regno);
+ }
+
+ /* The "global" block must contain all allocnos. */
+ num_allocnos_per_blk[0] = max_allocno;
+
+ /* Now reinitialize the reg_allocno array in terms of the
+ optimized regno to allocno mapping we created above. */
+ for (i = 0; i < (size_t) max_regno; i++)
+ reg_allocno[i] = -1;
+
+ max_bitnum = 0;
+ for (i = 0; i < (size_t) max_allocno; i++)
+ {
+ int regno = allocno[i].reg;
+ int blk = regno_basic_block (regno);
+ int row_size = --num_allocnos_per_blk[blk];
+ reg_allocno[regno] = (int) i;
+ partial_bitnum[i] = (row_size > 0) ? max_bitnum - ((int) i + 1) : -1;
+ max_bitnum += row_size;
+ }
+
+#ifdef ENABLE_CHECKING
+ gcc_assert (max_bitnum <=
+ (((HOST_WIDE_INT) max_allocno *
+ ((HOST_WIDE_INT) max_allocno - 1)) / 2));
+#endif
+
+ if (dump_file)
+ {
+ HOST_WIDE_INT num_bits, num_bytes, actual_bytes;
+
+ fprintf (dump_file, "## max_blk: %d\n", max_blk);
+ fprintf (dump_file, "## max_regno: %d\n", max_regno);
+ fprintf (dump_file, "## max_allocno: %d\n", max_allocno);
+
+ num_bits = max_bitnum;
+ num_bytes = CEIL (num_bits, 8);
+ actual_bytes = num_bytes;
+ fprintf (dump_file, "## Compressed triangular bitmatrix size: ");
+ fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bits, ", num_bits);
+ fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bytes\n", num_bytes);
+
+ num_bits = ((HOST_WIDE_INT) max_allocno *
+ ((HOST_WIDE_INT) max_allocno - 1)) / 2;
+ num_bytes = CEIL (num_bits, 8);
+ fprintf (dump_file, "## Standard triangular bitmatrix size: ");
+ fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bits, ", num_bits);
+ fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bytes [%.2f%%]\n",
+ num_bytes, 100.0 * ((double) actual_bytes / (double) num_bytes));
+
+ num_bits = (HOST_WIDE_INT) max_allocno * (HOST_WIDE_INT) max_allocno;
+ num_bytes = CEIL (num_bits, 8);
+ fprintf (dump_file, "## Square bitmatrix size: ");
+ fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bits, ", num_bits);
+ fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC " bytes [%.2f%%]\n",
+ num_bytes, 100.0 * ((double) actual_bytes / (double) num_bytes));
+ }
/* Calculate amount of usage of each hard reg by pseudos
allocated by local-alloc. This is to see if we want to
fprintf (dump_file, " %d", (int)i);
fprintf (dump_file, "\n");
}
- allocno_row_words = (max_allocno + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
- /* We used to use alloca here, but the size of what it would try to
- allocate would occasionally cause it to exceed the stack limit and
- cause unpredictable core dumps. Some examples were > 2Mb in size. */
- conflicts = XCNEWVEC (HOST_WIDE_INT, max_allocno * allocno_row_words);
+ conflicts = NULL;
+ adjacency = NULL;
+ adjacency_pool = NULL;
/* If there is work to be done (at least one reg to allocate),
perform global conflict analysis and allocate the regs. */
if (max_allocno > 0)
{
+ /* We used to use alloca here, but the size of what it would try to
+ allocate would occasionally cause it to exceed the stack limit and
+ cause unpredictable core dumps. Some examples were > 2Mb in size. */
+ conflicts = XCNEWVEC (HOST_WIDEST_FAST_INT,
+ CEIL(max_bitnum, HOST_BITS_PER_WIDEST_FAST_INT));
+
+ adjacency = XCNEWVEC (adjacency_t *, max_allocno);
+ adjacency_pool = create_alloc_pool ("global_alloc adjacency list pool",
+ sizeof (adjacency_t), 1024);
+
/* Scan all the insns and compute the conflicts among allocnos
and between allocnos and hard regs. */
global_conflicts. */
df_set_flags (DF_NO_INSN_RESCAN);
- mirror_conflicts ();
-
/* Eliminate conflicts between pseudos and eliminable registers. If
the register is not eliminated, the pseudo won't really be able to
live in the eliminable register, so the conflict doesn't matter.
}
free (allocno_order);
+ free (conflicts);
}
/* Do the reloads now while the allocno data still exists, so that we can
/* Clean up. */
free (reg_allocno);
+ free (num_allocnos_per_blk);
+ free (partial_bitnum);
free (allocno);
- free (conflicts);
+ if (adjacency != NULL)
+ {
+ free_alloc_pool (adjacency_pool);
+ free (adjacency);
+ }
return retval;
}
+/* Sort predicate for ordering the regnos. We want the regno to allocno
+ mapping to have the property that all "global" regnos (ie, regnos that
+ are referenced in more than one basic block) have smaller allocno values
+ than "local" regnos (ie, regnos referenced in only one basic block).
+ In addition, for two basic blocks "i" and "j" with i < j, all regnos
+ local to basic block i should have smaller allocno values than regnos
+ local to basic block j.
+ Returns -1 (1) if *v1p should be allocated before (after) *v2p. */
+
+static int
+regno_compare (const void *v1p, const void *v2p)
+{
+ int regno1 = *(const int *)v1p;
+ int regno2 = *(const int *)v2p;
+ int blk1 = REG_BASIC_BLOCK (regno1);
+ int blk2 = REG_BASIC_BLOCK (regno2);
+
+ /* Prefer lower numbered basic blocks. Note that global and unknown
+ blocks have negative values, giving them high precedence. */
+ if (blk1 - blk2)
+ return blk1 - blk2;
+
+ /* If both regs are referenced from the same block, sort by regno. */
+ return regno1 - regno2;
+}
+
/* Sort predicate for ordering the allocnos.
Returns -1 (1) if *v1 should be allocated before (after) *v2. */
if (REG_NOTE_KIND (link) == REG_DEAD
&& REG_P (XEXP (link, 0))
&& reg_allocno[REGNO (XEXP (link, 0))] >= 0
- && ! CONFLICTP (reg_allocno[REGNO (SET_DEST (set))],
- reg_allocno[REGNO (XEXP (link, 0))]))
+ && ! conflict_p (reg_allocno[REGNO (SET_DEST (set))],
+ reg_allocno[REGNO (XEXP (link, 0))]))
{
int a1 = reg_allocno[REGNO (SET_DEST (set))];
int a2 = reg_allocno[REGNO (XEXP (link, 0))];
these registers). */
HARD_REG_SET temp, temp2;
int allocno2;
+ adjacency_iter ai;
num = allocno_order[i];
CLEAR_HARD_REG_SET (temp);
CLEAR_HARD_REG_SET (temp2);
- EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + num * allocno_row_words,
- allocno2,
+ FOR_EACH_CONFLICT (num, allocno2, ai)
{
if (allocno_to_order[allocno2] > i)
{
IOR_HARD_REG_SET (temp2,
allocno[allocno2].hard_reg_full_preferences);
}
- });
+ }
AND_COMPL_HARD_REG_SET (temp, allocno[num].hard_reg_full_preferences);
IOR_HARD_REG_SET (temp, temp2);
int i, best_reg, pass;
HARD_REG_SET used, used1, used2;
- enum reg_class class = (alt_regs_p
+ enum reg_class rclass = (alt_regs_p
? reg_alternate_class (allocno[num].reg)
: reg_preferred_class (allocno[num].reg));
enum machine_mode mode = PSEUDO_REGNO_MODE (allocno[num].reg);
if (losers)
IOR_HARD_REG_SET (used1, losers);
- IOR_COMPL_HARD_REG_SET (used1, reg_class_contents[(int) class]);
+ IOR_COMPL_HARD_REG_SET (used1, reg_class_contents[(int) rclass]);
+
+#ifdef EH_RETURN_DATA_REGNO
+ if (allocno[num].no_eh_reg)
+ {
+ unsigned int j;
+ for (j = 0; ; ++j)
+ {
+ unsigned int regno = EH_RETURN_DATA_REGNO (j);
+ if (regno == INVALID_REGNUM)
+ break;
+ SET_HARD_REG_BIT (used1, regno);
+ }
+ }
+#endif
+
COPY_HARD_REG_SET (used2, used1);
IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
if (! accept_call_clobbered
&& allocno[num].calls_crossed != 0
&& allocno[num].throwing_calls_crossed == 0
- && CALLER_SAVE_PROFITABLE (allocno[num].n_refs,
- allocno[num].calls_crossed))
+ && CALLER_SAVE_PROFITABLE (optimize_function_for_size_p (cfun) ? allocno[num].n_refs : allocno[num].freq,
+ optimize_function_for_size_p (cfun) ? allocno[num].calls_crossed
+ : allocno[num].freq_calls_crossed))
{
HARD_REG_SET new_losers;
if (! losers)
{
int lim, j;
HARD_REG_SET this_reg;
+ adjacency_iter ai;
/* Yes. Record it as the hard register of this pseudo-reg. */
reg_renumber[allocno[num].reg] = best_reg;
}
/* For each other pseudo-reg conflicting with this one,
mark it as conflicting with the hard regs this one occupies. */
- lim = num;
- EXECUTE_IF_SET_IN_ALLOCNO_SET (conflicts + lim * allocno_row_words, j,
+ FOR_EACH_CONFLICT (num, j, ai)
{
IOR_HARD_REG_SET (allocno[j].hard_reg_conflicts, this_reg);
- });
+ }
}
}
\f
}
}
\f
-/* If CONFLICTP (i, j) is true, make sure CONFLICTP (j, i) is also true. */
-static void
-mirror_conflicts (void)
-{
- int i, j;
- int rw = allocno_row_words;
- int rwb = rw * HOST_BITS_PER_WIDE_INT;
- HOST_WIDE_INT *p = conflicts;
- HOST_WIDE_INT *q0 = conflicts, *q1, *q2;
- unsigned HOST_WIDE_INT mask;
-
- for (i = max_allocno - 1, mask = 1; i >= 0; i--, mask <<= 1)
- {
- if (! mask)
- {
- mask = 1;
- q0++;
- }
- for (j = allocno_row_words - 1, q1 = q0; j >= 0; j--, q1 += rwb)
- {
- unsigned HOST_WIDE_INT word;
-
- for (word = (unsigned HOST_WIDE_INT) *p++, q2 = q1; word;
- word >>= 1, q2 += rw)
- {
- if (word & 1)
- *q2 |= mask;
- }
- }
- }
-}
-\f
/* Indicate that hard register number FROM was eliminated and replaced with
an offset from hard register number TO. The status of hard registers live
at the start of a basic block is updated by replacing a use of FROM with
FOR_EACH_BB (bb)
{
- regset r = DF_LIVE_IN (bb);
+ /* We don't use LIVE info in IRA. */
+ regset r = (flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb));
if (REGNO_REG_SET_P (r, from))
{
CLEAR_REGNO_REG_SET (r, from);
}
}
\f
+/* Print chain C to FILE. */
+
static void
print_insn_chain (FILE *file, struct insn_chain *c)
{
bitmap_print (file, &c->dead_or_set, "dead_or_set: ", "\n");
}
+
+/* Print all reload_insn_chains to FILE. */
+
static void
print_insn_chains (FILE *file)
{
for (c = reload_insn_chain; c ; c = c->next)
print_insn_chain (file, c);
}
+
+/* Return true if pseudo REGNO should be added to set live_throughout
+ or dead_or_set of the insn chains for reload consideration. */
+
+static bool
+pseudo_for_reload_consideration_p (int regno)
+{
+ /* Consider spilled pseudos too for IRA because they still have a
+ chance to get hard-registers in the reload when IRA is used. */
+ return (reg_renumber[regno] >= 0
+ || (flag_ira && optimize && flag_ira_share_spill_slots));
+}
+
/* Walk the insns of the current function and build reload_insn_chain,
and record register life information. */
-static void
+
+void
build_insn_chain (void)
{
unsigned int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (eliminable_regset, i))
bitmap_set_bit (elim_regset, i);
-
FOR_EACH_BB_REVERSE (bb)
{
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), FIRST_PSEUDO_REGISTER, i, bi)
{
- if (reg_renumber[i] >= 0)
+ if (pseudo_for_reload_consideration_p (i))
bitmap_set_bit (live_relevant_regs, i);
}
if (!NOTE_P (insn) && !BARRIER_P (insn))
{
unsigned int uid = INSN_UID (insn);
- struct df_ref **def_rec;
- struct df_ref **use_rec;
+ df_ref *def_rec;
+ df_ref *use_rec;
c = new_insn_chain ();
c->next = next;
if (INSN_P (insn))
for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
{
- struct df_ref *def = *def_rec;
+ df_ref def = *def_rec;
unsigned int regno = DF_REF_REGNO (def);
/* Ignore may clobbers because these are generated
{
if (regno < FIRST_PSEUDO_REGISTER)
{
- if (! fixed_regs[regno])
+ if (!fixed_regs[regno])
bitmap_set_bit (&c->dead_or_set, regno);
}
- else if (reg_renumber[regno] >= 0)
+ else if (pseudo_for_reload_consideration_p (regno))
bitmap_set_bit (&c->dead_or_set, regno);
}
- if ((regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+ if ((regno < FIRST_PSEUDO_REGISTER
+ || reg_renumber[regno] >= 0
+ || (flag_ira && optimize))
&& (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
{
rtx reg = DF_REF_REG (def);
+
/* We can model subregs, but not if they are
wrapped in ZERO_EXTRACTS. */
if (GET_CODE (reg) == SUBREG
- && !DF_REF_FLAGS_IS_SET (def, DF_REF_EXTRACT))
+ && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
{
unsigned int start = SUBREG_BYTE (reg);
- unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
+ unsigned int last = start
+ + GET_MODE_SIZE (GET_MODE (reg));
- ra_init_live_subregs (bitmap_bit_p (live_relevant_regs, regno),
- live_subregs, live_subregs_used,
+ ra_init_live_subregs (bitmap_bit_p (live_relevant_regs,
+ regno),
+ live_subregs,
+ live_subregs_used,
regno, reg);
+
+ if (!DF_REF_FLAGS_IS_SET
+ (def, DF_REF_STRICT_LOW_PART))
+ {
+ /* Expand the range to cover entire words.
+ Bytes added here are "don't care". */
+ start = start / UNITS_PER_WORD * UNITS_PER_WORD;
+ last = ((last + UNITS_PER_WORD - 1)
+ / UNITS_PER_WORD * UNITS_PER_WORD);
+ }
+
/* Ignore the paradoxical bits. */
if ((int)last > live_subregs_used[regno])
last = live_subregs_used[regno];
if (INSN_P (insn))
for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
{
- struct df_ref *use = *use_rec;
+ df_ref use = *use_rec;
unsigned int regno = DF_REF_REGNO (use);
rtx reg = DF_REF_REG (use);
precisely so we do not need to look at the
fabricated use. */
if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE)
- && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT)
+ && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)
&& DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
continue;
{
if (regno < FIRST_PSEUDO_REGISTER)
{
- if (! fixed_regs[regno])
+ if (!fixed_regs[regno])
bitmap_set_bit (&c->dead_or_set, regno);
}
- else if (reg_renumber[regno] >= 0)
+ else if (pseudo_for_reload_consideration_p (regno))
bitmap_set_bit (&c->dead_or_set, regno);
}
- if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+ if (regno < FIRST_PSEUDO_REGISTER
+ || pseudo_for_reload_consideration_p (regno))
{
if (GET_CODE (reg) == SUBREG
- && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT))
+ && !DF_REF_FLAGS_IS_SET (use,
+ DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
{
unsigned int start = SUBREG_BYTE (reg);
- unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
+ unsigned int last = start
+ + GET_MODE_SIZE (GET_MODE (reg));
- ra_init_live_subregs (bitmap_bit_p (live_relevant_regs, regno),
- live_subregs, live_subregs_used,
+ ra_init_live_subregs (bitmap_bit_p (live_relevant_regs,
+ regno),
+ live_subregs,
+ live_subregs_used,
regno, reg);
/* Ignore the paradoxical bits. */
}
}
}
+
+ /* FIXME!! The following code is a disaster. Reload needs to see the
+ labels and jump tables that are just hanging out in between
+ the basic blocks. See pr33676. */
+ insn = BB_HEAD (bb);
+
+ /* Skip over the barriers and cruft. */
+ while (insn && (BARRIER_P (insn) || NOTE_P (insn)
+ || BLOCK_FOR_INSN (insn) == bb))
+ insn = PREV_INSN (insn);
+
+ /* While we add anything except barriers and notes, the focus is
+ to get the labels and jump tables into the
+ reload_insn_chain. */
+ while (insn)
+ {
+ if (!NOTE_P (insn) && !BARRIER_P (insn))
+ {
+ if (BLOCK_FOR_INSN (insn))
+ break;
+
+ c = new_insn_chain ();
+ c->next = next;
+ next = c;
+ *p = c;
+ p = &c->prev;
+
+ /* The block makes no sense here, but it is what the old
+ code did. */
+ c->block = bb->index;
+ c->insn = insn;
+ bitmap_copy (&c->live_throughout, live_relevant_regs);
+ }
+ insn = PREV_INSN (insn);
+ }
}
- for (i = 0; i < (unsigned int)max_regno; i++)
+ for (i = 0; i < (unsigned int) max_regno; i++)
if (live_subregs[i])
free (live_subregs[i]);
dump_conflicts (FILE *file)
{
int i;
+ int regno;
int has_preferences;
int nregs;
nregs = 0;
nregs++;
}
fprintf (file, ";; %d regs to allocate:", nregs);
- for (i = 0; i < max_allocno; i++)
- {
- int j;
- if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
- continue;
- fprintf (file, " %d", allocno[allocno_order[i]].reg);
- for (j = 0; j < max_regno; j++)
- if (reg_allocno[j] == allocno_order[i]
- && j != allocno[allocno_order[i]].reg)
- fprintf (file, "+%d", j);
- if (allocno[allocno_order[i]].size != 1)
- fprintf (file, " (%d)", allocno[allocno_order[i]].size);
- }
+ for (regno = 0; regno < max_regno; regno++)
+ if ((i = reg_allocno[regno]) >= 0)
+ {
+ int j;
+ if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
+ continue;
+ fprintf (file, " %d", allocno[allocno_order[i]].reg);
+ for (j = 0; j < max_regno; j++)
+ if (reg_allocno[j] == allocno_order[i]
+ && j != allocno[allocno_order[i]].reg)
+ fprintf (file, "+%d", j);
+ if (allocno[allocno_order[i]].size != 1)
+ fprintf (file, " (%d)", allocno[allocno_order[i]].size);
+ }
fprintf (file, "\n");
- for (i = 0; i < max_allocno; i++)
- {
- int j;
- fprintf (file, ";; %d conflicts:", allocno[i].reg);
- for (j = 0; j < max_allocno; j++)
- if (CONFLICTP (j, i))
- fprintf (file, " %d", allocno[j].reg);
- for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
- if (TEST_HARD_REG_BIT (allocno[i].hard_reg_conflicts, j) && ! fixed_regs[j])
- fprintf (file, " %d", j);
- fprintf (file, "\n");
-
- has_preferences = 0;
- for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
- if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
- has_preferences = 1;
-
- if (! has_preferences)
- continue;
- fprintf (file, ";; %d preferences:", allocno[i].reg);
- for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
- if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
- fprintf (file, " %d", j);
- fprintf (file, "\n");
- }
+ for (regno = 0; regno < max_regno; regno++)
+ if ((i = reg_allocno[regno]) >= 0)
+ {
+ int j;
+ adjacency_iter ai;
+ fprintf (file, ";; %d conflicts:", allocno[i].reg);
+ FOR_EACH_CONFLICT (i, j, ai)
+ {
+ fprintf (file, " %d", allocno[j].reg);
+ }
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (TEST_HARD_REG_BIT (allocno[i].hard_reg_conflicts, j)
+ && !fixed_regs[j])
+ fprintf (file, " %d", j);
+ fprintf (file, "\n");
+
+ has_preferences = 0;
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
+ has_preferences = 1;
+
+ if (!has_preferences)
+ continue;
+ fprintf (file, ";; %d preferences:", allocno[i].reg);
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (TEST_HARD_REG_BIT (allocno[i].hard_reg_preferences, j))
+ fprintf (file, " %d", j);
+ fprintf (file, "\n");
+ }
fprintf (file, "\n");
}
fprintf (file, "\n\n");
}
+
+static bool
+gate_handle_global_alloc (void)
+{
+ return ! flag_ira;
+}
+
/* Run old register allocator. Return TRUE if we must exit
rest_of_compilation upon return. */
static unsigned int
failure = reload (get_insns (), 0);
}
- if (dump_enabled_p (pass_global_alloc.static_pass_number))
+ if (dump_enabled_p (pass_global_alloc.pass.static_pass_number))
{
timevar_push (TV_DUMP);
dump_global_regs (dump_file);
reload_completed = !failure;
/* The world has changed so much that at this point we might as well
- just rescan everything. Not that df_rescan_all_insns is not
+ just rescan everything. Note that df_rescan_all_insns is not
going to help here because it does not touch the artificial uses
and defs. */
df_finish_pass (true);
return 0;
}
-struct tree_opt_pass pass_global_alloc =
+struct rtl_opt_pass pass_global_alloc =
{
+ {
+ RTL_PASS,
"greg", /* name */
- NULL, /* gate */
+ gate_handle_global_alloc, /* gate */
rest_of_handle_global_alloc, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_verify_rtl_sharing
- | TODO_ggc_collect, /* todo_flags_finish */
- 'g' /* letter */
+ | TODO_ggc_collect /* todo_flags_finish */
+ }
};