This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to add builtin strcat/strncat/strspn/strcspn
- To: gcc-patches at gcc dot gnu dot org
- Subject: Patch to add builtin strcat/strncat/strspn/strcspn
- From: "Kaveh R. Ghazi" <ghazi at caip dot rutgers dot edu>
- Date: Mon, 27 Nov 2000 14:04:04 -0500 (EST)
Here are some more string builtins from the "projects" page. The
transformations done are:
strcat (dst, "") -> dst
strncat (dst, "", n) -> dst
(handling side-effects in n)
strncat (dst, src, 0) -> dst
(handling side-effects in src)
strncat (dst, "string", n) -> __builtin_strcat (dst, "string")
(where n is constant and strlen("string") <= n)
strspn ("string1", "string2") -> compile-time eval
strspn (s1, "") -> 0
(handling side-effects in s1)
strcspn ("string1", "string2") -> compile-time eval
strcspn (s1, "") -> __builtin_strlen(s1)
Bootstrap/testsuite underway on solaris2.7. Assuming no regressions,
ok to install?
Thanks,
--Kaveh
2000-11-27 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.c (expand_builtin_strcat, expand_builtin_strncat,
expand_builtin_strspn, expand_builtin_strcspn): New functions.
(expand_builtin): Handle BUILT_IN_STRCAT, BUILT_IN_STRNCAT,
BUILT_IN_STRSPN and BUILT_IN_STRCSPN.
* builtins.def (BUILT_IN_STRCAT, BUILT_IN_STRNCAT,
BUILT_IN_STRSPN, BUILT_IN_STRCSPN): New entries.
* c-common.c (c_common_nodes_and_builtins): Declare builtin
strcat, strncat, strspn and strcspn.
(string_ftype_string_cstring): Renamed from `string_ftype_ptr_ptr'.
* extend.texi (strcat, strcspn, strncat, strspn): Document new
builtins.
testsuite:
* gcc.c-torture/execute/string-opt-9.c: New test.
* gcc.c-torture/execute/string-opt-10.c: Likewise.
* gcc.c-torture/execute/string-opt-11.c: Likewise.
* gcc.c-torture/execute/string-opt-12.c: Likewise.
diff -rup orig/egcs-CVS20001127/gcc/builtins.c egcs-CVS20001127/gcc/builtins.c
--- orig/egcs-CVS20001127/gcc/builtins.c Sun Nov 26 23:51:13 2000
+++ egcs-CVS20001127/gcc/builtins.c Mon Nov 27 13:50:40 2000
@@ -106,6 +106,14 @@ static rtx expand_builtin_strcmp PARAMS
enum machine_mode));
static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
enum machine_mode));
+static rtx expand_builtin_strcat PARAMS ((tree, rtx,
+ enum machine_mode));
+static rtx expand_builtin_strncat PARAMS ((tree, rtx,
+ enum machine_mode));
+static rtx expand_builtin_strspn PARAMS ((tree, rtx,
+ enum machine_mode));
+static rtx expand_builtin_strcspn PARAMS ((tree, rtx,
+ enum machine_mode));
static rtx expand_builtin_memcpy PARAMS ((tree));
static rtx expand_builtin_strcpy PARAMS ((tree));
static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
@@ -2189,6 +2197,205 @@ expand_builtin_strncmp (exp, target, mod
return 0;
}
+/* Expand expression EXP, which is a call to the strcat builtin.
+ Return 0 if we failed the caller should emit a normal call,
+ otherwise try to get the result in TARGET, if convenient. */
+static rtx
+expand_builtin_strcat (arglist, target, mode)
+ tree arglist;
+ rtx target;
+ enum machine_mode mode;
+{
+ /* If we need to check memory accesses, call the library function. */
+ if (current_function_check_memory_usage)
+ return 0;
+
+ if (arglist == 0
+ /* Arg could be non-pointer if user redeclared this fcn wrong. */
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || TREE_CHAIN (arglist) == 0
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+ != POINTER_TYPE))
+ return 0;
+ else
+ {
+ tree dst = TREE_VALUE (arglist),
+ src = TREE_VALUE (TREE_CHAIN (arglist)),
+ slen = c_strlen (src);
+
+ /* If the string length is zero, return the dst parameter. */
+ if (slen && compare_tree_int (slen, 0) == 0)
+ return expand_expr (dst, target, mode, EXPAND_NORMAL);
+
+ return 0;
+ }
+}
+
+/* Expand expression EXP, which is a call to the strncat builtin.
+ Return 0 if we failed the caller should emit a normal call,
+ otherwise try to get the result in TARGET, if convenient. */
+static rtx
+expand_builtin_strncat (arglist, target, mode)
+ tree arglist;
+ rtx target;
+ enum machine_mode mode;
+{
+ /* If we need to check memory accesses, call the library function. */
+ if (current_function_check_memory_usage)
+ return 0;
+
+ if (arglist == 0
+ /* Arg could be non-pointer if user redeclared this fcn wrong. */
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || TREE_CHAIN (arglist) == 0
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+ != POINTER_TYPE)
+ || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE
+ (TREE_CHAIN (TREE_CHAIN (arglist)))))
+ != INTEGER_TYPE))
+ return 0;
+ else
+ {
+ tree dst = TREE_VALUE (arglist),
+ src = TREE_VALUE (TREE_CHAIN (arglist)),
+ len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))),
+ slen = c_strlen (src),
+ fn = built_in_decls[BUILT_IN_STRCAT];
+
+ /* If the requested length is zero, or the src parameter string
+ length is zero, return the dst parameter. */
+ if ((TREE_CODE (len) == INTEGER_CST && compare_tree_int (len, 0) == 0)
+ || (slen && compare_tree_int (slen, 0) == 0))
+ {
+ /* Evaluate and ignore the src and len parameters in case
+ they have side-effects. */
+ expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return expand_expr (dst, target, mode, EXPAND_NORMAL);
+ }
+
+ /* If the replacement _DECL isn't initialized, don't do the
+ transformation. */
+ if (!fn)
+ return 0;
+
+ /* If the string len is less than or equal to the requested len,
+ call strcat. */
+ if (slen && TREE_CODE (len) == INTEGER_CST
+ && !tree_int_cst_lt (len, slen))
+ {
+ tree call_expr, newarglist =
+ tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
+ call_expr = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (fn)), fn);
+ call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ call_expr, newarglist, NULL_TREE);
+ TREE_SIDE_EFFECTS (call_expr) = 1;
+ return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+ }
+ return 0;
+ }
+}
+
+/* Expand expression EXP, which is a call to the strspn builtin.
+ Return 0 if we failed the caller should emit a normal call,
+ otherwise try to get the result in TARGET, if convenient. */
+static rtx
+expand_builtin_strspn (arglist, target, mode)
+ tree arglist;
+ rtx target;
+ enum machine_mode mode;
+{
+ /* If we need to check memory accesses, call the library function. */
+ if (current_function_check_memory_usage)
+ return 0;
+
+ if (arglist == 0
+ /* Arg could be non-pointer if user redeclared this fcn wrong. */
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || TREE_CHAIN (arglist) == 0
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+ != POINTER_TYPE))
+ return 0;
+ else
+ {
+ tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
+ const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
+
+ /* If both arguments are constants, evaluate at compile-time. */
+ if (p1 && p2)
+ {
+ const size_t r = strspn (p1, p2);
+ return expand_expr (build_int_2 (r, 0), target, mode, EXPAND_NORMAL);
+ }
+
+ /* If the second argument is "", return 0. */
+ if (p2 && strlen (p2) == 0)
+ {
+ /* Evaluate and ignore argument s1 in case it has
+ side-effects. */
+ expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return const0_rtx;
+ }
+ return 0;
+ }
+}
+
+/* Expand expression EXP, which is a call to the strcspn builtin.
+ Return 0 if we failed the caller should emit a normal call,
+ otherwise try to get the result in TARGET, if convenient. */
+static rtx
+expand_builtin_strcspn (arglist, target, mode)
+ tree arglist;
+ rtx target;
+ enum machine_mode mode;
+{
+ /* If we need to check memory accesses, call the library function. */
+ if (current_function_check_memory_usage)
+ return 0;
+
+ if (arglist == 0
+ /* Arg could be non-pointer if user redeclared this fcn wrong. */
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || TREE_CHAIN (arglist) == 0
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+ != POINTER_TYPE))
+ return 0;
+ else
+ {
+ tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
+ const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
+
+ /* If both arguments are constants, evaluate at compile-time. */
+ if (p1 && p2)
+ {
+ const size_t r = strcspn (p1, p2);
+ return expand_expr (build_int_2 (r, 0), target, mode, EXPAND_NORMAL);
+ }
+
+ /* If the second argument is "", return __builtin_strlen(s1). */
+ if (p2 && strlen (p2) == 0)
+ {
+ tree call_expr, newarglist = build_tree_list (NULL_TREE, s1),
+ fn = built_in_decls[BUILT_IN_STRLEN];
+
+ /* If the replacement _DECL isn't initialized, don't do the
+ transformation. */
+ if (!fn)
+ return 0;
+
+ call_expr = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (fn)), fn);
+ call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ call_expr, newarglist, NULL_TREE);
+ TREE_SIDE_EFFECTS (call_expr) = 1;
+ return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+ }
+ return 0;
+ }
+}
+
/* Expand a call to __builtin_saveregs, generating the result in TARGET,
if that's convenient. */
@@ -2892,6 +3099,8 @@ expand_builtin (exp, target, subtarget,
|| fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
|| fcode == BUILT_IN_STRNCPY || fcode == BUILT_IN_STRNCMP
|| fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRPBRK
+ || fcode == BUILT_IN_STRCAT || fcode == BUILT_IN_STRNCAT
+ || fcode == BUILT_IN_STRSPN || fcode == BUILT_IN_STRCSPN
|| fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
|| fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS
|| fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC
@@ -3022,6 +3231,30 @@ expand_builtin (exp, target, subtarget,
case BUILT_IN_STRNCPY:
target = expand_builtin_strncpy (arglist, target, mode);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_STRCAT:
+ target = expand_builtin_strcat (arglist, target, mode);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_STRNCAT:
+ target = expand_builtin_strncat (arglist, target, mode);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_STRSPN:
+ target = expand_builtin_strspn (arglist, target, mode);
+ if (target)
+ return target;
+ break;
+
+ case BUILT_IN_STRCSPN:
+ target = expand_builtin_strcspn (arglist, target, mode);
if (target)
return target;
break;
diff -rup orig/egcs-CVS20001127/gcc/builtins.def egcs-CVS20001127/gcc/builtins.def
--- orig/egcs-CVS20001127/gcc/builtins.def Sun Nov 26 23:51:14 2000
+++ egcs-CVS20001127/gcc/builtins.def Mon Nov 27 11:19:17 2000
@@ -38,6 +38,8 @@ DEF_BUILTIN(BUILT_IN_BZERO)
DEF_BUILTIN(BUILT_IN_BCMP)
DEF_BUILTIN(BUILT_IN_INDEX)
DEF_BUILTIN(BUILT_IN_RINDEX)
+DEF_BUILTIN(BUILT_IN_STRCAT)
+DEF_BUILTIN(BUILT_IN_STRNCAT)
DEF_BUILTIN(BUILT_IN_STRCPY)
DEF_BUILTIN(BUILT_IN_STRNCPY)
DEF_BUILTIN(BUILT_IN_STRCMP)
@@ -45,6 +47,8 @@ DEF_BUILTIN(BUILT_IN_STRNCMP)
DEF_BUILTIN(BUILT_IN_STRLEN)
DEF_BUILTIN(BUILT_IN_STRSTR)
DEF_BUILTIN(BUILT_IN_STRPBRK)
+DEF_BUILTIN(BUILT_IN_STRSPN)
+DEF_BUILTIN(BUILT_IN_STRCSPN)
DEF_BUILTIN(BUILT_IN_STRCHR)
DEF_BUILTIN(BUILT_IN_STRRCHR)
DEF_BUILTIN(BUILT_IN_FSQRT)
diff -rup orig/egcs-CVS20001127/gcc/c-common.c egcs-CVS20001127/gcc/c-common.c
--- orig/egcs-CVS20001127/gcc/c-common.c Sun Nov 26 23:51:15 2000
+++ egcs-CVS20001127/gcc/c-common.c Mon Nov 27 13:08:44 2000
@@ -4884,8 +4884,8 @@ c_common_nodes_and_builtins ()
tree void_ftype_any, void_ftype_int, int_ftype_any, sizet_ftype_any;
tree double_ftype_double, double_ftype_double_double;
tree float_ftype_float, ldouble_ftype_ldouble;
- tree int_ftype_cptr_cptr_sizet;
- tree int_ftype_string_string, string_ftype_ptr_ptr;
+ tree int_ftype_cptr_cptr_sizet, sizet_ftype_cstring_cstring;
+ tree int_ftype_string_string, string_ftype_string_cstring;
tree string_ftype_string_int, string_ftype_string_string;
tree string_ftype_string_cstring_sizet, int_ftype_cstring_cstring_sizet;
tree long_ftype_long;
@@ -4980,15 +4980,15 @@ c_common_nodes_and_builtins ()
void_zero_node = build_int_2 (0, 0);
TREE_TYPE (void_zero_node) = void_type_node;
- /* Prototype for strcpy. */
- string_ftype_ptr_ptr
+ /* Prototype for strcpy/strcat. */
+ string_ftype_string_cstring
= build_function_type (string_type_node,
tree_cons (NULL_TREE, string_type_node,
tree_cons (NULL_TREE,
const_string_type_node,
endlink)));
- /* Prototype for strncpy. */
+ /* Prototype for strncpy/strncat. */
string_ftype_string_cstring_sizet
= build_function_type (string_type_node,
tree_cons (NULL_TREE, string_type_node,
@@ -5010,6 +5010,14 @@ c_common_nodes_and_builtins ()
const_string_type_node,
endlink)));
+ /* Prototype for strspn/strcspn. */
+ sizet_ftype_cstring_cstring
+ = build_function_type (sizetype,
+ tree_cons (NULL_TREE, const_string_type_node,
+ tree_cons (NULL_TREE,
+ const_string_type_node,
+ endlink)));
+
/* Prototype for strncmp. */
int_ftype_cstring_cstring_sizet
= build_function_type (integer_type_node,
@@ -5277,12 +5285,22 @@ c_common_nodes_and_builtins ()
BUILT_IN_STRCHR, BUILT_IN_NORMAL, "strchr");
builtin_function ("__builtin_strrchr", string_ftype_string_int,
BUILT_IN_STRRCHR, BUILT_IN_NORMAL, "strrchr");
- builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
+ builtin_function ("__builtin_strcpy", string_ftype_string_cstring,
BUILT_IN_STRCPY, BUILT_IN_NORMAL, "strcpy");
builtin_function ("__builtin_strncpy", string_ftype_string_cstring_sizet,
BUILT_IN_STRNCPY, BUILT_IN_NORMAL, "strncpy");
- builtin_function ("__builtin_strlen", strlen_ftype,
- BUILT_IN_STRLEN, BUILT_IN_NORMAL, "strlen");
+ built_in_decls[BUILT_IN_STRCAT] =
+ builtin_function ("__builtin_strcat", string_ftype_string_cstring,
+ BUILT_IN_STRCAT, BUILT_IN_NORMAL, "strcat");
+ builtin_function ("__builtin_strncat", string_ftype_string_cstring_sizet,
+ BUILT_IN_STRNCAT, BUILT_IN_NORMAL, "strncat");
+ builtin_function ("__builtin_strspn", string_ftype_string_cstring,
+ BUILT_IN_STRSPN, BUILT_IN_NORMAL, "strspn");
+ builtin_function ("__builtin_strcspn", string_ftype_string_cstring_sizet,
+ BUILT_IN_STRCSPN, BUILT_IN_NORMAL, "strcspn");
+ built_in_decls[BUILT_IN_STRLEN] =
+ builtin_function ("__builtin_strlen", strlen_ftype,
+ BUILT_IN_STRLEN, BUILT_IN_NORMAL, "strlen");
builtin_function ("__builtin_sqrtf", float_ftype_float,
BUILT_IN_FSQRT, BUILT_IN_NORMAL, "sqrtf");
builtin_function ("__builtin_fsqrt", double_ftype_double,
@@ -5357,10 +5375,18 @@ c_common_nodes_and_builtins ()
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strpbrk", string_ftype_string_string, BUILT_IN_STRPBRK,
BUILT_IN_NORMAL, NULL_PTR);
- builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
+ builtin_function ("strcpy", string_ftype_string_cstring, BUILT_IN_STRCPY,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strncpy", string_ftype_string_cstring_sizet,
BUILT_IN_STRNCPY, BUILT_IN_NORMAL, NULL_PTR);
+ builtin_function ("strcat", string_ftype_string_cstring, BUILT_IN_STRCAT,
+ BUILT_IN_NORMAL, NULL_PTR);
+ builtin_function ("strncat", string_ftype_string_cstring_sizet,
+ BUILT_IN_STRNCAT, BUILT_IN_NORMAL, NULL_PTR);
+ builtin_function ("strspn", sizet_ftype_cstring_cstring, BUILT_IN_STRSPN,
+ BUILT_IN_NORMAL, NULL_PTR);
+ builtin_function ("strcspn", sizet_ftype_cstring_cstring,
+ BUILT_IN_STRCSPN, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT,
diff -rup orig/egcs-CVS20001127/gcc/extend.texi egcs-CVS20001127/gcc/extend.texi
--- orig/egcs-CVS20001127/gcc/extend.texi Sun Nov 26 23:52:29 2000
+++ egcs-CVS20001127/gcc/extend.texi Mon Nov 27 13:17:02 2000
@@ -3290,14 +3290,18 @@ function as well.
@findex sqrt
@findex sqrtf
@findex sqrtl
+@findex strcat
@findex strchr
@findex strcmp
@findex strcpy
+@findex strcspn
@findex strlen
+@findex strncat
@findex strncmp
@findex strncpy
@findex strpbrk
@findex strrchr
+@findex strspn
@findex strstr
GNU CC provides a large number of built-in functions other than the ones
diff -rup orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-10.c egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-10.c
--- orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-10.c Mon Nov 27 13:15:10 2000
+++ egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-10.c Mon Nov 27 13:52:30 2000
@@ -0,0 +1,78 @@
+/* Copyright (C) 2000 Free Software Foundation.
+
+ Ensure all expected transformations of builtin strncat occur and
+ perform correctly.
+
+ Written by Kaveh R. Ghazi, 11/27/2000. */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern char *strncat (char *, const char *, size_t);
+extern char *strcpy (char *, const char *);
+extern char *strcmp (const char *, const char *);
+int x = 123;
+
+int main ()
+{
+ const char *const s1 = "hello world";
+ const char *const s2 = "";
+ char dst[64], *d2;
+
+ strcpy (dst, s1);
+ if (strncat (dst, "", 100) != dst || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1);
+ if (strncat (dst, s2, 100) != dst || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2, s2, 100) != dst+1 || d2 != dst+1 || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2+5, s2, 100) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2+5, s1+11, 100) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2+5, s1, 0) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2+5, "", ++x) != dst+6 || d2 != dst+1 || x != 124
+ || strcmp (dst, s1))
+ abort();
+
+ strcpy (dst, s1);
+ if (strncat (dst, "foo", 3) != dst || strcmp (dst, "hello worldfoo"))
+ abort();
+ strcpy (dst, s1);
+ if (strncat (dst, "foo", 100) != dst || strcmp (dst, "hello worldfoo"))
+ abort();
+ strcpy (dst, s1);
+ if (strncat (dst, s1, 100) != dst || strcmp (dst, "hello worldhello world"))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2, s1, 100) != dst+1 || d2 != dst+1
+ || strcmp (dst, "hello worldhello world"))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2+5, s1, 100) != dst+6 || d2 != dst+1
+ || strcmp (dst, "hello worldhello world"))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strncat (++d2+5, s1+5, 100) != dst+6 || d2 != dst+1
+ || strcmp (dst, "hello world world"))
+ abort();
+
+ return 0;
+}
+
+#ifdef __OPTIMIZE__
+/* When optimizing, all the above cases should be transformed into
+ something else. So any remaining calls to the original function
+ should abort. */
+static char *
+strncat (char *s1, const char *s2, size_t n)
+{
+ abort();
+}
+#endif
diff -rup orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-11.c egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-11.c
--- orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-11.c Mon Nov 27 13:15:12 2000
+++ egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-11.c Mon Nov 27 13:12:23 2000
@@ -0,0 +1,50 @@
+/* Copyright (C) 2000 Free Software Foundation.
+
+ Ensure all expected transformations of builtin strspn occur and
+ perform correctly.
+
+ Written by Kaveh R. Ghazi, 11/27/2000. */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern size_t strspn (const char *, const char *);
+extern char *strcpy (char *, const char *);
+
+int main ()
+{
+ const char *const s1 = "hello world";
+ char dst[64], *d2;
+
+ if (strspn (s1, "hello") != 5)
+ abort();
+ if (strspn (s1+4, "hello") != 1)
+ abort();
+ if (strspn (s1, "z") != 0)
+ abort();
+ if (strspn (s1, "hello world") != 11)
+ abort();
+ if (strspn (s1, "") != 0)
+ abort();
+ strcpy (dst, s1);
+ if (strspn (dst, "") != 0)
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strspn (++d2, "") != 0 || d2 != dst+1)
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strspn (++d2+5, "") != 0 || d2 != dst+1)
+ abort();
+
+ return 0;
+}
+
+#ifdef __OPTIMIZE__
+/* When optimizing, all the above cases should be transformed into
+ something else. So any remaining calls to the original function
+ should abort. */
+static size_t
+strspn (const char *s1, const char *s2)
+{
+ abort();
+}
+#endif
diff -rup orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-12.c egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-12.c
--- orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-12.c Mon Nov 27 13:15:13 2000
+++ egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-12.c Mon Nov 27 13:12:17 2000
@@ -0,0 +1,50 @@
+/* Copyright (C) 2000 Free Software Foundation.
+
+ Ensure all expected transformations of builtin strcspn occur and
+ perform correctly.
+
+ Written by Kaveh R. Ghazi, 11/27/2000. */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern size_t strcspn (const char *, const char *);
+extern char *strcpy (char *, const char *);
+
+int main ()
+{
+ const char *const s1 = "hello world";
+ char dst[64], *d2;
+
+ if (strcspn (s1, "hello") != 0)
+ abort();
+ if (strcspn (s1, "z") != 11)
+ abort();
+ if (strcspn (s1+4, "z") != 7)
+ abort();
+ if (strcspn (s1, "hello world") != 0)
+ abort();
+ if (strcspn (s1, "") != 11)
+ abort();
+ strcpy (dst, s1);
+ if (strcspn (dst, "") != 11)
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strcspn (++d2, "") != 10 || d2 != dst+1)
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strcspn (++d2+5, "") != 5 || d2 != dst+1)
+ abort();
+
+ return 0;
+}
+
+#ifdef __OPTIMIZE__
+/* When optimizing, all the above cases should be transformed into
+ something else. So any remaining calls to the original function
+ should abort. */
+static size_t
+strcspn (const char *s1, const char *s2)
+{
+ abort();
+}
+#endif
diff -rup orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c
--- orig/egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c Mon Nov 27 13:15:08 2000
+++ egcs-CVS20001127/gcc/testsuite/gcc.c-torture/execute/string-opt-9.c Mon Nov 27 12:50:38 2000
@@ -0,0 +1,48 @@
+/* Copyright (C) 2000 Free Software Foundation.
+
+ Ensure all expected transformations of builtin strcat occur and
+ perform correctly.
+
+ Written by Kaveh R. Ghazi, 11/27/2000. */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern char *strcat (char *, const char *);
+extern char *strcpy (char *, const char *);
+extern char *strcmp (const char *, const char *);
+
+int main ()
+{
+ const char *const s1 = "hello world";
+ const char *const s2 = "";
+ char dst[64], *d2;
+
+ strcpy (dst, s1);
+ if (strcat (dst, "") != dst || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1);
+ if (strcat (dst, s2) != dst || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strcat (++d2, s2) != dst+1 || d2 != dst+1 || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strcat (++d2+5, s2) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
+ abort();
+ strcpy (dst, s1); d2 = dst;
+ if (strcat (++d2+5, s1+11) != dst+6 || d2 != dst+1 || strcmp (dst, s1))
+ abort();
+
+ return 0;
+}
+
+#ifdef __OPTIMIZE__
+/* When optimizing, all the above cases should be transformed into
+ something else. So any remaining calls to the original function
+ should abort. */
+static char *
+strcat (char *s1, const char *s2)
+{
+ abort();
+}
+#endif