]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
builtins.c (c_strlen): Add only_value argument.
authorJakub Jelinek <jakub@redhat.com>
Sat, 28 Jun 2003 12:19:27 +0000 (14:19 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Sat, 28 Jun 2003 12:19:27 +0000 (14:19 +0200)
* 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
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/builtins/string-8-lib.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/builtins/string-8.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/stdio-opt-1.c
gcc/testsuite/gcc.c-torture/execute/string-opt-7.c

index e5e91095a71b55752fc66d67c9a2cb2b81c57388..565830330bce3be5d8b1278a6116459db7f997a0 100644 (file)
@@ -1,3 +1,14 @@
+2003-06-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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  <zlomekj@suse.cz>
 
        * bb-reorder.c (find_traces_1_round): Do not send basic block
index 20ccda3dfe6c8f4484bdb2790353ab0dc2c3fcb6..7297f676839c5c06f9c68da3ab71ab7d20b670a7 100644 (file)
@@ -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".  */
index e551aae327aa096ef6c1b875884dbad19bd21735..bc2058a0ee2f0521183efe8f8fe3d89b64500844 100644 (file)
@@ -1,3 +1,10 @@
+2003-06-28  Jakub Jelinek  <jakub@redhat.com>
+
+       * 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  <mark@codesourcery.com>
 
        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 (file)
index 0000000..9753c24
--- /dev/null
@@ -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 (file)
index 0000000..220b6ed
--- /dev/null
@@ -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 ();
+}
index fc43c5721e883ebc5444ba4e2b462ddd5093cc4f..8cfb4ebe08ea30da0e99ba1cc1fa3236c9add18e 100644 (file)
@@ -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;
 }
 
index ed1b2a4095ab5f4478f787b88b25006c0c72cc93..5b915d7a7d33f8437aff926e1cc8f6f335338ed7 100644 (file)
@@ -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;
 }