From fdb029353d7f5597d5f51aaff9131ff6bb1acf12 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 6 Mar 2016 06:38:21 -0800
Subject: [PATCH] Add 3 target hooks for memset

Add TARGET_READ_MEMSET_VALUE, TARGET_GEN_MEMSET_VALUE and
TARGET_GEN_MEMSET_VALUE_FROM_PREV to support target instructions to
duplicate QImode value to TImode/OImode/XImode value for memmset.

	PR middle-end/90773
	* builtins.c: Include "targhooks.h".
	(gen_memset_value_from_prev): New function.
	(builtin_memset_read_str): Rewrite.
	(builtin_memset_gen_str): Likewise.
	* target.def (read_memset_value): New hook.
	(gen_memset_value): Likewise.
	(gen_memset_value_from_prev): Likewise.
	* targhooks.c: Inclue "builtins.h".
	(default_read_memset_value): New function.
	(default_gen_memset_value): Likewise.
	(default_gen_memset_value_from_prev): Likewise.
	* targhooks.h (default_read_memset_value): New prototype.
	(default_gen_memset_value): Likewise.
	(default_gen_memset_value_from_prev): Likewise.
	* doc/tm.texi.in: Add TARGET_READ_MEMSET_VALUE
	TARGET_GEN_MEMSET_VALUE and TARGET_GEN_MEMSET_VALUE_FROM_PREV
	hooks.
	* doc/tm.texi: Regenerated.
---
 gcc/builtins.c     | 75 ++++++++++++++++++++++++----------------------
 gcc/doc/tm.texi    | 18 +++++++++++
 gcc/doc/tm.texi.in |  6 ++++
 gcc/target.def     | 24 +++++++++++++++
 gcc/targhooks.c    | 44 +++++++++++++++++++++++++++
 gcc/targhooks.h    |  4 +++
 6 files changed, 135 insertions(+), 36 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index b0c880dc3b5..1ee580094ec 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "attr-fnspec.h"
 #include "demangle.h"
+#include "targhooks.h"
 
 struct target_builtins default_target_builtins;
 #if SWITCHABLE_TARGET
@@ -6584,30 +6585,48 @@ expand_builtin_strncpy (tree exp, rtx target)
   return NULL_RTX;
 }
 
-/* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
-   bytes from constant string DATA + OFFSET and return it as target
-   constant.  If PREV isn't nullptr, it has the RTL info from the
+/* Return the RTL of a register in MODE generated from PREV in the
    previous iteration.  */
 
-rtx
-builtin_memset_read_str (void *data, void *prevp,
-			 HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
-			 scalar_int_mode mode)
+static rtx
+gen_memset_value_from_prev (void *prevp, scalar_int_mode mode)
 {
   by_pieces_prev *prev = (by_pieces_prev *) prevp;
+  rtx value;
   if (prev != nullptr && prev->data != nullptr)
     {
       /* Use the previous data in the same mode.  */
       if (prev->mode == mode)
 	return prev->data;
+
+      value = targetm.gen_memset_value_from_prev (prevp, mode);
     }
+  else
+    value = nullptr;
+  return value;
+}
 
-  const char *c = (const char *) data;
-  char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
+/* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
+   bytes from constant string DATA + OFFSET and return it as target
+   constant.  If PREV isn't nullptr, it has the RTL info from the
+   previous iteration.  */
 
-  memset (p, *c, GET_MODE_SIZE (mode));
+rtx
+builtin_memset_read_str (void *data, void *prev,
+			 HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
+			 scalar_int_mode mode)
+{
+  const char *str = (const char *) data;
+
+  /* Don't use the previous value if size is 1.  */
+  if (GET_MODE_SIZE (mode) == 1)
+    return default_read_memset_value (str, mode);
 
-  return c_readstr (p, mode);
+  rtx value = gen_memset_value_from_prev (prev, mode);
+  if (value)
+    return value;
+
+  return targetm.read_memset_value (str, mode);
 }
 
 /* Callback routine for store_by_pieces.  Return the RTL of a register
@@ -6617,37 +6636,21 @@ builtin_memset_read_str (void *data, void *prevp,
    nullptr, it has the RTL info from the previous iteration.  */
 
 static rtx
