diff mbox

[SH,committed] Add support for additional SH2A post-inc/pre-dec addressing modes

Message ID 1462347068.23746.9.camel@t-online.de
State New
Headers show

Commit Message

Oleg Endo May 4, 2016, 7:31 a.m. UTC
Hi,

The attached patch adds support for the following SH2A addressing
modes:
	mov.b	@-Rm,R0
	mov.w	@-Rm,R0
	mov.l	@-Rm,R0
	mov.b	R0,@Rn+
	mov.w	R0,@Rn+
	mov.l	R0,@Rn+

The patch also tweaks the post-inc/pre-dec addressing mode usage on non
-SH2A targets.  CSiBE shows a total code size reduction of 1568 bytes (
-0.047074 %) for non-SH2A and a code size increase of +247 (+0.007505
%) for SH2A.

The code size increase on SH2A is due to increased register
usage/pressure.  Where before displacement modes were used (reg +
disp), it now tends to use post-inc stores.  To do that, the address
register (often the stack pointer) is often copied into another
register first.  Hopefully this issue can be improved later by the AMS
optimization.

Tested on sh-elf with
make -k check RUNTESTFLAGS="--target_board=sh-sim\{-m2/-ml,-m2/-mb,
-m2a/-mb,-m4/-ml,-m4/-mb,-m4a/-ml,-m4a/-mb}"

Committed as r235859.

Cheers,
Oleg

gcc/ChangeLog:
	* config/sh/predicates (post_inc_mem, pre_dec_mem): New predicates.
	* config/sh/sh-protos.h (sh_find_set_of_reg): Return null result if
	result.set_rtx is null instead of aborting.
	* config/sh/sh.h (USE_LOAD_POST_INCREMENT, USE_STORE_PRE_DECREMENT):
	Always enable.
	(USE_LOAD_PRE_DECREMENT, USE_STORE_POST_INCREMENT): Enable for SH2A.
	* config/sh/sh.md (*extend<mode>si2_predec, *mov<mode>_load_predec,
	*mov<mode>_store_postinc): New patterns.
diff mbox

Patch

diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index 3e69d88..b582637 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -230,6 +230,18 @@ 
        (match_test "sh_disp_addr_displacement (op)
 		    <= sh_max_mov_insn_displacement (GET_MODE (op), false)")))
 
+;; Returns true if OP is a post-increment addressing mode memory reference.
+(define_predicate "post_inc_mem"
+  (and (match_code "mem")
+       (match_code "post_inc" "0")
+       (match_code "reg" "00")))
+
+;; Returns true if OP is a pre-decrement addressing mode memory reference.
+(define_predicate "pre_dec_mem"
+  (and (match_code "mem")
+       (match_code "pre_dec" "0")
+       (match_code "reg" "00")))
+
 ;; Returns 1 if the operand can be used in an SH2A movu.{b|w} insn.
 (define_predicate "zero_extend_movu_operand"
   (and (ior (match_operand 0 "displacement_mem_operand")
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index ea7e847..c47e2ea 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -224,8 +224,12 @@  sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc,
 	}
     }
 
-  if (result.set_src != NULL)
-    gcc_assert (result.insn != NULL && result.set_rtx != NULL);
+  /* If the searched reg is found inside a (mem (post_inc:SI (reg))), set_of
+     will return NULL and set_rtx will be NULL.
+     In this case report a 'not found'.  result.insn will always be non-null
+     at this point, so no need to check it.  */
+  if (result.set_src != NULL && result.set_rtx == NULL)
+    result.set_src = NULL;
 
   return result;
 }
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 60c6250..16b4a8e 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -1307,12 +1307,10 @@  struct sh_args {
 #define HAVE_POST_INCREMENT  TARGET_SH1
 #define HAVE_PRE_DECREMENT   TARGET_SH1
 
-#define USE_LOAD_POST_INCREMENT(mode)    ((mode == SImode || mode == DImode) \
-					  ? 0 : TARGET_SH1)
-#define USE_LOAD_PRE_DECREMENT(mode)     0
-#define USE_STORE_POST_INCREMENT(mode)   0
-#define USE_STORE_PRE_DECREMENT(mode)    ((mode == SImode || mode == DImode) \
-					  ? 0 : TARGET_SH1)
+#define USE_LOAD_POST_INCREMENT(mode) TARGET_SH1
+#define USE_LOAD_PRE_DECREMENT(mode) TARGET_SH2A
+#define USE_STORE_POST_INCREMENT(mode) TARGET_SH2A
+#define USE_STORE_PRE_DECREMENT(mode) TARGET_SH1
 
 /* If a memory clear move would take CLEAR_RATIO or more simple
    move-instruction pairs, we will do a setmem instead.  */
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 2d9502b..2a8fbc8 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -4820,6 +4820,15 @@ 
   [(set_attr "type" "load")
    (set_attr "length" "2,2,4")])
 
+;; The pre-dec and post-inc mems must be captured by the '<' and '>'
+;; constraints, otherwise wrong code might get generated.
+(define_insn "*extend<mode>si2_predec"
+  [(set (match_operand:SI 0 "arith_reg_dest" "=z")
+	(sign_extend:SI (match_operand:QIHI 1 "pre_dec_mem" "<")))]
+  "TARGET_SH2A"
+  "mov.<bw>	%1,%0"
+  [(set_attr "type" "load")])
+
 ;; 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
@@ -5261,6 +5270,22 @@ 
   prepare_move_operands (operands, <MODE>mode);
 })
 
+;; The pre-dec and post-inc mems must be captured by the '<' and '>'
+;; constraints, otherwise wrong code might get generated.
+(define_insn "*mov<mode>_load_predec"
+  [(set (match_operand:QIHISI 0 "arith_reg_dest" "=z")
+	(match_operand:QIHISI 1 "pre_dec_mem" "<"))]
+  "TARGET_SH2A"
+  "mov.<bwl>	%1,%0"
+  [(set_attr "type" "load")])
+
+(define_insn "*mov<mode>_store_postinc"
+  [(set (match_operand:QIHISI 0 "post_inc_mem" "=>")
+	(match_operand:QIHISI 1 "arith_reg_operand" "z"))]
+  "TARGET_SH2A"
+  "mov.<bwl>	%1,%0"
+  [(set_attr "type" "store")])
+
 ;; Specifying the displacement addressing load / store patterns separately
 ;; before the generic movqi / movhi pattern allows controlling the order
 ;; in which load / store insns are selected in a more fine grained way.