From 9661b15f951d61710cadd3b4c85d5b29078e116e Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 28 Apr 2003 21:58:52 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 8 ++ gcc/c-decl.c | 24 +++- gcc/expr.c | 70 +++++++--- gcc/expr.h | 3 + gcc/testsuite/ChangeLog | 3 + .../gcc.c-torture/execute/string-opt-asm-1.c | 82 +++++++++++ .../gcc.c-torture/execute/string-opt-asm-2.c | 131 ++++++++++++++++++ 7 files changed, 297 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c5900668f45..ecf8202b84e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2003-04-28 Jakub Jelinek + + * 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 * config/sparc/sparc.c (print_operand): Add 's' to sign-extend. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index ee987858421..e16c2b6205c 100644 --- a/gcc/c-decl.c +++ b/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)); } diff --git a/gcc/expr.c b/gcc/expr.c index 0d6118778b8..73f9baf6eb5 100644 --- a/gcc/expr.c +++ b/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. diff --git a/gcc/expr.h b/gcc/expr.h index 214ada97bda..7e157cdf302 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -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. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ee090a74e6f..ccd7e529dfc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 PR c++/10506 diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c new file mode 100644 index 00000000000..5f50f91c550 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-asm-1.c @@ -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; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c new file mode 100644 index 00000000000..9c629a2b8d1 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-asm-2.c @@ -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'; +} -- 2.30.2