summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2000-11-07 16:08:57 +0000
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2000-11-07 16:08:57 +0000
commit46f3a74a93033df2cb3b285e7dbb3d1d07598577 (patch)
treee972720ba7132b95f7ec0a0b456b6daf624432c8
parent8f6cf59c314ca9b1be56322b347cef121314588c (diff)
downloadgcc-46f3a74a93033df2cb3b285e7dbb3d1d07598577.tar.gz
* builtins.c (expand_builtin_strpbrk): New function.
(expand_builtin): Handle BUILT_IN_STRPBRK. * builtins.def (BUILT_IN_STRPBRK): New entry. * c-common.c (c_common_nodes_and_builtins): Declare builtin strpbrk. testsuite: * gcc.c-torture/execute/string-opt-2.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@37291 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/builtins.c104
-rw-r--r--gcc/builtins.def1
-rw-r--r--gcc/c-common.c6
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/string-opt-2.c48
6 files changed, 171 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b99a4c54788..a142fab0082 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2000-11-07 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * builtins.c (expand_builtin_strpbrk): New function.
+ (expand_builtin): Handle BUILT_IN_STRPBRK.
+
+ * builtins.def (BUILT_IN_STRPBRK): New entry.
+
+ * c-common.c (c_common_nodes_and_builtins): Declare builtin
+ strpbrk.
+
2000-11-07 David O'Brien <obrien@dragon.nuxi.com>
* config/alpha/freebsd.h: New file -- FreeBSD/alpha architecture file.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index c058ebaca2c..0021f760757 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -109,6 +109,8 @@ static rtx expand_builtin_bzero PARAMS ((tree));
static rtx expand_builtin_strlen PARAMS ((tree, rtx));
static rtx expand_builtin_strstr PARAMS ((tree, rtx,
enum machine_mode));
+static rtx expand_builtin_strpbrk PARAMS ((tree, rtx,
+ enum machine_mode));
static rtx expand_builtin_alloca PARAMS ((tree, rtx));
static rtx expand_builtin_ffs PARAMS ((tree, rtx, rtx));
static rtx expand_builtin_frame_address PARAMS ((tree));
@@ -1459,6 +1461,100 @@ expand_builtin_strstr (arglist, target, mode)
}
}
+/* Expand a call to the strpbrk builtin. 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_strpbrk (arglist, target, mode)
+ tree arglist;
+ rtx target;
+ enum machine_mode mode;
+{
+ if (arglist == 0
+ || 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));
+ tree len1 = c_strlen (s1), len2 = c_strlen (s2);
+ tree stripped_s1 = s1, stripped_s2 = s2;
+
+ STRIP_NOPS (stripped_s1);
+ if (stripped_s1 && TREE_CODE (stripped_s1) == ADDR_EXPR)
+ stripped_s1 = TREE_OPERAND (stripped_s1, 0);
+ STRIP_NOPS (stripped_s2);
+ if (stripped_s2 && TREE_CODE (stripped_s2) == ADDR_EXPR)
+ stripped_s2 = TREE_OPERAND (stripped_s2, 0);
+
+ /* If both arguments are constants, calculate the result now. */
+ if (len1 && len2
+ && TREE_CODE (stripped_s1) == STRING_CST
+ && TREE_CODE (stripped_s2) == STRING_CST)
+ {
+ const char *const result =
+ strpbrk (TREE_STRING_POINTER (stripped_s1),
+ TREE_STRING_POINTER (stripped_s2));
+
+ if (result)
+ {
+ long offset = result - TREE_STRING_POINTER (stripped_s1);
+
+ /* Return an offset into the constant string argument. */
+ return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
+ s1, ssize_int (offset))),
+ target, mode, EXPAND_NORMAL);
+ }
+ else
+ return const0_rtx;
+ }
+
+ /* We must have been able to figure out the second argument's
+ length to do anything else. */
+ if (!len2)
+ return 0;
+
+ /* OK, handle some cases. */
+ switch (compare_tree_int (len2, 1))
+ {
+ case -1: /* length is 0, return NULL. */
+ {
+ /* Evaluate and ignore the arguments in case they had
+ side-effects. */
+ expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ return const0_rtx;
+ }
+ case 0: /* length is 1, return strchr(s1, s2[0]). */
+ {
+ tree call_expr, fn = built_in_decls[BUILT_IN_STRCHR];
+
+ if (!fn)
+ return 0;
+
+ /* New argument list transforming strpbrk(s1, s2) to
+ strchr(s1, s2[0]). */
+ arglist =
+ build_tree_list (NULL_TREE, build_int_2
+ (TREE_STRING_POINTER (stripped_s2)[0], 0));
+ arglist = tree_cons (NULL_TREE, s1, arglist);
+ call_expr = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (fn)), fn);
+ call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ call_expr, arglist, NULL_TREE);
+ TREE_SIDE_EFFECTS (call_expr) = 1;
+ return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+ }
+ case 1: /* length is greater than 1, really call strpbrk. */
+ return 0;
+ default:
+ abort();
+ }
+ }
+}
+
/* Expand a call to the memcpy builtin, with arguments in ARGLIST. */
static rtx
expand_builtin_memcpy (arglist)
@@ -2503,7 +2599,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|| fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP
|| fcode == BUILT_IN_BCMP || fcode == BUILT_IN_BZERO
|| fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
- || fcode == BUILT_IN_STRSTR
+ || fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRPBRK
|| fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
|| fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS
|| fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC
@@ -2638,6 +2734,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return target;
break;
+ case BUILT_IN_STRPBRK:
+ target = expand_builtin_strpbrk (arglist, target, mode);
+ if (target)
+ return target;
+ break;
+
case BUILT_IN_MEMCPY:
target = expand_builtin_memcpy (arglist);
if (target)
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 13e0f41839e..261c76a663c 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -40,6 +40,7 @@ DEF_BUILTIN(BUILT_IN_STRCPY)
DEF_BUILTIN(BUILT_IN_STRCMP)
DEF_BUILTIN(BUILT_IN_STRLEN)
DEF_BUILTIN(BUILT_IN_STRSTR)
+DEF_BUILTIN(BUILT_IN_STRPBRK)
DEF_BUILTIN(BUILT_IN_STRCHR)
DEF_BUILTIN(BUILT_IN_FSQRT)
DEF_BUILTIN(BUILT_IN_SIN)
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 1b7b028e92d..ac0a1010707 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -4935,7 +4935,7 @@ c_common_nodes_and_builtins ()
const_string_type_node,
endlink)));
- /* Prototype for strstr, etc. */
+ /* Prototype for strstr, strpbrk, etc. */
string_ftype_string_string
= build_function_type (string_type_node,
tree_cons (NULL_TREE, const_string_type_node,
@@ -5174,6 +5174,8 @@ c_common_nodes_and_builtins ()
BUILT_IN_STRCMP, BUILT_IN_NORMAL, "strcmp");
builtin_function ("__builtin_strstr", string_ftype_string_string,
BUILT_IN_STRSTR, BUILT_IN_NORMAL, "strstr");
+ builtin_function ("__builtin_strpbrk", string_ftype_string_string,
+ BUILT_IN_STRPBRK, BUILT_IN_NORMAL, "strpbrk");
built_in_decls[BUILT_IN_STRCHR] =
builtin_function ("__builtin_strchr", string_ftype_string_int,
BUILT_IN_STRCHR, BUILT_IN_NORMAL, "strchr");
@@ -5247,6 +5249,8 @@ c_common_nodes_and_builtins ()
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strstr", string_ftype_string_string, BUILT_IN_STRSTR,
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,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 61bc1c18beb..33091b9c945 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2000-11-07 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gcc.c-torture/execute/string-opt-2.c: New test.
+
2000-11-07 Nathan Sidwell <nathan@codesourcery.com>
* g++.old-deja/g++.pt/crash60.C: New test.
diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-2.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-2.c
new file mode 100644
index 00000000000..87144ded67c
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-2.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2000 Free Software Foundation.
+
+ Ensure all expected transformations of builtin strpbrk occur and
+ perform correctly.
+
+ Written by Kaveh R. Ghazi, 11/6/2000. */
+
+extern void abort(void);
+extern char *strpbrk (const char *, const char *);
+
+void fn (const char *foo, const char *const *bar)
+{
+ if (strcmp(strpbrk ("hello world", "lrooo"), "llo world") != 0)
+ abort();
+ if (strpbrk (foo, "") != 0)
+ abort();
+ if (strpbrk (foo + 4, "") != 0)
+ abort();
+ if (strpbrk (*bar--, "") != 0)
+ abort();
+ if (strpbrk (*bar, "h") != foo)
+ abort();
+ if (strpbrk (foo, "h") != foo)
+ abort();
+ if (strpbrk (foo, "w") != foo + 6)
+ abort();
+ if (strpbrk (foo + 6, "o") != foo + 7)
+ abort();
+}
+
+int main()
+{
+ const char *const foo[] = { "hello world", "bye bye world" };
+ fn (foo[0], foo + 1);
+ 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. */
+char *
+strpbrk(const char *s1, const char *s2)
+{
+ abort();
+}
+#endif