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> 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 * config/mn10300/mn10300.md (*am33_movqi, *mn10300_movqi): Merge into
(*movqi_internal): ... here. (*movqi_internal): ... here.
(*am33_movhi, *mn10300_movhi): Merge into... (*am33_movhi, *mn10300_movhi): Merge into...
......
...@@ -35,7 +35,6 @@ extern Cstar mn10300_output_cmp (rtx, rtx); ...@@ -35,7 +35,6 @@ extern Cstar mn10300_output_cmp (rtx, rtx);
extern void mn10300_print_operand (FILE *, rtx, int); extern void mn10300_print_operand (FILE *, rtx, int);
extern void mn10300_print_operand_address (FILE *, rtx); extern void mn10300_print_operand_address (FILE *, rtx);
extern void mn10300_print_reg_list (FILE *, int); 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 Mmode mn10300_select_cc_mode (rtx);
extern int mn10300_store_multiple_operation (rtx, Mmode); extern int mn10300_store_multiple_operation (rtx, Mmode);
extern int mn10300_symbolic_operand (rtx, Mmode); extern int mn10300_symbolic_operand (rtx, Mmode);
......
...@@ -1327,7 +1327,7 @@ static reg_class_t ...@@ -1327,7 +1327,7 @@ static reg_class_t
mn10300_preferred_reload_class (rtx x, reg_class_t rclass) mn10300_preferred_reload_class (rtx x, reg_class_t rclass)
{ {
if (x == stack_pointer_rtx && rclass != SP_REGS) 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) else if (MEM_P (x)
|| (REG_P (x) || (REG_P (x)
&& !HARD_REGISTER_P (x)) && !HARD_REGISTER_P (x))
...@@ -1345,72 +1345,83 @@ static reg_class_t ...@@ -1345,72 +1345,83 @@ static reg_class_t
mn10300_preferred_output_reload_class (rtx x, reg_class_t rclass) mn10300_preferred_output_reload_class (rtx x, reg_class_t rclass)
{ {
if (x == stack_pointer_rtx && rclass != SP_REGS) if (x == stack_pointer_rtx && rclass != SP_REGS)
return ADDRESS_OR_EXTENDED_REGS; return (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
return rclass; return rclass;
} }
/* What (if any) secondary registers are needed to move IN with mode /* Implement TARGET_SECONDARY_RELOAD. */
MODE into a register in register class RCLASS.
We might be able to simplify this. */
enum reg_class static reg_class_t
mn10300_secondary_reload_class (enum reg_class rclass, enum machine_mode mode, mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
rtx in) enum machine_mode mode, secondary_reload_info *sri)
{ {
rtx inner = in; enum reg_class rclass = (enum reg_class) rclass_i;
enum reg_class xclass = NO_REGS;
/* Strip off any SUBREG expressions from IN. Basically we want unsigned int xregno = INVALID_REGNUM;
to know if IN is a pseudo or (subreg (pseudo)) as those can
turn into MEMs during reload. */ if (REG_P (x))
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))
{ {
if (TARGET_AM33) xregno = REGNO (x);
return DATA_OR_EXTENDED_REGS; if (xregno >= FIRST_PSEUDO_REGISTER)
return DATA_REGS; 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 can't directly load sp + const_int into a register;
we must use an address register as an intermediate. */ we must use an address register as an scratch. */
if (rclass != SP_REGS if (in_p
&& rclass != ADDRESS_REGS && rclass != SP_REGS
&& rclass != SP_OR_ADDRESS_REGS && rclass != SP_OR_ADDRESS_REGS
&& rclass != SP_OR_EXTENDED_REGS && rclass != SP_OR_EXTENDED_REGS
&& rclass != ADDRESS_OR_EXTENDED_REGS
&& rclass != SP_OR_ADDRESS_OR_EXTENDED_REGS && rclass != SP_OR_ADDRESS_OR_EXTENDED_REGS
&& (in == stack_pointer_rtx && GET_CODE (x) == PLUS
|| (GET_CODE (in) == PLUS && (XEXP (x, 0) == stack_pointer_rtx
&& (XEXP (in, 0) == stack_pointer_rtx || XEXP (x, 1) == stack_pointer_rtx))
|| XEXP (in, 1) == stack_pointer_rtx)))) {
return ADDRESS_REGS; 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 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 rtx addr = NULL;
constant address. */
if (MEM_P (in) if (xregno >= FIRST_PSEUDO_REGISTER && xregno != INVALID_REGNUM)
&& CONSTANT_ADDRESS_P (XEXP (in, 0))) {
return DATA_OR_EXTENDED_REGS; 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 if (addr && CONSTANT_ADDRESS_P (addr))
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)))
return DATA_OR_EXTENDED_REGS; return DATA_OR_EXTENDED_REGS;
} }
...@@ -2802,7 +2813,10 @@ mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED, ...@@ -2802,7 +2813,10 @@ mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
#undef TARGET_PREFERRED_RELOAD_CLASS #undef TARGET_PREFERRED_RELOAD_CLASS
#define TARGET_PREFERRED_RELOAD_CLASS mn10300_preferred_reload_class #define TARGET_PREFERRED_RELOAD_CLASS mn10300_preferred_reload_class
#undef TARGET_PREFERRED_OUTPUT_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 #undef TARGET_TRAMPOLINE_INIT
#define TARGET_TRAMPOLINE_INIT mn10300_trampoline_init #define TARGET_TRAMPOLINE_INIT mn10300_trampoline_init
......
...@@ -416,9 +416,6 @@ enum reg_class ...@@ -416,9 +416,6 @@ enum reg_class
#define LIMIT_RELOAD_CLASS(MODE, CLASS) \ #define LIMIT_RELOAD_CLASS(MODE, CLASS) \
(!TARGET_AM33 && (MODE == QImode || MODE == HImode) ? DATA_REGS : 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 /* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */ needed to represent mode MODE in a register of class CLASS. */
......
...@@ -285,42 +285,52 @@ ...@@ -285,42 +285,52 @@
;; We use this to handle addition of two values when one operand is the ;; 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 ;; stack pointer and the other is a memory reference of some kind. Reload
;; does not handle them correctly without this expander. ;; does not handle them correctly without this expander.
(define_expand "reload_insi" (define_expand "reload_plus_sp_const"
[(set (match_operand:SI 0 "register_operand" "=a") [(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "impossible_plus_operand" "")) (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 gcc_assert (true_regnum (scratch) != true_regnum (dest));
&& (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 1))) emit_move_insn (scratch, stack_pointer_rtx);
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 1)))))) emit_insn (gen_addsi3 (dest, dest, scratch));
emit_move_insn (operands[2], }
gen_rtx_ZERO_EXTEND else if (TARGET_AM33 || REGNO_REG_CLASS (true_regnum (dest)) == ADDRESS_REGS)
(GET_MODE (XEXP (operands[1], 1)), {
SUBREG_REG (XEXP (operands[1], 1)))); emit_move_insn (dest, stack_pointer_rtx);
else if (other == stack_pointer_rtx)
emit_move_insn (operands[2], XEXP (operands[1], 1)); emit_insn (gen_addsi3 (dest, dest, dest));
emit_move_insn (operands[0], XEXP (operands[1], 0)); else if (other != const0_rtx)
emit_insn (gen_addsi3 (dest, dest, other));
} }
else else
{ {
if (GET_CODE (XEXP (operands[1], 0)) == SUBREG emit_move_insn (scratch, stack_pointer_rtx);
&& (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 0))) if (other == stack_pointer_rtx)
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 0)))))) {
emit_move_insn (operands[2], emit_move_insn (dest, scratch);
gen_rtx_ZERO_EXTEND emit_insn (gen_addsi3 (dest, dest, dest));
(GET_MODE (XEXP (operands[1], 0)), }
SUBREG_REG (XEXP (operands[1], 0)))); else if (other != const0_rtx)
{
emit_move_insn (dest, other);
emit_insn (gen_addsi3 (dest, dest, scratch));
}
else else
emit_move_insn (operands[2], XEXP (operands[1], 0)); emit_move_insn (dest, scratch);
emit_move_insn (operands[0], XEXP (operands[1], 1));
} }
emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
DONE; 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