+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
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,
}
/* 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))
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);
#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;
}
}
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. */
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:
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)
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;
"__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",
"__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,
@findex logl
@findex memcmp
@findex memcpy
+@findex mempcpy
@findex memset
@findex nearbyint
@findex nearbyintf
@findex sqrtf
@findex sqrtl
@findex sscanf
+@findex stpcpy
@findex strcat
@findex strchr
@findex strcmp
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.
+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
--- /dev/null
+#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
+}