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]

[PATCH] Built-in redirection (take 2)


On Sun, Apr 27, 2003 at 12:39:25PM -0700, Zack Weinberg wrote:
> You've got two patches mixed up together here.  One is the change you
> described, and another adds builtin bcopy and memmove.  Please split
> it up.  The patch to add builtin bcopy and memmove, by itself, should
> be uncontroversial, so please resubmit that one first.

And here is the second.

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

	* c-decl.c (finish_decl): When prototype with asmspec is found
	for built-in, adjust built_in_decls as well as expr.c decls.
	* expr.c (init_block_move_fn, init_block_clear_fn): New functions.
	(emit_block_move_libcall_fn, clear_storage_libcall_fn): Use it.
	* expr.c (init_block_move_fn, init_block_clear_fn): New prototypes.

	* gcc.c-torture/execute/string-opt-asm-1.c: New test.
	* gcc.c-torture/execute/string-opt-asm-2.c: New test.

--- gcc/c-decl.c.jj	2003-04-23 15:56:25.000000000 -0400
+++ gcc/c-decl.c	2003-04-26 17:32:54.000000000 -0400
@@ -2867,12 +2867,28 @@ finish_decl (decl, init, asmspec_tree)
 	TREE_USED (decl) = 1;
     }
 
-  /* If this is a function and an assembler name is specified, it isn't
-     builtin any more.  Also reset DECL_RTL so we can give it its new
-     name.  */
+  /* If this is a function and an assembler name is specified, reset DECL_RTL
+     so we can give it its new name.  Also, update built_in_decls if it
+     was a normal built-in.  */
   if (TREE_CODE (decl) == FUNCTION_DECL && asmspec)
     {
-      DECL_BUILT_IN_CLASS (decl) = NOT_BUILT_IN;
+      if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+	{
+	  tree builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
+	  SET_DECL_RTL (builtin, NULL_RTX);
+	  SET_DECL_ASSEMBLER_NAME (builtin, get_identifier (asmspec));
+#ifdef TARGET_MEM_FUNCTIONS
+	  if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMCPY)
+	    init_block_move_fn (asmspec);
+	  else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MEMSET)
+	    init_block_clear_fn (asmspec);
+#else
+	  if (DECL_FUNCTION_CODE (decl) == BUILT_IN_BCOPY)
+	    init_block_move_fn (asmspec);
+	  else if (DECL_FUNCTION_CODE (decl) == BUILT_IN_BZERO)
+	    init_block_clear_fn (asmspec);
+#endif
+	}
       SET_DECL_RTL (decl, NULL_RTX);
       SET_DECL_ASSEMBLER_NAME (decl, get_identifier (asmspec));
     }
