+2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org>
+
+ * lra-constraints.c (process_address_1): Try if target can split
+ displacement with targetm.legitimize_address_displacement.
+ * target.def (legitimize_address_displacement): New hook.
+ * targhooks.c (default_legitimize_address_displacement): New function.
+ * targhooks.h (default_legitimize_address_displacement): Declare.
+ * config/sh/sh.c (sh_legitimize_address_displacement): New function.
+ (TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT): Define.
+ * doc/tm.texi.in (TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT): New hook.
+ * doc/tm.texi: Regenerate.
+
2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org>
* lra-constraints.c (get_equiv): Don't return memory equivalence
static rtx sh_legitimize_address (rtx, rtx, machine_mode);
static rtx sh_delegitimize_address (rtx);
static bool sh_cannot_substitute_mem_equiv_p (rtx);
+static bool sh_legitimize_address_displacement (rtx *, rtx *, machine_mode);
static int shmedia_target_regs_stack_space (HARD_REG_SET *);
static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *);
static int shmedia_target_regs_stack_adjust (HARD_REG_SET *);
#undef TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P
#define TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P sh_cannot_substitute_mem_equiv_p
+#undef TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT
+#define TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT \
+ sh_legitimize_address_displacement
+
#undef TARGET_TRAMPOLINE_INIT
#define TARGET_TRAMPOLINE_INIT sh_trampoline_init
#undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
return true;
}
+/* Return true if DISP can be legitimized. */
+static bool
+sh_legitimize_address_displacement (rtx *disp, rtx *offs,
+ machine_mode mode)
+{
+ if (TARGET_SHMEDIA)
+ return false;
+
+ if (((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode)
+ || (TARGET_SH2E && mode == SFmode))
+ return false;
+
+ struct disp_adjust adj = sh_find_mov_disp_adjust (mode, INTVAL (*disp));
+ if (adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX)
+ {
+ *disp = adj.mov_disp;
+ *offs = adj.offset_adjust;
+ return true;
+ }
+
+ return false;
+}
+
static void
sh_conditional_register_usage (void)
{
as SH, this hook can be used to avoid excessive spilling.
@end deftypefn
+@deftypefn {Target Hook} bool TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT (rtx *@var{disp}, rtx *@var{offset}, machine_mode @var{mode})
+A target hook which returns @code{true} if *@var{disp} is
+legitimezed to valid address displacement with subtracting *@var{offset}
+at memory mode @var{mode}.
+The default version of this target hook returns @code{false}.
+This hook will benefit machines with limited base plus displacement
+addressing.
+@end deftypefn
+
@deftypefn {Target Hook} reg_class_t TARGET_SPILL_CLASS (reg_class_t, @var{machine_mode})
This hook defines a class of registers which could be used for spilling pseudos of the given mode and class, or @code{NO_REGS} if only memory should be used. Not defining this hook is equivalent to returning @code{NO_REGS} for all inputs.
@end deftypefn
@hook TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P
+@hook TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT
+
@hook TARGET_SPILL_CLASS
@hook TARGET_CSTORE_MODE
delete_insns_since (PREV_INSN (last_insn));
}
}
+ /* Try if target can split displacement into legitimite new disp
+ and offset. If it's the case, we replace the last insn with
+ insns for base + offset => new_reg and set new_reg + new disp
+ to *ad.inner. */
+ last_insn = get_last_insn ();
+ if ((set = single_set (last_insn)) != NULL_RTX
+ && GET_CODE (SET_SRC (set)) == PLUS
+ && REG_P (XEXP (SET_SRC (set), 0))
+ && REGNO (XEXP (SET_SRC (set), 0)) < FIRST_PSEUDO_REGISTER
+ && CONST_INT_P (XEXP (SET_SRC (set), 1)))
+ {
+ rtx addend, disp = XEXP (SET_SRC (set), 1);
+ if (targetm.legitimize_address_displacement (&disp, &addend,
+ ad.mode))
+ {
+ rtx_insn *new_insns;
+ start_sequence ();
+ lra_emit_add (new_reg, XEXP (SET_SRC (set), 0), addend);
+ new_insns = get_insns ();
+ end_sequence ();
+ new_reg = gen_rtx_PLUS (Pmode, new_reg, disp);
+ delete_insns_since (PREV_INSN (last_insn));
+ add_insn (new_insns);
+ insns = get_insns ();
+ }
+ }
end_sequence ();
emit_insn (insns);
*ad.inner = new_reg;
bool, (rtx subst),
hook_bool_rtx_false)
+/* This target hook allows the backend to legitimize base plus
+ displacement addressing. */
+DEFHOOK
+(legitimize_address_displacement,
+ "A target hook which returns @code{true} if *@var{disp} is\n\
+legitimezed to valid address displacement with subtracting *@var{offset}\n\
+at memory mode @var{mode}.\n\
+The default version of this target hook returns @code{false}.\n\
+This hook will benefit machines with limited base plus displacement\n\
+addressing.",
+ bool, (rtx *disp, rtx *offset, machine_mode mode),
+ default_legitimize_address_displacement)
+
/* This target hook allows the backend to perform additional
processing while initializing for variable expansion. */
DEFHOOK
return x;
}
+bool
+default_legitimize_address_displacement (rtx *disp ATTRIBUTE_UNUSED,
+ rtx *offset ATTRIBUTE_UNUSED,
+ machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+
rtx
default_expand_builtin_saveregs (void)
{
extern void default_external_libcall (rtx);
extern rtx default_legitimize_address (rtx, rtx, machine_mode);
+extern bool default_legitimize_address_displacement (rtx *, rtx *,
+ machine_mode);
extern int default_unspec_may_trap_p (const_rtx, unsigned);
extern machine_mode default_promote_function_mode (const_tree, machine_mode,