From: ebotcazou Date: Wed, 28 Apr 2010 19:11:50 +0000 (+0000) Subject: Uniquization of constants at the Tree level X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=commitdiff_plain;h=ac8fd5474578307044262b7cb23d1a6682f6a2ce Uniquization of constants at the Tree level * tree.h (DECL_IN_CONSTANT_POOL): New macro (tree_decl_with_vis): Add in_constant_pool bit, move shadowed_for_var_p bit to the end. (tree_output_constant_def): Declare. * gimplify.c (gimplify_init_constructor): When using block copy, uniquize the constant constructor on the RHS. * lto-streamer-in.c (unpack_ts_decl_with_vis_value_fields): Deal with DECL_IN_CONSTANT_POOL flag. * lto-streamer-out.c (pack_ts_decl_with_vis_value_fields): Likewise. * varasm.c (make_decl_rtl): Deal with variables belonging to the global constant pool. (assemble_variable): Deal with symbols belonging to the tree constant pool. (get_constant_section): Add ALIGN parameter and simplify. (build_constant_desc): Build a VAR_DECL and attach it to the symbol. (assemble_constant_contents): Use the expression of the VAR_DECL. (output_constant_def_contents): Use the alignment of the VAR_DECL. (tree_output_constant_def): New global function. (mark_constant): Use the expression of the VAR_DECL. (place_block_symbol): Use the alignment of the VAR_DECL and the size of its expression. (output_object_block): Likewise and assemble the expression. ada/ * gcc-interface/trans.c (gnat_gimplify_expr) : Uniquize constant constructors before taking their address. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158838 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0dbca97c8fb..2dffe7d2267 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,31 @@ 2010-04-28 Eric Botcazou + Uniquization of constants at the Tree level + * tree.h (DECL_IN_CONSTANT_POOL): New macro + (tree_decl_with_vis): Add in_constant_pool bit, move shadowed_for_var_p + bit to the end. + (tree_output_constant_def): Declare. + * gimplify.c (gimplify_init_constructor): When using block copy, + uniquize the constant constructor on the RHS. + * lto-streamer-in.c (unpack_ts_decl_with_vis_value_fields): Deal + with DECL_IN_CONSTANT_POOL flag. + * lto-streamer-out.c (pack_ts_decl_with_vis_value_fields): Likewise. + * varasm.c (make_decl_rtl): Deal with variables belonging to the + global constant pool. + (assemble_variable): Deal with symbols belonging to the tree constant + pool. + (get_constant_section): Add ALIGN parameter and simplify. + (build_constant_desc): Build a VAR_DECL and attach it to the symbol. + (assemble_constant_contents): Use the expression of the VAR_DECL. + (output_constant_def_contents): Use the alignment of the VAR_DECL. + (tree_output_constant_def): New global function. + (mark_constant): Use the expression of the VAR_DECL. + (place_block_symbol): Use the alignment of the VAR_DECL and the size + of its expression. + (output_object_block): Likewise and assemble the expression. + +2010-04-28 Eric Botcazou + * lto-streamer.c [LTO_STREAMER_DEBUG] (tree_htab, tree_hash_entry, hash_tree, eq_tree): New tree hash table. (lto_streamer_init) [LTO_STREAMER_DEBUG]: Initialize it. diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index c5dac667602..6303c3927c4 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2010-04-28 Eric Botcazou + + * gcc-interface/trans.c (gnat_gimplify_expr) : Uniquize + constant constructors before taking their address. + 2010-04-25 Eric Botcazou * exp_dbug.ads: Fix outdated description. Mention link between XVS diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 84fa1387870..743a6521094 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -6036,16 +6036,8 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p, the reference is in an elaboration procedure. */ if (TREE_CONSTANT (op)) { - tree new_var = create_tmp_var_raw (TREE_TYPE (op), "C"); - TREE_ADDRESSABLE (new_var) = 1; - gimple_add_tmp_var (new_var); - - TREE_READONLY (new_var) = 1; - TREE_STATIC (new_var) = 1; - DECL_INITIAL (new_var) = op; - - TREE_OPERAND (expr, 0) = new_var; - recompute_tree_invariant_for_addr_expr (expr); + tree addr = build_fold_addr_expr (tree_output_constant_def (op)); + *expr_p = fold_convert (TREE_TYPE (expr), addr); } /* Otherwise explicitly create the local temporary. That's required diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 2f4e12067e0..68148a6a7d9 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -3758,25 +3758,11 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && num_nonzero_elements > 1 && !can_move_by_pieces (size, align)) { - tree new_tree; - if (notify_temp_creation) return GS_ERROR; - new_tree = create_tmp_var_raw (type, "C"); - - gimple_add_tmp_var (new_tree); - TREE_STATIC (new_tree) = 1; - TREE_READONLY (new_tree) = 1; - DECL_INITIAL (new_tree) = ctor; - if (align > DECL_ALIGN (new_tree)) - { - DECL_ALIGN (new_tree) = align; - DECL_USER_ALIGN (new_tree) = 1; - } - walk_tree (&DECL_INITIAL (new_tree), force_labels_r, NULL, NULL); - - TREE_OPERAND (*expr_p, 1) = new_tree; + walk_tree (&ctor, force_labels_r, NULL, NULL); + TREE_OPERAND (*expr_p, 1) = tree_output_constant_def (ctor); /* This is no longer an assignment of a CONSTRUCTOR, but we still may have processing to do on the LHS. So diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a35d126585c..7e3834df916 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-04-28 Eric Botcazou + + * gcc.dg/const-uniq-1.c: New test. + * gcc.dg/lto/const-uniq_[01].c: Likewise. + 2010-04-28 Xinliang David Li * gcc.dg/uninit-pred-2_b.c: New test. diff --git a/gcc/tree.h b/gcc/tree.h index 6954e5a1263..99bf29b9eb2 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2963,6 +2963,11 @@ struct GTY(()) tree_parm_decl { #define DECL_IN_TEXT_SECTION(NODE) \ (VAR_DECL_CHECK (NODE)->decl_with_vis.in_text_section) +/* In a VAR_DECL that's static, + nonzero if it belongs to the global constant pool. */ +#define DECL_IN_CONSTANT_POOL(NODE) \ + (VAR_DECL_CHECK (NODE)->decl_with_vis.in_constant_pool) + /* Nonzero for a given ..._DECL node means that this node should be put in .common, if possible. If a DECL_INITIAL is given, and it is not error_mark_node, then the decl cannot be put in .common. */ @@ -3102,9 +3107,8 @@ struct GTY(()) tree_decl_with_vis { unsigned thread_local : 1; unsigned common_flag : 1; unsigned in_text_section : 1; + unsigned in_constant_pool : 1; unsigned dllimport_flag : 1; - /* Used by C++. Might become a generic decl flag. */ - unsigned shadowed_for_var_p : 1; /* Don't belong to VAR_DECL exclusively. */ unsigned weak_flag : 1; @@ -3117,7 +3121,9 @@ struct GTY(()) tree_decl_with_vis { /* Belong to FUNCTION_DECL exclusively. */ unsigned init_priority_p : 1; - /* 15 unused bits. */ + /* Used by C++ only. Might become a generic decl flag. */ + unsigned shadowed_for_var_p : 1; + /* 14 unused bits. */ }; extern tree decl_debug_expr_lookup (tree); @@ -5184,6 +5190,7 @@ extern void internal_reference_types (void); extern unsigned int update_alignment_for_field (record_layout_info, tree, unsigned int); /* varasm.c */ +extern tree tree_output_constant_def (tree); extern void make_decl_rtl (tree); extern rtx make_decl_rtl_for_debug (tree); extern void make_decl_one_only (tree, tree); diff --git a/gcc/varasm.c b/gcc/varasm.c index 35b65a932e3..bcb5b114238 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1354,6 +1354,14 @@ make_decl_rtl (tree decl) return; } + /* If this variable belongs to the global constant pool, retrieve the + pre-computed RTL or recompute it in LTO mode. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_IN_CONSTANT_POOL (decl)) + { + SET_DECL_RTL (decl, output_constant_def (DECL_INITIAL (decl), 1)); + return; + } + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); if (name[0] != '*' && TREE_CODE (decl) != FUNCTION_DECL @@ -2198,8 +2206,6 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, if (flag_syntax_only) return; - app_disable (); - if (! dont_output_data && ! host_integerp (DECL_SIZE_UNIT (decl), 1)) { @@ -2210,6 +2216,19 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, gcc_assert (MEM_P (decl_rtl)); gcc_assert (GET_CODE (XEXP (decl_rtl, 0)) == SYMBOL_REF); symbol = XEXP (decl_rtl, 0); + + /* If this symbol belongs to the tree constant pool, output the constant + if it hasn't already been written. */ + if (TREE_CONSTANT_POOL_ADDRESS_P (symbol)) + { + tree decl = SYMBOL_REF_DECL (symbol); + if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl))) + output_constant_def_contents (symbol); + return; + } + + app_disable (); + name = XSTR (symbol, 0); if (TREE_PUBLIC (decl) && DECL_NAME (decl)) notice_global_symbol (decl); @@ -2790,7 +2809,6 @@ decode_addr_const (tree exp, struct addr_const *value) { if (TREE_CODE (target) == COMPONENT_REF && host_integerp (byte_position (TREE_OPERAND (target, 1)), 0)) - { offset += int_byte_position (TREE_OPERAND (target, 1)); target = TREE_OPERAND (target, 0); @@ -2847,7 +2865,6 @@ decode_addr_const (tree exp, struct addr_const *value) static GTY((param_is (struct constant_descriptor_tree))) htab_t const_desc_htab; -static struct constant_descriptor_tree * build_constant_desc (tree); static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int); /* Constant pool accessor function. */ @@ -3236,31 +3253,14 @@ copy_constant (tree exp) } } -/* Return the alignment of constant EXP in bits. */ - -static unsigned int -get_constant_alignment (tree exp) -{ - unsigned int align; - - align = TYPE_ALIGN (TREE_TYPE (exp)); -#ifdef CONSTANT_ALIGNMENT - align = CONSTANT_ALIGNMENT (exp, align); -#endif - return align; -} - /* Return the section into which constant EXP should be placed. */ static section * -get_constant_section (tree exp) +get_constant_section (tree exp, unsigned int align) { - if (IN_NAMED_SECTION (exp)) - return get_named_section (exp, NULL, compute_reloc_for_constant (exp)); - else - return targetm.asm_out.select_section (exp, - compute_reloc_for_constant (exp), - get_constant_alignment (exp)); + return targetm.asm_out.select_section (exp, + compute_reloc_for_constant (exp), + align); } /* Return the size of constant EXP in bytes. */ @@ -3286,11 +3286,11 @@ get_constant_size (tree exp) static struct constant_descriptor_tree * build_constant_desc (tree exp) { - rtx symbol; - rtx rtl; + struct constant_descriptor_tree *desc; + rtx symbol, rtl; char label[256]; int labelno; - struct constant_descriptor_tree *desc; + tree decl; desc = GGC_NEW (struct constant_descriptor_tree); desc->value = copy_constant (exp); @@ -3303,17 +3303,41 @@ build_constant_desc (tree exp) labelno = const_labelno++; ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno); - /* We have a symbol name; construct the SYMBOL_REF and the MEM. */ + /* Construct the VAR_DECL associated with the constant. */ + decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (label), + TREE_TYPE (exp)); + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + TREE_READONLY (decl) = 1; + TREE_STATIC (decl) = 1; + TREE_ADDRESSABLE (decl) = 1; + /* We don't set the RTL yet as this would cause varpool to assume that the + variable is referenced. Moreover, it would just be dropped in LTO mode. + Instead we set the flag that will be recognized in make_decl_rtl. */ + DECL_IN_CONSTANT_POOL (decl) = 1; + DECL_INITIAL (decl) = desc->value; + /* ??? CONSTANT_ALIGNMENT hasn't been updated for vector types on most + architectures so use DATA_ALIGNMENT as well, except for strings. */ + if (TREE_CODE (exp) == STRING_CST) + { +#ifdef CONSTANT_ALIGNMENT + DECL_ALIGN (decl) = CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl)); +#endif + } + else + align_variable (decl, 0); + + /* Now construct the SYMBOL_REF and the MEM. */ if (use_object_blocks_p ()) { - section *sect = get_constant_section (exp); + section *sect = get_constant_section (exp, DECL_ALIGN (decl)); symbol = create_block_symbol (ggc_strdup (label), get_block_for_section (sect), -1); } else symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label)); SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_LOCAL; - SET_SYMBOL_REF_DECL (symbol, desc->value); + SET_SYMBOL_REF_DECL (symbol, decl); TREE_CONSTANT_POOL_ADDRESS_P (symbol) = 1; rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), symbol); @@ -3330,7 +3354,6 @@ build_constant_desc (tree exp) ASM_OUTPUT_LABELREF will have to know how to strip this information. This call might invalidate our local variable SYMBOL; we can't use it afterward. */ - targetm.encode_section_info (exp, rtl, true); desc->rtl = rtl; @@ -3437,7 +3460,8 @@ assemble_constant_contents (tree exp, const char *label, unsigned int align) static void output_constant_def_contents (rtx symbol) { - tree exp = SYMBOL_REF_DECL (symbol); + tree decl = SYMBOL_REF_DECL (symbol); + tree exp = DECL_INITIAL (decl); unsigned int align; /* Make sure any other constants whose addresses appear in EXP @@ -3454,8 +3478,8 @@ output_constant_def_contents (rtx symbol) place_block_symbol (symbol); else { - switch_to_section (get_constant_section (exp)); - align = get_constant_alignment (exp); + align = DECL_ALIGN (decl); + switch_to_section (get_constant_section (exp, align)); if (align > BITS_PER_UNIT) ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); assemble_constant_contents (exp, XSTR (symbol, 0), align); @@ -3480,6 +3504,37 @@ lookup_constant_def (tree exp) return (desc ? desc->rtl : NULL_RTX); } + +/* Return a tree representing a reference to constant data in memory + for the constant expression EXP. + + This is the counterpart of output_constant_def at the Tree level. */ + +tree +tree_output_constant_def (tree exp) +{ + struct constant_descriptor_tree *desc, key; + void **loc; + tree decl; + + /* Look up EXP in the table of constant descriptors. If we didn't find + it, create a new one. */ + key.value = exp; + key.hash = const_hash_1 (exp); + loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT); + + desc = (struct constant_descriptor_tree *) *loc; + if (desc == 0) + { + desc = build_constant_desc (exp); + desc->hash = key.hash; + *loc = desc; + } + + decl = SYMBOL_REF_DECL (XEXP (desc->rtl, 0)); + varpool_finalize_decl (decl); + return decl; +} /* Used in the hash tables to avoid outputting the same constant twice. Unlike 'struct constant_descriptor_tree', RTX constants @@ -3949,8 +4004,8 @@ mark_constant (rtx *current_rtx, void *data ATTRIBUTE_UNUSED) } else if (TREE_CONSTANT_POOL_ADDRESS_P (x)) { - tree exp = SYMBOL_REF_DECL (x); - if (!TREE_ASM_WRITTEN (exp)) + tree decl = SYMBOL_REF_DECL (x); + if (!TREE_ASM_WRITTEN (DECL_INITIAL (decl))) { n_deferred_constants--; output_constant_def_contents (x); @@ -6912,8 +6967,8 @@ place_block_symbol (rtx symbol) else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol)) { decl = SYMBOL_REF_DECL (symbol); - alignment = get_constant_alignment (decl); - size = get_constant_size (decl); + alignment = DECL_ALIGN (decl); + size = get_constant_size (DECL_INITIAL (decl)); } else { @@ -7059,9 +7114,9 @@ output_object_block (struct object_block *block) else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol)) { decl = SYMBOL_REF_DECL (symbol); - assemble_constant_contents (decl, XSTR (symbol, 0), - get_constant_alignment (decl)); - offset += get_constant_size (decl); + assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0), + DECL_ALIGN (decl)); + offset += get_constant_size (DECL_INITIAL (decl)); } else {