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:
parent
62a3446bb8
commit
9661b15f95
@ -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.
|
||||
|
24
gcc/c-decl.c
24
gcc/c-decl.c
@ -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));
|
||||
}
|
||||
|
70
gcc/expr.c
70
gcc/expr.c
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
82
gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c
Normal file
82
gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c
Normal 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;
|
||||
}
|
131
gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c
Normal file
131
gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c
Normal 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';
|
||||
}
|
Loading…
Reference in New Issue
Block a user