c-decl.c (finish_decl): When prototype with asmspec is found for built-in...

* 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.

From-SVN: r66181
This commit is contained in:
Jakub Jelinek 2003-04-28 21:58:52 +02:00 committed by Jakub Jelinek
parent 62a3446bb8
commit 9661b15f95
7 changed files with 297 additions and 24 deletions

View File

@ -1,3 +1,11 @@
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.

View File

@ -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));
}

View File

@ -1994,15 +1994,14 @@ emit_block_move_via_libcall (dst, src, size)
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
@ -3089,15 +3104,14 @@ clear_storage_via_libcall (object, size)
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");
@ -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.

View File

@ -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.

View File

@ -2,6 +2,9 @@
* 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

View File

@ -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;
}

View File

@ -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';
}