--- gcc/expr.c.jj	2003-04-23 15:56:27.000000000 -0400
+++ gcc/expr.c	2003-04-26 17:30:07.000000000 -0400
@@ -1994,15 +1994,14 @@ emit_block_move_via_libcall (dst, src, s
 
 static GTY(()) tree block_move_fn;
 
-static tree
-emit_block_move_libcall_fn (for_call)
-      int for_call;
+void
+init_block_move_fn (asmspec)
+     const char *asmspec;
 {
-  static bool emitted_extern;
-  tree fn = block_move_fn, args;
-
-  if (!fn)
+  if (!block_move_fn)
     {
+      tree fn, args;
+
       if (TARGET_MEM_FUNCTIONS)
 	{
 	  fn = get_identifier ("memcpy");
@@ -2027,14 +2026,30 @@ emit_block_move_libcall_fn (for_call)
       block_move_fn = fn;
     }
 
+  if (asmspec)
+    {
+      SET_DECL_RTL (block_move_fn, NULL_RTX);
+      SET_DECL_ASSEMBLER_NAME (block_move_fn, get_identifier (asmspec));
+    }
+}
+
+static tree
+emit_block_move_libcall_fn (for_call)
+     int for_call;
+{
+  static bool emitted_extern;
+
+  if (!block_move_fn)
+    init_block_move_fn (NULL);
+
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (fn, NULL);
-      assemble_external (fn);
+      make_decl_rtl (block_move_fn, NULL);
+      assemble_external (block_move_fn);
     }
 
-  return fn;
+  return block_move_fn;
 }
 
 /* A subroutine of emit_block_move.  Copy the data via an explicit
@@ -3087,17 +3102,16 @@ clear_storage_via_libcall (object, size)
    for the function we use for block clears.  The first time FOR_CALL
    is true, we call assemble_external.  */
 
-static GTY(()) tree block_clear_fn;
+GTY(()) tree block_clear_fn;
 
-static tree
-clear_storage_libcall_fn (for_call)
-     int for_call;
+void
+init_block_clear_fn (asmspec)
+     const char *asmspec;
 {
-  static bool emitted_extern;
-  tree fn = block_clear_fn, args;
-
-  if (!fn)
+  if (!block_clear_fn)
     {
+      tree fn, args;
+
       if (TARGET_MEM_FUNCTIONS)
 	{
 	  fn = get_identifier ("memset");
@@ -3121,14 +3135,30 @@ clear_storage_libcall_fn (for_call)
       block_clear_fn = fn;
     }
 
+  if (asmspec)
+    {
+      SET_DECL_RTL (block_clear_fn, NULL_RTX);
+      SET_DECL_ASSEMBLER_NAME (block_clear_fn, get_identifier (asmspec));
+    }
+}
+
+static tree
+clear_storage_libcall_fn (for_call)
+     int for_call;
+{
+  static bool emitted_extern;
+
+  if (!block_clear_fn)
+    init_block_clear_fn (NULL);
+
   if (for_call && !emitted_extern)
     {
       emitted_extern = true;
-      make_decl_rtl (fn, NULL);
-      assemble_external (fn);
+      make_decl_rtl (block_clear_fn, NULL);
+      assemble_external (block_clear_fn);
     }
 
-  return fn;
+  return block_clear_fn;
 }
 
 /* Generate code to copy Y into X.
--- gcc/expr.h.jj	2003-04-15 05:33:51.000000000 -0400
+++ gcc/expr.h	2003-04-26 17:33:52.000000000 -0400
@@ -385,6 +385,9 @@ enum block_op_methods
   BLOCK_OP_CALL_PARM
 };
 
+extern void init_block_move_fn PARAMS ((const char *));
+extern void init_block_clear_fn PARAMS ((const char *));
+
 extern rtx emit_block_move PARAMS ((rtx, rtx, rtx, enum block_op_methods));
 
 /* Copy all or part of a value X into registers starting at REGNO.
--- gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c.jj	2003-04-26 17:46:13.000000000 -0400
+++ gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c	2003-04-27 08:24:06.000000000 -0400
@@ -0,0 +1,82 @@
+/* Copyright (C) 2000, 2003  Free Software Foundation.
+
+   Ensure all expected transformations of builtin strstr occur and
+   perform correctly in presence of redirect.  */
+
+typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+extern char *strstr (const char *, const char *)
+  __asm ("my_strstr");
+extern char *strchr (const char *, int);
+extern int strcmp (const char *, const char *);
+extern int strncmp (const char *, const char *, size_t);
+
+const char *p = "rld", *q = "hello world";
+
+int
+main (void)
+{
+  const char *const foo = "hello world";
+  
+  if (strstr (foo, "") != foo)
+    abort ();
+  if (strstr (foo + 4, "") != foo + 4)
+    abort ();
+  if (strstr (foo, "h") != foo)
+    abort ();
+  if (strstr (foo, "w") != foo + 6)
+    abort ();
+  if (strstr (foo + 6, "o") != foo + 7)
+    abort ();
+  if (strstr (foo + 1, "world") != foo + 6)
+    abort ();
+  if (strstr (foo + 2, p) != foo + 8)
+    abort ();
+  if (strstr (q, "") != q)
+    abort ();
+  if (strstr (q + 1, "o") != q + 4)
+    abort ();
+
+  /* Test at least one instance of the __builtin_ style.  We do this
+     to ensure that it works and that the prototype is correct.  */
+  if (__builtin_strstr (foo + 1, "world") != foo + 6)
+    abort ();
+  
+  return 0;
+}
+
+/* There should be no calls to real strstr.  */
+static char *real_strstr (const char *, const char *)
+  __asm ("strstr");
+
+__attribute__ ((noinline))
+static char *
+real_strstr (const char *s1, const char *s2)
+{
+  abort ();
+}
+
+static char *
+strstr (const char *s1, const char *s2)
+  __asm ("my_strstr");
+
+__attribute__ ((noinline))
+static char *
+strstr (const char *s1, const char *s2)
+{
+  size_t len = strlen (s2);
+
+#ifdef __OPTIMIZE__
+  /* If optimizing, we should be called only in the
+     strstr (foo + 2, p) case above.  All other cases should
+     be optimized.  */
+  if (s2 != p || strcmp (s1, "hello world" + 2) != 0)
+    abort ();
+#endif
+  if (len == 0)
+    return (char *) s1;
+  for (s1 = strchr (s1, *s2); s1; s1 = strchr (s1 + 1, *s2))
+    if (strncmp (s1, s2, len) == 0)
+      return (char *) s1;
+  return (char *) 0;
+}
--- gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c.jj	2003-04-26 17:46:13.000000000 -0400
+++ gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c	2003-04-27 07:03:49.000000000 -0400
@@ -0,0 +1,131 @@
+/* Copyright (C) 2003 Free Software Foundation.
+
+   Test memcpy and memset in presence of redirect.  */
+
+typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+extern void *memcpy (void *, const void *, size_t)
+  __asm ("my_memcpy");
+extern void bcopy (const void *, void *, size_t)
+  __asm ("my_bcopy");
+extern void *memset (void *, int, size_t)
+  __asm ("my_memset");
+extern void bzero (void *, size_t)
+  __asm ("my_bzero");
+extern int memcmp (const void *, const void *, size_t);
+
+struct A { char c[32]; } a = { "foobar" };
+char x[64] = "foobar", y[64];
+int i = 39, j = 6, k = 4;
+
+int
+main (void)
+{
+  struct A b = a;
+  struct A c = { { 'x' } };
+
+  if (memcmp (b.c, x, 32) || c.c[0] != 'x' || memcmp (c.c + 1, x + 32, 31))
+    abort ();
+  if (__builtin_memcpy (y, x, i) != y || memcmp (x, y, 64))
+    abort ();
+  if (memcpy (y + 6, x, j) != y + 6
+      || memcmp (x, y, 6) || memcmp (x, y + 6, 58))
+    abort ();
+  if (__builtin_memset (y + 2, 'X', k) != y + 2
+      || memcmp (y, "foXXXXfoobar", 13))
+    abort ();
+  bcopy (y + 1, y + 2, 6);
+  if (memcmp (y, "fooXXXXfobar", 13))
+    abort ();
+  __builtin_bzero (y + 4, 2);
+  if (memcmp (y, "fooX\0\0Xfobar", 13))
+    abort ();
+
+  return 0;
+}
+
+/* There should be no calls to real memcpy, memset, bcopy or bzero.  */
+static void *real_memcpy (void *, const void *, size_t)
+  __asm ("memcpy");
+static void real_bcopy (const void *, void *, size_t)
+  __asm ("bcopy");
+static void *real_memset (void *, int, size_t)
+  __asm ("memset");
+static void real_bzero (void *, size_t)
+  __asm ("bzero");
+
+__attribute__ ((noinline))
+static void *
+real_memcpy (void *d, const void *s, size_t n)
+{
+  abort ();
+}
+
+__attribute__ ((noinline))
+static void
+real_bcopy (const void *s, void *d, size_t n)
+{
+  abort ();
+}
+
+__attribute__ ((noinline))
+static void *
+real_memset (void *d, int c, size_t n)
+{
+  abort ();
+}
+
+__attribute__ ((noinline))
+static void
+real_bzero (void *d, size_t n)
+{
+  abort ();
+}
+
+__attribute__ ((noinline))
+void *
+memcpy (void *d, const void *s, size_t n)
+{
+  char *dst = (char *) d;
+  const char *src = (const char *) s;
+  while (n--)
+    *dst++ = *src++;
+  return (char *) d;
+}
+
+__attribute__ ((noinline))
+void
+bcopy (const void *s, void *d, size_t n)
+{
+  char *dst = (char *) d;
+  const char *src = (const char *) s;
+  if (src >= dst)
+    while (n--)
+      *dst++ = *src++;
+  else
+    {
+      dst += n;
+      src += n;
+      while (n--)
+        *--dst = *--src;
+    }
+}
+
+__attribute__ ((noinline))
+void *
+memset (void *d, int c, size_t n)
+{
+  char *dst = (char *) d;
+  while (n--)
+    *dst++ = c;
+  return (char *) d;
+}
+
+__attribute__ ((noinline))
+void
+bzero (void *d, size_t n)
+{
+  char *dst = (char *) d;
+  while (n--)
+    *dst++ = '\0';
+}


	Jakub


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