aboutsummaryrefslogtreecommitdiff
path: root/gcc/varasm.c
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2008-09-05 05:36:31 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2008-09-05 05:36:31 +0000
commit84320b0be2e9182ceeb110cebb98cd7006c484ab (patch)
tree196539a8298c9ee8421168b02df43b8032809556 /gcc/varasm.c
parent54193313580e8f4ced394e41cd8aa8f43597b09e (diff)
downloadgcc-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.c135
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: