From ae808627c355ab7fd2a703b379af52ac76f3be73 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 28 Jun 2003 14:19:27 +0200 Subject: [PATCH] builtins.c (c_strlen): Add only_value argument. * builtins.c (c_strlen): Add only_value argument. Handle COND_EXPR and COMPOUND_EXPR. (expand_builtin_strlen): Optimize also strlen (i++ ? "foo" : "bar"). Adjust c_strlen callers. (expand_builtin_strcpy, expand_builtin_strncpy, expand_builtin_strcmp, expand_builtin_strncmp, expand_builtin_fputs, expand_builtin_sprintf, fold_builtin): Adjust c_strlen callers. * gcc.c-torture/execute/builtins/string-8.c: New test. * gcc.c-torture/execute/builtins/string-8-lib.c: New. * gcc.c-torture/execute/stdio-opt-1.c (main): Add new tests. * gcc.c-torture/execute/string-opt-7.c (main): Add new test. From-SVN: r68634 --- gcc/ChangeLog | 11 ++++ gcc/builtins.c | 61 +++++++++++++++---- gcc/testsuite/ChangeLog | 7 +++ .../execute/builtins/string-8-lib.c | 1 + .../gcc.c-torture/execute/builtins/string-8.c | 41 +++++++++++++ .../gcc.c-torture/execute/stdio-opt-1.c | 11 ++++ .../gcc.c-torture/execute/string-opt-7.c | 8 +++ 7 files changed, 127 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/builtins/string-8-lib.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/builtins/string-8.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e5e91095a71..565830330bc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2003-06-28 Jakub Jelinek + + * builtins.c (c_strlen): Add only_value argument. + Handle COND_EXPR and COMPOUND_EXPR. + (expand_builtin_strlen): Optimize also strlen (i++ ? "foo" : "bar"). + Adjust c_strlen callers. + (expand_builtin_strcpy, expand_builtin_strncpy, + expand_builtin_strcmp, expand_builtin_strncmp, + expand_builtin_fputs, expand_builtin_sprintf, + fold_builtin): Adjust c_strlen callers. + 2003-06-28 Josef Zlomek * bb-reorder.c (find_traces_1_round): Do not send basic block diff --git a/gcc/builtins.c b/gcc/builtins.c index 20ccda3dfe6..7297f676839 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -85,7 +85,7 @@ static REAL_VALUE_TYPE dconstpi; static REAL_VALUE_TYPE dconste; static int get_pointer_alignment (tree, unsigned int); -static tree c_strlen (tree); +static tree c_strlen (tree, int); static const char *c_getstr (tree); static rtx c_readstr (const char *, enum machine_mode); static int target_char_cast (tree, char *); @@ -242,19 +242,42 @@ get_pointer_alignment (tree exp, unsigned int max_align) way, because it could contain a zero byte in the middle. TREE_STRING_LENGTH is the size of the character array, not the string. + ONLY_VALUE should be non-zero if the result is not going to be emitted + into the instruction stream and zero if it si going to be expanded. + E.g. with i++ ? "foo" : "bar", if ONLY_VALUE is non-zero, constant 3 + is returned, otherwise NULL, since + len = c_strlen (src, 1); if (len) expand_expr (len, ...); would not + evaluate the side-effects. + The value returned is of type `ssizetype'. Unfortunately, string_constant can't access the values of const char arrays with initializers, so neither can we do so here. */ static tree -c_strlen (tree src) +c_strlen (tree src, int only_value) { tree offset_node; HOST_WIDE_INT offset; int max; const char *ptr; + STRIP_NOPS (src); + if (TREE_CODE (src) == COND_EXPR + && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0)))) + { + tree len1, len2; + + len1 = c_strlen (TREE_OPERAND (src, 1), only_value); + len2 = c_strlen (TREE_OPERAND (src, 2), only_value); + if (tree_int_cst_equal (len1, len2)) + return len1; + } + + if (TREE_CODE (src) == COMPOUND_EXPR + && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0)))) + return c_strlen (TREE_OPERAND (src, 1), only_value); + src = string_constant (src, &offset_node); if (src == 0) return 0; @@ -2176,10 +2199,22 @@ expand_builtin_strlen (tree arglist, rtx target, int align; /* If the length can be computed at compile-time, return it. */ - len = c_strlen (src); + len = c_strlen (src, 0); if (len) return expand_expr (len, target, target_mode, EXPAND_NORMAL); + /* If the length can be computed at compile-time and is constant + integer, but there are side-effects in src, evaluate + src for side-effects, then return len. + E.g. x = strlen (i++ ? "xfoo" + 1 : "bar"); + can be optimized into: i++; x = 3; */ + len = c_strlen (src, 1); + if (len && TREE_CODE (len) == INTEGER_CST) + { + expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL); + return expand_expr (len, target, target_mode, EXPAND_NORMAL); + } + align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT; /* If SRC is not a pointer type, don't do this operation inline. */ @@ -2759,7 +2794,7 @@ expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode) return 0; src = TREE_VALUE (TREE_CHAIN (arglist)); - len = c_strlen (src); + len = c_strlen (src, 1); if (len == 0 || TREE_SIDE_EFFECTS (len)) return 0; @@ -2802,7 +2837,7 @@ expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode) because the latter will potentially produce pessimized code when used to produce the return value. */ src = TREE_VALUE (TREE_CHAIN (arglist)); - if (! c_getstr (src) || ! (len = c_strlen (src))) + if (! c_getstr (src) || ! (len = c_strlen (src, 0))) return 0; dst = TREE_VALUE (arglist); @@ -2841,7 +2876,7 @@ expand_builtin_strncpy (tree arglist, rtx target, enum machine_mode mode) return 0; else { - tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist))); + tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1); tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); tree fn; @@ -3267,8 +3302,8 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) enum machine_mode insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; - len1 = c_strlen (arg1); - len2 = c_strlen (arg2); + len1 = c_strlen (arg1, 1); + len2 = c_strlen (arg2, 1); if (len1) len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); @@ -3414,8 +3449,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) enum machine_mode insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; - len1 = c_strlen (arg1); - len2 = c_strlen (arg2); + len1 = c_strlen (arg1, 1); + len2 = c_strlen (arg2, 1); if (len1) len1 = size_binop (PLUS_EXPR, ssize_int (1), len1); @@ -4210,7 +4245,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked) /* Get the length of the string passed to fputs. If the length can't be determined, punt. */ - if (!(len = c_strlen (TREE_VALUE (arglist))) + if (!(len = c_strlen (TREE_VALUE (arglist), 1)) || TREE_CODE (len) != INTEGER_CST) return 0; @@ -4549,7 +4584,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) if (target != const0_rtx) { - len = c_strlen (arg); + len = c_strlen (arg, 1); if (! len || TREE_CODE (len) != INTEGER_CST) return 0; } @@ -5441,7 +5476,7 @@ fold_builtin (tree exp) case BUILT_IN_STRLEN: if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) { - tree len = c_strlen (TREE_VALUE (arglist)); + tree len = c_strlen (TREE_VALUE (arglist), 0); if (len) { /* Convert from the internal "sizetype" type to "size_t". */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e551aae327a..bc2058a0ee2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2003-06-28 Jakub Jelinek + + * gcc.c-torture/execute/builtins/string-8.c: New test. + * gcc.c-torture/execute/builtins/string-8-lib.c: New. + * gcc.c-torture/execute/stdio-opt-1.c (main): Add new tests. + * gcc.c-torture/execute/string-opt-7.c (main): Add new test. + 2003-06-27 Mark Mitchell PR c++/10468 diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/string-8-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/string-8-lib.c new file mode 100644 index 00000000000..9753c2498f1 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/string-8-lib.c @@ -0,0 +1 @@ +#include "lib/strlen.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/string-8.c b/gcc/testsuite/gcc.c-torture/execute/builtins/string-8.c new file mode 100644 index 00000000000..220b6ed8e2e --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/string-8.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Test strlen optimizations on conditional expressions. + + Written by Jakub Jelinek, June 23, 2003. */ + +typedef __SIZE_TYPE__ size_t; +extern char *strcpy (char *, const char *); +extern int memcmp (const void *, const void *, size_t); +extern void abort (void); +extern void exit (int); +extern int inside_main; + +size_t g, h, i, j, k, l; + +size_t +foo (void) +{ + if (l) + abort (); + return ++l; +} + +void +main_test (void) +{ + if (strlen (i ? "foo" + 1 : j ? "bar" + 1 : "baz" + 1) != 2) + abort (); + if (strlen (g++ ? "foo" : "bar") != 3 || g != 1) + abort (); + if (strlen (h++ ? "xfoo" + 1 : "bar") != 3 || h != 1) + abort (); + if (strlen ((i++, "baz")) != 3 || i != 1) + abort (); + /* The following calls might not optimize strlen call away. */ + inside_main = 0; + if (strlen (j ? "foo" + k++ : "bar" + k++) != 3 || k != 1) + abort (); + if (strlen (foo () ? "foo" : "bar") != 3 || l != 1) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/stdio-opt-1.c b/gcc/testsuite/gcc.c-torture/execute/stdio-opt-1.c index fc43c5721e8..8cfb4ebe08e 100644 --- a/gcc/testsuite/gcc.c-torture/execute/stdio-opt-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/stdio-opt-1.c @@ -12,6 +12,8 @@ extern void abort(void); If stdio.h provides one, that is okay. */ extern int fputs(); +int i; + int main() { FILE *s_array[] = {stdout, NULL}, **s_ptr = s_array; @@ -51,6 +53,15 @@ int main() __builtin_fputc ('\n', *s_ptr); __builtin_fwrite ("hello\n", 1, 6, *s_ptr); + /* Check side-effects in conditional expression. */ + s_ptr = s_array; + fputs (i++ ? "f" : "x", *s_ptr++); + if (s_ptr != s_array+1 || *s_ptr != 0 || i != 1) + abort(); + fputs (--i ? "\n" : "\n", *--s_ptr); + if (s_ptr != s_array || i != 0) + abort(); + return 0; } diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-7.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-7.c index ed1b2a4095a..5b915d7a7d3 100644 --- a/gcc/testsuite/gcc.c-torture/execute/string-opt-7.c +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-7.c @@ -12,6 +12,8 @@ extern int strcmp (const char *, const char *); extern int strncmp (const char *, const char *, size_t); extern void *memset (void *, int, size_t); +int i; + int main () { const char *const src = "hello world"; @@ -62,6 +64,12 @@ int main () if (__builtin_strncpy (dst, src, 4) != dst || strncmp (dst, src, 4)) abort(); + memset (dst, 0, sizeof (dst)); + if (strncpy (dst, i++ ? "xfoo" + 1 : "bar", 4) != dst + || strcmp (dst, "bar") + || i != 1) + abort (); + return 0; }