+2003-04-28 Jakub Jelinek <jakub@redhat.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.
+
2003-04-28 Richard Henderson <rth@redhat.com>
* config/sparc/sparc.c (print_operand): Add 's' to sign-extend.
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));
}
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");
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
static 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");
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;
}
\f
/* Generate code to copy Y into X.
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.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.
+
2003-04-27 Mark Mitchell <mark@codesourcery.com>
PR c++/10506
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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';
+}