summaryrefslogtreecommitdiff
path: root/gcc/config/sh
diff options
context:
space:
mode:
authorolegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-23 08:39:55 +0000
committerolegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4>2013-06-23 08:39:55 +0000
commit640c5f1f31dfa2503eaa5ef41a28d0aa1a23c8e8 (patch)
treed7df78d467eced8a08fab473d7ee5ed22340779c /gcc/config/sh
parentef21d40e1ef4c72997688d5716a6f4ef5a72b499 (diff)
downloadgcc-640c5f1f31dfa2503eaa5ef41a28d0aa1a23c8e8.tar.gz
PR target/52483
* config/sh/predicates.md (general_extend_operand): Invoke general_movsrc_operand for memory operands. (general_movsrc_operand): Allow reg+reg addressing, do not use general_operand for memory operands. PR target/52483 * gcc.target/sh/pr52483-1.c: New. * gcc.target/sh/pr52483-2.c: New. * gcc.target/sh/pr52483-3.c: New. * gcc.target/sh/pr52483-4.c: New. * gcc.target/sh/pr52483-5.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@200350 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/sh')
-rw-r--r--gcc/config/sh/predicates.md42
1 files changed, 33 insertions, 9 deletions
diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index 25949c62d23..998ba7300ad 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -398,9 +398,13 @@
(define_predicate "general_extend_operand"
(match_code "subreg,reg,mem,truncate")
{
- return (GET_CODE (op) == TRUNCATE
- ? arith_operand
- : nonimmediate_operand) (op, mode);
+ if (GET_CODE (op) == TRUNCATE)
+ return arith_operand (op, mode);
+
+ if (MEM_P (op) || (GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op))))
+ return general_movsrc_operand (op, mode);
+
+ return nonimmediate_operand (op, mode);
})
;; Returns 1 if OP is a simple register address.
@@ -468,17 +472,36 @@
return 0;
}
- if ((mode == QImode || mode == HImode)
- && mode == GET_MODE (op)
- && (MEM_P (op)
- || (GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op)))))
+ if (mode == GET_MODE (op)
+ && (MEM_P (op) || (GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op)))))
{
- rtx x = XEXP ((MEM_P (op) ? op : SUBREG_REG (op)), 0);
+ rtx mem_rtx = MEM_P (op) ? op : SUBREG_REG (op);
+ rtx x = XEXP (mem_rtx, 0);
- if (GET_CODE (x) == PLUS
+ if ((mode == QImode || mode == HImode)
+ && GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& CONST_INT_P (XEXP (x, 1)))
return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false);
+
+ /* Allow reg+reg addressing here without validating the register
+ numbers. Usually one of the regs must be R0 or a pseudo reg.
+ In some cases it can happen that arguments from hard regs are
+ propagated directly into address expressions. In this cases reload
+ will have to fix it up later. However, allow this only for native
+ 1, 2 or 4 byte addresses. */
+ if (can_create_pseudo_p () && GET_CODE (x) == PLUS
+ && GET_MODE_SIZE (mode) <= 4
+ && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1)))
+ return true;
+
+ /* 'general_operand' does not allow volatile mems during RTL expansion to
+ avoid matching arithmetic that operates on mems, it seems.
+ On SH this leads to redundant sign extensions for QImode or HImode
+ loads. Thus we mimic the behavior but allow volatile mems. */
+ if (memory_address_addr_space_p (GET_MODE (mem_rtx), x,
+ MEM_ADDR_SPACE (mem_rtx)))
+ return true;
}
if (TARGET_SHMEDIA
@@ -489,6 +512,7 @@
&& GET_CODE (op) == SUBREG && GET_MODE (op) == mode
&& SUBREG_REG (op) == const0_rtx && subreg_lowpart_p (op))
/* FIXME */ abort (); /* return 1; */
+
return general_operand (op, mode);
})