aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/cgraph.h2
-rw-r--r--gcc/cgraphunit.c3
-rw-r--r--gcc/expr.c132
-rw-r--r--gcc/gimple-fold.c27
-rw-r--r--gcc/ipa-inline-analysis.c3
-rw-r--r--gcc/ipa.c9
-rw-r--r--gcc/lto-cgraph.c7
-rw-r--r--gcc/lto/ChangeLog5
-rw-r--r--gcc/lto/lto-partition.c2
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/attr-alias-2.c30
-rw-r--r--gcc/tree-ssa-loop-ivcanon.c2
-rw-r--r--gcc/varpool.c90
14 files changed, 224 insertions, 112 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8b6bc6f..b2c2ee7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2013-06-19 Jan Hubicka <jh@suse.cz>
+
+ * cgraph.h (const_value_known_p): Replace by ...
+ (ctor_for_folding): .. this one.
+ * cgraphunit.c (process_function_and_variable_attributes): Use it.
+ * lto-cgraph.c (compute_ltrans_boundary): Use ctor_for_folding.
+ * expr.c (expand_expr_real_1): Likewise.
+ (string_constant): Likewise.
+ * tree-ssa-loop-ivcanon.c (constant_after_peeling): Likewise.
+ * ipa.c (process_references): Likewise.
+ (symtab_remove_unreachable_nodes): Likewise.
+ * ipa-inline-analysis.c (param_change_prob): Likewise.
+ * gimple-fold.c (canonicalize_constructor_val): Likewise.
+ (get_base_constructor): Likwise.
+ * varpool.c (varpool_remove_node): Likewise.
+ (varpool_remove_initializer): LIkewise.
+ (dump_varpool_node): LIkwise.
+ (const_value_known_p): Rewrite to ...
+ (ctor_for_folding): ... this one.
+
2013-06-19 Jakub Jelinek <jakub@redhat.com>
PR driver/57651
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 6259189..ef2a2a0 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -797,7 +797,7 @@ void varpool_analyze_node (struct varpool_node *);
struct varpool_node * varpool_extra_name_alias (tree, tree);
struct varpool_node * varpool_create_variable_alias (tree, tree);
void varpool_reset_queue (void);
-bool const_value_known_p (tree);
+tree ctor_for_folding (tree);
bool varpool_for_node_and_aliases (struct varpool_node *,
bool (*) (struct varpool_node *, void *),
void *, bool);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 51365eb..731a0e9 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -762,8 +762,7 @@ process_function_and_variable_attributes (struct cgraph_node *first,
{
tree decl = vnode->symbol.decl;
if (DECL_EXTERNAL (decl)
- && DECL_INITIAL (decl)
- && const_value_known_p (decl))
+ && DECL_INITIAL (decl))
varpool_finalize_decl (decl);
if (DECL_PRESERVE_P (decl))
vnode->symbol.force_output = true;
diff --git a/gcc/expr.c b/gcc/expr.c
index 2a7824b..bce96c9 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9698,6 +9698,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
{
tree array = treeop0;
tree index = treeop1;
+ tree init;
/* Fold an expression like: "foo"[2].
This is not done in fold so it won't happen inside &.
@@ -9744,76 +9745,72 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_MEMORY
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
- && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
- && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
- && const_value_known_p (array))
+ && TREE_CODE (index) == INTEGER_CST
+ && (TREE_CODE (array) == VAR_DECL
+ || TREE_CODE (array) == CONST_DECL)
+ && (init = ctor_for_folding (array)) != error_mark_node)
{
- if (TREE_CODE (index) == INTEGER_CST)
+ if (TREE_CODE (init) == CONSTRUCTOR)
{
- tree init = DECL_INITIAL (array);
+ unsigned HOST_WIDE_INT ix;
+ tree field, value;
- if (TREE_CODE (init) == CONSTRUCTOR)
- {
- unsigned HOST_WIDE_INT ix;
- tree field, value;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+ field, value)
+ if (tree_int_cst_equal (field, index))
+ {
+ if (TREE_SIDE_EFFECTS (value))
+ break;
- FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
- field, value)
- if (tree_int_cst_equal (field, index))
+ if (TREE_CODE (value) == CONSTRUCTOR)
{
- if (TREE_SIDE_EFFECTS (value))
+ /* If VALUE is a CONSTRUCTOR, this
+ optimization is only useful if
+ this doesn't store the CONSTRUCTOR
+ into memory. If it does, it is more
+ efficient to just load the data from
+ the array directly. */
+ rtx ret = expand_constructor (value, target,
+ modifier, true);
+ if (ret == NULL_RTX)
break;
-
- if (TREE_CODE (value) == CONSTRUCTOR)
- {
- /* If VALUE is a CONSTRUCTOR, this
- optimization is only useful if
- this doesn't store the CONSTRUCTOR
- into memory. If it does, it is more
- efficient to just load the data from
- the array directly. */
- rtx ret = expand_constructor (value, target,
- modifier, true);
- if (ret == NULL_RTX)
- break;
- }
-
- return expand_expr (fold (value), target, tmode,
- modifier);
}
- }
- else if(TREE_CODE (init) == STRING_CST)
+
+ return expand_expr (fold (value), target, tmode,
+ modifier);
+ }
+ }
+ else if(TREE_CODE (init) == STRING_CST)
+ {
+ tree index1 = index;
+ tree low_bound = array_ref_low_bound (exp);
+ index1 = fold_convert_loc (loc, sizetype,
+ treeop1);
+
+ /* Optimize the special-case of a zero lower bound.
+
+ We convert the low_bound to sizetype to avoid some problems
+ with constant folding. (E.g. suppose the lower bound is 1,
+ and its mode is QI. Without the conversion,l (ARRAY
+ +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
+ +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */
+
+ if (! integer_zerop (low_bound))
+ index1 = size_diffop_loc (loc, index1,
+ fold_convert_loc (loc, sizetype,
+ low_bound));
+
+ if (0 > compare_tree_int (index1,
+ TREE_STRING_LENGTH (init)))
{
- tree index1 = index;
- tree low_bound = array_ref_low_bound (exp);
- index1 = fold_convert_loc (loc, sizetype,
- treeop1);
-
- /* Optimize the special-case of a zero lower bound.
-
- We convert the low_bound to sizetype to avoid some problems
- with constant folding. (E.g. suppose the lower bound is 1,
- and its mode is QI. Without the conversion,l (ARRAY
- +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
- +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */
-
- if (! integer_zerop (low_bound))
- index1 = size_diffop_loc (loc, index1,
- fold_convert_loc (loc, sizetype,
- low_bound));
-
- if (0 > compare_tree_int (index1,
- TREE_STRING_LENGTH (init)))
- {
- tree type = TREE_TYPE (TREE_TYPE (init));
- enum machine_mode mode = TYPE_MODE (type);
-
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) == 1)
- return gen_int_mode (TREE_STRING_POINTER (init)
- [TREE_INT_CST_LOW (index1)],
- mode);
- }
+ tree type = TREE_TYPE (TREE_TYPE (init));
+ enum machine_mode mode = TYPE_MODE (type);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) == 1)
+ return gen_int_mode (TREE_STRING_POINTER (init)
+ [TREE_INT_CST_LOW (index1)],
+ mode);
}
}
}
@@ -10676,17 +10673,18 @@ string_constant (tree arg, tree *ptr_offset)
|| TREE_CODE (array) == CONST_DECL)
{
int length;
+ tree init = ctor_for_folding (array);
/* Variables initialized to string literals can be handled too. */
- if (!const_value_known_p (array)
- || !DECL_INITIAL (array)
- || TREE_CODE (DECL_INITIAL (array)) != STRING_CST)
+ if (init == error_mark_node
+ || !init
+ || TREE_CODE (init) != STRING_CST)
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
+ || (length = TREE_STRING_LENGTH (init)) <= 0
|| compare_tree_int (DECL_SIZE_UNIT (array), length) < 0)
return 0;
@@ -10699,7 +10697,7 @@ string_constant (tree arg, tree *ptr_offset)
return 0;
*ptr_offset = offset;
- return DECL_INITIAL (array);
+ return init;
}
return 0;
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 60fca6b..b6d22b3 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -192,9 +192,9 @@ canonicalize_constructor_val (tree cval, tree from_decl)
tree
get_symbol_constant_value (tree sym)
{
- if (const_value_known_p (sym))
+ tree val = ctor_for_folding (sym);
+ if (val != error_mark_node)
{
- tree val = DECL_INITIAL (sym);
if (val)
{
val = canonicalize_constructor_val (unshare_expr (val), sym);
@@ -2695,19 +2695,18 @@ get_base_constructor (tree base, HOST_WIDE_INT *bit_offset,
switch (TREE_CODE (base))
{
case VAR_DECL:
- if (!const_value_known_p (base))
- return NULL_TREE;
-
- /* Fallthru. */
case CONST_DECL:
- if (!DECL_INITIAL (base)
- && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
- return error_mark_node;
- /* Do not return an error_mark_node DECL_INITIAL. LTO uses this
- as special marker (_not_ zero ...) for its own purposes. */
- if (DECL_INITIAL (base) == error_mark_node)
- return NULL_TREE;
- return DECL_INITIAL (base);
+ {
+ tree init = ctor_for_folding (base);
+
+ /* Our semantic is exact oposite of ctor_for_folding;
+ NULL means unknown, while error_mark_node is 0. */
+ if (init == error_mark_node)
+ return NULL_TREE;
+ if (!init)
+ return error_mark_node;
+ return init;
+ }
case ARRAY_REF:
case COMPONENT_REF:
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index a25f517..9a36292 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -2106,8 +2106,9 @@ param_change_prob (gimple stmt, int i)
struct record_modified_bb_info info;
bitmap_iterator bi;
unsigned index;
+ tree init = ctor_for_folding (base);
- if (const_value_known_p (base))
+ if (init != error_mark_node)
return 0;
if (!bb->frequency)
return REG_BR_PROB_BASE;
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 0f2a5c8..7c0d495 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -145,7 +145,9 @@ process_references (struct ipa_ref_list *list,
constant folding. Keep references alive so partitioning
knows about potential references. */
|| (TREE_CODE (node->symbol.decl) == VAR_DECL
- && flag_wpa && const_value_known_p (node->symbol.decl)))))
+ && flag_wpa
+ && ctor_for_folding (node->symbol.decl)
+ != error_mark_node))))
pointer_set_insert (reachable, node);
enqueue_node ((symtab_node) node, first, reachable);
}
@@ -400,6 +402,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
}
else if (!pointer_set_contains (reachable, vnode))
{
+ tree init;
if (vnode->symbol.definition)
{
if (file)
@@ -411,8 +414,10 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
vnode->symbol.aux = NULL;
/* Keep body if it may be useful for constant folding. */
- if (!const_value_known_p (vnode->symbol.decl))
+ if ((init = ctor_for_folding (vnode->symbol.decl)) == error_mark_node)
varpool_remove_initializer (vnode);
+ else
+ DECL_INITIAL (vnode->symbol.decl) = init;
ipa_remove_all_references (&vnode->symbol.ref_list);
}
else
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index e3f8880..2122f70 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -766,10 +766,9 @@ compute_ltrans_boundary (lto_symtab_encoder_t in_encoder)
symtab_node node = lto_symtab_encoder_deref (encoder, i);
if (varpool_node *vnode = dyn_cast <varpool_node> (node))
{
- if (DECL_INITIAL (vnode->symbol.decl)
- && !lto_symtab_encoder_encode_initializer_p (encoder,
- vnode)
- && const_value_known_p (vnode->symbol.decl))
+ if (!lto_symtab_encoder_encode_initializer_p (encoder,
+ vnode)
+ && ctor_for_folding (vnode->symbol.decl) != error_mark_node)
{
lto_set_symtab_encoder_encode_initializer (encoder, vnode);
add_references (encoder, &vnode->symbol.ref_list);
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index aeda657..2723678 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,8 @@
+2013-06-19 Jan Hubicka <jh@suse.cz>
+
+ * lto-partition.c (add_references_to_partition): Use
+ ctor_for_folding.
+
2013-06-18 Richard Biener <rguenther@suse.de>
* lto.c (lto_register_var_decl_in_symtab): Pass in cache index
diff --git a/gcc/lto/lto-partition.c b/gcc/lto/lto-partition.c
index 6f45380..ffc8da3 100644
--- a/gcc/lto/lto-partition.c
+++ b/gcc/lto/lto-partition.c
@@ -146,7 +146,7 @@ add_references_to_partition (ltrans_partition part, symtab_node node)
Recursively look into the initializers of the constant variable and add
references, too. */
else if (is_a <varpool_node> (ref->referred)
- && const_value_known_p (ref->referred->symbol.decl)
+ && ctor_for_folding (ref->referred->symbol.decl) != error_mark_node
&& !lto_symtab_encoder_in_partition_p (part->encoder, ref->referred))
{
if (!part->initializers_visited)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f731837..baae9b9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2013-06-19 Jan Hubicka <jh@suse.cz>
+
+ * gcc.dg/tree-ssa/attr-alias-2.c: New testcase.
+
2013-06-19 Balaji V. Iyer <balaji.v.iyer@intel.com>
* c-c++-common/cilk-plus/AN/builtin_fn_custom.c: Replaced all the
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/attr-alias-2.c b/gcc/testsuite/gcc.dg/tree-ssa/attr-alias-2.c
new file mode 100644
index 0000000..50623a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/attr-alias-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+static int a=4;
+static int b __attribute__ ((alias("a")));
+main()
+{
+ return b+a;
+}
+/* { dg-final { scan-tree-dump "return 8" "optimized" } } */
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+static int a=4;
+static int b __attribute__ ((alias("a")));
+main()
+{
+ return b+a;
+}
+/* { dg-final { scan-tree-dump "return 8" "optimized" } } */
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+static int a=4;
+static int b __attribute__ ((alias("a")));
+main()
+{
+ return b+a;
+}
+/* { dg-final { scan-tree-dump "return 8" "optimized" } } */
diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
index 45774e6..91cf8c1 100644
--- a/gcc/tree-ssa-loop-ivcanon.c
+++ b/gcc/tree-ssa-loop-ivcanon.c
@@ -174,7 +174,7 @@ constant_after_peeling (tree op, gimple stmt, struct loop *loop)
while (handled_component_p (base))
base = TREE_OPERAND (base, 0);
if ((DECL_P (base)
- && const_value_known_p (base))
+ && ctor_for_folding (base) != error_mark_node)
|| CONSTANT_CLASS_P (base))
{
/* If so, see if we understand all the indices. */
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 80e98b3..b426757 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -66,12 +66,15 @@ void
varpool_remove_node (struct varpool_node *node)
{
symtab_unregister_node ((symtab_node)node);
+ tree init;
/* Because we remove references from external functions before final compilation,
we may end up removing useful constructors.
FIXME: We probably want to trace boundaries better. */
- if (!const_value_known_p (node->symbol.decl))
+ if ((init = ctor_for_folding (node->symbol.decl)) == error_mark_node)
varpool_remove_initializer (node);
+ else
+ DECL_INITIAL (node->symbol.decl) = init;
ggc_free (node);
}
@@ -109,7 +112,7 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
fprintf (f, " output");
if (TREE_READONLY (node->symbol.decl))
fprintf (f, " read-only");
- if (const_value_known_p (node->symbol.decl))
+ if (ctor_for_folding (node->symbol.decl) != error_mark_node)
fprintf (f, " const-value-known");
fprintf (f, "\n");
}
@@ -144,44 +147,93 @@ varpool_node_for_asm (tree asmname)
}
/* Return if DECL is constant and its initial value is known (so we can do
- constant folding using DECL_INITIAL (decl)). */
+ constant folding using DECL_INITIAL (decl)).
+ Return ERROR_MARK_NODE when value is unknown. */
-bool
-const_value_known_p (tree decl)
+tree
+ctor_for_folding (tree decl)
{
+ struct varpool_node *node, *real_node;
+ tree real_decl;
+
if (TREE_CODE (decl) != VAR_DECL
- &&TREE_CODE (decl) != CONST_DECL)
- return false;
+ && TREE_CODE (decl) != CONST_DECL)
+ return error_mark_node;
if (TREE_CODE (decl) == CONST_DECL
|| DECL_IN_CONSTANT_POOL (decl))
- return true;
+ return DECL_INITIAL (decl);
+
+ if (TREE_THIS_VOLATILE (decl))
+ return error_mark_node;
+
+ /* Do not care about automatic variables. Those are never initialized
+ anyway, because gimplifier exapnds the code*/
+ if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+ {
+ gcc_assert (!TREE_PUBLIC (decl));
+ return error_mark_node;
+ }
gcc_assert (TREE_CODE (decl) == VAR_DECL);
- if (!TREE_READONLY (decl) || TREE_THIS_VOLATILE (decl))
- return false;
+ node = varpool_get_node (decl);
+ if (node)
+ {
+ real_node = varpool_variable_node (node);
+ real_decl = real_node->symbol.decl;
+ }
+ else
+ real_decl = decl;
+
+ /* See if we are dealing with alias.
+ In most cases alias is just alternative symbol pointing to a given
+ constructor. This allows us to use interposition rules of DECL
+ constructor of REAL_NODE. However weakrefs are special by being just
+ alternative name of their target (if defined). */
+ if (decl != real_decl)
+ {
+ gcc_assert (!DECL_INITIAL (decl)
+ || DECL_INITIAL (decl) == error_mark_node);
+ if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl)))
+ {
+ node = varpool_alias_target (node);
+ decl = node->symbol.decl;
+ }
+ }
- /* Gimplifier takes away constructors of local vars */
- if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
- return DECL_INITIAL (decl) != NULL;
+ /* Vtables are defined by their types and must match no matter of interposition
+ rules. */
+ if (DECL_VIRTUAL_P (real_decl))
+ {
+ gcc_checking_assert (TREE_READONLY (real_decl));
+ return DECL_INITIAL (real_decl);
+ }
+
+ /* If thre is no constructor, we have nothing to do. */
+ if (DECL_INITIAL (real_decl) == error_mark_node)
+ return error_mark_node;
- gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
+ /* Non-readonly alias of readonly variable is also de-facto readonly,
+ because the variable itself is in readonly section.
+ We also honnor READONLY flag on alias assuming that user knows
+ what he is doing. */
+ if (!TREE_READONLY (decl) && !TREE_READONLY (real_decl))
+ return error_mark_node;
/* Variables declared 'const' without an initializer
have zero as the initializer if they may not be
overridden at link or run time. */
- if (!DECL_INITIAL (decl)
- && (DECL_EXTERNAL (decl)
- || decl_replaceable_p (decl)))
- return false;
+ if (!DECL_INITIAL (real_decl)
+ && (DECL_EXTERNAL (decl) || decl_replaceable_p (decl)))
+ return error_mark_node;
/* Variables declared `const' with an initializer are considered
to not be overwritable with different initializer by default.
??? Previously we behaved so for scalar variables but not for array
accesses. */
- return true;
+ return DECL_INITIAL (real_decl);
}
/* Add the variable DECL to the varpool.