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


Hi!

The following patch implements what should help glibc to cut down the number
of .plt slots.
ATM GCC, if it sees prototype like:
viod *memcpy (void *, const void *, size_t) __asm ("__GI_memcpy");
memcpy is no longer a builtin (but memcpy calls generated internally by the
compiler still are calls to memcpy, not __GI_memcpy).
With this patch, memcpy is still the builtin, but if GCC decides to call
memcpy, it will call it using the __GI_memcpy name as requested by the
redirection.
Ok to commit?

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.

	* 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.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/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,85 @@ 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 (exp)
+     tree exp;
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+  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 bzero instead of memset.  */
+
+  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 (exp);
+      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,59 @@
+/* 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.  */
+#ifdef __OPTIMIZE__
+__attribute__ ((noinline))
+static void *
+memmove (void *d, const void *s, size_t n)
+{
+  abort ();
+}
+
+__attribute__ ((noinline))
+static void
+bcopy (const void *s, void *d, size_t n)
+{
+  abort ();
+}
+#endif
--- 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]