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]
Other format: [Raw text]

Re: [PATCH] Add builtin memmove and bcopy


On Sun, Apr 27, 2003 at 10:01:37PM -0400, Kaveh R. Ghazi wrote:
>  > +      /* If src is a string constant and strings are not writable,
>  > +       we can use normal memcpy.  */
>  > +      if (!flag_writable_strings && c_getstr (src))
>  > +      return expand_builtin_memcpy (arglist, target, mode, 0);
> 
> More generally, can't we call memcpy if we're sure src and dest don't
> alias each other?

Probably yes, I'm just not sure what all programs will suddenly mysteriously
break and whether the gains justify it.
Certainly it can be done in a different patch.

>  > +static rtx
>  > +expand_builtin_bcopy (exp)
>  > +     tree exp;
>  > +{
>  > +  tree arglist = TREE_OPERAND (exp, 1);
> 
> Minor nit, this function probably can take arglist as it's parameter
> rather than exp, since all it does it dig out arglist.

Thanks for your and Zacks comments. Here is what I've actually commited.

2003-04-28  Jakub Jelinek  <jakub at redhat dot com>

	* builtins.def (BUILT_IN_BCOPY, BUILT_IN_MEMMOVE): New.
	* builtin-types.def (BT_FN_VOID_CONST_PTR_PTR_SIZE): New.
	* builtins.c (expand_builtin_memmove, expand_builtin_bcopy): New
	functions.
	(expand_builtin): Handle BUILT_IN_BCOPY and BUILT_IN_MEMMOVE.

	* gcc.c-torture/execute/string-opt-19.c: New test.

--- gcc/builtins.def.jj	2003-04-15 05:33:48.000000000 -0400
+++ gcc/builtins.def	2003-04-26 09:04:03.000000000 -0400
@@ -286,9 +286,9 @@ DEF_C99_BUILTIN(BUILT_IN_CIMAGL,
 		BT_FN_LONG_DOUBLE_COMPLEX_LONG_DOUBLE,
 		ATTR_CONST_NOTHROW_LIST)
 
-/* The system prototypes for `bzero' and `bcmp' functions have many
-   variations, so don't specify parameters to avoid conflicts.  The
-   expand_* functions check the argument types anyway.  */
+/* The system prototypes for `bzero', 'bcopy' and `bcmp' functions
+   have many variations, so don't specify parameters to avoid conflicts.
+   The expand_* functions check the argument types anyway.  */
 DEF_BUILTIN (BUILT_IN_BZERO,
 	     "__builtin_bzero",
 	     BUILT_IN_NORMAL,
@@ -296,6 +296,13 @@ DEF_BUILTIN (BUILT_IN_BZERO,
 	     BT_FN_VOID_VAR,
 	     true, true, true,
 	     ATTR_NOTHROW_LIST, false)
+DEF_BUILTIN (BUILT_IN_BCOPY,
+	     "__builtin_bcopy",
+	     BUILT_IN_NORMAL,
+	     BT_FN_VOID_CONST_PTR_PTR_SIZE, 
+	     BT_FN_VOID_VAR,
+	     true, true, true,
+	     ATTR_NOTHROW_LIST, false)
 DEF_BUILTIN (BUILT_IN_BCMP,
 	     "__builtin_bcmp",
 	     BUILT_IN_NORMAL,
@@ -380,6 +387,10 @@ DEF_LIB_BUILTIN(BUILT_IN_MEMCPY,
 		"__builtin_memcpy",
 		BT_FN_PTR_PTR_CONST_PTR_SIZE,
 		ATTR_NOTHROW_LIST)
+DEF_LIB_BUILTIN(BUILT_IN_MEMMOVE,
+		"__builtin_memmove",
+		BT_FN_PTR_PTR_CONST_PTR_SIZE,
+		ATTR_NOTHROW_LIST)
 DEF_LIB_BUILTIN(BUILT_IN_MEMCMP,
 		"__builtin_memcmp",
 		BT_FN_INT_CONST_PTR_CONST_PTR_SIZE,
--- gcc/builtin-types.def.jj	2003-04-15 05:33:48.000000000 -0400
+++ gcc/builtin-types.def	2003-04-26 09:06:11.000000000 -0400
@@ -174,6 +174,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_INT_S
 	             BT_PTR, BT_PTR, BT_INT, BT_SIZE)
 DEF_FUNCTION_TYPE_3 (BT_FN_VOID_PTR_INT_INT,
 		     BT_VOID, BT_PTR, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_3 (BT_FN_VOID_CONST_PTR_PTR_SIZE,
+		     BT_VOID, BT_CONST_PTR, BT_PTR, BT_SIZE)
 DEF_FUNCTION_TYPE_3 (BT_FN_INT_STRING_CONST_STRING_VALIST_ARG,
 		     BT_INT, BT_STRING, BT_CONST_STRING, BT_VALIST_ARG)
 DEF_FUNCTION_TYPE_3 (BT_FN_INT_CONST_STRING_CONST_STRING_VALIST_ARG,
--- gcc/builtins.c.jj	2003-04-23 15:56:25.000000000 -0400
+++ gcc/builtins.c	2003-04-26 14:57:06.000000000 -0400
@@ -126,6 +126,9 @@ static rtx expand_builtin_strcspn	PARAMS
 						 enum machine_mode));
 static rtx expand_builtin_memcpy	PARAMS ((tree, rtx,
 						 enum machine_mode, int));
+static rtx expand_builtin_memmove	PARAMS ((tree, rtx,
+						 enum machine_mode));
+static rtx expand_builtin_bcopy		PARAMS ((tree));
 static rtx expand_builtin_strcpy	PARAMS ((tree, rtx,
 						 enum machine_mode));
 static rtx expand_builtin_stpcpy	PARAMS ((tree, rtx,
@@ -2364,6 +2367,84 @@ expand_builtin_memcpy (arglist, target, 
     }
 }
 
+/* Expand expression EXP, which is a call to the memmove builtin.  Return 0
+   if we failed the caller should emit a normal call.  */
+
+static rtx
+expand_builtin_memmove (arglist, target, mode)
+     tree arglist;
+     rtx target;
+     enum machine_mode mode;
+{
+  if (!validate_arglist (arglist,
+			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return 0;
+  else
+    {
+      tree dest = TREE_VALUE (arglist);
+      tree src = TREE_VALUE (TREE_CHAIN (arglist));
+      tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+      unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+      unsigned int dest_align
+	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+
+      /* If DEST is not a pointer type, call the normal function.  */
+      if (dest_align == 0)
+	return 0;
+
+      /* If the LEN parameter is zero, return DEST.  */
+      if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
+	{
+	  /* Evaluate and ignore SRC in case it has side-effects.  */
+	  expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+	  return expand_expr (dest, target, mode, EXPAND_NORMAL);
+	}
+
+      /* If either SRC is not a pointer type, don't do this
+         operation in-line.  */
+      if (src_align == 0)
+	return 0;
+
+      /* If src is a string constant and strings are not writable,
+	 we can use normal memcpy.  */
+      if (!flag_writable_strings && c_getstr (src))
+	return expand_builtin_memcpy (arglist, target, mode, 0);
+
+      /* Otherwise, call the normal function.  */
+      return 0;
+   }
+}
+
+/* Expand expression EXP, which is a call to the bcopy builtin.  Return 0
+   if we failed the caller should emit a normal call.  */
+
+static rtx
+expand_builtin_bcopy (arglist)
+     tree arglist;
+{
+  tree src, dest, size, newarglist;
+
+  if (!validate_arglist (arglist,
+			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return NULL_RTX;
+
+  src = TREE_VALUE (arglist);
+  dest = TREE_VALUE (TREE_CHAIN (arglist));
+  size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+  /* New argument list transforming bcopy(ptr x, ptr y, int z) to
+     memmove(ptr y, ptr x, size_t z).   This is done this way
+     so that if it isn't expanded inline, we fallback to
+     calling bcopy instead of memmove.  */
+
+  newarglist = build_tree_list (NULL_TREE, convert (sizetype, size));
+  newarglist = tree_cons (NULL_TREE, src, newarglist);
+  newarglist = tree_cons (NULL_TREE, dest, newarglist);
+
+  return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode);
+}
+
 /* Expand expression EXP, which is a call to the strcpy builtin.  Return 0
    if we failed the caller should emit a normal call, otherwise try to get
    the result in TARGET, if convenient (and in mode MODE if that's
@@ -4177,8 +4259,10 @@ expand_builtin (exp, target, subtarget, 
       case BUILT_IN_MEMCPY:
       case BUILT_IN_MEMCMP:
       case BUILT_IN_MEMPCPY:
+      case BUILT_IN_MEMMOVE:
       case BUILT_IN_BCMP:
       case BUILT_IN_BZERO:
+      case BUILT_IN_BCOPY:
       case BUILT_IN_INDEX:
       case BUILT_IN_RINDEX:
       case BUILT_IN_STPCPY:
@@ -4543,6 +4627,18 @@ expand_builtin (exp, target, subtarget, 
 	return target;
       break;
 
+    case BUILT_IN_MEMMOVE:
+      target = expand_builtin_memmove (arglist, target, mode);
+      if (target)
+	return target;
+      break;
+
+    case BUILT_IN_BCOPY:
+      target = expand_builtin_bcopy (arglist);
+      if (target)
+	return target;
+      break;
+
     case BUILT_IN_MEMSET:
       target = expand_builtin_memset (exp, target, mode);
       if (target)
--- gcc/testsuite/gcc.c-torture/execute/string-opt-19.c.jj	2003-04-26 17:46:13.000000000 -0400
+++ gcc/testsuite/gcc.c-torture/execute/string-opt-19.c	2003-04-26 14:45:03.000000000 -0400
@@ -0,0 +1,89 @@
+/* Copyright (C) 2003  Free Software Foundation.
+
+   Ensure builtin memmove and bcopy perform correctly.
+
+   Written by Jakub Jelinek, 4/26/2003.  */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern void *memmove (void *, const void *, size_t);
+extern void bcopy (const void *, void *, size_t);
+extern int memcmp (const void *, const void *, size_t);
+
+const char s1[] = "123";
+char p[32] = "";
+
+int main()
+{
+  int i;
+  const char *s;
+
+  if (memmove (p, "abcde", 6) != p || memcmp (p, "abcde", 6))
+    abort ();
+  s = s1;
+  if (memmove (p + 2, ++s, 0) != p + 2 || memcmp (p, "abcde", 6) || s != s1 + 1)
+    abort ();
+  if (__builtin_memmove (p + 3, "", 1) != p + 3 || memcmp (p, "abc\0e", 6))
+    abort ();
+  bcopy ("fghijk", p + 2, 4);
+  if (memcmp (p, "abfghi", 7))
+    abort ();
+  s = s1 + 1;
+  bcopy (s++, p + 1, 0);
+  if (memcmp (p, "abfghi", 7) || s != s1 + 2)
+    abort ();
+  __builtin_bcopy ("ABCDE", p + 4, 1);
+  if (memcmp (p, "abfgAi", 7))
+    abort ();
+
+  return 0;
+}
+
+/* When optimizing, all the above cases should be transformed into
+   something else.  So any remaining calls to the original function
+   should abort.  When not optimizing, provide memmove/bcopy implementation
+   just in case target lacks these in its libc.  */
+__attribute__ ((noinline))
+static void *
+memmove (void *d, const void *s, size_t n)
+{
+#ifdef __OPTIMIZE__
+  abort ();
+#else
+  char *dst = (char *) d;
+  const char *src = (const char *) s;
+  if (src < dst)
+    {
+      dst += n;
+      src += n;
+      while (n--)
+        *--dst = *--src;
+    }
+  else
+    while (n--)
+      *dst++ = *src++;
+  return (char *) d;
+#endif
+}
+
+__attribute__ ((noinline))
+static void
+bcopy (const void *s, void *d, size_t n)
+{
+#ifdef __OPTIMIZE__
+  abort ();
+#else
+  char *dst = (char *) d;
+  const char *src = (const char *) s;
+  if (src < dst)
+    {
+      dst += n;
+      src += n;
+      while (n--)
+        *--dst = *--src;
+    }
+  else
+    while (n--)
+      *dst++ = *src++;
+#endif
+}


	Jakub


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