diff options
author | Ian Lance Taylor <iant@google.com> | 2008-09-05 05:36:31 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2008-09-05 05:36:31 +0000 |
commit | 84320b0be2e9182ceeb110cebb98cd7006c484ab (patch) | |
tree | 196539a8298c9ee8421168b02df43b8032809556 /gcc/varasm.c | |
parent | 54193313580e8f4ced394e41cd8aa8f43597b09e (diff) | |
download | gcc-84320b0be2e9182ceeb110cebb98cd7006c484ab.zip gcc-84320b0be2e9182ceeb110cebb98cd7006c484ab.tar.gz gcc-84320b0be2e9182ceeb110cebb98cd7006c484ab.tar.bz2 |
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
Diffstat (limited to 'gcc/varasm.c')
-rw-r--r-- | gcc/varasm.c | 135 |
1 files changed, 80 insertions, 55 deletions
diff --git a/gcc/varasm.c b/gcc/varasm.c index 5aa0140..5728d19 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: |