diff options
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 3304b68..abb6747 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -108,6 +108,8 @@ static rtx expand_builtin_memset PARAMS ((tree)); static rtx expand_builtin_bzero PARAMS ((tree)); static rtx expand_builtin_strlen PARAMS ((tree, rtx, enum machine_mode)); +static rtx expand_builtin_strstr 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)); @@ -1431,6 +1433,64 @@ expand_builtin_strlen (exp, target, mode) } } +/* Expand a call to the strstr 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_strstr (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 len = c_strlen (s2); + + if (!len) + return 0; + + switch (compare_tree_int (len, 1)) + { + case -1: /* length is 0, return s1. */ + return expand_expr (s1, target, mode, EXPAND_NORMAL); + case 0: /* length is 1, return strchr(s1, s2[0]). */ + { + tree call_expr, fn = built_in_decls[BUILT_IN_STRCHR]; + + if (!fn) + return 0; + STRIP_NOPS (s2); + if (s2 && TREE_CODE (s2) == ADDR_EXPR) + s2 = TREE_OPERAND (s2, 0); + + /* New argument list transforming strstr(s1, s2) to + strchr(s1, s2[0]). */ + arglist = + build_tree_list (NULL_TREE, + build_int_2 (TREE_STRING_POINTER (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 strstr. */ + return 0; + default: + abort(); + } + } +} + /* Expand a call to the memcpy builtin, with arguments in ARGLIST. */ static rtx expand_builtin_memcpy (arglist) @@ -2475,6 +2535,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_STRCMP || fcode == BUILT_IN_FFS || fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS || fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC @@ -2603,6 +2664,12 @@ expand_builtin (exp, target, subtarget, mode, ignore) return target; break; + case BUILT_IN_STRSTR: + target = expand_builtin_strstr (arglist, target, mode); + if (target) + return target; + break; + case BUILT_IN_MEMCPY: target = expand_builtin_memcpy (arglist); if (target) @@ -2696,6 +2763,7 @@ expand_builtin (exp, target, subtarget, mode, ignore) case BUILT_IN_PUTS: case BUILT_IN_FPUTC: case BUILT_IN_FWRITE: + case BUILT_IN_STRCHR: break; case BUILT_IN_FPUTS: |