diff options
author | Jakub Jelinek <jakub@redhat.com> | 2004-09-15 11:05:03 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2004-09-15 11:05:03 +0200 |
commit | a45f71f53768d5be6e5dac1906a3bd2bee19e38b (patch) | |
tree | 0cbdbd1cbd67bff87c68a499e533bf6a9938dc68 | |
parent | 9a520f407392f0a984e7b74aa819e9f6eb3b0b90 (diff) | |
download | gcc-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/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/expr.c | 90 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3-lib.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/builtins/strlen-3.c | 68 |
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. @@ -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; +} |