summaryrefslogtreecommitdiff
path: root/gcc/config/sh
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/sh')
-rw-r--r--gcc/config/sh/predicates.md42
-rw-r--r--gcc/config/sh/sh.c6
-rw-r--r--gcc/config/sh/sh.md45
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" "")