This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Optimize memset(x, ' ', 8)


Hi!

This patch does 2 things: tries to optimize memset with non-zero argument
using store_by_pieces (as suggested by Kaveh) and also for functions which
take int argument where char is really meant (strchr, strrchr, memset) they
cast the constants to target char and check whether it fits into host char,
so that if the target has e.g. 32bit char the optimization does not break
something.
I'll bootstrap this together with other changes later today, ok to commit if
it succeeds without regressions?

2000-12-01  Jakub Jelinek  <jakub@redhat.com>

	* builtins.c (expand_builtin_strchr): Cast second argument to
	target char and see if it fits into host char first.
	(expand_builtin_strrchr): Likewise.
	(builtin_memset_read_str): New function.
	(expand_builtin_memset): Cast second argument to target char
	and see if it fits into host char first.  Try to optimize memset
	with second argument non-zero using store_by_pieces.

	* gcc.c-torture/execute/string-opt-5.c: Add some memset tests.

--- gcc/builtins.c.jj	Wed Nov 29 19:15:29 2000
+++ gcc/builtins.c	Fri Dec  1 10:39:30 2000
@@ -116,6 +116,8 @@ static rtx builtin_strncpy_read_str	PARA
 						 enum machine_mode));
 static rtx expand_builtin_strncpy	PARAMS ((tree, rtx,
 						 enum machine_mode));
+static rtx builtin_memset_read_str	PARAMS ((PTR, HOST_WIDE_INT,
+						 enum machine_mode));
 static rtx expand_builtin_memset	PARAMS ((tree));
 static rtx expand_builtin_bzero		PARAMS ((tree));
 static rtx expand_builtin_strlen	PARAMS ((tree, rtx));