-builtin_memset_gen_str (void *data, void *prevp,
+builtin_memset_gen_str (void *datap, void *prev,
 			HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
 			scalar_int_mode mode)
 {
-  rtx target, coeff;
-  size_t size;
-  char *p;
-
-  by_pieces_prev *prev = (by_pieces_prev *) prevp;
-  if (prev != nullptr && prev->data != nullptr)
-    {
-      /* Use the previous data in the same mode.  */
-      if (prev->mode == mode)
-	return prev->data;
-
-      target = simplify_gen_subreg (mode, prev->data, prev->mode, 0);
-      if (target != nullptr)
-	return target;
-    }
+  rtx data = (rtx) datap;
 
-  size = GET_MODE_SIZE (mode);
-  if (size == 1)
-    return (rtx) data;
+  /* Don't use the previous value if size is 1.  */
+  if (GET_MODE_SIZE (mode) == 1)
+    return data;
 
-  p = XALLOCAVEC (char, size);
-  memset (p, 1, size);
-  coeff = c_readstr (p, mode);
+  rtx value = gen_memset_value_from_prev (prev, mode);
+  if (value)
+    return value;
 
-  target = convert_to_mode (mode, (rtx) data, 1);
-  target = expand_mult (mode, target, coeff, NULL_RTX, 1);
-  return force_reg (mode, target);
+  return targetm.gen_memset_value (data, mode);
 }
 
 /* Expand expression EXP, which is a call to the memset builtin.  Return
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 85ea9395560..4119961e4fd 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11868,6 +11868,24 @@ This function prepares to emit a conditional comparison within a sequence
  @var{bit_code} is @code{AND} or @code{IOR}, which is the op on the compares.
 @end deftypefn
 
+@deftypefn {Target Hook} rtx TARGET_READ_MEMSET_VALUE (const char *@var{c}, scalar_int_mode @var{mode})
+This function returns the RTL of a constant integer corresponding to
+target reading @code{GET_MODE_SIZE (@var{mode})} bytes from the string
+constant @var{c}.
+@end deftypefn
+
+@deftypefn {Target Hook} rtx TARGET_GEN_MEMSET_VALUE (rtx @var{data}, scalar_int_mode @var{mode})
+This function returns the RTL of a register containing
+@code{GET_MODE_SIZE (@var{mode})} consecutive copies of the unsigned
+char value given in the RTL register @var{data}.  For example, if
+@var{mode} is 4 bytes wide, return the RTL for 0x01010101*@var{data}.
+@end deftypefn
+
+@deftypefn {Target Hook} rtx TARGET_GEN_MEMSET_VALUE_FROM_PREV (void *@var{prev}, scalar_int_mode @var{mode})
+This function returns the RTL of a register in @var{mode} generated
+from @var{PREV} in the previous iteration.
+@end deftypefn
+
 @deftypefn {Target Hook} unsigned TARGET_LOOP_UNROLL_ADJUST (unsigned @var{nunroll}, class loop *@var{loop})
 This target hook returns a new value for the number of times @var{loop}
 should be unrolled. The parameter @var{nunroll} is the number of times
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index d8e3de14af1..443ea26ff15 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -7956,6 +7956,12 @@ lists.
 
 @hook TARGET_GEN_CCMP_NEXT
 
+@hook TARGET_READ_MEMSET_VALUE
+
+@hook TARGET_GEN_MEMSET_VALUE
+
+@hook TARGET_GEN_MEMSET_VALUE_FROM_PREV
+
 @hook TARGET_LOOP_UNROLL_ADJUST
 
 @defmac POWI_MAX_MULTS
diff --git a/gcc/target.def b/gcc/target.def
index bbaf6b4f3a0..e6592f2582d 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2694,6 +2694,30 @@ DEFHOOK
  rtx, (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx prev, int cmp_code, tree op0, tree op1, int bit_code),
  NULL)
 
+DEFHOOK
+(read_memset_value,
+ "This function returns the RTL of a constant integer corresponding to\n\
+target reading @code{GET_MODE_SIZE (@var{mode})} bytes from the string\n\
+constant @var{c}.",
+ rtx, (const char *c, scalar_int_mode mode),
+ default_read_memset_value)
+
+DEFHOOK
+(gen_memset_value,
+ "This function returns the RTL of a register containing\n\
+@code{GET_MODE_SIZE (@var{mode})} consecutive copies of the unsigned\n\
+char value given in the RTL register @var{data}.  For example, if\n\
+@var{mode} is 4 bytes wide, return the RTL for 0x01010101*@var{data}.",
+ rtx, (rtx data, scalar_int_mode mode),
+ default_gen_memset_value)
+
+DEFHOOK
+(gen_memset_value_from_prev,
+ "This function returns the RTL of a register in @var{mode} generated\n\
+from @var{PREV} in the previous iteration.",
+ rtx, (void *prev, scalar_int_mode mode),
+ default_gen_memset_value_from_prev)
+
 /* Return a new value for loop unroll size.  */
 DEFHOOK
 (loop_unroll_adjust,
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 2d2de0431f3..a93e1e4b491 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -93,6 +93,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple.h"
 #include "cfgloop.h"
 #include "tree-vectorizer.h"
+#include "builtins.h"
 
 bool
 default_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
@@ -2634,4 +2635,47 @@ default_memtag_untagged_pointer (rtx tagged_pointer, rtx target)
   return untagged_base;
 }
 
+/* Default implementation of TARGET_READ_MEMSET_VALUE.  */
+
+rtx
+default_read_memset_value (const char *c, scalar_int_mode mode)
+{
+  char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
+
+  memset (p, *c, GET_MODE_SIZE (mode));
+
+  return c_readstr (p, mode);
+}
+
+/* Default implementation of TARGET_GEN_MEMSET_VALUE.  */
+
+rtx
+default_gen_memset_value (rtx data, scalar_int_mode mode)
+{
+  rtx target, coeff;
+  size_t size;
+  char *p;
+
+  size = GET_MODE_SIZE (mode);
+  if (size == 1)
+    return data;
+
+  p = XALLOCAVEC (char, size);
+  memset (p, 1, size);
+  coeff = c_readstr (p, mode);
+
+  target = convert_to_mode (mode, data, 1);
+  target = expand_mult (mode, target, coeff, NULL_RTX, 1);
+  return force_reg (mode, target);
+}
+
+/* Default implementation of TARGET_GEN_MEMSET_VALUE_FROM_PREV.  */
+
+rtx
+default_gen_memset_value_from_prev (void *prevp, scalar_int_mode mode)
+{
+  by_pieces_prev *prev = (by_pieces_prev *) prevp;
+  return simplify_gen_subreg (mode, prev->data, prev->mode, 0);
+}
+
 #include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index b537038c0aa..bb103159ae3 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -300,4 +300,8 @@ extern rtx default_memtag_set_tag (rtx, rtx, rtx);
 extern rtx default_memtag_extract_tag (rtx, rtx);
 extern rtx default_memtag_untagged_pointer (rtx, rtx);
 
+extern rtx default_read_memset_value (const char *, scalar_int_mode);
+extern rtx default_gen_memset_value (rtx, scalar_int_mode);
+extern rtx default_gen_memset_value_from_prev (void *, scalar_int_mode);
+
 #endif /* GCC_TARGHOOKS_H */
-- 
2.31.1

