cgraph.h (const_value_known_p): Replace by ...

* 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.

	* lto-partition.c (add_references_to_partition): Use
	ctor_for_folding.

	* gcc.dg/tree-ssa/attr-alias-2.c: New testcase.

From-SVN: r200211
This commit is contained in:
Jan Hubicka 2013-06-19 20:06:12 +02:00 committed by Jan Hubicka
parent 216c12abf6
commit 6a6dac5293
14 changed files with 223 additions and 111 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);
tree type = TREE_TYPE (TREE_TYPE (init));
enum machine_mode mode = TYPE_MODE (type);
/* 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);
}
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;

View File

@ -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:

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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" } } */

View File

@ -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. */

View File

@ -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;
/* Gimplifier takes away constructors of local vars */
if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
return DECL_INITIAL (decl) != NULL;
/* 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;
}
}
gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
/* 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;
/* 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.