summaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2000-12-03 03:46:03 +0000
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2000-12-03 03:46:03 +0000
commit49f0327b7ddfd2e2ecdd61eda95c6630ed2e58f4 (patch)
tree24241ef620273494e9e408df936e6f35081239e8 /gcc/builtins.c
parentef6c187e8a23acc5e1e17a1fc18304983ea4ea55 (diff)
downloadgcc-49f0327b7ddfd2e2ecdd61eda95c6630ed2e58f4.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@37964 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 0ed47078799..7994f63dcad 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -111,6 +111,14 @@ static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
enum machine_mode));
static rtx builtin_memcpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
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 builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
@@ -2423,6 +2431,206 @@ expand_builtin_strncmp (exp, target, mode)
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));
+ const char *p = c_getstr (src);
+
+ /* If the string length is zero, return the dst parameter. */
+ if (p && *p == '\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)));
+ const char *p = c_getstr (src);
+
+ /* 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)
+ || (p && *p == '\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 requested len is greater than or equal to the string
+ length, call strcat. */
+ if (TREE_CODE (len) == INTEGER_CST && p
+ && compare_tree_int (len, strlen (p)) >= 0)
+ {
+ tree call_expr, newarglist =
+ tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src)),
+ fn = built_in_decls[BUILT_IN_STRCAT];
+
+ /* 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 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 (size_int (r), target, mode, EXPAND_NORMAL);
+ }
+
+ /* If the second argument is "", return 0. */
+ if (p2 && *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 (size_int (r), target, mode, EXPAND_NORMAL);
+ }
+
+ /* If the second argument is "", return __builtin_strlen(s1). */
+ if (p2 && *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. */
@@ -3127,6 +3335,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|| 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
@@ -3262,6 +3472,30 @@ expand_builtin (exp, target, subtarget, mode, ignore)
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;
+
case BUILT_IN_STRSTR:
target = expand_builtin_strstr (arglist, target, mode);
if (target)