summaryrefslogtreecommitdiff
path: root/gcc/config/mn10300
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-19 17:02:57 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-19 17:02:57 +0000
commitc78ac6686edc00400269983122ae6fe14c6199d0 (patch)
tree4f7c0a2912485b76df2116017beedc648533166f /gcc/config/mn10300
parentedad0637abbd8210787e4cd8e750980653f3e799 (diff)
downloadgcc-c78ac6686edc00400269983122ae6fe14c6199d0.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@169005 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/mn10300')
-rw-r--r--gcc/config/mn10300/mn10300-protos.h1
-rw-r--r--gcc/config/mn10300/mn10300.c120
-rw-r--r--gcc/config/mn10300/mn10300.h3
-rw-r--r--gcc/config/mn10300/mn10300.md60
4 files changed, 102 insertions, 82 deletions
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index d6cf850a52c..37968ff5cc9 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -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);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index f9be6ea6c58..29cf3373a60 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -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
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 3f63498d086..1ed13b9b181 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -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. */
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 9cddebf3e79..7dd33676cf0 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -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;
}")