mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-31 03:00:25 +08:00
builtins.c (expand_builtin_memcpy): Add `endp' argument, use it.
gcc: * builtins.c (expand_builtin_memcpy): Add `endp' argument, use it. (expand_builtin_stpcpy): New. (expand_builtin): Add BUILT_IN_MEMPCPY & BUILT_IN_STPCPY. * builtins.def: Add mempcpy & stpcpy support. * doc/extend.texi (mempcpy, stpcpy): Document new builtins. testsuite: * gcc.c-torture/execute/string-opt-18.c: New test. From-SVN: r65551
This commit is contained in:
parent
f4f4610e03
commit
9cb65f923c
@ -1,3 +1,11 @@
|
||||
2003-04-13 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* builtins.c (expand_builtin_memcpy): Add `endp' argument, use it.
|
||||
(expand_builtin_stpcpy): New.
|
||||
(expand_builtin): Add BUILT_IN_MEMPCPY & BUILT_IN_STPCPY.
|
||||
* builtins.def: Add mempcpy & stpcpy support.
|
||||
* doc/extend.texi (mempcpy, stpcpy): Document new builtins.
|
||||
|
||||
2003-04-13 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
* config/rs6000/rs6000.c: Replace occurrences of "GNU CC" with
|
||||
|
@ -125,9 +125,11 @@ static rtx expand_builtin_strspn PARAMS ((tree, rtx,
|
||||
static rtx expand_builtin_strcspn PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_memcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
enum machine_mode, int));
|
||||
static rtx expand_builtin_strcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_stpcpy PARAMS ((tree, rtx,
|
||||
enum machine_mode));
|
||||
static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
|
||||
enum machine_mode));
|
||||
static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
|
||||
@ -2252,15 +2254,18 @@ builtin_memcpy_read_str (data, offset, mode)
|
||||
}
|
||||
|
||||
/* Expand a call to the memcpy builtin, with arguments in ARGLIST.
|
||||
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 convenient). */
|
||||
|
||||
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 convenient). If ENDP is 0 return the
|
||||
destination pointer, if ENDP is 1 return the end pointer ala
|
||||
mempcpy, and if ENDP is 2 return the end pointer minus one ala
|
||||
stpcpy. */
|
||||
static rtx
|
||||
expand_builtin_memcpy (arglist, target, mode)
|
||||
expand_builtin_memcpy (arglist, target, mode, endp)
|
||||
tree arglist;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
int endp;
|
||||
{
|
||||
if (!validate_arglist (arglist,
|
||||
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
|
||||
@ -2316,7 +2321,15 @@ expand_builtin_memcpy (arglist, target, mode)
|
||||
if (GET_MODE (dest_mem) != ptr_mode)
|
||||
dest_mem = convert_memory_address (ptr_mode, dest_mem);
|
||||
#endif
|
||||
return dest_mem;
|
||||
if (endp)
|
||||
{
|
||||
rtx result = gen_rtx_PLUS (GET_MODE(dest_mem), dest_mem, len_rtx);
|
||||
if (endp == 2)
|
||||
result = simplify_gen_binary (MINUS, GET_MODE(result), result, const1_rtx);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return dest_mem;
|
||||
}
|
||||
|
||||
src_mem = get_memory_rtx (src);
|
||||
@ -2335,7 +2348,15 @@ expand_builtin_memcpy (arglist, target, mode)
|
||||
#endif
|
||||
}
|
||||
|
||||
return dest_addr;
|
||||
if (endp)
|
||||
{
|
||||
rtx result = gen_rtx_PLUS (GET_MODE (dest_addr), dest_addr, len_rtx);
|
||||
if (endp == 2)
|
||||
result = simplify_gen_binary (MINUS, GET_MODE(result), result, const1_rtx);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return dest_addr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2370,6 +2391,31 @@ expand_builtin_strcpy (exp, target, mode)
|
||||
target, mode, EXPAND_NORMAL);
|
||||
}
|
||||
|
||||
/* Expand a call to the stpcpy builtin, with arguments in ARGLIST.
|
||||
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 convenient). */
|
||||
|
||||
static rtx
|
||||
expand_builtin_stpcpy (arglist, target, mode)
|
||||
tree arglist;
|
||||
rtx target;
|
||||
enum machine_mode mode;
|
||||
{
|
||||
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
|
||||
chainon (arglist, build_tree_list (NULL_TREE, len));
|
||||
return expand_builtin_memcpy (arglist, target, mode, /*endp=*/2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
|
||||
bytes from constant string DATA + OFFSET and return it as target
|
||||
constant. */
|
||||
@ -4036,10 +4082,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
case BUILT_IN_MEMSET:
|
||||
case BUILT_IN_MEMCPY:
|
||||
case BUILT_IN_MEMCMP:
|
||||
case BUILT_IN_MEMPCPY:
|
||||
case BUILT_IN_BCMP:
|
||||
case BUILT_IN_BZERO:
|
||||
case BUILT_IN_INDEX:
|
||||
case BUILT_IN_RINDEX:
|
||||
case BUILT_IN_STPCPY:
|
||||
case BUILT_IN_STRCHR:
|
||||
case BUILT_IN_STRRCHR:
|
||||
case BUILT_IN_STRLEN:
|
||||
@ -4303,6 +4351,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_STPCPY:
|
||||
target = expand_builtin_stpcpy (arglist, target, mode);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_STRCAT:
|
||||
target = expand_builtin_strcat (arglist, target, mode);
|
||||
if (target)
|
||||
@ -4354,7 +4408,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMCPY:
|
||||
target = expand_builtin_memcpy (arglist, target, mode);
|
||||
target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
||||
case BUILT_IN_MEMPCPY:
|
||||
target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/1);
|
||||
if (target)
|
||||
return target;
|
||||
break;
|
||||
|
@ -388,6 +388,10 @@ DEF_LIB_BUILTIN(BUILT_IN_MEMSET,
|
||||
"__builtin_memset",
|
||||
BT_FN_PTR_PTR_INT_SIZE,
|
||||
ATTR_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN(BUILT_IN_MEMPCPY,
|
||||
"__builtin_mempcpy",
|
||||
BT_FN_PTR_PTR_CONST_PTR_SIZE,
|
||||
ATTR_NOTHROW_LIST)
|
||||
|
||||
DEF_LIB_BUILTIN(BUILT_IN_STRCAT,
|
||||
"__builtin_strcat",
|
||||
@ -397,6 +401,10 @@ DEF_LIB_BUILTIN(BUILT_IN_STRNCAT,
|
||||
"__builtin_strncat",
|
||||
BT_FN_STRING_STRING_CONST_STRING_SIZE,
|
||||
ATTR_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN(BUILT_IN_STPCPY,
|
||||
"__builtin_stpcpy",
|
||||
BT_FN_STRING_STRING_CONST_STRING,
|
||||
ATTR_NOTHROW_LIST)
|
||||
DEF_LIB_BUILTIN(BUILT_IN_STRCPY,
|
||||
"__builtin_strcpy",
|
||||
BT_FN_STRING_STRING_CONST_STRING,
|
||||
|
@ -4598,6 +4598,7 @@ v4si f (v4si a, v4si b, v4si c)
|
||||
@findex logl
|
||||
@findex memcmp
|
||||
@findex memcpy
|
||||
@findex mempcpy
|
||||
@findex memset
|
||||
@findex nearbyint
|
||||
@findex nearbyintf
|
||||
@ -4623,6 +4624,7 @@ v4si f (v4si a, v4si b, v4si c)
|
||||
@findex sqrtf
|
||||
@findex sqrtl
|
||||
@findex sscanf
|
||||
@findex stpcpy
|
||||
@findex strcat
|
||||
@findex strchr
|
||||
@findex strcmp
|
||||
@ -4667,8 +4669,8 @@ be emitted.
|
||||
Outside strict ISO C mode (@option{-ansi}, @option{-std=c89} or
|
||||
@option{-std=c99}), the functions @code{alloca}, @code{bcmp},
|
||||
@code{bzero}, @code{_exit}, @code{ffs}, @code{fprintf_unlocked},
|
||||
@code{fputs_unlocked}, @code{index}, @code{printf_unlocked},
|
||||
and @code{rindex} may be handled as built-in functions.
|
||||
@code{fputs_unlocked}, @code{index}, @code{mempcpy}, @code{printf_unlocked},
|
||||
@code{rindex}, and @code{stpcpy} may be handled as built-in functions.
|
||||
All these functions have corresponding versions
|
||||
prefixed with @code{__builtin_}, which may be used even in strict C89
|
||||
mode.
|
||||
|
@ -1,3 +1,7 @@
|
||||
2003-04-13 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* gcc.c-torture/execute/string-opt-18.c: New test.
|
||||
|
||||
2003-04-13 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
PR c++/10300
|
||||
|
91
gcc/testsuite/gcc.c-torture/execute/string-opt-18.c
Normal file
91
gcc/testsuite/gcc.c-torture/execute/string-opt-18.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <stdio.h>
|
||||
/* Copyright (C) 2000 Free Software Foundation.
|
||||
|
||||
Ensure builtin mempcpy and stpcpy perform correctly.
|
||||
|
||||
Written by Kaveh Ghazi, 4/11/2003. */
|
||||
|
||||
extern void abort (void);
|
||||
extern char *strcpy (char *, const char *);
|
||||
extern char *stpcpy (char *, const char *);
|
||||
/*typedef __SIZE_TYPE__ size_t;*/
|
||||
extern size_t strlen(const char *);
|
||||
extern void *memcpy (void *, const void *, size_t);
|
||||
extern void *mempcpy (void *, const 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 (stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6))
|
||||
abort ();
|
||||
if (stpcpy (p + 16, "vwxyz" + 1) != p + 16 + 4 || memcmp (p + 16, "wxyz", 5))
|
||||
abort ();
|
||||
if (stpcpy (p + 1, "") != p + 1 + 0 || memcmp (p, "a\0cde", 6))
|
||||
abort ();
|
||||
if (stpcpy (p + 3, "fghij") != p + 3 + 5 || memcmp (p, "a\0cfghij", 9))
|
||||
abort ();
|
||||
if (mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6))
|
||||
abort ();
|
||||
if (mempcpy (p + 16, "VWX" + 1, 2) != p + 16 + 2 || memcmp (p + 16, "WXyz", 5))
|
||||
abort ();
|
||||
if (mempcpy (p + 1, "", 1) != p + 1 + 1 || memcmp (p, "A\0CDE", 6))
|
||||
abort ();
|
||||
if (mempcpy (p + 3, "FGHI", 4) != p + 3 + 4 || memcmp (p, "A\0CFGHIj", 9))
|
||||
abort ();
|
||||
|
||||
i = 8;
|
||||
memcpy (p + 20, "qrstu", 6);
|
||||
if (stpcpy ((i++, p + 20 + 1), "23") != (p + 20 + 1 + 2) || i != 9 || memcmp (p + 20, "q23\0u", 6))
|
||||
abort ();
|
||||
|
||||
s = s1; i = 3;
|
||||
memcpy (p + 25, "QRSTU", 6);
|
||||
if (mempcpy (p + 25 + 1, s++, i++) != (p + 25 + 1 + 3) || i != 4 || s != s1 + 1 || memcmp (p + 25, "Q123U", 6))
|
||||
abort ();
|
||||
|
||||
if (stpcpy (stpcpy (p, "ABCD"), "EFG") != p + 7 || memcmp (p, "ABCDEFG", 8))
|
||||
abort();
|
||||
if (mempcpy (mempcpy (p, "abcdEFG", 4), "efg", 4) != p + 8 || memcmp (p, "abcdefg", 8))
|
||||
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_stpcpy (p, "abcde") != p + 5 || memcmp (p, "abcde", 6))
|
||||
abort ();
|
||||
if (__builtin_mempcpy (p, "ABCDE", 6) != p + 6 || memcmp (p, "ABCDE", 6))
|
||||
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. When not optimizing, we provide fallback funcs for
|
||||
platforms that don't have mempcpy or stpcpy in libc.*/
|
||||
__attribute__ ((noinline))
|
||||
static char *
|
||||
stpcpy (char *d, const char *s)
|
||||
{
|
||||
#ifdef __OPTIMIZE__
|
||||
abort ();
|
||||
#else
|
||||
return strcpy (d, s) + strlen (s);
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__ ((noinline))
|
||||
static void *
|
||||
mempcpy (void *dst, const void *src, size_t sz)
|
||||
{
|
||||
#ifdef __OPTIMIZE__
|
||||
abort ();
|
||||
#else
|
||||
return (char *) memcpy (dst, src, sz) + sz;
|
||||
#endif
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user