aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorOleg Endo <olegendo@gcc.gnu.org>2012-04-11 11:35:32 +0000
committerOleg Endo <olegendo@gcc.gnu.org>2012-04-11 11:35:32 +0000
commit8c2a3f3b6cc7bc38af483ac4923258d376f90954 (patch)
tree07b8b694f4fd16b55292cb37ed731c28edfb17ed /gcc
parentb16212bd3c3ecd421c09c3a632b43ec68674b6bf (diff)
downloadgcc-8c2a3f3b6cc7bc38af483ac4923258d376f90954.zip
gcc-8c2a3f3b6cc7bc38af483ac4923258d376f90954.tar.gz
gcc-8c2a3f3b6cc7bc38af483ac4923258d376f90954.tar.bz2
re PR target/50751 (SH Target: Displacement addressing does not work for QImode and HImode)
PR target/50751 * config/sh/sh-protos.h (sh_legitimate_index_p): Add new arguments consider_sh2a and allow_zero. * config/sh/sh.c (sh_legitimate_index_p): Likewise. (disp_addr_displacement): New function. (sh_address_cost): Use disp_addr_displacement function instead of DISP_ADDR_OFFSET. (sh_legitimate_address_p): Adapt to changed sh_legitimate_index_p declaration. (sh_find_mov_disp_adjust): Remove HImode check. (sh_secondary_reload): Add HImode case. Use satisfies_constraint_Sdd, disp_addr_displacement and max_mov_insn_displacement. (max_mov_insn_displacement): Remove HImode check. * config/sh/sh.h (CONST_OK_FOR_K04, CONST_OK_FOR_K12, DISP_ADDR_P, DISP_ADDR_OFFSET): Remove. * config/sh/constraints.md (K05, K13): New constraints. (K12): Correct comment. (Sdd): Do not use DISP_ADDR_P macro. (Snd, Sbw): Use satisfies_constraint_Sdd. * config/sh/sh.md (extendhisi2): Remove constraints from expander. (*extendhisi2_compact, movhi_i): Remove. (*extendhisi2_compact_reg, *extendhisi2_compact_mem_disp, *extendhisi2_compact_mem_disp, *extendhisi2_compact_snd, *movhi_reg_reg, *movhi_store_mem_disp05, *movhi_store_mem_disp13, *movhi_load_mem_disp, *movhi_load_mem_disp, *movhi): New insns. (*extendqisi2_compact_mem_disp, *extendqisi2_compact_mem_disp, *movqi_store_mem_disp04, *movqi_store_mem_disp12, *movqi_load_mem_disp, *movqi_load_mem_disp): Use sh_legitimate_index_p instead of CONST_OK_FOR_Kxx. Add new peepholes for HImode displacement addressing. From-SVN: r186311
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog33
-rw-r--r--gcc/config/sh/constraints.md36
-rw-r--r--gcc/config/sh/predicates.md4
-rw-r--r--gcc/config/sh/sh-protos.h2
-rw-r--r--gcc/config/sh/sh.c43
-rw-r--r--gcc/config/sh/sh.h12
-rw-r--r--gcc/config/sh/sh.md258
7 files changed, 276 insertions, 112 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f0ae48f..f456157 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,38 @@
2012-04-11 Oleg Endo <olegendo@gcc.gnu.org>
+ PR target/50751
+ * config/sh/sh-protos.h (sh_legitimate_index_p): Add new arguments
+ consider_sh2a and allow_zero.
+ * config/sh/sh.c (sh_legitimate_index_p): Likewise.
+ (disp_addr_displacement): New function.
+ (sh_address_cost): Use disp_addr_displacement function instead
+ of DISP_ADDR_OFFSET.
+ (sh_legitimate_address_p): Adapt to changed
+ sh_legitimate_index_p declaration.
+ (sh_find_mov_disp_adjust): Remove HImode check.
+ (sh_secondary_reload): Add HImode case. Use satisfies_constraint_Sdd,
+ disp_addr_displacement and max_mov_insn_displacement.
+ (max_mov_insn_displacement): Remove HImode check.
+ * config/sh/sh.h (CONST_OK_FOR_K04, CONST_OK_FOR_K12,
+ DISP_ADDR_P, DISP_ADDR_OFFSET): Remove.
+ * config/sh/constraints.md (K05, K13): New constraints.
+ (K12): Correct comment.
+ (Sdd): Do not use DISP_ADDR_P macro.
+ (Snd, Sbw): Use satisfies_constraint_Sdd.
+ * config/sh/sh.md (extendhisi2): Remove constraints from expander.
+ (*extendhisi2_compact, movhi_i): Remove.
+ (*extendhisi2_compact_reg, *extendhisi2_compact_mem_disp,
+ *extendhisi2_compact_mem_disp, *extendhisi2_compact_snd,
+ *movhi_reg_reg, *movhi_store_mem_disp05, *movhi_store_mem_disp13,
+ *movhi_load_mem_disp, *movhi_load_mem_disp, *movhi): New insns.
+ (*extendqisi2_compact_mem_disp, *extendqisi2_compact_mem_disp,
+ *movqi_store_mem_disp04, *movqi_store_mem_disp12, *movqi_load_mem_disp,
+ *movqi_load_mem_disp): Use sh_legitimate_index_p instead of
+ CONST_OK_FOR_Kxx.
+ Add new peepholes for HImode displacement addressing.
+
+2012-04-11 Oleg Endo <olegendo@gcc.gnu.org>
+
* config/sh/sh.h (SIDI_OFF): Remove.
* config/sh/sh.md: Use gen_highpart and gen_lowpart to access
DImode subregs instead of gen_rtx_REG or simplifly_gen_subreg
diff --git a/gcc/config/sh/constraints.md b/gcc/config/sh/constraints.md
index 3a5fc36..6c9bc5e 100644
--- a/gcc/config/sh/constraints.md
+++ b/gcc/config/sh/constraints.md
@@ -145,16 +145,28 @@
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 15")))
+(define_constraint "K05"
+ "An unsigned 5-bit constant, as used in mov.w displacement addressing."
+ (and (match_code "const_int")
+ (match_test "ival >= 0 && ival <= 31")))
+
(define_constraint "K08"
"An unsigned 8-bit constant, as used in and, or, etc."
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 255")))
(define_constraint "K12"
- "An unsigned 12-bit constant, as used in SH2A 12-bit displacement addressing."
+ "An unsigned 12-bit constant, as used in SH2A 12-bit mov.b displacement
+ addressing."
(and (match_code "const_int")
(match_test "ival >= 0 && ival <= 4095")))
+(define_constraint "K13"
+ "An unsigned 13-bit constant, as used in SH2A 12-bit mov.w displacement
+ addressing."
+ (and (match_code "const_int")
+ (match_test "ival >= 0 && ival <= 8191")))
+
(define_constraint "K16"
"An unsigned 16-bit constant, as used in SHmedia shori."
(and (match_code "const_int")
@@ -262,6 +274,16 @@
(and (match_test "memory_operand (op, GET_MODE (op))")
(match_test "GET_CODE (XEXP (op, 0)) != PLUS")))
+(define_memory_constraint "Sdd"
+ "A memory reference that uses displacement addressing."
+ (and (match_test "MEM_P (op) && GET_CODE (XEXP (op, 0)) == PLUS")
+ (match_test "REG_P (XEXP (XEXP (op, 0), 0))")
+ (match_test "CONST_INT_P (XEXP (XEXP (op, 0), 1))")))
+
+(define_memory_constraint "Snd"
+ "A memory reference that excludes displacement addressing."
+ (match_test "! satisfies_constraint_Sdd (op)"))
+
(define_memory_constraint "Sbv"
"A memory reference, as used in SH2A bclr.b, bset.b, etc."
(and (match_test "MEM_P (op) && GET_MODE (op) == QImode")
@@ -269,15 +291,7 @@
(define_memory_constraint "Sbw"
"A memory reference, as used in SH2A bclr.b, bset.b, etc."
- (and (match_test "MEM_P (op) && GET_MODE (op) == QImode")
- (match_test "GET_CODE (XEXP (op, 0)) == PLUS")
- (match_test "REG_P (XEXP (XEXP (op, 0), 0))")
+ (and (match_test "satisfies_constraint_Sdd (op)")
+ (match_test "GET_MODE (op) == QImode")
(match_test "satisfies_constraint_K12 (XEXP (XEXP (op, 0), 1))")))
-(define_memory_constraint "Snd"
- "A memory reference that excludes displacement addressing."
- (match_test "! DISP_ADDR_P (op)"))
-
-(define_memory_constraint "Sdd"
- "A memory reference that uses displacement addressing."
- (match_test "DISP_ADDR_P (op)"))
diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index b00ad14..c6d0d46 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -404,7 +404,7 @@
if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& CONST_INT_P (XEXP (x, 1)))
- return sh_legitimate_index_p (mode, XEXP (x, 1));
+ return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false);
}
if (TARGET_SHMEDIA
@@ -466,7 +466,7 @@
if (GET_CODE (x) == PLUS
&& REG_P (XEXP (x, 0))
&& CONST_INT_P (XEXP (x, 1)))
- return sh_legitimate_index_p (mode, XEXP (x, 1));
+ return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false);
}
return general_operand (op, mode);
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index 8143749..cb9ad0f 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -56,7 +56,7 @@ extern int sh_loop_align (rtx);
extern bool fp_zero_operand (rtx);
extern bool fp_one_operand (rtx);
extern rtx get_fpscr_rtx (void);
-extern bool sh_legitimate_index_p (enum machine_mode, rtx);
+extern bool sh_legitimate_index_p (enum machine_mode, rtx, bool, bool);
extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
extern bool nonpic_symbol_mentioned_p (rtx);
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 443f800..e7e1945 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -304,6 +304,7 @@ static bool sh_legitimate_constant_p (enum machine_mode, rtx);
static int mov_insn_size (enum machine_mode, bool);
static int max_mov_insn_displacement (enum machine_mode, bool);
static int mov_insn_alignment_mask (enum machine_mode, bool);
+static HOST_WIDE_INT disp_addr_displacement (rtx);
static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
@@ -3160,11 +3161,6 @@ max_mov_insn_displacement (enum machine_mode mode, bool consider_sh2a)
scale the max. displacement value accordingly. */
const int disp_scale = consider_sh2a ? (4095 / 15) : 1;
- /* FIXME: HImode with displacement addressing is not supported yet.
- Make it purposefully fail for now. */
- if (mode == HImode)
- return 0;
-
/* SH2A supports FPU move insns with 12 bit displacements.
Other variants to do not support any kind of displacements for
FPU move insns. */
@@ -3194,15 +3190,24 @@ mov_insn_alignment_mask (enum machine_mode mode, bool consider_sh2a)
return mov_insn_sz > 0 ? (mov_insn_sz - 1) : 0;
}
+/* Return the displacement value of a displacement address. */
+
+static inline HOST_WIDE_INT
+disp_addr_displacement (rtx x)
+{
+ gcc_assert (satisfies_constraint_Sdd (x));
+ return INTVAL (XEXP (XEXP (x, 0), 1));
+}
+
/* Compute the cost of an address. */
static int
sh_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
{
/* 'reg + disp' addressing. */
- if (DISP_ADDR_P (x))
+ if (satisfies_constraint_Sdd (x))
{
- const HOST_WIDE_INT offset = DISP_ADDR_OFFSET (x);
+ const HOST_WIDE_INT offset = disp_addr_displacement (x);
const enum machine_mode mode = GET_MODE (x);
/* The displacement would fit into a 2 byte move insn. */
@@ -9665,7 +9670,8 @@ sh_insn_length_adjustment (rtx insn)
with MODE. */
bool
-sh_legitimate_index_p (enum machine_mode mode, rtx op)
+sh_legitimate_index_p (enum machine_mode mode, rtx op, bool consider_sh2a,
+ bool allow_zero)
{
if (! CONST_INT_P (op))
return false;
@@ -9686,15 +9692,15 @@ sh_legitimate_index_p (enum machine_mode mode, rtx op)
else
{
const HOST_WIDE_INT offset = INTVAL (op);
- const int max_disp = max_mov_insn_displacement (mode, TARGET_SH2A);
- const int align_mask = mov_insn_alignment_mask (mode, TARGET_SH2A);
+ const int max_disp = max_mov_insn_displacement (mode, consider_sh2a);
+ const int align_mask = mov_insn_alignment_mask (mode, consider_sh2a);
/* If the mode does not support any displacement always return false.
Even though an index of '0' is actually always valid, it will cause
troubles when e.g. a DFmode move is split into two SFmode moves,
where one SFmode move will have index '0' and the other move will
have index '4'. */
- if (max_disp < 1)
+ if (!allow_zero && max_disp < 1)
return false;
return offset >= 0 && offset <= max_disp && (offset & align_mask) == 0;
@@ -9728,7 +9734,7 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
if (GET_MODE_SIZE (mode) <= 8
&& MAYBE_BASE_REGISTER_RTX_P (xop0, strict)
- && sh_legitimate_index_p (mode, xop1))
+ && sh_legitimate_index_p (mode, xop1, TARGET_SH2A, false))
return true;
if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode
@@ -9875,11 +9881,6 @@ sh_find_mov_disp_adjust (enum machine_mode mode, HOST_WIDE_INT offset)
if (mode_sz < 1 || mode_sz > 8 || max_disp < 1)
return res;
- /* FIXME: HImode with displacement addressing is not supported yet.
- Make it purposefully fail for now. */
- if (mov_insn_sz == 2)
- return res;
-
/* Keeps the previous behavior for QImode displacement addressing.
This just decides how the offset is re-based. Removing this special
case will result in slightly bigger code on average, but it's not that
@@ -12566,12 +12567,14 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
if (rclass == FPUL_REGS && true_regnum (x) == -1)
return GENERAL_REGS;
- /* Force mov.b displacement addressing insn to use R0 as the other operand.
+ /* Force mov.b / mov.w displacement addressing insn to use R0 as
+ the other operand.
On SH2A could also just leave it alone here, which would result in a
4 byte move insn being generated instead. However, for this to work
the insns must have the appropriate alternatives. */
- if (mode == QImode && rclass != R0_REGS
- && DISP_ADDR_P (x) && DISP_ADDR_OFFSET (x) < 16)
+ if ((mode == QImode || mode == HImode) && rclass != R0_REGS
+ && satisfies_constraint_Sdd (x)
+ && disp_addr_displacement (x) <= max_mov_insn_displacement (mode, false))
return R0_REGS;
/* When reload is trying to address a QImode or HImode subreg on the stack,
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 498109a..1ee0d01 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -1210,24 +1210,12 @@ extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
((HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) 0xffffffff) \
|| (HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) -1 << 32))
-#define CONST_OK_FOR_K04(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \
- && ((HOST_WIDE_INT)(VALUE)) <= 15)
-
#define CONST_OK_FOR_K08(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \
&& ((HOST_WIDE_INT)(VALUE)) <= 255)
-#define CONST_OK_FOR_K12(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \
- && ((HOST_WIDE_INT)(VALUE)) <= 4095)
-
#define ZERO_EXTRACT_ANDMASK(EXTRACT_SZ_RTX, EXTRACT_POS_RTX)\
(((1 << INTVAL (EXTRACT_SZ_RTX)) - 1) << INTVAL (EXTRACT_POS_RTX))
-#define DISP_ADDR_P(X) (MEM_P (X) && GET_CODE (XEXP (X, 0)) == PLUS \
- && REG_P (XEXP (XEXP (X, 0), 0)) \
- && CONST_INT_P (XEXP (XEXP (X, 0), 1)))
-
-#define DISP_ADDR_OFFSET(X) (INTVAL (XEXP (XEXP (X, 0), 1)))
-
#if 0
#define SECONDARY_INOUT_RELOAD_CLASS(CLASS,MODE,X,ELSE) \
((((REGCLASS_HAS_FP_REG (CLASS) \
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index d6ae799..45a5edf 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -4743,20 +4743,18 @@ label:
operands[1] = XEXP (operands[1], 0);
})
+;; FIXME: Maybe fold HImode and QImode stuff with mode iterator?
(define_expand "extendhisi2"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
- (sign_extend:SI (match_operand:HI 1 "general_extend_operand" "r,m")))]
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (sign_extend:SI (match_operand:HI 1 "general_extend_operand" "")))]
""
"")
-(define_insn "*extendhisi2_compact"
- [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
- (sign_extend:SI (match_operand:HI 1 "general_movsrc_operand" "r,m")))]
- "TARGET_SH1"
- "@
- exts.w %1,%0
- mov.w %1,%0"
- [(set_attr "type" "arith,load")])
+(define_expand "extendqisi2"
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))]
+ ""
+ "")
(define_insn "*extendhisi2_media"
[(set (match_operand:SI 0 "register_operand" "=r,r")
@@ -4786,12 +4784,6 @@ label:
subreg_lowpart_offset (SImode, GET_MODE (op1)));
})
-(define_expand "extendqisi2"
- [(set (match_operand:SI 0 "arith_reg_dest" "")
- (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))]
- ""
- "")
-
(define_insn "*extendqisi2_compact_reg"
[(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
(sign_extend:SI (match_operand:QI 1 "register_operand" "r,t")))]
@@ -4801,6 +4793,15 @@ label:
movt %0"
[(set_attr "type" "arith,arith")])
+(define_insn "*extendhisi2_compact_reg"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r,r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r,t")))]
+ "TARGET_SH1"
+ "@
+ exts.w %1,%0
+ movt %0"
+ [(set_attr "type" "arith,arith")])
+
;; FIXME: Fold non-SH2A and SH2A alternatives with "enabled" attribute.
;; See movqi insns.
(define_insn "*extendqisi2_compact_mem_disp"
@@ -4808,20 +4809,31 @@ label:
(sign_extend:SI
(mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
(match_operand:SI 2 "const_int_operand" "K04,N")))))]
- "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))"
+ "TARGET_SH1 && ! TARGET_SH2A
+ && sh_legitimate_index_p (QImode, operands[2], false, true)"
"@
mov.b @(%O2,%1),%0
mov.b @%1,%0"
[(set_attr "type" "load")])
+(define_insn "*extendhisi2_compact_mem_disp"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=z,r")
+ (sign_extend:SI
+ (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
+ (match_operand:SI 2 "const_int_operand" "K05,N")))))]
+ "TARGET_SH1 && ! TARGET_SH2A
+ && sh_legitimate_index_p (HImode, operands[2], false, true)"
+ "@
+ mov.w @(%O2,%1),%0
+ mov.w @%1,%0"
+ [(set_attr "type" "load")])
+
(define_insn "*extendqisi2_compact_mem_disp"
[(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r")
(sign_extend:SI
(mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
(match_operand:SI 2 "const_int_operand" "K04,N,K12")))))]
- "TARGET_SH2A
- && (CONST_OK_FOR_K04 (INTVAL (operands[2]))
- || (CONST_OK_FOR_K12 (INTVAL (operands[2]))))"
+ "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)"
"@
mov.b @(%O2,%1),%0
mov.b @%1,%0
@@ -4829,8 +4841,23 @@ label:
[(set_attr "type" "load")
(set_attr "length" "2,2,4")])
-;; This will take care of other QImode addressing modes than displacement
-;; addressing.
+(define_insn "*extendhisi2_compact_mem_disp"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r")
+ (sign_extend:SI
+ (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
+ (match_operand:SI 2 "const_int_operand" "K05,N,K13")))))]
+ "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)"
+ "@
+ mov.w @(%O2,%1),%0
+ mov.w @%1,%0
+ mov.w @(%O2,%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "2,2,4")])
+
+;; The *_snd patterns will take care of other QImode/HImode addressing
+;; modes than displacement addressing. They must be defined _after_ the
+;; displacement addressing patterns. Otherwise the displacement addressing
+;; patterns will not be picked.
(define_insn "*extendqisi2_compact_snd"
[(set (match_operand:SI 0 "arith_reg_dest" "=r")
(sign_extend:SI (match_operand:QI 1 "movsrc_no_disp_mem_operand" "Snd")))]
@@ -4838,6 +4865,13 @@ label:
"mov.b %1,%0"
[(set_attr "type" "load")])
+(define_insn "*extendhisi2_compact_snd"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (sign_extend:SI (match_operand:HI 1 "movsrc_no_disp_mem_operand" "Snd")))]
+ "TARGET_SH1"
+ "mov.w %1,%0"
+ [(set_attr "type" "load")])
+
(define_insn "*extendqisi2_media"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(sign_extend:SI (match_operand:QI 1 "general_extend_operand" "r,m")))]
@@ -5416,6 +5450,14 @@ label:
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_movdst_operand" "")
+ (match_operand:HI 1 "general_movsrc_operand" ""))]
+ ""
+{
+ prepare_move_operands (operands, HImode);
+})
+
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
@@ -5431,6 +5473,7 @@ label:
;; With the movqi_reg_reg being specified before movqi it will be intially
;; picked to load/store regs. If the regs regs are on the stack reload will
;; try other insns and not stick to movqi_reg_reg.
+;; The same applies to the movhi variants.
(define_insn "*movqi_reg_reg"
[(set (match_operand:QI 0 "arith_reg_dest" "=r,r")
(match_operand:QI 1 "register_operand" "r,t"))]
@@ -5440,44 +5483,82 @@ label:
movt %0"
[(set_attr "type" "move,arith")])
+(define_insn "*movhi_reg_reg"
+ [(set (match_operand:HI 0 "arith_reg_dest" "=r,r")
+ (match_operand:HI 1 "register_operand" "r,t"))]
+ "TARGET_SH1"
+ "@
+ mov %1,%0
+ movt %0"
+ [(set_attr "type" "move,arith")])
+
;; FIXME: The non-SH2A and SH2A variants should be combined by adding
;; "enabled" attribute as it is done in other targets.
(define_insn "*movqi_store_mem_disp04"
[(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r")
(match_operand:SI 1 "const_int_operand" "K04,N")))
(match_operand:QI 2 "arith_reg_operand" "z,r"))]
- "TARGET_SH1 && CONST_OK_FOR_K04 (INTVAL (operands[1]))"
+ "TARGET_SH1 && sh_legitimate_index_p (QImode, operands[1], false, true)"
"@
mov.b %2,@(%O1,%0)
mov.b %2,@%0"
[(set_attr "type" "store")])
+(define_insn "*movhi_store_mem_disp05"
+ [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r")
+ (match_operand:SI 1 "const_int_operand" "K05,N")))
+ (match_operand:HI 2 "arith_reg_operand" "z,r"))]
+ "TARGET_SH1 && sh_legitimate_index_p (HImode, operands[1], false, true)"
+ "@
+ mov.w %2,@(%O1,%0)
+ mov.w %2,@%0"
+ [(set_attr "type" "store")])
+
(define_insn "*movqi_store_mem_disp12"
[(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r")
(match_operand:SI 1 "const_int_operand" "K12")))
(match_operand:QI 2 "arith_reg_operand" "r"))]
- "TARGET_SH2A && CONST_OK_FOR_K12 (INTVAL (operands[1]))"
+ "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[1], true, true)"
"mov.b %2,@(%O1,%0)"
[(set_attr "type" "store")
(set_attr "length" "4")])
+(define_insn "*movhi_store_mem_disp13"
+ [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r")
+ (match_operand:SI 1 "const_int_operand" "K13")))
+ (match_operand:HI 2 "arith_reg_operand" "r"))]
+ "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[1], true, true)"
+ "mov.w %2,@(%O1,%0)"
+ [(set_attr "type" "store")
+ (set_attr "length" "4")])
+
(define_insn "*movqi_load_mem_disp"
[(set (match_operand:QI 0 "arith_reg_dest" "=z,r")
(mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
(match_operand:SI 2 "const_int_operand" "K04,N"))))]
- "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))"
+ "TARGET_SH1 && ! TARGET_SH2A
+ && sh_legitimate_index_p (QImode, operands[2], false, true)"
"@
mov.b @(%O2,%1),%0
mov.b @%1,%0"
[(set_attr "type" "load")])
+(define_insn "*movhi_load_mem_disp"
+ [(set (match_operand:HI 0 "arith_reg_dest" "=z,r")
+ (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r")
+ (match_operand:SI 2 "const_int_operand" "K05,N"))))]
+ "TARGET_SH1 && ! TARGET_SH2A
+ && sh_legitimate_index_p (HImode, operands[2], false, true)"
+ "@
+ mov.w @(%O2,%1),%0
+ mov.w @%1,%0"
+ [(set_attr "type" "load")])
+
(define_insn "*movqi_load_mem_disp"
[(set (match_operand:QI 0 "arith_reg_dest" "=z,r,r")
(mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
(match_operand:SI 2 "const_int_operand" "K04,N,K12"))))]
- "TARGET_SH2A
- && (CONST_OK_FOR_K04 (INTVAL (operands[2]))
- || CONST_OK_FOR_K12 (INTVAL (operands[2])))"
+ "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)"
"@
mov.b @(%O2,%1),%0
mov.b @%1,%0
@@ -5485,6 +5566,18 @@ label:
[(set_attr "type" "load")
(set_attr "length" "2,2,4")])
+(define_insn "*movhi_load_mem_disp"
+ [(set (match_operand:HI 0 "arith_reg_dest" "=z,r,r")
+ (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r")
+ (match_operand:SI 2 "const_int_operand" "K05,N,K13"))))]
+ "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)"
+ "@
+ mov.w @(%O2,%1),%0
+ mov.w @%1,%0
+ mov.w @(%O2,%1),%0"
+ [(set_attr "type" "load")
+ (set_attr "length" "2,2,4")])
+
;; The m constraints basically allow any kind of addresses to be used with any
;; source/target register as the other operand. This is not true for
;; displacement addressing modes on anything but SH2A. That's why the
@@ -5503,6 +5596,21 @@ label:
lds %1,%0"
[(set_attr "type" "movi8,load,store,prget,prset")])
+(define_insn "*movhi"
+ [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,m,r,l")
+ (match_operand:HI 1 "general_movsrc_operand" "Q,i,m,r,l,r"))]
+ "TARGET_SH1
+ && (arith_reg_operand (operands[0], HImode)
+ || arith_reg_operand (operands[1], HImode))"
+ "@
+ mov.w %1,%0
+ mov %1,%0
+ mov.w %1,%0
+ mov.w %1,%0
+ sts %1,%0
+ lds %1,%0"
+ [(set_attr "type" "pcload,movi8,load,store,prget,prset")])
+
(define_insn "*movqi_media"
[(set (match_operand:QI 0 "general_movdst_operand" "=r,r,r,m")
(match_operand:QI 1 "general_movsrc_operand" "r,I16Css,m,rZ"))]
@@ -5535,28 +5643,6 @@ label:
operands[3] = gen_rtx_REG (DImode, REGNO (operands[2]));
})
-;; When storing r0, we have to avoid reg+reg addressing.
-(define_insn "movhi_i"
- [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m,r,l,r")
- (match_operand:HI 1 "general_movsrc_operand" "Q,rI08,m,t,r,l,r,i"))]
- "TARGET_SH1
- && (arith_reg_operand (operands[0], HImode)
- || arith_reg_operand (operands[1], HImode))
- && (!MEM_P (operands[0])
- || GET_CODE (XEXP (operands[0], 0)) != PLUS
- || !REG_P (XEXP (XEXP (operands[0], 0), 1))
- || ! refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0))"
- "@
- mov.w %1,%0
- mov %1,%0
- mov.w %1,%0
- movt %0
- mov.w %1,%0
- sts %1,%0
- lds %1,%0
- fake %1,%0"
- [(set_attr "type" "pcload,move,load,move,store,move,move,pcload")])
-
(define_insn "*movhi_media"
[(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m")
(match_operand:HI 1 "general_movsrc_operand" "r,I16Css,n,m,rZ"))]
@@ -5582,14 +5668,6 @@ label:
&& ! satisfies_constraint_I16 (operands[1])"
[(set (subreg:DI (match_dup 0) 0) (match_dup 1))])
-(define_expand "movhi"
- [(set (match_operand:HI 0 "general_movdst_operand" "")
- (match_operand:HI 1 "general_movsrc_operand" ""))]
- ""
-{
- prepare_move_operands (operands, HImode);
-})
-
(define_expand "reload_inhi"
[(set (match_operand:SI 2 "" "=&r")
(match_operand:HI 1 "inqhi_operand" ""))
@@ -11538,10 +11616,10 @@ label:
;; Fold sequence:
;; mov #54,r0
-;; mov.b @(r0,r15),r0
+;; mov.{b,w} @(r0,r15),r0
;; mov r0,r3
;; into:
-;; mov.b @(54,r15),r3
+;; mov.{b,w} @(54,r15),r3
;;
(define_peephole2
[(set (match_operand:SI 0 "arith_reg_dest" "")
@@ -11553,17 +11631,33 @@ label:
(set (match_operand:QI 4 "arith_reg_dest" "")
(match_operand:QI 5 "arith_reg_operand" ""))]
"TARGET_SH2A
- && CONST_OK_FOR_K12 (INTVAL (operands[1]))
+ && sh_legitimate_index_p (QImode, operands[1], true, true)
&& REGNO (operands[2]) == REGNO (operands[5])
&& peep2_reg_dead_p (3, operands[5])"
[(set (match_dup 4) (mem:QI (plus:SI (match_dup 3) (match_dup 1))))]
"")
+(define_peephole2
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (match_operand:SI 1 "const_int_operand" ""))
+ (set (match_operand:SI 2 "arith_reg_dest" "")
+ (sign_extend:SI
+ (mem:HI (plus:SI (match_dup 0)
+ (match_operand:SI 3 "arith_reg_operand" "")))))
+ (set (match_operand:HI 4 "arith_reg_dest" "")
+ (match_operand:HI 5 "arith_reg_operand" ""))]
+ "TARGET_SH2A
+ && sh_legitimate_index_p (HImode, operands[1], true, true)
+ && REGNO (operands[2]) == REGNO (operands[5])
+ && peep2_reg_dead_p (3, operands[5])"
+ [(set (match_dup 4) (mem:HI (plus:SI (match_dup 3) (match_dup 1))))]
+ "")
+
;; Fold sequence:
;; mov #54,r0
-;; mov.b @(r0,r15),r1
+;; mov.{b,w} @(r0,r15),r1
;; into:
-;; mov.b @(54,r15),r1
+;; mov.{b,w} @(54,r15),r1
;;
(define_peephole2
[(set (match_operand:SI 0 "arith_reg_dest" "")
@@ -11573,19 +11667,37 @@ label:
(mem:QI (plus:SI (match_dup 0)
(match_operand:SI 3 "arith_reg_operand" "")))))]
"TARGET_SH2A
- && CONST_OK_FOR_K12 (INTVAL (operands[1]))
+ && sh_legitimate_index_p (QImode, operands[1], true, true)
&& (peep2_reg_dead_p (2, operands[0])
|| REGNO (operands[0]) == REGNO (operands[2]))"
[(set (match_dup 2)
(sign_extend:SI (mem:QI (plus:SI (match_dup 3) (match_dup 1)))))]
"")
+(define_peephole2
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (match_operand:SI 1 "const_int_operand" ""))
+ (set (match_operand:SI 2 "arith_reg_dest" "")
+ (sign_extend:SI
+ (mem:HI (plus:SI (match_dup 0)
+ (match_operand:SI 3 "arith_reg_operand" "")))))]
+ "TARGET_SH2A
+ && sh_legitimate_index_p (HImode, operands[1], true, true)
+ && (peep2_reg_dead_p (2, operands[0])
+ || REGNO (operands[0]) == REGNO (operands[2]))"
+ [(set (match_dup 2)
+ (sign_extend:SI (mem:HI (plus:SI (match_dup 3) (match_dup 1)))))]
+ "")
+
;; Fold sequence:
-;; mov.b @(r0,r15),r0
+;; mov.{b,w} @(r0,r15),r0
;; mov r0,r3
;; into:
-;; mov.b @(r0,r15),r3
+;; mov.{b,w} @(r0,r15),r3
;;
+;; This can happen when initially a displacement address is picked, where
+;; the destination reg is fixed to r0, and then the address is transformed
+;; into 'r0 + reg'.
(define_peephole2
[(set (match_operand:SI 0 "arith_reg_dest" "")
(sign_extend:SI
@@ -11600,6 +11712,20 @@ label:
(mem:QI (plus:SI (match_dup 1) (match_dup 2))))]
"")
+(define_peephole2
+ [(set (match_operand:SI 0 "arith_reg_dest" "")
+ (sign_extend:SI
+ (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "")
+ (match_operand:SI 2 "arith_reg_operand" "")))))
+ (set (match_operand:HI 3 "arith_reg_dest" "")
+ (match_operand:HI 4 "arith_reg_operand" ""))]
+ "TARGET_SH1
+ && REGNO (operands[0]) == REGNO (operands[4])
+ && peep2_reg_dead_p (2, operands[0])"
+ [(set (match_dup 3)
+ (mem:HI (plus:SI (match_dup 1) (match_dup 2))))]
+ "")
+
;; These convert sequences such as `mov #k,r0; add r15,r0; mov.l @r0,rn'
;; to `mov #k,r0; mov.l @(r0,r15),rn'. These sequences are generated by
;; reload when the constant is too large for a reg+offset address.