From 84320b0be2e9182ceeb110cebb98cd7006c484ab Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor <iant@google.com> Date: Fri, 5 Sep 2008 05:36:31 +0000 Subject: [PATCH] varasm.c (narrowing_initializer_constant_valid_p): New static function. ./: * varasm.c (narrowing_initializer_constant_valid_p): New static function. (initializer_constant_valid_p): Call it. testsuite/: * g++.dg/init/const7.C: New test. From-SVN: r140025 --- gcc/ChangeLog | 6 ++ gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/init/const7.C | 13 +++ gcc/varasm.c | 135 +++++++++++++++++------------ 4 files changed, 103 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/g++.dg/init/const7.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ecb3bdca277e..036e97bd92cc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2008-09-04 Ian Lance Taylor <iant@google.com> + + * varasm.c (narrowing_initializer_constant_valid_p): New + static function. + (initializer_constant_valid_p): Call it. + 2008-09-04 Jeff Law <law@redhat.com> * fold-const.c (native_encode_real): Fix computation of WORDS. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e2e111f7237f..35c2f992e516 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-09-04 Ian Lance Taylor <iant@google.com> + + * g++.dg/init/const7.C: New test. + 2008-09-04 Adam Nemet <anemet@caviumnetworks.com> * gcc.target/mips/seq-1.c: New test. diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C new file mode 100644 index 000000000000..18d04625db2d --- /dev/null +++ b/gcc/testsuite/g++.dg/init/const7.C @@ -0,0 +1,13 @@ +// { dg-do compile } +// { dg-options "-fdump-tree-gimple" } + +struct s { int x, y; }; +short offsets[1] = { + ((char*) &(((struct s*)16)->y) - (char *)16), +}; + +// This ensures that we get a dump whether or not the bug is present. +void fn() { } + +// { dg-final { scan-tree-dump-not "initialization" "gimple" } } +// { dg-final { cleanup-tree-dump "gimple" } } diff --git a/gcc/varasm.c b/gcc/varasm.c index 5aa0140e002a..5728d195e095 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -4063,6 +4063,73 @@ constructor_static_from_elts_p (const_tree ctor) && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor))); } +/* A subroutine of initializer_constant_valid_p. VALUE is either a + MINUS_EXPR or a POINTER_PLUS_EXPR, and ENDTYPE is a narrowing + conversion to something smaller than a pointer. This returns + null_pointer_node if the resulting value is an absolute constant + which can be used to initialize a static variable. Otherwise it + returns NULL. */ + +static tree +narrowing_initializer_constant_valid_p (tree value, tree endtype) +{ + tree op0, op1; + + op0 = TREE_OPERAND (value, 0); + op1 = TREE_OPERAND (value, 1); + + /* Like STRIP_NOPS except allow the operand mode to widen. This + works around a feature of fold that simplifies (int)(p1 - p2) to + ((int)p1 - (int)p2) under the theory that the narrower operation + is cheaper. */ + + while (CONVERT_EXPR_P (op0) + || TREE_CODE (op0) == NON_LVALUE_EXPR) + { + tree inner = TREE_OPERAND (op0, 0); + if (inner == error_mark_node + || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner))) + || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))) + > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner))))) + break; + op0 = inner; + } + + while (CONVERT_EXPR_P (op1) + || TREE_CODE (op1) == NON_LVALUE_EXPR) + { + tree inner = TREE_OPERAND (op1, 0); + if (inner == error_mark_node + || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner))) + || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1))) + > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner))))) + break; + op1 = inner; + } + + op0 = initializer_constant_valid_p (op0, endtype); + op1 = initializer_constant_valid_p (op1, endtype); + + /* Both initializers must be known. */ + if (op0 && op1) + { + if (op0 == op1) + return null_pointer_node; + + /* Support differences between labels. */ + if (TREE_CODE (op0) == LABEL_DECL + && TREE_CODE (op1) == LABEL_DECL) + return null_pointer_node; + + if (TREE_CODE (op0) == STRING_CST + && TREE_CODE (op1) == STRING_CST + && operand_equal_p (op0, op1, 1)) + return null_pointer_node; + } + + return NULL_TREE; +} + /* Return nonzero if VALUE is a valid constant-valued expression for use in initializing a static variable; one that can be an element of a "constant" initializer. @@ -4076,6 +4143,8 @@ constructor_static_from_elts_p (const_tree ctor) tree initializer_constant_valid_p (tree value, tree endtype) { + tree ret; + switch (TREE_CODE (value)) { case CONSTRUCTOR: @@ -4216,6 +4285,14 @@ initializer_constant_valid_p (tree value, tree endtype) if (valid1 == null_pointer_node) return valid0; } + + /* Support narrowing pointer differences. */ + if (TREE_CODE (value) == POINTER_PLUS_EXPR) + { + ret = narrowing_initializer_constant_valid_p (value, endtype); + if (ret != NULL_TREE) + return ret; + } break; case MINUS_EXPR: @@ -4244,62 +4321,10 @@ initializer_constant_valid_p (tree value, tree endtype) } /* Support narrowing differences. */ - if (INTEGRAL_TYPE_P (endtype)) - { - tree op0, op1; + ret = narrowing_initializer_constant_valid_p (value, endtype); + if (ret != NULL_TREE) + return ret; - op0 = TREE_OPERAND (value, 0); - op1 = TREE_OPERAND (value, 1); - - /* Like STRIP_NOPS except allow the operand mode to widen. - This works around a feature of fold that simplifies - (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory - that the narrower operation is cheaper. */ - - while (CONVERT_EXPR_P (op0) - || TREE_CODE (op0) == NON_LVALUE_EXPR) - { - tree inner = TREE_OPERAND (op0, 0); - if (inner == error_mark_node - || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner))) - || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))) - > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner))))) - break; - op0 = inner; - } - - while (CONVERT_EXPR_P (op1) - || TREE_CODE (op1) == NON_LVALUE_EXPR) - { - tree inner = TREE_OPERAND (op1, 0); - if (inner == error_mark_node - || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner))) - || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1))) - > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner))))) - break; - op1 = inner; - } - - op0 = initializer_constant_valid_p (op0, endtype); - op1 = initializer_constant_valid_p (op1, endtype); - - /* Both initializers must be known. */ - if (op0 && op1) - { - if (op0 == op1) - return null_pointer_node; - - /* Support differences between labels. */ - if (TREE_CODE (op0) == LABEL_DECL - && TREE_CODE (op1) == LABEL_DECL) - return null_pointer_node; - - if (TREE_CODE (op0) == STRING_CST - && TREE_CODE (op1) == STRING_CST - && operand_equal_p (op0, op1, 1)) - return null_pointer_node; - } - } break; default: -- GitLab