aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorChristian Bruel <christian.bruel@st.com>2014-04-14 10:27:56 +0200
committerChristian Bruel <chrbr@gcc.gnu.org>2014-04-14 10:27:56 +0200
commitfa1aecc1c218eca8a1b5643e9276bffe485f6e67 (patch)
tree81398b547687d90b41283bf728cb8c51c4669e61 /gcc/config
parenta3c77ce941aeee074370680b38de3704d59983c6 (diff)
downloadgcc-fa1aecc1c218eca8a1b5643e9276bffe485f6e67.zip
gcc-fa1aecc1c218eca8a1b5643e9276bffe485f6e67.tar.gz
gcc-fa1aecc1c218eca8a1b5643e9276bffe485f6e67.tar.bz2
sh.md (setmemqi): New expand pattern.
2014-04-14 Christian Bruel <christian.bruel@st.com> * config/sh/sh.md (setmemqi): New expand pattern. * config/sh/sh.h (CLEAR_RATIO): Define. * config/sh/sh-mem.cc (sh_expand_setmem): Define. * config/sh/sh-protos.h (sh_expand_setmem): Declare. From-SVN: r209357
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/sh/sh-mem.cc103
-rw-r--r--gcc/config/sh/sh-protos.h1
-rw-r--r--gcc/config/sh/sh.h5
-rw-r--r--gcc/config/sh/sh.md14
4 files changed, 123 insertions, 0 deletions
diff --git a/gcc/config/sh/sh-mem.cc b/gcc/config/sh/sh-mem.cc
index 45af23a..d499b3b 100644
--- a/gcc/config/sh/sh-mem.cc
+++ b/gcc/config/sh/sh-mem.cc
@@ -608,3 +608,106 @@ sh_expand_strlen (rtx *operands)
return true;
}
+
+/* Emit code to perform a memset
+
+ OPERANDS[0] is the destination.
+ OPERANDS[1] is the size;
+ OPERANDS[2] is the char to search.
+ OPERANDS[3] is the alignment. */
+void
+sh_expand_setmem (rtx *operands)
+{
+ rtx L_loop_byte = gen_label_rtx ();
+ rtx L_loop_word = gen_label_rtx ();
+ rtx L_return = gen_label_rtx ();
+ rtx jump;
+ rtx dest = copy_rtx (operands[0]);
+ rtx dest_addr = copy_addr_to_reg (XEXP (dest, 0));
+ rtx val = force_reg (SImode, operands[2]);
+ int align = INTVAL (operands[3]);
+ int count = 0;
+ rtx len = force_reg (SImode, operands[1]);
+
+ if (! CONST_INT_P (operands[1]))
+ return;
+
+ count = INTVAL (operands[1]);
+
+ if (CONST_INT_P (operands[2])
+ && (INTVAL (operands[2]) == 0 || INTVAL (operands[2]) == -1) && count > 8)
+ {
+ rtx lenw = gen_reg_rtx (SImode);
+
+ if (align < 4)
+ {
+ emit_insn (gen_tstsi_t (GEN_INT (3), dest_addr));
+ jump = emit_jump_insn (gen_branch_false (L_loop_byte));
+ add_int_reg_note (jump, REG_BR_PROB, prob_likely);
+ }
+
+ /* word count. Do we have iterations ? */
+ emit_insn (gen_lshrsi3 (lenw, len, GEN_INT (2)));
+
+ dest = adjust_automodify_address (dest, SImode, dest_addr, 0);
+
+ /* start loop. */
+ emit_label (L_loop_word);
+
+ if (TARGET_SH2)
+ emit_insn (gen_dect (lenw, lenw));
+ else
+ {
+ emit_insn (gen_addsi3 (lenw, lenw, GEN_INT (-1)));
+ emit_insn (gen_tstsi_t (lenw, lenw));
+ }
+
+ emit_move_insn (dest, val);
+ emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr,
+ GET_MODE_SIZE (SImode)));
+
+
+ jump = emit_jump_insn (gen_branch_false (L_loop_word));
+ add_int_reg_note (jump, REG_BR_PROB, prob_likely);
+ count = count % 4;
+
+ dest = adjust_address (dest, QImode, 0);
+
+ val = gen_lowpart (QImode, val);
+
+ while (count--)
+ {
+ emit_move_insn (dest, val);
+ emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr,
+ GET_MODE_SIZE (QImode)));
+ }
+
+ jump = emit_jump_insn (gen_jump_compact (L_return));
+ emit_barrier_after (jump);
+ }
+
+ dest = adjust_automodify_address (dest, QImode, dest_addr, 0);
+
+ /* start loop. */
+ emit_label (L_loop_byte);
+
+ if (TARGET_SH2)
+ emit_insn (gen_dect (len, len));
+ else
+ {
+ emit_insn (gen_addsi3 (len, len, GEN_INT (-1)));
+ emit_insn (gen_tstsi_t (len, len));
+ }
+
+ val = gen_lowpart (QImode, val);
+ emit_move_insn (dest, val);
+ emit_move_insn (dest_addr, plus_constant (Pmode, dest_addr,
+ GET_MODE_SIZE (QImode)));
+
+ jump = emit_jump_insn (gen_branch_false (L_loop_byte));
+ add_int_reg_note (jump, REG_BR_PROB, prob_likely);
+
+ emit_label (L_return);
+
+ return;
+}
diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h
index defc76a..685cd23 100644
--- a/gcc/config/sh/sh-protos.h
+++ b/gcc/config/sh/sh-protos.h
@@ -119,6 +119,7 @@ extern void prepare_move_operands (rtx[], enum machine_mode mode);
extern bool sh_expand_cmpstr (rtx *);
extern bool sh_expand_cmpnstr (rtx *);
extern bool sh_expand_strlen (rtx *);
+extern void sh_expand_setmem (rtx *);
extern enum rtx_code prepare_cbranch_operands (rtx *, enum machine_mode mode,
enum rtx_code comparison);
extern void expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int);
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index 8819300..8c30e5c 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -1594,6 +1594,11 @@ struct sh_args {
#define SET_BY_PIECES_P(SIZE, ALIGN) STORE_BY_PIECES_P(SIZE, ALIGN)
+/* If a memory clear move would take CLEAR_RATIO or more simple
+ move-instruction pairs, we will do a setmem instead. */
+
+#define CLEAR_RATIO(speed) ((speed) ? 15 : 3)
+
/* Macros to check register numbers against specific register classes. */
/* These assume that REGNO is a hard or pseudo reg number.
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index ab1f0a5..9035bfc 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -12089,6 +12089,20 @@ label:
FAIL;
})
+(define_expand "setmemqi"
+ [(parallel [(set (match_operand:BLK 0 "memory_operand")
+ (match_operand 2 "const_int_operand"))
+ (use (match_operand:QI 1 "const_int_operand"))
+ (use (match_operand:QI 3 "const_int_operand"))])]
+ "TARGET_SH1 && optimize"
+ {
+ if (optimize_insn_for_size_p ())
+ FAIL;
+
+ sh_expand_setmem (operands);
+ DONE;
+ })
+
;; -------------------------------------------------------------------------
;; Floating point instructions.