+2014-10-12 Oleg Endo <olegendo@gcc.gnu.org>
+
+ PR target/59401
+ * config/sh/sh-protos (sh_find_equiv_gbr_addr): Use rtx_insn* instead
+ of rtx.
+ * config/sh/sh.c (sh_find_equiv_gbr_addr): Use def chains instead of
+ insn walking.
+ (sh_find_equiv_gbr_addr): Do nothing if input mem is already a GBR
+ address. Use def chains to handle GBR clobbering call insns.
+
2014-10-12 Trevor Saunders <tsaunders@mozilla.com>
-* asan.c, cfgloop.c, cfgloop.h, cgraph.c, cgraph.h,
+ * asan.c, cfgloop.c, cfgloop.h, cgraph.c, cgraph.h,
config/darwin.c, config/m32c/m32c.c, config/mep/mep.c,
config/mips/mips.c, config/rs6000/rs6000.c, dwarf2out.c,
function.c, function.h, gimple-ssa.h, libfuncs.h, optabs.c,
2014-10-11 Martin Liska <mliska@suse.cz>
- PR/63376
+ PR middle-end/63376
* cgraphunit.c (symbol_table::process_new_functions): Missing call
for call_cgraph_insertion_hooks added.
}
/* Find the base register and calculate the displacement for a given
- address rtx 'x'.
- This is done by walking the insn list backwards and following SET insns
- that set the value of the specified reg 'x'. */
+ address rtx 'x'. */
static base_reg_disp
-sh_find_base_reg_disp (rtx insn, rtx x, disp_t disp = 0, rtx base_reg = NULL)
+sh_find_base_reg_disp (rtx_insn* insn, rtx x, disp_t disp = 0,
+ rtx base_reg = NULL)
{
if (REG_P (x))
{
if (REGNO (x) < FIRST_PSEUDO_REGISTER)
return base_reg_disp (base_reg != NULL ? base_reg : x, disp);
- /* Try to find the previous insn that sets the reg. */
- for (rtx i = prev_nonnote_insn (insn); i != NULL;
- i = prev_nonnote_insn (i))
+ /* Find the def of the reg and trace it. If there are more than one
+ defs and they are not the same, assume it's not safe to proceed. */
+ rtx_insn* last_i = NULL;
+ rtx last_set = NULL;
+ for (df_ref d = DF_REG_DEF_CHAIN (REGNO (x)); d != NULL;
+ d = DF_REF_NEXT_REG (d))
{
- if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG)
- && CALL_P (i))
- break;
-
- if (!NONJUMP_INSN_P (i))
- continue;
+ rtx set = const_cast<rtx> (set_of (x, DF_REF_INSN (d)));
- rtx p = PATTERN (i);
- if (p != NULL && GET_CODE (p) == SET && REG_P (XEXP (p, 0))
- && REGNO (XEXP (p, 0)) == REGNO (x))
+ /* Accept multiple defs, as long as they are equal. */
+ if (last_set == NULL || rtx_equal_p (last_set, set))
+ {
+ last_i = DF_REF_INSN (d);
+ last_set = set;
+ }
+ else
{
- /* If the recursion can't find out any more details about the
- source of the set, then this reg becomes our new base reg. */
- return sh_find_base_reg_disp (i, XEXP (p, 1), disp, XEXP (p, 0));
+ last_i = NULL;
+ last_set = NULL;
+ break;
}
}
- /* When here, no previous insn was found that sets the reg.
- The input reg is already the base reg. */
- return base_reg_disp (x, disp);
- }
+ if (last_set != NULL && last_i != NULL)
+ return sh_find_base_reg_disp (last_i, XEXP (last_set, 1), disp,
+ XEXP (last_set, 0));
+
+ /* When here, no previous insn was found that sets the reg.
+ The input reg is already the base reg. */
+ return base_reg_disp (x, disp);
+ }
else if (GET_CODE (x) == PLUS)
{
based memory address and return the corresponding new memory address.
Return NULL_RTX if not found. */
rtx
-sh_find_equiv_gbr_addr (rtx insn, rtx mem)
+sh_find_equiv_gbr_addr (rtx_insn* insn, rtx mem)
{
- if (!MEM_P (mem))
+ if (!MEM_P (mem) || gbr_address_mem (mem, GET_MODE (mem)))
return NULL_RTX;
/* Leave post/pre inc/dec or any other side effect addresses alone. */
if (side_effects_p (XEXP (mem, 0)))
return NULL_RTX;
+ /* When not optimizing there might be no dataflow available. */
+ if (df == NULL)
+ return NULL_RTX;
+
base_reg_disp gbr_disp = sh_find_base_reg_disp (insn, XEXP (mem, 0));
if (gbr_disp.is_reg () && REGNO (gbr_disp.reg ()) == GBR_REG)
{
+ /* If GBR is marked as call clobbered we bail out if we see a call.
+ FIXME: Actually should check if this mem refers to the gbr value
+ before or after the call. If there is a store_gbr preceeding this
+ mem, it's safe to use GBR for this mem.
+
+ If GBR is not marked as call clobbered, but there is some other
+ def than a call, it's probably a load_gbr upon which we also
+ bail out to be on the safe side.
+ FIXME: Should check if we have a use-after-def case, such as
+ the call case above. */
+ for (df_ref d = DF_REG_DEF_CHAIN (GBR_REG); d != NULL;
+ d = DF_REF_NEXT_REG (d))
+ {
+ if (CALL_P (DF_REF_INSN (d)))
+ {
+ if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG))
+ return NULL_RTX;
+ else
+ continue;
+ }
+ else
+ return NULL_RTX;
+ }
+
rtx disp = GEN_INT (gbr_disp.disp ());
if (gbr_displacement (disp, GET_MODE (mem)))
return gen_rtx_PLUS (SImode, gen_rtx_REG (SImode, GBR_REG), disp);