This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to add builtin mempcpy and stpcpy
- From: "Kaveh R. Ghazi" <ghazi at caip dot rutgers dot edu>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 11 Apr 2003 23:41:21 -0400 (EDT)
- Subject: Patch to add builtin mempcpy and stpcpy
This patch adds two new builtins, mempcpy and stpcpy. These builtin
functions are added as the "extension" type, like alloca, bzero, etc.
The transformations for these two are the same as those for memcpy and
strcpy except the return values for these are different as commonly
defined in glibc et al.
Bootstrapped on sparc-sun-solaris2.7, no regressions. And the new
testcase passes.
Ok for mainline?
Thanks,
--Kaveh
2003-04-11 Kaveh R. Ghazi <ghazi at caip dot rutgers dot edu>
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 builtin.
testsuite:
* gcc.c-torture/execute/string-opt-18.c: New test.
diff -rup orig/egcc-CVS20030410/gcc/builtins.c egcc-CVS20030410/gcc/builtins.c
--- orig/egcc-CVS20030410/gcc/builtins.c 2003-04-08 21:01:05.000000000 -0400
+++ egcc-CVS20030410/gcc/builtins.c 2003-04-11 17:34:41.285255000 -0400
@@ -125,9 +125,11 @@ static rtx expand_builtin_strspn PARAMS
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, m
}
/* 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,
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,
#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. */
@@ -4055,10 +4101,12 @@ expand_builtin (exp, target, subtarget,
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:
@@ -4322,6 +4370,12 @@ expand_builtin (exp, target, subtarget,
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)
@@ -4373,7 +4427,13 @@ expand_builtin (exp, target, subtarget,
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;
diff -rup orig/egcc-CVS20030410/gcc/builtins.def egcc-CVS20030410/gcc/builtins.def
--- orig/egcc-CVS20030410/gcc/builtins.def 2003-03-09 21:27:05.000000000 -0500
+++ egcc-CVS20030410/gcc/builtins.def 2003-04-11 14:54:17.249427000 -0400
@@ -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,
diff -rup orig/egcc-CVS20030410/gcc/doc/extend.texi egcc-CVS20030410/gcc/doc/extend.texi
--- orig/egcc-CVS20030410/gcc/doc/extend.texi 2003-04-07 21:01:44.000000000 -0400
+++ egcc-CVS20030410/gcc/doc/extend.texi 2003-04-11 14:54:59.036035000 -0400
@@ -4582,6 +4582,7 @@ v4si f (v4si a, v4si b, v4si c)
@findex logl
@findex memcmp
@findex memcpy
+ at findex mempcpy
@findex memset
@findex nearbyint
@findex nearbyintf
@@ -4607,6 +4608,7 @@ v4si f (v4si a, v4si b, v4si c)
@findex sqrtf
@findex sqrtl
@findex sscanf
+ at findex stpcpy
@findex strcat
@findex strchr
@findex strcmp
@@ -4651,8 +4653,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},
- at code{fputs_unlocked}, @code{index}, @code{printf_unlocked},
-and @code{rindex} may be handled as built-in functions.
+ at code{fputs_unlocked}, @code{index}, @code{mempcpy}, @code{printf_unlocked},
+ at 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.
diff -rup orig/egcc-CVS20030410/gcc/testsuite/gcc.c-torture/execute/string-opt-18.c egcc-CVS20030410/gcc/testsuite/gcc.c-torture/execute/string-opt-18.c
--- orig/egcc-CVS20030410/gcc/testsuite/gcc.c-torture/execute/string-opt-18.c 2003-04-11 15:06:39.068170000 -0400
+++ egcc-CVS20030410/gcc/testsuite/gcc.c-torture/execute/string-opt-18.c 2003-04-11 17:48:17.518862000 -0400
@@ -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
+}