aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2004-09-15 11:05:03 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2004-09-15 11:05:03 +0200
commita45f71f53768d5be6e5dac1906a3bd2bee19e38b (patch)
tree0cbdbd1cbd67bff87c68a499e533bf6a9938dc68
parent9a520f407392f0a984e7b74aa819e9f6eb3b0b90 (diff)
downloadgcc-a45f71f53768d5be6e5dac1906a3bd2bee19e38b.zip
gcc-a45f71f53768d5be6e5dac1906a3bd2bee19e38b.tar.gz
gcc-a45f71f53768d5be6e5dac1906a3bd2bee19e38b.tar.bz2
expr.c (string_constant): Handle also read-only variables initialized to string literals.
* 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
-rw-r--r--gcc/ChangeLog3
-rw-r--r--gcc/expr.c90
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c1
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c68
5 files changed, 148 insertions, 17 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cfa747b..0696e50 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/expr.c b/gcc/expr.c
index 83c8be5..e5ed2f6 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8cda9ff..d2d481d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..9753c24
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c
@@ -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
index 0000000..f912c02
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c
@@ -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;
+}