#ifdef ADJUST_REG_ALLOC_ORDER
ADJUST_REG_ALLOC_ORDER;
#endif
- COPY_HARD_REG_SET (no_unit_alloc_regs, fixed_reg_set);
+ COPY_HARD_REG_SET (no_unit_alloc_regs, fixed_nonglobal_reg_set);
if (! use_hard_frame_p)
SET_HARD_REG_BIT (no_unit_alloc_regs, HARD_FRAME_POINTER_REGNUM);
setup_class_hard_regs ();
}
if (commutative < 0)
break;
- if (curr_swapped)
- break;
+ /* Swap forth and back to avoid changing recog_data. */
std::swap (recog_data.operand[commutative],
recog_data.operand[commutative + 1]);
+ if (curr_swapped)
+ break;
}
}
{
df_ref def;
- if (NONDEBUG_INSN_P (insn) && extract_asm_operands (PATTERN (insn)))
+ if (NONDEBUG_INSN_P (insn) && asm_noperands (PATTERN (insn)) >= 0)
FOR_EACH_INSN_DEF (def, insn)
{
unsigned int dregno = DF_REF_REGNO (def);
unsigned char replace : 1;
/* Set if this register has no known equivalence. */
unsigned char no_equiv : 1;
+ /* Set if this register is mentioned in a paradoxical subreg. */
+ unsigned char pdx_subregs : 1;
};
/* reg_equiv[N] (where N is a pseudo reg number) is the equivalence
structure for that register. */
static struct equivalence *reg_equiv;
-/* Used for communication between the following two functions: contains
- a MEM that we wish to ensure remains unchanged. */
-static rtx equiv_mem;
+/* Used for communication between the following two functions. */
+struct equiv_mem_data
+{
+ /* A MEM that we wish to ensure remains unchanged. */
+ rtx equiv_mem;
-/* Set nonzero if EQUIV_MEM is modified. */
-static int equiv_mem_modified;
+ /* Set true if EQUIV_MEM is modified. */
+ bool equiv_mem_modified;
+};
/* If EQUIV_MEM is modified by modifying DEST, indicate that it is modified.
Called via note_stores. */
static void
validate_equiv_mem_from_store (rtx dest, const_rtx set ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
+ void *data)
{
+ struct equiv_mem_data *info = (struct equiv_mem_data *) data;
+
if ((REG_P (dest)
- && reg_overlap_mentioned_p (dest, equiv_mem))
+ && reg_overlap_mentioned_p (dest, info->equiv_mem))
|| (MEM_P (dest)
- && anti_dependence (equiv_mem, dest)))
- equiv_mem_modified = 1;
+ && anti_dependence (info->equiv_mem, dest)))
+ info->equiv_mem_modified = true;
}
+enum valid_equiv { valid_none, valid_combine, valid_reload };
+
/* Verify that no store between START and the death of REG invalidates
MEMREF. MEMREF is invalidated by modifying a register used in MEMREF,
by storing into an overlapping memory location, or with a non-const
CALL_INSN.
- Return 1 if MEMREF remains valid. */
-static int
+ Return VALID_RELOAD if MEMREF remains valid for both reload and
+ combine_and_move insns, VALID_COMBINE if only valid for
+ combine_and_move_insns, and VALID_NONE otherwise. */
+static enum valid_equiv
validate_equiv_mem (rtx_insn *start, rtx reg, rtx memref)
{
rtx_insn *insn;
rtx note;
-
- equiv_mem = memref;
- equiv_mem_modified = 0;
+ struct equiv_mem_data info = { memref, false };
+ enum valid_equiv ret = valid_reload;
/* If the memory reference has side effects or is volatile, it isn't a
valid equivalence. */
if (side_effects_p (memref))
- return 0;
+ return valid_none;
- for (insn = start; insn && ! equiv_mem_modified; insn = NEXT_INSN (insn))
+ for (insn = start; insn; insn = NEXT_INSN (insn))
{
- if (! INSN_P (insn))
+ if (!INSN_P (insn))
continue;
if (find_reg_note (insn, REG_DEAD, reg))
- return 1;
+ return ret;
- /* This used to ignore readonly memory and const/pure calls. The problem
- is the equivalent form may reference a pseudo which gets assigned a
- call clobbered hard reg. When we later replace REG with its
- equivalent form, the value in the call-clobbered reg has been
- changed and all hell breaks loose. */
if (CALL_P (insn))
- return 0;
+ {
+ /* We can combine a reg def from one insn into a reg use in
+ another over a call if the memory is readonly or the call
+ const/pure. However, we can't set reg_equiv notes up for
+ reload over any call. The problem is the equivalent form
+ may reference a pseudo which gets assigned a call
+ clobbered hard reg. When we later replace REG with its
+ equivalent form, the value in the call-clobbered reg has
+ been changed and all hell breaks loose. */
+ ret = valid_combine;
+ if (!MEM_READONLY_P (memref)
+ && !RTL_CONST_OR_PURE_CALL_P (insn))
+ return valid_none;
+ }
- note_stores (PATTERN (insn), validate_equiv_mem_from_store, NULL);
+ note_stores (PATTERN (insn), validate_equiv_mem_from_store, &info);
+ if (info.equiv_mem_modified)
+ return valid_none;
/* If a register mentioned in MEMREF is modified via an
auto-increment, we lose the equivalence. Do the same if one
|| REG_NOTE_KIND (note) == REG_DEAD)
&& REG_P (XEXP (note, 0))
&& reg_overlap_mentioned_p (XEXP (note, 0), memref))
- return 0;
+ return valid_none;
}
- return 0;
+ return valid_none;
}
/* Returns zero if X is known to be invariant. */
return 1;
}
-/* TRUE if X uses any registers for which reg_equiv[REGNO].replace is
- true. */
-static int
-contains_replace_regs (rtx x)
-{
- int i, j;
- const char *fmt;
- enum rtx_code code = GET_CODE (x);
-
- switch (code)
- {
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- CASE_CONST_ANY:
- case PC:
- case CC0:
- case HIGH:
- return 0;
-
- case REG:
- return reg_equiv[REGNO (x)].replace;
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- switch (fmt[i])
- {
- case 'e':
- if (contains_replace_regs (XEXP (x, i)))
- return 1;
- break;
- case 'E':
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (contains_replace_regs (XVECEXP (x, i, j)))
- return 1;
- break;
- }
-
- return 0;
-}
-
/* TRUE if X references a memory location that would be affected by a store
to MEMREF. */
static int
}
/* TRUE if some insn in the range (START, END] references a memory location
- that would be affected by a store to MEMREF. */
+ that would be affected by a store to MEMREF.
+
+ Callers should not call this routine if START is after END in the
+ RTL chain. */
+
static int
memref_used_between_p (rtx memref, rtx_insn *start, rtx_insn *end)
{
rtx_insn *insn;
- for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);
+ for (insn = NEXT_INSN (start);
+ insn && insn != NEXT_INSN (end);
insn = NEXT_INSN (insn))
{
if (!NONDEBUG_INSN_P (insn))
return 1;
}
+ gcc_assert (insn == NEXT_INSN (end));
return 0;
}
in PDX_SUBREGS. */
static void
-set_paradoxical_subreg (rtx_insn *insn, bool *pdx_subregs)
+set_paradoxical_subreg (rtx_insn *insn)
{
subrtx_iterator::array_type array;
FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
{
const_rtx reg = SUBREG_REG (subreg);
if (REG_P (reg) && paradoxical_subreg_p (subreg))
- pdx_subregs[REGNO (reg)] = true;
+ reg_equiv[REGNO (reg)].pdx_subregs = true;
}
}
}
return NULL_RTX;
}
-/* Nonzero if we recorded an equivalence for a LABEL_REF. */
-static int recorded_label_ref;
-
/* Find registers that are equivalent to a single value throughout the
compilation (either because they can be referenced in memory or are
set once from a single constant). Lower their priority for a
value into the using insn. If it succeeds, we can eliminate the
register completely.
- Initialize init_insns in ira_reg_equiv array.
-
- Return non-zero if jump label rebuilding should be done. */
-static int
+ Initialize init_insns in ira_reg_equiv array. */
+static void
update_equiv_regs (void)
{
rtx_insn *insn;
basic_block bb;
- int loop_depth;
- bitmap cleared_regs;
- bool *pdx_subregs;
-
- /* We need to keep track of whether or not we recorded a LABEL_REF so
- that we know if the jump optimizer needs to be rerun. */
- recorded_label_ref = 0;
-
- /* Use pdx_subregs to show whether a reg is used in a paradoxical
- subreg. */
- pdx_subregs = XCNEWVEC (bool, max_regno);
- reg_equiv = XCNEWVEC (struct equivalence, max_regno);
- grow_reg_equivs ();
-
- init_alias_analysis ();
-
- /* Scan insns and set pdx_subregs[regno] if the reg is used in a
- paradoxical subreg. Don't set such reg equivalent to a mem,
+ /* Scan insns and set pdx_subregs if the reg is used in a
+ paradoxical subreg. Don't set such reg equivalent to a mem,
because lra will not substitute such equiv memory in order to
prevent access beyond allocated memory for paradoxical memory subreg. */
FOR_EACH_BB_FN (bb, cfun)
FOR_BB_INSNS (bb, insn)
if (NONDEBUG_INSN_P (insn))
- set_paradoxical_subreg (insn, pdx_subregs);
+ set_paradoxical_subreg (insn);
/* Scan the insns and find which registers have equivalences. Do this
in a separate scan of the insns because (due to -fcse-follow-jumps)
a register can be set below its use. */
+ bitmap setjmp_crosses = regstat_get_setjmp_crosses ();
FOR_EACH_BB_FN (bb, cfun)
{
- loop_depth = bb_loop_depth (bb);
+ int loop_depth = bb_loop_depth (bb);
for (insn = BB_HEAD (bb);
insn != NEXT_INSN (BB_END (bb));
/* If this insn contains more (or less) than a single SET,
only mark all destinations as having no known equivalence. */
- if (set == NULL_RTX)
+ if (set == NULL_RTX
+ || side_effects_p (SET_SRC (set)))
{
note_stores (PATTERN (insn), no_equiv, NULL);
continue;
continue;
}
- /* Don't set reg (if pdx_subregs[regno] == true) equivalent to a mem. */
- if (MEM_P (src) && pdx_subregs[regno])
+ /* Don't set reg mentioned in a paradoxical subreg
+ equivalent to a mem. */
+ if (MEM_P (src) && reg_equiv[regno].pdx_subregs)
{
note_stores (set, no_equiv, NULL);
continue;
note. */
note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
- if (note == NULL_RTX && REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
- && MEM_P (SET_SRC (set))
- && validate_equiv_mem (insn, dest, SET_SRC (set)))
- note = set_unique_reg_note (insn, REG_EQUIV, copy_rtx (SET_SRC (set)));
-
+ rtx replacement = NULL_RTX;
if (note)
+ replacement = XEXP (note, 0);
+ else if (REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
+ && MEM_P (SET_SRC (set)))
{
- int regno = REGNO (dest);
- rtx x = XEXP (note, 0);
+ enum valid_equiv validity;
+ validity = validate_equiv_mem (insn, dest, SET_SRC (set));
+ if (validity != valid_none)
+ {
+ replacement = copy_rtx (SET_SRC (set));
+ if (validity == valid_reload)
+ note = set_unique_reg_note (insn, REG_EQUIV, replacement);
+ }
+ }
- /* If we haven't done so, record for reload that this is an
- equivalencing insn. */
- if (!reg_equiv[regno].is_arg_equivalence)
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn,
- ira_reg_equiv[regno].init_insns);
+ /* If we haven't done so, record for reload that this is an
+ equivalencing insn. */
+ if (note && !reg_equiv[regno].is_arg_equivalence)
+ ira_reg_equiv[regno].init_insns
+ = gen_rtx_INSN_LIST (VOIDmode, insn,
+ ira_reg_equiv[regno].init_insns);
- /* Record whether or not we created a REG_EQUIV note for a LABEL_REF.
- We might end up substituting the LABEL_REF for uses of the
- pseudo here or later. That kind of transformation may turn an
- indirect jump into a direct jump, in which case we must rerun the
- jump optimizer to ensure that the JUMP_LABEL fields are valid. */
- if (GET_CODE (x) == LABEL_REF
- || (GET_CODE (x) == CONST
- && GET_CODE (XEXP (x, 0)) == PLUS
- && (GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)))
- recorded_label_ref = 1;
-
- reg_equiv[regno].replacement = x;
+ if (replacement)
+ {
+ reg_equiv[regno].replacement = replacement;
reg_equiv[regno].src_p = &SET_SRC (set);
reg_equiv[regno].loop_depth = (short) loop_depth;
/* Don't mess with things live during setjmp. */
- if (REG_LIVE_LENGTH (regno) >= 0 && optimize)
+ if (optimize && !bitmap_bit_p (setjmp_crosses, regno))
{
- /* Note that the statement below does not affect the priority
- in local-alloc! */
- REG_LIVE_LENGTH (regno) *= 2;
-
/* If the register is referenced exactly twice, meaning it is
set once and used once, indicate that the reference may be
replaced by the equivalence we computed above. Do this
calls. */
if (REG_N_REFS (regno) == 2
- && (rtx_equal_p (x, src)
+ && (rtx_equal_p (replacement, src)
|| ! equiv_init_varies_p (src))
&& NONJUMP_INSN_P (insn)
&& equiv_init_movable_p (PATTERN (insn), regno))
}
}
}
+}
- if (!optimize)
- goto out;
-
- /* A second pass, to gather additional equivalences with memory. This needs
- to be done after we know which registers we are going to replace. */
+/* For insns that set a MEM to the contents of a REG that is only used
+ in a single basic block, see if the register is always equivalent
+ to that memory location and if moving the store from INSN to the
+ insn that sets REG is safe. If so, put a REG_EQUIV note on the
+ initializing insn. */
+static void
+add_store_equivs (void)
+{
+ bitmap_head seen_insns;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ bitmap_initialize (&seen_insns, NULL);
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx set, src, dest;
unsigned regno;
+ rtx_insn *init_insn;
+
+ bitmap_set_bit (&seen_insns, INSN_UID (insn));
if (! INSN_P (insn))
continue;
dest = SET_DEST (set);
src = SET_SRC (set);
- /* If this sets a MEM to the contents of a REG that is only used
- in a single basic block, see if the register is always equivalent
- to that memory location and if moving the store from INSN to the
- insn that set REG is safe. If so, put a REG_EQUIV note on the
- initializing insn.
-
- Don't add a REG_EQUIV note if the insn already has one. The existing
- REG_EQUIV is likely more useful than the one we are adding.
-
- If one of the regs in the address has reg_equiv[REGNO].replace set,
- then we can't add this REG_EQUIV note. The reg_equiv[REGNO].replace
- optimization may move the set of this register immediately before
- insn, which puts it after reg_equiv[REGNO].init_insns, and hence
- the mention in the REG_EQUIV note would be to an uninitialized
- pseudo. */
-
+ /* Don't add a REG_EQUIV note if the insn already has one. The existing
+ REG_EQUIV is likely more useful than the one we are adding. */
if (MEM_P (dest) && REG_P (src)
&& (regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
&& REG_BASIC_BLOCK (regno) >= NUM_FIXED_BLOCKS
&& DF_REG_DEF_COUNT (regno) == 1
+ && ! reg_equiv[regno].pdx_subregs
&& reg_equiv[regno].init_insns != NULL
- && reg_equiv[regno].init_insns->insn () != NULL
- && ! find_reg_note (XEXP (reg_equiv[regno].init_insns, 0),
- REG_EQUIV, NULL_RTX)
- && ! contains_replace_regs (XEXP (dest, 0))
- && ! pdx_subregs[regno])
+ && (init_insn = reg_equiv[regno].init_insns->insn ()) != 0
+ && bitmap_bit_p (&seen_insns, INSN_UID (init_insn))
+ && ! find_reg_note (init_insn, REG_EQUIV, NULL_RTX)
+ && validate_equiv_mem (init_insn, src, dest) == valid_reload
+ && ! memref_used_between_p (dest, init_insn, insn)
+ /* Attaching a REG_EQUIV note will fail if INIT_INSN has
+ multiple sets. */
+ && set_unique_reg_note (init_insn, REG_EQUIV, copy_rtx (dest)))
{
- rtx_insn *init_insn =
- as_a <rtx_insn *> (XEXP (reg_equiv[regno].init_insns, 0));
- if (validate_equiv_mem (init_insn, src, dest)
- && ! memref_used_between_p (dest, init_insn, insn)
- /* Attaching a REG_EQUIV note will fail if INIT_INSN has
- multiple sets. */
- && set_unique_reg_note (init_insn, REG_EQUIV, copy_rtx (dest)))
- {
- /* This insn makes the equivalence, not the one initializing
- the register. */
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
- df_notes_rescan (init_insn);
- }
+ /* This insn makes the equivalence, not the one initializing
+ the register. */
+ ira_reg_equiv[regno].init_insns
+ = gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
+ df_notes_rescan (init_insn);
+ if (dump_file)
+ fprintf (dump_file,
+ "Adding REG_EQUIV to insn %d for source of insn %d\n",
+ INSN_UID (init_insn),
+ INSN_UID (insn));
}
}
+ bitmap_clear (&seen_insns);
+}
- cleared_regs = BITMAP_ALLOC (NULL);
- /* Now scan all regs killed in an insn to see if any of them are
- registers only used that once. If so, see if we can replace the
- reference with the equivalent form. If we can, delete the
- initializing reference and this register will go away. If we
- can't replace the reference, and the initializing reference is
- within the same loop (or in an inner loop), then move the register
- initialization just before the use, so that they are in the same
- basic block. */
- FOR_EACH_BB_REVERSE_FN (bb, cfun)
- {
- loop_depth = bb_loop_depth (bb);
- for (insn = BB_END (bb);
- insn != PREV_INSN (BB_HEAD (bb));
- insn = PREV_INSN (insn))
- {
- rtx link;
-
- if (! INSN_P (insn))
- continue;
-
- /* Don't substitute into a non-local goto, this confuses CFG. */
- if (JUMP_P (insn)
- && find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
- continue;
-
- for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
- {
- if (REG_NOTE_KIND (link) == REG_DEAD
- /* Make sure this insn still refers to the register. */
- && reg_mentioned_p (XEXP (link, 0), PATTERN (insn)))
- {
- int regno = REGNO (XEXP (link, 0));
- rtx equiv_insn;
-
- if (! reg_equiv[regno].replace
- || reg_equiv[regno].loop_depth < (short) loop_depth
- /* There is no sense to move insns if live range
- shrinkage or register pressure-sensitive
- scheduling were done because it will not
- improve allocation but worsen insn schedule
- with a big probability. */
- || flag_live_range_shrinkage
- || (flag_sched_pressure && flag_schedule_insns))
- continue;
-
- /* reg_equiv[REGNO].replace gets set only when
- REG_N_REFS[REGNO] is 2, i.e. the register is set
- once and used once. (If it were only set, but
- not used, flow would have deleted the setting
- insns.) Hence there can only be one insn in
- reg_equiv[REGNO].init_insns. */
- gcc_assert (reg_equiv[regno].init_insns
- && !XEXP (reg_equiv[regno].init_insns, 1));
- equiv_insn = XEXP (reg_equiv[regno].init_insns, 0);
-
- /* We may not move instructions that can throw, since
- that changes basic block boundaries and we are not
- prepared to adjust the CFG to match. */
- if (can_throw_internal (equiv_insn))
- continue;
-
- if (asm_noperands (PATTERN (equiv_insn)) < 0
- && validate_replace_rtx (regno_reg_rtx[regno],
- *(reg_equiv[regno].src_p), insn))
- {
- rtx equiv_link;
- rtx last_link;
- rtx note;
-
- /* Find the last note. */
- for (last_link = link; XEXP (last_link, 1);
- last_link = XEXP (last_link, 1))
- ;
-
- /* Append the REG_DEAD notes from equiv_insn. */
- equiv_link = REG_NOTES (equiv_insn);
- while (equiv_link)
- {
- note = equiv_link;
- equiv_link = XEXP (equiv_link, 1);
- if (REG_NOTE_KIND (note) == REG_DEAD)
- {
- remove_note (equiv_insn, note);
- XEXP (last_link, 1) = note;
- XEXP (note, 1) = NULL_RTX;
- last_link = note;
- }
- }
+/* Scan all regs killed in an insn to see if any of them are registers
+ only used that once. If so, see if we can replace the reference
+ with the equivalent form. If we can, delete the initializing
+ reference and this register will go away. If we can't replace the
+ reference, and the initializing reference is within the same loop
+ (or in an inner loop), then move the register initialization just
+ before the use, so that they are in the same basic block. */
+static void
+combine_and_move_insns (void)
+{
+ bitmap cleared_regs = BITMAP_ALLOC (NULL);
+ int max = max_reg_num ();
- remove_death (regno, insn);
- SET_REG_N_REFS (regno, 0);
- REG_FREQ (regno) = 0;
- delete_insn (equiv_insn);
+ for (int regno = FIRST_PSEUDO_REGISTER; regno < max; regno++)
+ {
+ if (!reg_equiv[regno].replace)
+ continue;
- reg_equiv[regno].init_insns
- = reg_equiv[regno].init_insns->next ();
+ rtx_insn *use_insn = 0;
+ for (df_ref use = DF_REG_USE_CHAIN (regno);
+ use;
+ use = DF_REF_NEXT_REG (use))
+ if (DF_REF_INSN_INFO (use))
+ {
+ if (DEBUG_INSN_P (DF_REF_INSN (use)))
+ continue;
+ gcc_assert (!use_insn);
+ use_insn = DF_REF_INSN (use);
+ }
+ gcc_assert (use_insn);
- ira_reg_equiv[regno].init_insns = NULL;
- bitmap_set_bit (cleared_regs, regno);
- }
- /* Move the initialization of the register to just before
- INSN. Update the flow information. */
- else if (prev_nondebug_insn (insn) != equiv_insn)
- {
- rtx_insn *new_insn;
+ /* Don't substitute into jumps. indirect_jump_optimize does
+ this for anything we are prepared to handle. */
+ if (JUMP_P (use_insn))
+ continue;
- new_insn = emit_insn_before (PATTERN (equiv_insn), insn);
- REG_NOTES (new_insn) = REG_NOTES (equiv_insn);
- REG_NOTES (equiv_insn) = 0;
- /* Rescan it to process the notes. */
- df_insn_rescan (new_insn);
+ df_ref def = DF_REG_DEF_CHAIN (regno);
+ gcc_assert (DF_REG_DEF_COUNT (regno) == 1 && DF_REF_INSN_INFO (def));
+ rtx_insn *def_insn = DF_REF_INSN (def);
- /* Make sure this insn is recognized before
- reload begins, otherwise
- eliminate_regs_in_insn will die. */
- INSN_CODE (new_insn) = INSN_CODE (equiv_insn);
+ /* We may not move instructions that can throw, since that
+ changes basic block boundaries and we are not prepared to
+ adjust the CFG to match. */
+ if (can_throw_internal (def_insn))
+ continue;
- delete_insn (equiv_insn);
+ basic_block use_bb = BLOCK_FOR_INSN (use_insn);
+ basic_block def_bb = BLOCK_FOR_INSN (def_insn);
+ if (bb_loop_depth (use_bb) > bb_loop_depth (def_bb))
+ continue;
- XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
+ if (asm_noperands (PATTERN (def_insn)) < 0
+ && validate_replace_rtx (regno_reg_rtx[regno],
+ *reg_equiv[regno].src_p, use_insn))
+ {
+ rtx link;
+ /* Append the REG_DEAD notes from def_insn. */
+ for (rtx *p = ®_NOTES (def_insn); (link = *p) != 0; )
+ {
+ if (REG_NOTE_KIND (XEXP (link, 0)) == REG_DEAD)
+ {
+ *p = XEXP (link, 1);
+ XEXP (link, 1) = REG_NOTES (use_insn);
+ REG_NOTES (use_insn) = link;
+ }
+ else
+ p = &XEXP (link, 1);
+ }
- REG_BASIC_BLOCK (regno) = bb->index;
- REG_N_CALLS_CROSSED (regno) = 0;
- REG_FREQ_CALLS_CROSSED (regno) = 0;
- REG_N_THROWING_CALLS_CROSSED (regno) = 0;
- REG_LIVE_LENGTH (regno) = 2;
+ remove_death (regno, use_insn);
+ SET_REG_N_REFS (regno, 0);
+ REG_FREQ (regno) = 0;
+ delete_insn (def_insn);
- if (insn == BB_HEAD (bb))
- BB_HEAD (bb) = PREV_INSN (insn);
+ reg_equiv[regno].init_insns = NULL;
+ ira_reg_equiv[regno].init_insns = NULL;
+ bitmap_set_bit (cleared_regs, regno);
+ }
- ira_reg_equiv[regno].init_insns
- = gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
- bitmap_set_bit (cleared_regs, regno);
- }
- }
+ /* Move the initialization of the register to just before
+ USE_INSN. Update the flow information. */
+ else if (prev_nondebug_insn (use_insn) != def_insn)
+ {
+ rtx_insn *new_insn;
+
+ new_insn = emit_insn_before (PATTERN (def_insn), use_insn);
+ REG_NOTES (new_insn) = REG_NOTES (def_insn);
+ REG_NOTES (def_insn) = 0;
+ /* Rescan it to process the notes. */
+ df_insn_rescan (new_insn);
+
+ /* Make sure this insn is recognized before reload begins,
+ otherwise eliminate_regs_in_insn will die. */
+ INSN_CODE (new_insn) = INSN_CODE (def_insn);
+
+ delete_insn (def_insn);
+
+ XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
+
+ REG_BASIC_BLOCK (regno) = use_bb->index;
+ REG_N_CALLS_CROSSED (regno) = 0;
+
+ if (use_insn == BB_HEAD (use_bb))
+ BB_HEAD (use_bb) = new_insn;
+
+ /* We know regno dies in use_insn, but inside a loop
+ REG_DEAD notes might be missing when def_insn was in
+ another basic block. However, when we move def_insn into
+ this bb we'll definitely get a REG_DEAD note and reload
+ will see the death. It's possible that update_equiv_regs
+ set up an equivalence referencing regno for a reg set by
+ use_insn, when regno was seen as non-local. Now that
+ regno is local to this block, and dies, such an
+ equivalence is invalid. */
+ if (find_reg_note (use_insn, REG_EQUIV, NULL_RTX))
+ {
+ rtx set = single_set (use_insn);
+ if (set && REG_P (SET_DEST (set)))
+ no_equiv (SET_DEST (set), set, NULL);
}
+
+ ira_reg_equiv[regno].init_insns
+ = gen_rtx_INSN_LIST (VOIDmode, new_insn, NULL_RTX);
+ bitmap_set_bit (cleared_regs, regno);
}
}
if (!bitmap_empty_p (cleared_regs))
{
+ basic_block bb;
+
FOR_EACH_BB_FN (bb, cfun)
{
bitmap_and_compl_into (DF_LR_IN (bb), cleared_regs);
bitmap_and_compl_into (DF_LR_OUT (bb), cleared_regs);
- if (! df_live)
+ if (!df_live)
continue;
bitmap_and_compl_into (DF_LIVE_IN (bb), cleared_regs);
bitmap_and_compl_into (DF_LIVE_OUT (bb), cleared_regs);
/* Last pass - adjust debug insns referencing cleared regs. */
if (MAY_HAVE_DEBUG_INSNS)
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (DEBUG_INSN_P (insn))
{
rtx old_loc = INSN_VAR_LOCATION_LOC (insn);
}
BITMAP_FREE (cleared_regs);
+}
- out:
- /* Clean up. */
+/* A pass over indirect jumps, converting simple cases to direct jumps.
+ Combine does this optimization too, but only within a basic block. */
+static void
+indirect_jump_optimize (void)
+{
+ basic_block bb;
+ bool rebuild_p = false;
- end_alias_analysis ();
- free (reg_equiv);
- free (pdx_subregs);
- return recorded_label_ref;
-}
+ FOR_EACH_BB_REVERSE_FN (bb, cfun)
+ {
+ rtx_insn *insn = BB_END (bb);
+ if (!JUMP_P (insn)
+ || find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
+ continue;
-\f
+ rtx x = pc_set (insn);
+ if (!x || !REG_P (SET_SRC (x)))
+ continue;
+
+ int regno = REGNO (SET_SRC (x));
+ if (DF_REG_DEF_COUNT (regno) == 1)
+ {
+ df_ref def = DF_REG_DEF_CHAIN (regno);
+ if (!DF_REF_IS_ARTIFICIAL (def))
+ {
+ rtx_insn *def_insn = DF_REF_INSN (def);
+ rtx lab = NULL_RTX;
+ rtx set = single_set (def_insn);
+ if (set && GET_CODE (SET_SRC (set)) == LABEL_REF)
+ lab = SET_SRC (set);
+ else
+ {
+ rtx eqnote = find_reg_note (def_insn, REG_EQUAL, NULL_RTX);
+ if (eqnote && GET_CODE (XEXP (eqnote, 0)) == LABEL_REF)
+ lab = XEXP (eqnote, 0);
+ }
+ if (lab && validate_replace_rtx (SET_SRC (x), lab, insn))
+ rebuild_p = true;
+ }
+ }
+ }
+ if (rebuild_p)
+ {
+ timevar_push (TV_JUMP);
+ rebuild_jump_labels (get_insns ());
+ if (purge_all_dead_edges ())
+ delete_unreachable_blocks ();
+ timevar_pop (TV_JUMP);
+ }
+}
+\f
/* Set up fields memory, constant, and invariant from init_insns in
the structures of array ira_reg_equiv. */
static void
{
bool loops_p;
int ira_max_point_before_emit;
- int rebuild_p;
bool saved_flag_caller_saves = flag_caller_saves;
enum ira_region saved_flag_ira_region = flag_ira_region;
df_clear_flags (DF_NO_INSN_RESCAN);
+ indirect_jump_optimize ();
+ if (delete_trivially_dead_insns (get_insns (), max_reg_num ()))
+ df_analyze ();
+
regstat_init_n_sets_and_refs ();
regstat_compute_ri ();
if (resize_reg_info () && flag_ira_loop_pressure)
ira_set_pseudo_classes (true, ira_dump_file);
- rebuild_p = update_equiv_regs ();
- setup_reg_equiv ();
- setup_reg_equiv_init ();
+ init_alias_analysis ();
+ loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+ reg_equiv = XCNEWVEC (struct equivalence, max_reg_num ());
+ update_equiv_regs ();
+
+ /* Don't move insns if live range shrinkage or register
+ pressure-sensitive scheduling were done because it will not
+ improve allocation but likely worsen insn scheduling. */
+ if (optimize
+ && !flag_live_range_shrinkage
+ && !(flag_sched_pressure && flag_schedule_insns))
+ combine_and_move_insns ();
+
+ /* Gather additional equivalences with memory. */
+ if (optimize)
+ add_store_equivs ();
- bool update_regstat = false;
+ loop_optimizer_finalize ();
+ free_dominance_info (CDI_DOMINATORS);
+ end_alias_analysis ();
+ free (reg_equiv);
- if (optimize && rebuild_p)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- if (purge_all_dead_edges ())
- {
- delete_unreachable_blocks ();
- update_regstat = true;
- }
- timevar_pop (TV_JUMP);
- }
+ setup_reg_equiv ();
+ grow_reg_equivs ();
+ setup_reg_equiv_init ();
allocated_reg_info_size = max_reg_num ();
- if (delete_trivially_dead_insns (get_insns (), max_reg_num ()))
- {
- df_analyze ();
- update_regstat = true;
- }
-
/* It is not worth to do such improvement when we use a simple
allocation because of -O0 usage or because the function is too
big. */
check_allocation ();
#endif
- if (update_regstat || max_regno != max_regno_before_ira)
+ if (max_regno != max_regno_before_ira)
{
regstat_free_n_sets_and_refs ();
regstat_free_ri ();
{
df_set_flags (DF_NO_INSN_RESCAN);
build_insn_chain ();
-
- need_dce = reload (get_insns (), ira_conflicts_p);
+ need_dce = reload (get_insns (), ira_conflicts_p);
}
timevar_pop (TV_RELOAD);
inform (DECL_SOURCE_LOCATION (decl), "for %qD", decl);
}
+ /* If we are doing generic stack checking, give a warning if this
+ function's frame size is larger than we expect. */
+ if (flag_stack_check == GENERIC_STACK_CHECK)
+ {
+ HOST_WIDE_INT size = get_frame_size () + STACK_CHECK_FIXED_FRAME_SIZE;
+
+ for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (df_regs_ever_live_p (i) && !fixed_regs[i] && call_used_regs[i])
+ size += UNITS_PER_WORD;
+
+ if (size > STACK_CHECK_MAX_FRAME_SIZE)
+ warning (0, "frame size too large for reliable stack checking");
+ }
+
if (pic_offset_table_regno != INVALID_REGNUM)
pic_offset_table_rtx = gen_rtx_REG (Pmode, pic_offset_table_regno);