diff options
author | olegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-23 08:39:55 +0000 |
---|---|---|
committer | olegendo <olegendo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2013-06-23 08:39:55 +0000 |
commit | 640c5f1f31dfa2503eaa5ef41a28d0aa1a23c8e8 (patch) | |
tree | d7df78d467eced8a08fab473d7ee5ed22340779c /gcc/config/sh | |
parent | ef21d40e1ef4c72997688d5716a6f4ef5a72b499 (diff) | |
download | gcc-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.md | 42 |
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); }) |