@@ -1583,7 +1585,20 @@ expand_builtin_strchr (arglist, target, 
       p1 = c_getstr (s1);
       if (p1 != NULL)
 	{
-	  const char *r = strchr (p1, (char) TREE_INT_CST_LOW (s2));
+	  rtx cst;
+	  const char *r;
+
+	  /* Cast s2 to target char, see if it fits into host char.  */
+	  cst = immed_double_const (TREE_INT_CST_LOW (s2),
+				    TREE_INT_CST_HIGH (s2),
+				    mode_for_size (CHAR_TYPE_SIZE,
+						   MODE_INT, 0));
+	  if (GET_CODE (cst) != CONST_INT
+	      || (INTVAL (cst) != (char) INTVAL (cst)
+		  && INTVAL (cst) != (unsigned char) INTVAL (cst)))
+	    return 0;
+
+	  r = strchr (p1, (char) INTVAL (cst));
 
 	  if (r == NULL)
 	    return const0_rtx;
@@ -1628,7 +1643,20 @@ expand_builtin_strrchr (arglist, target,
       p1 = c_getstr (s1);
       if (p1 != NULL)
 	{
-	  const char *r = strrchr (p1, (char) TREE_INT_CST_LOW (s2));
+	  rtx cst;
+	  const char *r;
+	  
+	  /* Cast s2 to target char, see if it fits into host char.  */
+	  cst = immed_double_const (TREE_INT_CST_LOW (s2),
+				    TREE_INT_CST_HIGH (s2),
+				    mode_for_size (CHAR_TYPE_SIZE,
+						   MODE_INT, 0));
+	  if (GET_CODE (cst) != CONST_INT
+	      || (INTVAL (cst) != (char) INTVAL (cst)
+		  && INTVAL (cst) != (unsigned char) INTVAL (cst)))
+	    return 0;
+
+	  r = strrchr (p1, (char) INTVAL (cst));
 
 	  if (r == NULL)
 	    return const0_rtx;
@@ -1945,6 +1973,24 @@ expand_builtin_strncpy (arglist, target,
     }
 }
 
+/* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
+   bytes from constant string DATA + OFFSET and return it as target
+   constant.  */
+
+static rtx
+builtin_memset_read_str (data, offset, mode)
+     PTR data;
+     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
+{
+  const char *c = (const char *) data;
+  char *p = alloca (GET_MODE_SIZE (mode));
+
+  memset (p, *c, GET_MODE_SIZE (mode));
+
+  return c_readstr (p, mode);
+}
+
 /* Expand expression EXP, which is a call to the memset builtin.  Return 0
    if we failed the caller should emit a normal call.  */
 
@@ -1971,6 +2017,7 @@ expand_builtin_memset (exp)
       tree dest = TREE_VALUE (arglist);
       tree val = TREE_VALUE (TREE_CHAIN (arglist));
       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      rtx cst;
 
       int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, dest_addr, len_rtx;
@@ -1980,18 +2027,36 @@ expand_builtin_memset (exp)
       if (dest_align == 0)
 	return 0;
 
-      /* If the arguments have side-effects, then we can only evaluate
-	 them at most once.  The following code evaluates them twice if
-	 they are not constants because we break out to expand_call
-	 in that case.  They can't be constants if they have side-effects
-	 so we can check for that first.  Alternatively, we could call
-	 save_expr to make multiple evaluation safe.  */
-      if (TREE_SIDE_EFFECTS (val) || TREE_SIDE_EFFECTS (len))
+      if (TREE_CODE (val) != INTEGER_CST)
 	return 0;
-
-      /* If VAL is not 0, don't do this operation in-line. */
-      if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
+	  
+      /* Cast val to target char, see if it fits into host char.  */
+      cst = immed_double_const (TREE_INT_CST_LOW (val),
+				TREE_INT_CST_HIGH (val),
+				mode_for_size (CHAR_TYPE_SIZE, MODE_INT, 0));
+      if (GET_CODE (cst) != CONST_INT
+	  || (INTVAL (cst) != (char) INTVAL (cst)
+	      && INTVAL (cst) != (unsigned char) INTVAL (cst)))
 	return 0;
+
+      if (INTVAL (cst))
+	{
+	  char c = INTVAL (cst);
+
+	  if (TREE_CODE (len) != INTEGER_CST || TREE_INT_CST_HIGH (len))
+	    return 0;
+	  if (current_function_check_memory_usage
+	      || !can_store_by_pieces (TREE_INT_CST_LOW (len),
+				       builtin_memset_read_str,
+				       (PTR) &c, dest_align))
+	    return 0;
+
+	  dest_mem = get_memory_rtx (dest);
+	  store_by_pieces (dest_mem, TREE_INT_CST_LOW (len),
+			   builtin_memset_read_str,
+			   (PTR) &c, dest_align);
+	  return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+	}
 
       len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
 
--- gcc/testsuite/gcc.c-torture/execute/string-opt-5.c.jj	Wed Nov 29 01:05:24 2000
+++ gcc/testsuite/gcc.c-torture/execute/string-opt-5.c	Fri Dec  1 11:02:15 2000
@@ -17,6 +17,7 @@ extern int memcmp (const void *, const v
 int x = 6;
 int y = 1;
 char *bar = "hi world";
+char buf [64];
 
 int main()
 {
@@ -79,7 +80,28 @@ int main()
     abort ();
   memset (dst, ' ', sizeof dst);
   if (strncpy (dst, "hello", 8) != dst || memcmp (dst, "hello\0\0\0 ", 9))
-    abort();
+    abort ();
+  x = '!';
+  memset (buf, ' ', sizeof buf);
+  if (memset (buf, x++, ++y) != buf
+      || x != '!' + 1
+      || y != 3
+      || memcmp (buf, "!!!", 3))
+    abort ();
+  if (memset (buf + y++, '-', 8) != buf + 3
+      || y != 4
+      || memcmp (buf, "!!!--------", 11))
+    abort ();
+  x = 10;
+  if (memset (buf + ++x, 0, y++) != buf + 11
+      || x != 11
+      || y != 5
+      || memcmp (buf + 8, "---\0\0\0", 7))
+    abort ();
+  if (memset (buf + (x += 4), 0, 6) != buf + 15
+      || x != 15
+      || memcmp (buf + 10, "-\0\0\0\0\0\0\0\0\0", 11))
+    abort ();
 
   return 0;
 }

	Jakub

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]