On Mon, Jun 17, 2013 at 11:53 AM, Jan Hubicka <hubi...@ucw.cz> wrote: > Hi, > this patch makes it possible to fold through aliases. It may seem > unimportant, but we > run into those cases in C++ where extra name aliases may get used by > devirtualization > machinery. The patch also fixes the following long standing bug: > jh@gcc10:~/trunk/build2/gcc$ cat t.c > static int a=4; > static int b __attribute__ ((alias("a"))); > main() > { > return b+a; > }
The gimple alias machinery also happily treats a and b as different decls btw (so does the PTA code). To fix that the lookups have to be fast (no hashtable query at least for the case where there is no alias). Richard. > jh@gcc10:~/trunk/build2/gcc$ gcc -O2 t.c -S > jh@gcc10:~/trunk/build2/gcc$ more t.s > .file "t.c" > .text > .p2align 4,,15 > .globl main > .type main, @function > main: > .LFB0: > .cfi_startproc > movl $4, %eax > ret > .cfi_endproc > .LFE0: > .size main, .-main > .section .rodata > .align 4 > .type a, @object > .size a, 4 > a: > .long 4 > .set b,a > .ident "GCC: (Debian 4.4.5-8) 4.4.5" > .section .note.GNU-stack,"",@progbits > jh@gcc10:~/trunk/build2/gcc$ gcc --version > gcc (Debian 4.4.5-8) 4.4.5 > Copyright (C) 2010 Free Software Foundation, Inc. > This is free software; see the source for copying conditions. There is NO > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. > > jh@gcc10:~/trunk/build2/gcc$ ./xgcc -B ./ -O2 t.c -S > jh@gcc10:~/trunk/build2/gcc$ more t.s > .file "t.c" > .section .text.startup,"ax",@progbits > .p2align 4,,15 > .globl main > .type main, @function > main: > .LFB0: > .cfi_startproc > movl $8, %eax > ret > .cfi_endproc > .LFE0: > .size main, .-main > .ident "GCC: (GNU) 4.9.0 20130616 (experimental)" > .section .note.GNU-stack,"",@progbits > > The main idea is to replace const_value_known_p predicate by ctor_for_folding > that returns the ctor and is able to look through aliases via the symbol > table. > The huge change in expand_expr_real_1 is really just a reformating. > > I have bootstrapped/regtested the patch on x86_64-linux and tested with > Firefox build. > I am running now PPC64 test and will wait for Richard's renaming patch. > > Honza > > * 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. > Index: cgraph.h > =================================================================== > *** cgraph.h (revision 200147) > --- cgraph.h (working copy) > *************** void varpool_analyze_node (struct varpoo > *** 797,803 **** > 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); > bool varpool_for_node_and_aliases (struct varpool_node *, > bool (*) (struct varpool_node *, void *), > void *, bool); > --- 797,803 ---- > struct varpool_node * varpool_extra_name_alias (tree, tree); > struct varpool_node * varpool_create_variable_alias (tree, tree); > void varpool_reset_queue (void); > ! tree ctor_for_folding (tree); > bool varpool_for_node_and_aliases (struct varpool_node *, > bool (*) (struct varpool_node *, void *), > void *, bool); > Index: cgraphunit.c > =================================================================== > *** cgraphunit.c (revision 200147) > --- cgraphunit.c (working copy) > *************** process_function_and_variable_attributes > *** 761,768 **** > { > tree decl = vnode->symbol.decl; > if (DECL_EXTERNAL (decl) > ! && DECL_INITIAL (decl) > ! && const_value_known_p (decl)) > varpool_finalize_decl (decl); > if (DECL_PRESERVE_P (decl)) > vnode->symbol.force_output = true; > --- 761,767 ---- > { > tree decl = vnode->symbol.decl; > if (DECL_EXTERNAL (decl) > ! && DECL_INITIAL (decl)) > varpool_finalize_decl (decl); > if (DECL_PRESERVE_P (decl)) > vnode->symbol.force_output = true; > Index: testsuite/gcc.dg/tree-ssa/attr-alias-2.c > =================================================================== > *** testsuite/gcc.dg/tree-ssa/attr-alias-2.c (revision 0) > --- testsuite/gcc.dg/tree-ssa/attr-alias-2.c (revision 0) > *************** > *** 0 **** > --- 1,10 ---- > + /* { 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" } } */ > Index: lto-cgraph.c > =================================================================== > *** lto-cgraph.c (revision 200147) > --- lto-cgraph.c (working copy) > *************** compute_ltrans_boundary (lto_symtab_enco > *** 766,775 **** > 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)) > { > lto_set_symtab_encoder_encode_initializer (encoder, vnode); > add_references (encoder, &vnode->symbol.ref_list); > --- 766,774 ---- > symtab_node node = lto_symtab_encoder_deref (encoder, i); > if (varpool_node *vnode = dyn_cast <varpool_node> (node)) > { > ! 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); > Index: expr.c > =================================================================== > *** expr.c (revision 200147) > --- expr.c (working copy) > *************** expand_expr_real_1 (tree exp, rtx target > *** 9698,9703 **** > --- 9698,9704 ---- > { > 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 &. > *************** expand_expr_real_1 (tree exp, rtx target > *** 9744,9819 **** > && 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)) > { > ! if (TREE_CODE (index) == INTEGER_CST) > { > ! tree init = DECL_INITIAL (array); > > ! 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; > > ! 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) > { > ! 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); > ! } > } > } > } > --- 9745,9816 ---- > && modifier != EXPAND_INITIALIZER > && modifier != EXPAND_MEMORY > && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (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 (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; > > ! 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) > ! { > ! 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); > } > } > } > *************** string_constant (tree arg, tree *ptr_off > *** 10676,10692 **** > || TREE_CODE (array) == CONST_DECL) > { > int length; > > /* 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) > 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 > || compare_tree_int (DECL_SIZE_UNIT (array), length) < 0) > return 0; > > --- 10673,10690 ---- > || TREE_CODE (array) == CONST_DECL) > { > int length; > + tree init = ctor_for_folding (array); > > /* Variables initialized to string literals can be handled too. */ > ! 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 (init)) <= 0 > || compare_tree_int (DECL_SIZE_UNIT (array), length) < 0) > return 0; > > *************** string_constant (tree arg, tree *ptr_off > *** 10699,10705 **** > return 0; > > *ptr_offset = offset; > ! return DECL_INITIAL (array); > } > > return 0; > --- 10697,10703 ---- > return 0; > > *ptr_offset = offset; > ! return init; > } > > return 0; > Index: tree-ssa-loop-ivcanon.c > =================================================================== > *** tree-ssa-loop-ivcanon.c (revision 200147) > --- tree-ssa-loop-ivcanon.c (working copy) > *************** constant_after_peeling (tree op, gimple > *** 174,180 **** > while (handled_component_p (base)) > base = TREE_OPERAND (base, 0); > if ((DECL_P (base) > ! && const_value_known_p (base)) > || CONSTANT_CLASS_P (base)) > { > /* If so, see if we understand all the indices. */ > --- 174,180 ---- > while (handled_component_p (base)) > base = TREE_OPERAND (base, 0); > if ((DECL_P (base) > ! && ctor_for_folding (base) != error_mark_node) > || CONSTANT_CLASS_P (base)) > { > /* If so, see if we understand all the indices. */ > Index: ipa.c > =================================================================== > *** ipa.c (revision 200147) > --- ipa.c (working copy) > *************** process_references (struct ipa_ref_list > *** 145,151 **** > 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))))) > pointer_set_insert (reachable, node); > enqueue_node ((symtab_node) node, first, reachable); > } > --- 145,153 ---- > constant folding. Keep references alive so partitioning > knows about potential references. */ > || (TREE_CODE (node->symbol.decl) == VAR_DECL > ! && flag_wpa > ! && ctor_for_folding (node->symbol.decl) > ! != error_mark_node)))) > pointer_set_insert (reachable, node); > enqueue_node ((symtab_node) node, first, reachable); > } > *************** symtab_remove_unreachable_nodes (bool be > *** 400,405 **** > --- 402,408 ---- > } > else if (!pointer_set_contains (reachable, vnode)) > { > + tree init; > if (vnode->symbol.definition) > { > if (file) > *************** symtab_remove_unreachable_nodes (bool be > *** 411,418 **** > vnode->symbol.aux = NULL; > > /* Keep body if it may be useful for constant folding. */ > ! if (!const_value_known_p (vnode->symbol.decl)) > varpool_remove_initializer (vnode); > ipa_remove_all_references (&vnode->symbol.ref_list); > } > else > --- 414,423 ---- > vnode->symbol.aux = NULL; > > /* Keep body if it may be useful for constant folding. */ > ! 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 > Index: ipa-inline-analysis.c > =================================================================== > *** ipa-inline-analysis.c (revision 200147) > --- ipa-inline-analysis.c (working copy) > *************** param_change_prob (gimple stmt, int i) > *** 2106,2113 **** > struct record_modified_bb_info info; > bitmap_iterator bi; > unsigned index; > > ! if (const_value_known_p (base)) > return 0; > if (!bb->frequency) > return REG_BR_PROB_BASE; > --- 2106,2114 ---- > struct record_modified_bb_info info; > bitmap_iterator bi; > unsigned index; > + tree init = ctor_for_folding (base); > > ! if (init != error_mark_node) > return 0; > if (!bb->frequency) > return REG_BR_PROB_BASE; > Index: gimple-fold.c > =================================================================== > *** gimple-fold.c (revision 200147) > --- gimple-fold.c (working copy) > *************** canonicalize_constructor_val (tree cval, > *** 192,200 **** > tree > get_symbol_constant_value (tree sym) > { > ! if (const_value_known_p (sym)) > { > - tree val = DECL_INITIAL (sym); > if (val) > { > val = canonicalize_constructor_val (unshare_expr (val), sym); > --- 192,200 ---- > tree > get_symbol_constant_value (tree sym) > { > ! tree val = ctor_for_folding (sym); > ! if (val != error_mark_node) > { > if (val) > { > val = canonicalize_constructor_val (unshare_expr (val), sym); > *************** get_base_constructor (tree base, HOST_WI > *** 2695,2713 **** > 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); > > case ARRAY_REF: > case COMPONENT_REF: > --- 2695,2712 ---- > switch (TREE_CODE (base)) > { > case VAR_DECL: > case CONST_DECL: > ! { > ! 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: > Index: lto/lto-partition.c > =================================================================== > *** lto/lto-partition.c (revision 200147) > --- lto/lto-partition.c (working copy) > *************** add_references_to_partition (ltrans_part > *** 146,152 **** > 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) > && !lto_symtab_encoder_in_partition_p (part->encoder, > ref->referred)) > { > if (!part->initializers_visited) > --- 146,152 ---- > Recursively look into the initializers of the constant variable and > add > references, too. */ > else if (is_a <varpool_node> (ref->referred) > ! && ctor_for_folding (ref->referred->symbol.decl) != > error_mark_node > && !lto_symtab_encoder_in_partition_p (part->encoder, > ref->referred)) > { > if (!part->initializers_visited) > Index: varpool.c > =================================================================== > *** varpool.c (revision 200147) > --- varpool.c (working copy) > *************** void > *** 66,77 **** > varpool_remove_node (struct varpool_node *node) > { > symtab_unregister_node ((symtab_node)node); > > /* 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)) > varpool_remove_initializer (node); > ggc_free (node); > } > > --- 66,80 ---- > 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 ((init = ctor_for_folding (node->symbol.decl)) == error_mark_node) > varpool_remove_initializer (node); > + else > + DECL_INITIAL (node->symbol.decl) = init; > ggc_free (node); > } > > *************** varpool_remove_initializer (struct varpo > *** 84,90 **** > /* Keep vtables for BINFO folding. */ > && !DECL_VIRTUAL_P (node->symbol.decl) > /* FIXME: http://gcc.gnu.org/PR55395 */ > ! && debug_info_level == DINFO_LEVEL_NONE) > DECL_INITIAL (node->symbol.decl) = error_mark_node; > } > > --- 87,96 ---- > /* Keep vtables for BINFO folding. */ > && !DECL_VIRTUAL_P (node->symbol.decl) > /* FIXME: http://gcc.gnu.org/PR55395 */ > ! && debug_info_level == DINFO_LEVEL_NONE > ! /* During LTO streaming we may have multiple nodes > ! associated to a given decl. */ > ! && cgraph_state != CGRAPH_LTO_STREAMING) > DECL_INITIAL (node->symbol.decl) = error_mark_node; > } > > *************** dump_varpool_node (FILE *f, struct varpo > *** 104,110 **** > fprintf (f, " output"); > if (TREE_READONLY (node->symbol.decl)) > fprintf (f, " read-only"); > ! if (const_value_known_p (node->symbol.decl)) > fprintf (f, " const-value-known"); > fprintf (f, "\n"); > } > --- 110,116 ---- > fprintf (f, " output"); > if (TREE_READONLY (node->symbol.decl)) > fprintf (f, " read-only"); > ! if (ctor_for_folding (node->symbol.decl) != error_mark_node) > fprintf (f, " const-value-known"); > fprintf (f, "\n"); > } > *************** varpool_node_for_asm (tree asmname) > *** 139,182 **** > } > > /* Return if DECL is constant and its initial value is known (so we can do > ! constant folding using DECL_INITIAL (decl)). */ > > ! bool > ! const_value_known_p (tree decl) > { > if (TREE_CODE (decl) != VAR_DECL > ! &&TREE_CODE (decl) != CONST_DECL) > ! return false; > > if (TREE_CODE (decl) == CONST_DECL > || DECL_IN_CONSTANT_POOL (decl)) > ! return true; > ! > ! gcc_assert (TREE_CODE (decl) == VAR_DECL); > > ! if (!TREE_READONLY (decl) || TREE_THIS_VOLATILE (decl)) > ! return false; > > ! /* Gimplifier takes away constructors of local vars */ > if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) > ! return DECL_INITIAL (decl) != NULL; > > ! gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); > > /* 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; > > /* 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; > } > > /* Add the variable DECL to the varpool. > --- 145,237 ---- > } > > /* Return if DECL is constant and its initial value is known (so we can do > ! constant folding using DECL_INITIAL (decl)). > ! Return ERROR_MARK_NODE when value is unknown. */ > > ! 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 error_mark_node; > > if (TREE_CODE (decl) == CONST_DECL > || DECL_IN_CONSTANT_POOL (decl)) > ! 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); > ! > ! 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; > ! } > ! } > ! > ! /* 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 (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 DECL_INITIAL (real_decl); > } > > /* Add the variable DECL to the varpool.