diff options
Diffstat (limited to 'gcc/config/sh')
-rw-r--r-- | gcc/config/sh/predicates.md | 42 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 6 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 45 |
3 files changed, 74 insertions, 19 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); }) diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 5976206f8b4..60f45452036 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -19,12 +19,6 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -/* FIXME: This is a temporary hack, so that we can include <algorithm> - below. <algorithm> will try to include <cstdlib> which will reference - malloc & co, which are poisoned by "system.h". The proper solution is - to include <cstdlib> in "system.h" instead of <stdlib.h>. */ -#include <cstdlib> - #include "config.h" #include "system.h" #include "coretypes.h" diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 71ad1c1a2f6..8a140687654 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -12251,10 +12251,10 @@ label: ;; FMA (fused multiply-add) patterns (define_expand "fmasf4" - [(set (match_operand:SF 0 "fp_arith_reg_operand" "") - (fma:SF (match_operand:SF 1 "fp_arith_reg_operand" "") - (match_operand:SF 2 "fp_arith_reg_operand" "") - (match_operand:SF 3 "fp_arith_reg_operand" "")))] + [(set (match_operand:SF 0 "fp_arith_reg_operand") + (fma:SF (match_operand:SF 1 "fp_arith_reg_operand") + (match_operand:SF 2 "fp_arith_reg_operand") + (match_operand:SF 3 "fp_arith_reg_operand")))] "TARGET_SH2E || TARGET_SHMEDIA_FPU" { if (TARGET_SH2E) @@ -12285,6 +12285,43 @@ label: "fmac.s %1, %2, %0" [(set_attr "type" "fparith_media")]) +;; For some cases such as 'a * b + a' the FMA pattern is not generated by +;; previous transformations. If FMA is generally allowed, let the combine +;; pass utilize it. +(define_insn_and_split "*fmasf4" + [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") + (plus:SF (mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%w") + (match_operand:SF 2 "fp_arith_reg_operand" "f")) + (match_operand:SF 3 "arith_reg_operand" "0"))) + (use (match_operand:PSI 4 "fpscr_operand"))] + "TARGET_SH2E && flag_fp_contract_mode != FP_CONTRACT_OFF" + "fmac %1,%2,%0" + "&& can_create_pseudo_p ()" + [(parallel [(set (match_dup 0) + (fma:SF (match_dup 1) (match_dup 2) (match_dup 3))) + (use (match_dup 4))])] +{ + /* Change 'b * a + a' into 'a * b + a'. + This is better for register allocation. */ + if (REGNO (operands[2]) == REGNO (operands[3])) + { + rtx tmp = operands[1]; + operands[1] = operands[2]; + operands[2] = tmp; + } +} + [(set_attr "type" "fp") + (set_attr "fp_mode" "single")]) + +(define_insn "*fmasf4_media" + [(set (match_operand:SF 0 "fp_arith_reg_operand" "=f") + (plus:SF (mult:SF (match_operand:SF 1 "fp_arith_reg_operand" "%f") + (match_operand:SF 2 "fp_arith_reg_operand" "f")) + (match_operand:SF 3 "fp_arith_reg_operand" "0")))] + "TARGET_SHMEDIA_FPU && flag_fp_contract_mode != FP_CONTRACT_OFF" + "fmac.s %1, %2, %0" + [(set_attr "type" "fparith_media")]) + (define_expand "divsf3" [(set (match_operand:SF 0 "arith_reg_operand" "") (div:SF (match_operand:SF 1 "arith_reg_operand" "") |