Commit 8b119bb6 by Richard Henderson Committed by Richard Henderson

mn10300: Cleanup secondary reloads

Handles output reloads for QI/HImode properly; previously we were
only handing input reloads properly.

Handles reloads involving the stack pointer better; note that the
AM33 allows copying SP to DATA_REGS as well as ADDRESS and EXTENDED.

From-SVN: r169005
parent b1efde2a
2011-01-19 Richard Henderson <rth@redhat.com>
* config/mn10300/mn10300.c (mn10300_preferred_reload_class): Allow
DATA_REGS for AM33 stack-pointer destination.
(mn10300_preferred_output_reload_class): Likewise.
(mn10300_secondary_reload): Rearrange mn10300_secondary_reload_class
into a form appropriate for ...
(TARGET_SECONDARY_RELOAD): New.
* config/mn10300/mn10300.h (SECONDARY_RELOAD_CLASS): Remove.
* config/mn10300/mn10300-protos.h: Update.
* config/mn10300/mn10300.md (reload_plus_sp_const): Rename from
reload_insi; use the "A" constraint for the scratch; handle AM33
moves of sp to non-address registers.
* config/mn10300/mn10300.md (*am33_movqi, *mn10300_movqi): Merge into
(*movqi_internal): ... here.
(*am33_movhi, *mn10300_movhi): Merge into...
......
......@@ -35,7 +35,6 @@ extern Cstar mn10300_output_cmp (rtx, rtx);
extern void mn10300_print_operand (FILE *, rtx, int);
extern void mn10300_print_operand_address (FILE *, rtx);
extern void mn10300_print_reg_list (FILE *, int);
extern Rclas mn10300_secondary_reload_class (Rclas, Mmode, rtx);
extern Mmode mn10300_select_cc_mode (rtx);
extern int mn10300_store_multiple_operation (rtx, Mmode);
extern int mn10300_symbolic_operand (rtx, Mmode);
......
......@@ -1327,7 +1327,7 @@ static reg_class_t
mn10300_preferred_reload_class (rtx x, reg_class_t rclass)
{
if (x == stack_pointer_rtx && rclass != SP_REGS)
return ADDRESS_OR_EXTENDED_REGS;
return (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
else if (MEM_P (x)
|| (REG_P (x)
&& !HARD_REGISTER_P (x))
......@@ -1345,72 +1345,83 @@ static reg_class_t
mn10300_preferred_output_reload_class (rtx x, reg_class_t rclass)
{
if (x == stack_pointer_rtx && rclass != SP_REGS)
return ADDRESS_OR_EXTENDED_REGS;
return (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
return rclass;
}
/* What (if any) secondary registers are needed to move IN with mode
MODE into a register in register class RCLASS.
We might be able to simplify this. */
/* Implement TARGET_SECONDARY_RELOAD. */
enum reg_class
mn10300_secondary_reload_class (enum reg_class rclass, enum machine_mode mode,
rtx in)
static reg_class_t
mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
enum machine_mode mode, secondary_reload_info *sri)
{
rtx inner = in;
/* Strip off any SUBREG expressions from IN. Basically we want
to know if IN is a pseudo or (subreg (pseudo)) as those can
turn into MEMs during reload. */
while (GET_CODE (inner) == SUBREG)
inner = SUBREG_REG (inner);
/* Memory loads less than a full word wide can't have an
address or stack pointer destination. They must use
a data register as an intermediate register. */
if ((MEM_P (in)
|| (REG_P (inner)
&& REGNO (inner) >= FIRST_PSEUDO_REGISTER))
&& (mode == QImode || mode == HImode)
&& (rclass == ADDRESS_REGS || rclass == SP_REGS
|| rclass == SP_OR_ADDRESS_REGS))
enum reg_class rclass = (enum reg_class) rclass_i;
enum reg_class xclass = NO_REGS;
unsigned int xregno = INVALID_REGNUM;
if (REG_P (x))
{
if (TARGET_AM33)
return DATA_OR_EXTENDED_REGS;
return DATA_REGS;
xregno = REGNO (x);
if (xregno >= FIRST_PSEUDO_REGISTER)
xregno = true_regnum (x);
if (xregno != INVALID_REGNUM)
xclass = REGNO_REG_CLASS (xregno);
}
if (!TARGET_AM33)
{
/* Memory load/stores less than a full word wide can't have an
address or stack pointer destination. They must use a data
register as an intermediate register. */
if (rclass != DATA_REGS
&& (mode == QImode || mode == HImode)
&& xclass == NO_REGS)
return DATA_REGS;
/* We can only move SP to/from an address register. */
if (in_p
&& rclass == SP_REGS
&& xclass != ADDRESS_REGS)
return ADDRESS_REGS;
if (!in_p
&& xclass == SP_REGS
&& rclass != ADDRESS_REGS
&& rclass != SP_OR_ADDRESS_REGS)
return ADDRESS_REGS;
}
/* We can't directly load sp + const_int into a data register;
we must use an address register as an intermediate. */
if (rclass != SP_REGS
&& rclass != ADDRESS_REGS
/* We can't directly load sp + const_int into a register;
we must use an address register as an scratch. */
if (in_p
&& rclass != SP_REGS
&& rclass != SP_OR_ADDRESS_REGS
&& rclass != SP_OR_EXTENDED_REGS
&& rclass != ADDRESS_OR_EXTENDED_REGS
&& rclass != SP_OR_ADDRESS_OR_EXTENDED_REGS
&& (in == stack_pointer_rtx
|| (GET_CODE (in) == PLUS
&& (XEXP (in, 0) == stack_pointer_rtx
|| XEXP (in, 1) == stack_pointer_rtx))))
return ADDRESS_REGS;
&& GET_CODE (x) == PLUS
&& (XEXP (x, 0) == stack_pointer_rtx
|| XEXP (x, 1) == stack_pointer_rtx))
{
sri->icode = CODE_FOR_reload_plus_sp_const;
return NO_REGS;
}
/* We can't load/store an FP register from a constant address. */
if (TARGET_AM33_2
&& rclass == FP_REGS)
&& (rclass == FP_REGS || xclass == FP_REGS)
&& (xclass == NO_REGS || rclass == NO_REGS))
{
/* We can't load directly into an FP register from a
constant address. */
if (MEM_P (in)
&& CONSTANT_ADDRESS_P (XEXP (in, 0)))
return DATA_OR_EXTENDED_REGS;
rtx addr = NULL;
if (xregno >= FIRST_PSEUDO_REGISTER && xregno != INVALID_REGNUM)
{
addr = reg_equiv_mem [xregno];
if (addr)
addr = XEXP (addr, 0);
}
else if (MEM_P (x))
addr = XEXP (x, 0);
/* Handle case were a pseudo may not get a hard register
but has an equivalent memory location defined. */
if (REG_P (inner)
&& REGNO (inner) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem [REGNO (inner)]
&& CONSTANT_ADDRESS_P (XEXP (reg_equiv_mem [REGNO (inner)], 0)))
if (addr && CONSTANT_ADDRESS_P (addr))
return DATA_OR_EXTENDED_REGS;
}
......@@ -2802,7 +2813,10 @@ mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
#undef TARGET_PREFERRED_RELOAD_CLASS
#define TARGET_PREFERRED_RELOAD_CLASS mn10300_preferred_reload_class
#undef TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS mn10300_preferred_output_reload_class
#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS \
mn10300_preferred_output_reload_class
#undef TARGET_SECONDARY_RELOAD
#define TARGET_SECONDARY_RELOAD mn10300_secondary_reload
#undef TARGET_TRAMPOLINE_INIT
#define TARGET_TRAMPOLINE_INIT mn10300_trampoline_init
......
......@@ -416,9 +416,6 @@ enum reg_class
#define LIMIT_RELOAD_CLASS(MODE, CLASS) \
(!TARGET_AM33 && (MODE == QImode || MODE == HImode) ? DATA_REGS : CLASS)
#define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \
mn10300_secondary_reload_class(CLASS,MODE,IN)
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */
......
......@@ -285,42 +285,52 @@
;; We use this to handle addition of two values when one operand is the
;; stack pointer and the other is a memory reference of some kind. Reload
;; does not handle them correctly without this expander.
(define_expand "reload_insi"
[(set (match_operand:SI 0 "register_operand" "=a")
(define_expand "reload_plus_sp_const"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "impossible_plus_operand" ""))
(clobber (match_operand:SI 2 "register_operand" "=&r"))]
(clobber (match_operand:SI 2 "register_operand" "=&A"))]
""
"
{
gcc_assert (REGNO (operands[0]) != REGNO (operands[2]));
rtx dest, scratch, other;
if (XEXP (operands[1], 0) == stack_pointer_rtx)
dest = operands[0];
scratch = operands[2];
other = XEXP (operands[1], 1);
if (other == stack_pointer_rtx)
other = XEXP (operands[1], 0);
if (true_regnum (other) == true_regnum (dest))
{
if (GET_CODE (XEXP (operands[1], 1)) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 1)))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 1))))))
emit_move_insn (operands[2],
gen_rtx_ZERO_EXTEND
(GET_MODE (XEXP (operands[1], 1)),
SUBREG_REG (XEXP (operands[1], 1))));
else
emit_move_insn (operands[2], XEXP (operands[1], 1));
emit_move_insn (operands[0], XEXP (operands[1], 0));
gcc_assert (true_regnum (scratch) != true_regnum (dest));
emit_move_insn (scratch, stack_pointer_rtx);
emit_insn (gen_addsi3 (dest, dest, scratch));
}
else if (TARGET_AM33 || REGNO_REG_CLASS (true_regnum (dest)) == ADDRESS_REGS)
{
emit_move_insn (dest, stack_pointer_rtx);
if (other == stack_pointer_rtx)
emit_insn (gen_addsi3 (dest, dest, dest));
else if (other != const0_rtx)
emit_insn (gen_addsi3 (dest, dest, other));
}
else
{
if (GET_CODE (XEXP (operands[1], 0)) == SUBREG
&& (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 0)))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 0))))))
emit_move_insn (operands[2],
gen_rtx_ZERO_EXTEND
(GET_MODE (XEXP (operands[1], 0)),
SUBREG_REG (XEXP (operands[1], 0))));
emit_move_insn (scratch, stack_pointer_rtx);
if (other == stack_pointer_rtx)
{
emit_move_insn (dest, scratch);
emit_insn (gen_addsi3 (dest, dest, dest));
}
else if (other != const0_rtx)
{
emit_move_insn (dest, other);
emit_insn (gen_addsi3 (dest, dest, scratch));
}
else
emit_move_insn (operands[2], XEXP (operands[1], 0));
emit_move_insn (operands[0], XEXP (operands[1], 1));
emit_move_insn (dest, scratch);
}
emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
DONE;
}")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment