expr.c (string_constant): Handle also read-only variables initialized to string literals.
authorJakub Jelinek <jakub@redhat.com>
Wed, 15 Sep 2004 09:05:03 +0000 (11:05 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 15 Sep 2004 09:05:03 +0000 (11:05 +0200)
* expr.c (string_constant): Handle also read-only variables
initialized to string literals.

* gcc.c-torture/execute/builtins/strlen-3.c: New test.
* gcc.c-torture/execute/builtins/strlen-3-lib.c: New.

From-SVN: r87540

gcc/ChangeLog
gcc/expr.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c [new file with mode: 0644]

index cfa747bbb608b74fe7b87ce397e1df55f8a773dc..0696e50aa768849c157ab7a7204dd7095c48496f 100644 (file)
@@ -1,5 +1,8 @@
 2004-09-15  Jakub Jelinek  <jakub@redhat.com>
 
+       * expr.c (string_constant): Handle also read-only variables
+       initialized to string literals.
+
        * builtins.c (expand_builtin_memmove): Optimize memmove (x, y, 1)
        into memcpy (x, y, 1) if memcpy can be expanded inline.
 
index 83c8be5240f5986ddd0224c0c9667cb1c669b6aa..e5ed2f654c504dea67c8813d11ba49fb8d5f6b74 100644 (file)
@@ -8299,20 +8299,31 @@ is_aligning_offset (tree offset, tree exp)
 tree
 string_constant (tree arg, tree *ptr_offset)
 {
+  tree array, offset;
   STRIP_NOPS (arg);
 
-  if (TREE_CODE (arg) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
+  if (TREE_CODE (arg) == ADDR_EXPR)
     {
-      *ptr_offset = size_zero_node;
-      return TREE_OPERAND (arg, 0);
-    }
-  if (TREE_CODE (arg) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
-      && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)) == STRING_CST)
-    {
-      *ptr_offset = convert (sizetype, TREE_OPERAND (TREE_OPERAND (arg, 0), 1));
-      return TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+      if (TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
+       {
+         *ptr_offset = size_zero_node;
+         return TREE_OPERAND (arg, 0);
+       }
+      else if (TREE_CODE (TREE_OPERAND (arg, 0)) == VAR_DECL)
+       {
+         array = TREE_OPERAND (arg, 0);
+         offset = size_zero_node;
+       }
+      else if (TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
+       {
+         array = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+         offset = TREE_OPERAND (TREE_OPERAND (arg, 0), 1);
+         if (TREE_CODE (array) != STRING_CST
+             && TREE_CODE (array) != VAR_DECL)
+           return 0;
+       }
+      else
+       return 0;
     }
   else if (TREE_CODE (arg) == PLUS_EXPR)
     {
@@ -8323,17 +8334,62 @@ string_constant (tree arg, tree *ptr_offset)
       STRIP_NOPS (arg1);
 
       if (TREE_CODE (arg0) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST)
+         && (TREE_CODE (TREE_OPERAND (arg0, 0)) == STRING_CST
+             || TREE_CODE (TREE_OPERAND (arg0, 0)) == VAR_DECL))
        {
-         *ptr_offset = convert (sizetype, arg1);
-         return TREE_OPERAND (arg0, 0);
+         array = TREE_OPERAND (arg0, 0);
+         offset = arg1;
        }
       else if (TREE_CODE (arg1) == ADDR_EXPR
-              && TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST)
+              && (TREE_CODE (TREE_OPERAND (arg1, 0)) == STRING_CST
+                  || TREE_CODE (TREE_OPERAND (arg1, 0)) == VAR_DECL))
        {
-         *ptr_offset = convert (sizetype, arg0);
-         return TREE_OPERAND (arg1, 0);
+         array = TREE_OPERAND (arg1, 0);
+         offset = arg0;
        }
+      else
+       return 0;
+    }
+  else
+    return 0;
+
+  if (TREE_CODE (array) == STRING_CST)
+    {
+      *ptr_offset = convert (sizetype, offset);
+      return array;
+    }
+  else if (TREE_CODE (array) == VAR_DECL)
+    {
+      int length;
+
+      /* Variables initialized to string literals can be handled too.  */
+      if (DECL_INITIAL (array) == NULL_TREE
+         || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
+       return 0;
+
+      /* If they are read-only, non-volatile and bind locally.  */
+      if (! TREE_READONLY (array)
+         || TREE_SIDE_EFFECTS (array)
+         || ! targetm.binds_local_p (array))
+       return 0;
+
+      /* Avoid const char foo[4] = "abcde";  */
+      if (DECL_SIZE_UNIT (array) == NULL_TREE
+         || TREE_CODE (DECL_SIZE_UNIT (array)) != INTEGER_CST
+         || (length = TREE_STRING_LENGTH (DECL_INITIAL (array))) <= 0
+         || compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
+       return 0;
+
+      /* If variable is bigger than the string literal, OFFSET must be constant
+        and inside of the bounds of the string literal.  */
+      offset = convert (sizetype, offset);
+      if (compare_tree_int (DECL_SIZE_UNIT (array), length) > 0
+         && (! host_integerp (offset, 1)
+             || compare_tree_int (offset, length) >= 0))
+       return 0;
+
+      *ptr_offset = offset;
+      return DECL_INITIAL (array);
     }
 
   return 0;
index 8cda9ffb6893aa1c351bf49289aa48ec3f4cb54a..d2d481d14013745ba113ce2bf049cb713e719d6d 100644 (file)
@@ -1,5 +1,8 @@
 2004-09-15  Jakub Jelinek  <jakub@redhat.com>
 
+       * gcc.c-torture/execute/builtins/strlen-3.c: New test.
+       * gcc.c-torture/execute/builtins/strlen-3-lib.c: New.
+
        * gcc.c-torture/execute/builtins/memmove.c (main_test): Formatting.
        * gcc.c-torture/execute/builtins/memmove-2.c: New test.
        * gcc.c-torture/execute/builtins/memmove-2-lib.c: New.
diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-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/strlen-3.c b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c
new file mode 100644 (file)
index 0000000..f912c02
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2004  Free Software Foundation.
+
+   Test strlen on const variables initialized to string literals.
+
+   Written by Jakub Jelinek, 9/14/2004.  */
+
+extern void abort (void);
+extern __SIZE_TYPE__ strlen (const char *);
+extern char *strcpy (char *, const char *);
+const char bar[] = "Hello, World!";
+const char baz[] = "hello, world?";
+const char larger[20] = "short string";
+extern volatile int inside_main;
+
+int l1 = 1;
+int x = 6;
+
+void
+main_test(void)
+{
+  const char *foo;
+  int i;
+
+  if (strlen (bar) != 13)
+    abort ();
+
+  if (strlen (bar + 3) != 10)
+    abort ();
+
+  if (strlen (&bar[6]) != 7)
+    abort ();
+
+  if (strlen (bar + (x++ & 7)) != 7)
+    abort ();
+  if (x != 7)
+    abort ();
+
+#ifdef __OPTIMIZE__
+  foo = bar;
+  for (i = 0; i < 4; ++i)
+    {
+      if (i == l1 - 1)
+       foo = "HELLO, WORLD!";
+      else if (i == l1)
+       foo = bar;
+      else if (i == l1 + 1)
+       foo = "hello, world!";
+      else
+       foo = baz;
+    }
+  if (strlen (foo) != 13)
+    abort ();
+#endif
+
+  if (strlen (larger) != 12)
+    abort ();
+  if (strlen (&larger[10]) != 2)
+    abort ();
+
+  inside_main = 0;
+  /* This will result in strlen call, because larger
+     array is bigger than its initializer.  */
+  if (strlen (larger + (x++ & 7)) != 5)
+    abort ();
+  if (x != 8)
+    abort ();
+  inside_main = 1;
+}