diff options
author | Diego Novillo <dnovillo@gcc.gnu.org> | 2009-09-03 00:07:12 -0400 |
---|---|---|
committer | Diego Novillo <dnovillo@gcc.gnu.org> | 2009-09-03 00:07:12 -0400 |
commit | 4537ec0c8652889bc6decbcf5647f889d2a14733 (patch) | |
tree | 1a56a7d77636c5b967ccca276324809f1b6251a7 /gcc | |
parent | e25ea117b5a436eac4112d495a413b906f6bca8f (diff) | |
download | gcc-4537ec0c8652889bc6decbcf5647f889d2a14733.zip gcc-4537ec0c8652889bc6decbcf5647f889d2a14733.tar.gz gcc-4537ec0c8652889bc6decbcf5647f889d2a14733.tar.bz2 |
[multiple changes]
2009-09-01 Diego Novillo <dnovillo@google.com>
* c-lang.c (lang_hooks): Remove const qualifier.
java/ChangeLog
* lang.c (lang_hooks): Remove const qualifier.
objc/ChangeLog
* objc-lang.c (lang_hooks): Remove const qualifier.
objcp/ChangeLog
* objcp-lang.c (lang_hooks): Remove const qualifier.
ada/ChangeLog
* gcc-interface/misc.c (lang_hooks): Remove const qualifier.
fortran/ChangeLog
* f95-lang.c (lang_hooks): Remove const qualifier.
cp/ChangeLog
* cp-lang.c (lang_hooks): Remove const qualifier.
2009-09-01 Diego Novillo <dnovillo@google.com>
* cgraph.c (cgraph_node_for_decl): New.
* cgraph.h (cgraph_node_for_decl): Declare.
* tree.c (host_integerp): Return 0 if T is NULL.
2009-09-01 Diego Novillo <dnovillo@google.com>
* tree.h (struct alias_pair): Move from varasm.c.
(alias_pairs): Likewise.
(TYPE_MAXVAL): Define.
(TYPE_MINVAL): Define.
(iterative_hash_host_wide_int): Declare.
(remove_unreachable_alias_pairs): Declare.
* tree-pass.h (pass_ipa_free_lang_data): Declare.
* diagnostic.c (default_diagnostic_starter): Make extern.
(default_diagnostic_finalizer): Make extern.
* diagnostic.h (default_diagnostic_starter): Declare.
(default_diagnostic_finalizer): Declare.
(default_tree_printer): Declare.
* toplev.c (default_tree_printer): Make extern.
2009-09-01 Richard Guenther <rguenther@suse.de>
Diego Novillo <dnovillo@google.com>
* cgraph.c (cgraph_add_new_function): Remove gimplification.
* cgraphunit.c (cgraph_expand_function): Do not emit
associated thunks from here.
(cgraph_emit_thunks): New.
(cgraph_optimize): Call it.
Return if any IPA pass finds an error.
* varasm.c (finish_aliases_1): Ignore errorneous aliases used
by thunks.
2009-09-01 Simon Baldwin <simonb@google.com>
Rafael Espindola <espindola@google.com>
Richard Guenther <rguenther@suse.de>
Doug Kwan <dougkwan@google.com>
Diego Novillo <dnovillo@google.com>
* tree.c: Include tree-pass.h, langhooks-def.h,
diagnostic.h, cgraph.h, timevar.h, except.h and debug.h.
(free_lang_data_in_type): New.
(need_assembler_name_p): New.
(free_lang_data_in_block): New.
(free_lang_data_in_decl): New.
(struct free_lang_data_d): New.
(add_tree_to_fld_list): New.
(find_decls_types_r): New.
(get_eh_types_for_runtime): New.
(find_decls_types_in_eh_region): New.
(find_decls_types_in_node): New.
(find_decls_types_in_var): New.
(free_lang_data_in_cgraph): New.
(free_lang_data): New.
(gate_free_lang_data): New.
(pass_ipa_free_lang_data): New.
2009-09-01 Diego Novillo <dnovillo@google.com>
* timevar.def (TV_IPA_FREE_LANG_DATA): Define.
* langhooks.h (struct lang_hooks): Add field free_lang_data.
(lang_hooks): Remove const qualifier.
* ipa.c (cgraph_remove_unreachable_nodes): Call
remove_unreachable_alias_pairs.
* except.c (add_type_for_runtime): Check if TYPE has
already been converted.
(lookup_type_for_runtime): Likewise.
(check_handled): Handle converted types.
* varasm.c (remove_unreachable_alias_pairs): New.
* gimple.c: Include demangle.h.
(gimple_decl_printable_name): New.
(gimple_fold_obj_type_ref): New.
* gimple.h (gimple_decl_printable_name): Declare.
(gimple_fold_obj_type_ref): Declare.
* passes.c (init_optimization_passes): Add pass
pass_ipa_free_lang_data.
* langhooks-def.h (LANG_HOOKS_FREE_LANG_DATA): Define.
(LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_FREE_LANG_DATA.
testsuite/ChangeLog
2009-09-01 Diego Novillo <dnovillo@google.com>
* gcc.dg/gomp/combined-1.c: Adjust expected pattern.
* g++.dg/tree-prof/inline_mismatch_args.C: Likewise.
* g++.dg/warn/unit-1.C: Likewise.
* g++.dg/ipa/iinline-1.C: Likewise.
* g++.dg/template/cond2.C: Adjust expected line location for the
error.
* g++.dg/template/pr35240.C: Likewise.
cp/ChangeLog
2009-09-01 Doug Kwan <dougkwan@google.com>
* tree.c (cp_fix_function_decl_p): New.
(cp_free_lang_data): New.
2009-09-01 Diego Novillo <dnovillo@google.com>
* Make-lang.in (decl2.o): Add dependency on $(POINTER_SET_H).
* decl2.c: Include pointer-set.h.
(collect_candidates_for_java_method_aliases): New.
(cp_write_global_declarations): Call it.
Add local variable CANDIDATES. If set, call
build_java_method_aliases.
(build_java_method_aliases): Add argument CANDIDATES.
Use it to determine if FNDECL should get a hidden alias.
* cp-objcp-common.h (LANG_HOOKS_FREE_LANG_DATA): Define.
* cp-tree.h (cp_free_lang_data): Declare.
2009-09-03 Richard Guenther <rguenther@suse.de>
* method.c (use_thunk): Use cgraph_finalize_function to hand
off thunks to the cgraph.
* semantics.c (emit_associated_thunks): Do not emit thunks
for really extern functions.
From-SVN: r151360
Diffstat (limited to 'gcc')
46 files changed, 1319 insertions, 62 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c0e33a0..b0abc83 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,87 @@ +2009-09-03 Diego Novillo <dnovillo@google.com> + + * cgraph.c (cgraph_node_for_decl): New. + * cgraph.h (cgraph_node_for_decl): Declare. + * tree.c (host_integerp): Return 0 if T is NULL. + +2009-09-03 Diego Novillo <dnovillo@google.com> + + * tree.h (struct alias_pair): Move from varasm.c. + (alias_pairs): Likewise. + (TYPE_MAXVAL): Define. + (TYPE_MINVAL): Define. + (iterative_hash_host_wide_int): Declare. + (remove_unreachable_alias_pairs): Declare. + * tree-pass.h (pass_ipa_free_lang_data): Declare. + * diagnostic.c (default_diagnostic_starter): Make extern. + (default_diagnostic_finalizer): Make extern. + * diagnostic.h (default_diagnostic_starter): Declare. + (default_diagnostic_finalizer): Declare. + (default_tree_printer): Declare. + * toplev.c (default_tree_printer): Make extern. + +2009-09-03 Richard Guenther <rguenther@suse.de> + Diego Novillo <dnovillo@google.com> + + * cgraph.c (cgraph_add_new_function): Remove gimplification. + * cgraphunit.c (cgraph_expand_function): Do not emit + associated thunks from here. + (cgraph_emit_thunks): New. + (cgraph_optimize): Call it. + Return if any IPA pass finds an error. + * varasm.c (finish_aliases_1): Ignore errorneous aliases used + by thunks. + +2009-09-03 Simon Baldwin <simonb@google.com> + Rafael Espindola <espindola@google.com> + Richard Guenther <rguenther@suse.de> + Doug Kwan <dougkwan@google.com> + Diego Novillo <dnovillo@google.com> + + * tree.c: Include tree-pass.h, langhooks-def.h, + diagnostic.h, cgraph.h, timevar.h, except.h and debug.h. + (free_lang_data_in_type): New. + (need_assembler_name_p): New. + (free_lang_data_in_block): New. + (free_lang_data_in_decl): New. + (struct free_lang_data_d): New. + (add_tree_to_fld_list): New. + (find_decls_types_r): New. + (get_eh_types_for_runtime): New. + (find_decls_types_in_eh_region): New. + (find_decls_types_in_node): New. + (find_decls_types_in_var): New. + (free_lang_data_in_cgraph): New. + (free_lang_data): New. + (gate_free_lang_data): New. + (pass_ipa_free_lang_data): New. + +2009-09-03 Diego Novillo <dnovillo@google.com> + + * timevar.def (TV_IPA_FREE_LANG_DATA): Define. + * langhooks.h (struct lang_hooks): Add field free_lang_data. + (lang_hooks): Remove const qualifier. + * ipa.c (cgraph_remove_unreachable_nodes): Call + remove_unreachable_alias_pairs. + * except.c (add_type_for_runtime): Check if TYPE has + already been converted. + (lookup_type_for_runtime): Likewise. + (check_handled): Handle converted types. + * varasm.c (remove_unreachable_alias_pairs): New. + * gimple.c: Include demangle.h. + (gimple_decl_printable_name): New. + (gimple_fold_obj_type_ref): New. + * gimple.h (gimple_decl_printable_name): Declare. + (gimple_fold_obj_type_ref): Declare. + * passes.c (init_optimization_passes): Add pass + pass_ipa_free_lang_data. + * langhooks-def.h (LANG_HOOKS_FREE_LANG_DATA): Define. + (LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_FREE_LANG_DATA. + +2009-09-03 Diego Novillo <dnovillo@google.com> + + * c-lang.c (lang_hooks): Remove const qualifier. + 2009-09-02 Loren James Rittle <ljrittle@acm.org> * doc/install.texi (*-*-freebsd*): Update target information. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 53c7ffed..526ec70 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2164,7 +2164,8 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ all-tree.def $(FLAGS_H) $(FUNCTION_H) $(PARAMS_H) \ $(TOPLEV_H) $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) langhooks.h \ $(REAL_H) gt-tree.h $(TREE_INLINE_H) tree-iterator.h $(BASIC_BLOCK_H) \ - $(TREE_FLOW_H) $(OBSTACK_H) pointer-set.h fixed-value.h + $(TREE_FLOW_H) $(OBSTACK_H) pointer-set.h fixed-value.h tree-pass.h \ + langhooks-def.h $(DIAGNOSTIC_H) $(CGRAPH_H) $(TIMEVAR_H) except.h debug.h tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) langhooks.h $(TOPLEV_H) $(SPLAY_TREE_H) $(TREE_DUMP_H) \ tree-iterator.h $(TREE_PASS_H) $(DIAGNOSTIC_H) $(REAL_H) fixed-value.h diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 43c7542..9b92ce5 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,7 @@ +2009-09-03 Diego Novillo <dnovillo@google.com> + + * gcc-interface/misc.c (lang_hooks): Remove const qualifier. + 2009-09-02 Richard Henderson <rth@redhat.com> * tb-gcc.c (__gnat_backtrace): Mark all arguments unused. diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c index 46e762f..f39a60e 100644 --- a/gcc/ada/gcc-interface/misc.c +++ b/gcc/ada/gcc-interface/misc.c @@ -131,7 +131,7 @@ static void gnat_get_subrange_bounds (const_tree, tree *, tree *); #undef LANG_HOOKS_BUILTIN_FUNCTION #define LANG_HOOKS_BUILTIN_FUNCTION gnat_builtin_function -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* How much we want of our DWARF extensions. Some of our dwarf+ extensions are incompatible with regular GDB versions, so we must make sure to only diff --git a/gcc/c-lang.c b/gcc/c-lang.c index 42004f5..7e0236d 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -46,7 +46,7 @@ enum c_language_kind c_language = clk_c; #define LANG_HOOKS_INIT c_objc_common_init /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Final processing of file-scope data. The Objective-C version of this function still does something. */ diff --git a/gcc/cgraph.c b/gcc/cgraph.c index f7a0f96..2f5bd2a 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -404,6 +404,33 @@ hash_node (const void *p) return (hashval_t) DECL_UID (n->decl); } + +/* Return the cgraph node associated with function DECL. If none + exists, return NULL. */ + +struct cgraph_node * +cgraph_node_for_decl (tree decl) +{ + struct cgraph_node *node; + void **slot; + + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); + + node = NULL; + if (cgraph_hash) + { + struct cgraph_node key; + + key.decl = decl; + slot = htab_find_slot (cgraph_hash, &key, NO_INSERT); + if (slot && *slot) + node = (struct cgraph_node *) *slot; + } + + return node; +} + + /* Returns nonzero if P1 and P2 are equal. */ static int @@ -1893,9 +1920,6 @@ cgraph_add_new_function (tree fndecl, bool lowered) push_cfun (DECL_STRUCT_FUNCTION (fndecl)); current_function_decl = fndecl; gimple_register_cfg_hooks (); - /* C++ Thunks are emitted late via this function, gimplify them. */ - if (!gimple_body (fndecl)) - gimplify_function_tree (fndecl); tree_lowering_passes (fndecl); bitmap_obstack_initialize (NULL); if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl))) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 6eadc27..67670ef 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -391,7 +391,8 @@ struct cgraph_edge *cgraph_create_edge (struct cgraph_node *, struct cgraph_node * cgraph_get_node (tree); struct cgraph_node *cgraph_node (tree); -struct cgraph_node *cgraph_node_for_asm (tree asmname); +struct cgraph_node *cgraph_node_for_asm (tree); +struct cgraph_node *cgraph_node_for_decl (tree); struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple); void cgraph_set_call_stmt (struct cgraph_edge *, gimple); void cgraph_set_call_stmt_including_clones (struct cgraph_node *, gimple, gimple); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index eb7de10..1505b56 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -1108,9 +1108,6 @@ cgraph_expand_function (struct cgraph_node *node) gcc_assert (node->lowered); /* Generate RTL for the body of DECL. */ - if (lang_hooks.callgraph.emit_associated_thunks - && node->finalized_by_frontend) - lang_hooks.callgraph.emit_associated_thunks (decl); tree_rest_of_compilation (decl); /* Make sure that BE didn't give up on compiling. */ @@ -1324,6 +1321,30 @@ ipa_passes (void) bitmap_obstack_release (NULL); } + +/* Emit thunks for every node in the cgraph. + FIXME: We really ought to emit thunks only for functions that are needed. */ + +static void +cgraph_emit_thunks (void) +{ + struct cgraph_node *n; + + for (n = cgraph_nodes; n; n = n->next) + { + /* Only emit thunks on functions defined in this TU. + Note that this may emit more thunks than strictly necessary. + During optimization some nodes may disappear. It would be + nice to only emit thunks only for the functions that will be + emitted, but we cannot know that until the inliner and other + IPA passes have run (see the sequencing of the call to + cgraph_mark_functions_to_output in cgraph_optimize). */ + if (!DECL_EXTERNAL (n->decl)) + lang_hooks.callgraph.emit_associated_thunks (n->decl); + } +} + + /* Perform simple optimizations based on callgraph. */ static void @@ -1336,6 +1357,14 @@ cgraph_optimize (void) verify_cgraph (); #endif + /* Emit thunks, if needed. */ + if (lang_hooks.callgraph.emit_associated_thunks) + { + cgraph_emit_thunks (); + if (errorcount || sorrycount) + return; + } + /* Call functions declared with the "constructor" or "destructor" attribute. */ cgraph_build_cdtor_fns (); @@ -1359,6 +1388,10 @@ cgraph_optimize (void) if (errorcount == 0 && sorrycount == 0) ipa_passes (); + /* Do nothing else if any IPA pass found errors. */ + if (errorcount || sorrycount) + return; + /* This pass remove bodies of extern inline functions we never inlined. Do this later so other IPA passes see what is really going on. */ cgraph_remove_unreachable_nodes (false, dump_file); @@ -1428,6 +1461,8 @@ cgraph_optimize (void) } #endif } + + /* Generate and emit a static constructor or destructor. WHICH must be one of 'I' (for a constructor) or 'D' (for a destructor). BODY is a STATEMENT_LIST containing GENERIC statements. PRIORITY is the diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0a351b2..bac7098 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,32 @@ +2009-09-03 Doug Kwan <dougkwan@google.com> + + * tree.c (cp_fix_function_decl_p): New. + (cp_free_lang_data): New. + +2009-09-03 Diego Novillo <dnovillo@google.com> + + * Make-lang.in (decl2.o): Add dependency on $(POINTER_SET_H). + * decl2.c: Include pointer-set.h. + (collect_candidates_for_java_method_aliases): New. + (cp_write_global_declarations): Call it. + Add local variable CANDIDATES. If set, call + build_java_method_aliases. + (build_java_method_aliases): Add argument CANDIDATES. + Use it to determine if FNDECL should get a hidden alias. + * cp-objcp-common.h (LANG_HOOKS_FREE_LANG_DATA): Define. + * cp-tree.h (cp_free_lang_data): Declare. + +2009-09-03 Richard Guenther <rguenther@suse.de> + + * method.c (use_thunk): Use cgraph_finalize_function to hand + off thunks to the cgraph. + * semantics.c (emit_associated_thunks): Do not emit thunks + for really extern functions. + +2009-09-03 Diego Novillo <dnovillo@google.com> + + * cp-lang.c (lang_hooks): Remove const qualifier. + 2009-09-02 Jason Merrill <jason@redhat.com> * semantics.c (describable_type): Don't pretend to be in a template. diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index a3190f4..356565f 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -257,7 +257,7 @@ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \ debug.h gt-cp-decl.h $(TIMEVAR_H) $(TREE_FLOW_H) $(TARGET_H) $(PLUGIN_H) cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h $(EXPR_H) \ output.h except.h toplev.h $(RTL_H) $(C_COMMON_H) gt-cp-decl2.h $(CGRAPH_H) \ - $(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H) + $(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H) $(POINTER_SET_H) cp/cp-objcp-common.o : cp/cp-objcp-common.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) $(TREE_H) $(CXX_TREE_H) $(C_COMMON_H) toplev.h \ langhooks.h $(LANGHOOKS_DEF_H) $(DIAGNOSTIC_H) debug.h \ diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index 0278028..f818e5b 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -73,7 +73,7 @@ static enum classify_record cp_classify_record (tree type); #define LANG_HOOKS_INIT_TS cp_init_ts /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Lang hook routines common to C++ and ObjC++ appear in cp/cp-objcp-common.c; there should be very few routines below. */ diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h index 19fce29..818540c 100644 --- a/gcc/cp/cp-objcp-common.h +++ b/gcc/cp/cp-objcp-common.h @@ -32,6 +32,8 @@ extern bool cp_function_decl_explicit_p (tree decl); specific to C++ or ObjC++ go in cp/cp-lang.c and objcp/objcp-lang.c, respectively. */ +#undef LANG_HOOKS_FREE_LANG_DATA +#define LANG_HOOKS_FREE_LANG_DATA cp_free_lang_data #undef LANG_HOOKS_TREE_SIZE #define LANG_HOOKS_TREE_SIZE cp_tree_size #undef LANG_HOOKS_FINISH diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a76b2d2..23b41d3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4891,6 +4891,7 @@ extern tree finish_decltype_type (tree, bool); extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); /* in tree.c */ +void cp_free_lang_data (tree t); extern tree force_target_expr (tree, tree); extern tree build_target_expr_with_type (tree, tree); extern void lang_check_failed (const char *, int, diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index da9c2b7..cc4317a 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-dump.h" #include "intl.h" #include "gimple.h" +#include "pointer-set.h" extern cpp_reader *parse_in; @@ -3288,27 +3289,60 @@ cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED) /* Java requires that we be able to reference a local address for a method, and not be confused by PLT entries. If hidden aliases are - supported, emit one for each java function that we've emitted. */ + supported, collect and return all the functions for which we should + emit a hidden alias. */ -static void -build_java_method_aliases (void) +static struct pointer_set_t * +collect_candidates_for_java_method_aliases (void) { struct cgraph_node *node; + struct pointer_set_t *candidates = NULL; #ifndef HAVE_GAS_HIDDEN - return; + return candidates; #endif for (node = cgraph_nodes; node ; node = node->next) { tree fndecl = node->decl; - if (TREE_ASM_WRITTEN (fndecl) - && DECL_CONTEXT (fndecl) + if (DECL_CONTEXT (fndecl) && TYPE_P (DECL_CONTEXT (fndecl)) && TYPE_FOR_JAVA (DECL_CONTEXT (fndecl)) && TARGET_USE_LOCAL_THUNK_ALIAS_P (fndecl)) { + if (candidates == NULL) + candidates = pointer_set_create (); + pointer_set_insert (candidates, fndecl); + } + } + + return candidates; +} + + +/* Java requires that we be able to reference a local address for a + method, and not be confused by PLT entries. If hidden aliases are + supported, emit one for each java function that we've emitted. + CANDIDATES is the set of FUNCTION_DECLs that were gathered + by collect_candidates_for_java_method_aliases. */ + +static void +build_java_method_aliases (struct pointer_set_t *candidates) +{ + struct cgraph_node *node; + +#ifndef HAVE_GAS_HIDDEN + return; +#endif + + for (node = cgraph_nodes; node ; node = node->next) + { + tree fndecl = node->decl; + + if (TREE_ASM_WRITTEN (fndecl) + && pointer_set_contains (candidates, fndecl)) + { /* Mangle the name in a predictable way; we need to reference this from a java compiled object file. */ tree oid, nid, alias; @@ -3379,6 +3413,7 @@ cp_write_global_declarations (void) unsigned ssdf_count = 0; int retries = 0; tree decl; + struct pointer_set_t *candidates; locus = input_location; at_eof = 1; @@ -3676,6 +3711,9 @@ cp_write_global_declarations (void) linkage now. */ pop_lang_context (); + /* Collect candidates for Java hidden aliases. */ + candidates = collect_candidates_for_java_method_aliases (); + cgraph_finalize_compilation_unit (); /* Now, issue warnings about static, but not defined, functions, @@ -3690,7 +3728,11 @@ cp_write_global_declarations (void) } /* Generate hidden aliases for Java. */ - build_java_method_aliases (); + if (candidates) + { + build_java_method_aliases (candidates); + pointer_set_destroy (candidates); + } finish_repo (); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 1e5255e8..477140c 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3186,7 +3186,9 @@ emit_associated_thunks (tree fn) is so that you can know statically the entire set of thunks that will ever be needed for a given virtual function, thereby enabling you to output all the thunks with the function itself. */ - if (DECL_VIRTUAL_P (fn)) + if (DECL_VIRTUAL_P (fn) + /* Do not emit thunks for extern template instantiations. */ + && ! DECL_REALLY_EXTERN (fn)) { tree thunk; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index f09b036..808a18a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3030,6 +3030,53 @@ cast_valid_in_integral_constant_expression_p (tree type) || type == error_mark_node); } +/* Return true if we need to fix linkage information of DECL. */ + +static bool +cp_fix_function_decl_p (tree decl) +{ + /* Skip if DECL is not externally visible. */ + if (!TREE_PUBLIC (decl)) + return false; + + /* We need to fix DECL if it a appears to be exported but with no + function body. Thunks do not have CFGs and we may need to + handle them specially later. */ + if (!gimple_has_body_p (decl) + && !DECL_THUNK_P (decl) + && !DECL_EXTERNAL (decl)) + return true; + + return false; +} + +/* Clean the C++ specific parts of the tree T. */ + +void +cp_free_lang_data (tree t) +{ + if (TREE_CODE (t) == METHOD_TYPE + || TREE_CODE (t) == FUNCTION_TYPE) + { + /* Default args are not interesting anymore. */ + tree argtypes = TYPE_ARG_TYPES (t); + while (argtypes) + { + TREE_PURPOSE (argtypes) = 0; + argtypes = TREE_CHAIN (argtypes); + } + } + else if (TREE_CODE (t) == FUNCTION_DECL + && cp_fix_function_decl_p (t)) + { + /* If T is used in this translation unit at all, the definition + must exist somewhere else since we have decided to not emit it + in this TU. So make it an external reference. */ + DECL_EXTERNAL (t) = 1; + TREE_STATIC (t) = 0; + } +} + #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) /* Complain that some language-specific thing hanging off a tree diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index b8e025a..bca7478 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -48,11 +48,6 @@ along with GCC; see the file COPYING3. If not see /* Prototypes. */ static char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1; -static void default_diagnostic_starter (diagnostic_context *, - diagnostic_info *); -static void default_diagnostic_finalizer (diagnostic_context *, - diagnostic_info *); - static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN; static void diagnostic_action_after_output (diagnostic_context *, @@ -266,7 +261,7 @@ diagnostic_report_current_module (diagnostic_context *context) } } -static void +void default_diagnostic_starter (diagnostic_context *context, diagnostic_info *diagnostic) { @@ -274,7 +269,7 @@ default_diagnostic_starter (diagnostic_context *context, pp_set_prefix (context->printer, diagnostic_build_prefix (diagnostic)); } -static void +void default_diagnostic_finalizer (diagnostic_context *context, diagnostic_info *diagnostic ATTRIBUTE_UNUSED) { diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index b9bff22..c2c08bc 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -213,6 +213,8 @@ extern bool emit_diagnostic (diagnostic_t, location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(4,5); #endif extern char *diagnostic_build_prefix (diagnostic_info *); +void default_diagnostic_starter (diagnostic_context *, diagnostic_info *); +void default_diagnostic_finalizer (diagnostic_context *, diagnostic_info *); /* Pure text formatting support functions. */ extern char *file_name_as_prefix (const char *); @@ -239,4 +241,8 @@ extern void print_gimple_stmt (FILE *, gimple, int, int); extern void print_gimple_expr (FILE *, gimple, int, int); extern void dump_gimple_stmt (pretty_printer *, gimple, int, int); +/* In toplev.c */ +extern bool default_tree_printer (pretty_printer *, text_info *, const char *, + int, bool, bool, bool); + #endif /* ! GCC_DIAGNOSTIC_H */ diff --git a/gcc/except.c b/gcc/except.c index ed489d9..c97928e 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -1688,6 +1688,10 @@ add_type_for_runtime (tree type) { tree *slot; + /* If TYPE is NOP_EXPR, it means that it already is a runtime type. */ + if (TREE_CODE (type) == NOP_EXPR) + return; + slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, TREE_HASH (type), INSERT); if (*slot == NULL) @@ -1702,6 +1706,10 @@ lookup_type_for_runtime (tree type) { tree *slot; + /* If TYPE is NOP_EXPR, it means that it already is a runtime type. */ + if (TREE_CODE (type) == NOP_EXPR) + return type; + slot = (tree *) htab_find_slot_with_hash (type_to_runtime_map, type, TREE_HASH (type), NO_INSERT); @@ -2881,8 +2889,33 @@ check_handled (tree handled, tree type) if (! lang_eh_type_covers) { for (t = handled; t ; t = TREE_CHAIN (t)) - if (TREE_VALUE (t) == type) - return 1; + { + tree t1 = TREE_VALUE (t); + tree t2 = type; + + /* If the types have been converted to runtime types (i.e., + when the IL is being read from disk in an LTO + compilation), then T1 and T2 will be pointers to the + runtime type of the form '(void *) &<runtime_type>' (See + cp/except.c:build_eh_type_type). Strip the conversion + and the address. */ + if (CONVERT_EXPR_P (t1)) + { + STRIP_NOPS (t1); + gcc_assert (TREE_CODE (t1) == ADDR_EXPR); + t1 = TREE_OPERAND (t1, 0); + } + + if (CONVERT_EXPR_P (t2)) + { + STRIP_NOPS (t2); + gcc_assert (TREE_CODE (t2) == ADDR_EXPR); + t2 = TREE_OPERAND (t2, 0); + } + + if (t1 == t2) + return 1; + } } else { diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 5afb061..aeae283 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,7 @@ +2009-09-03 Diego Novillo <dnovillo@google.com> + + * f95-lang.c (lang_hooks): Remove const qualifier. + 2009-09-01 Richard Guenther <rguenther@suse.de> * f95-lang.c (gfc_mark_addressable): Remove. diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 181f0fc..e061538 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -154,7 +154,7 @@ static void gfc_init_ts (void); #define LANG_HOOKS_BUILTIN_FUNCTION gfc_builtin_function #define LANG_HOOKS_GET_ARRAY_DESCR_INFO gfc_get_array_descr_info -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; #define NULL_BINDING_LEVEL (struct binding_level *) NULL diff --git a/gcc/gimple.c b/gcc/gimple.c index 7db3410..9223aaa 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-flow.h" #include "value-prof.h" #include "flags.h" +#include "demangle.h" #define DEFGSCODE(SYM, NAME, STRUCT) NAME, const char *const gimple_code_name[] = { @@ -3427,4 +3428,75 @@ gimple_ior_addresses_taken (bitmap addresses_taken, gimple stmt) gimple_ior_addresses_taken_1); } + +/* Return a printable name for symbol DECL. */ + +const char * +gimple_decl_printable_name (tree decl, int verbosity) +{ + gcc_assert (decl && DECL_NAME (decl)); + + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + { + const char *str, *mangled_str; + int dmgl_opts = DMGL_NO_OPTS; + + if (verbosity >= 2) + { + dmgl_opts = DMGL_VERBOSE + | DMGL_TYPES + | DMGL_ANSI + | DMGL_GNU_V3 + | DMGL_RET_POSTFIX; + if (TREE_CODE (decl) == FUNCTION_DECL) + dmgl_opts |= DMGL_PARAMS; + } + + mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + str = cplus_demangle_v3 (mangled_str, dmgl_opts); + return (str) ? str : mangled_str; + } + + return IDENTIFIER_POINTER (DECL_NAME (decl)); +} + + +/* Fold a OBJ_TYPE_REF expression to the address of a function. + KNOWN_TYPE carries the true type of OBJ_TYPE_REF_OBJECT(REF). Adapted + from cp_fold_obj_type_ref, but it tolerates types with no binfo + data. */ + +tree +gimple_fold_obj_type_ref (tree ref, tree known_type) +{ + HOST_WIDE_INT index; + HOST_WIDE_INT i; + tree v; + tree fndecl; + + if (TYPE_BINFO (known_type) == NULL_TREE) + return NULL_TREE; + + v = BINFO_VIRTUALS (TYPE_BINFO (known_type)); + index = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1); + i = 0; + while (i != index) + { + i += (TARGET_VTABLE_USES_DESCRIPTORS + ? TARGET_VTABLE_USES_DESCRIPTORS : 1); + v = TREE_CHAIN (v); + } + + fndecl = TREE_VALUE (v); + +#ifdef ENABLE_CHECKING + gcc_assert (tree_int_cst_equal (OBJ_TYPE_REF_TOKEN (ref), + DECL_VINDEX (fndecl))); +#endif + + cgraph_node (fndecl)->local.vtable_method = true; + + return build_fold_addr_expr (fndecl); +} + #include "gt-gimple.h" diff --git a/gcc/gimple.h b/gcc/gimple.h index 7a034a1..97d2c37 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -836,6 +836,8 @@ bool gimple_assign_rhs_could_trap_p (gimple); void gimple_regimplify_operands (gimple, gimple_stmt_iterator *); bool empty_body_p (gimple_seq); unsigned get_gimple_rhs_num_ops (enum tree_code); +const char *gimple_decl_printable_name (tree, int); +tree gimple_fold_obj_type_ref (tree, tree); /* Returns true iff T is a valid GIMPLE statement. */ extern bool is_gimple_stmt (tree); @@ -240,6 +240,11 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) #ifdef ENABLE_CHECKING verify_cgraph (); #endif + + /* Reclaim alias pairs for functions that have disappeared from the + call graph. */ + remove_unreachable_alias_pairs (); + return changed; } diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 1437c5a..569b5fe 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,7 @@ +2009-09-03 Diego Novillo <dnovillo@google.com> + + * lang.c (lang_hooks): Remove const qualifier. + 2009-09-01 Jakub Jelinek <jakub@redhat.com> * boehm.c (mark_reference_fields): Compute % in HOST_WIDE_INT diff --git a/gcc/java/lang.c b/gcc/java/lang.c index 109ec51..d97b508 100644 --- a/gcc/java/lang.c +++ b/gcc/java/lang.c @@ -159,7 +159,7 @@ struct GTY(()) language_function { #define LANG_HOOKS_ATTRIBUTE_TABLE java_attribute_table /* Each front end provides its own. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* * process java-specific compiler command-line options diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index aebab55..63a0dcd 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -99,6 +99,7 @@ extern void lhd_omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *, #define LANG_HOOKS_PRINT_ERROR_FUNCTION lhd_print_error_function #define LANG_HOOKS_DECL_PRINTABLE_NAME lhd_decl_printable_name #define LANG_HOOKS_DWARF_NAME lhd_dwarf_name +#define LANG_HOOKS_FREE_LANG_DATA lhd_do_nothing_t #define LANG_HOOKS_TREE_SIZE lhd_tree_size #define LANG_HOOKS_TYPES_COMPATIBLE_P lhd_types_compatible_p #define LANG_HOOKS_BUILTIN_FUNCTION lhd_builtin_function @@ -229,6 +230,7 @@ extern tree lhd_make_node (enum tree_code); #define LANG_HOOKS_INITIALIZER { \ LANG_HOOKS_NAME, \ LANG_HOOKS_IDENTIFIER_SIZE, \ + LANG_HOOKS_FREE_LANG_DATA, \ LANG_HOOKS_TREE_SIZE, \ LANG_HOOKS_INIT_OPTIONS, \ LANG_HOOKS_INITIALIZE_DIAGNOSTICS, \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index cf3bda0..8342004 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -235,6 +235,9 @@ struct lang_hooks identifier nodes long enough for the language-specific slots. */ size_t identifier_size; + /* Remove any parts of the tree that are used only by the FE. */ + void (*free_lang_data) (tree); + /* Determines the size of any language-specific tcc_constant or tcc_exceptional nodes. Since it is called from make_node, the only information available is the tree code. Expected to die @@ -416,7 +419,7 @@ struct lang_hooks }; /* Each front end provides its own. */ -extern const struct lang_hooks lang_hooks; +extern struct lang_hooks lang_hooks; extern tree add_builtin_function (const char *name, tree type, int function_code, enum built_in_class cl, const char *library_name, diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index f1b5722..d499f0a 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,7 @@ +2009-09-03 Diego Novillo <dnovillo@google.com> + + * objc-lang.c (lang_hooks): Remove const qualifier. + 2009-08-20 Richard Guenther <rguenther@suse.de> * objc-act.c: Include c-lang.h diff --git a/gcc/objc/objc-lang.c b/gcc/objc/objc-lang.c index c8a3160..98f46d7 100644 --- a/gcc/objc/objc-lang.c +++ b/gcc/objc/objc-lang.c @@ -52,7 +52,7 @@ static void objc_init_ts (void); #define LANG_HOOKS_INIT_TS objc_init_ts /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Lang hook routines common to C and ObjC appear in c-objc-common.c; there should be very few (if any) routines below. */ diff --git a/gcc/objcp/ChangeLog b/gcc/objcp/ChangeLog index a19627c..9acf08b 100644 --- a/gcc/objcp/ChangeLog +++ b/gcc/objcp/ChangeLog @@ -1,3 +1,7 @@ +2009-09-03 Diego Novillo <dnovillo@google.com> + + * objcp-lang.c (lang_hooks): Remove const qualifier. + 2009-07-14 Taras Glek <tglek@mozilla.com> Rafael Espindola <espindola@google.com> diff --git a/gcc/objcp/objcp-lang.c b/gcc/objcp/objcp-lang.c index 75cc6f2..1b54ba8 100644 --- a/gcc/objcp/objcp-lang.c +++ b/gcc/objcp/objcp-lang.c @@ -52,7 +52,7 @@ static void objcxx_init_ts (void); #define LANG_HOOKS_INIT_TS objcxx_init_ts /* Each front end provides its own lang hook initializer. */ -const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Lang hook routines common to C++ and ObjC++ appear in cp/cp-objcp-common.c; there should be very few (if any) routines below. */ diff --git a/gcc/passes.c b/gcc/passes.c index 7731da6..531dc60 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -535,6 +535,7 @@ init_optimization_passes (void) NEXT_PASS (pass_inline_parameters); NEXT_PASS (pass_rebuild_cgraph_edges); } + NEXT_PASS (pass_ipa_free_lang_data); NEXT_PASS (pass_early_local_passes); { struct opt_pass **p = &pass_early_local_passes.pass.sub; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ba464ed..277bcc7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2009-09-03 Diego Novillo <dnovillo@google.com> + + * gcc.dg/gomp/combined-1.c: Adjust expected pattern. + * g++.dg/tree-prof/inline_mismatch_args.C: Likewise. + * g++.dg/warn/unit-1.C: Likewise. + * g++.dg/ipa/iinline-1.C: Likewise. + * g++.dg/template/cond2.C: Adjust expected line location for the + error. + * g++.dg/template/pr35240.C: Likewise. + 2009-09-02 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> * gcc.dg/tree-ssa/inline-3.c: Add -fpie when pic. diff --git a/gcc/testsuite/g++.dg/ipa/iinline-1.C b/gcc/testsuite/g++.dg/ipa/iinline-1.C index 83490aa..1453c7e 100644 --- a/gcc/testsuite/g++.dg/ipa/iinline-1.C +++ b/gcc/testsuite/g++.dg/ipa/iinline-1.C @@ -44,5 +44,5 @@ int main (int argc, char *argv[]) return 0; } -/* { dg-final { scan-ipa-dump "String::funcOne\[^\\n\]*inline copy in int main" "inline" } } */ +/* { dg-final { scan-ipa-dump "String::funcOne\[^\\n\]*inline copy in main" "inline" } } */ /* { dg-final { cleanup-ipa-dump "inline" } } */ diff --git a/gcc/testsuite/g++.dg/template/cond2.C b/gcc/testsuite/g++.dg/template/cond2.C index abb6ebb..e6bd19d 100644 --- a/gcc/testsuite/g++.dg/template/cond2.C +++ b/gcc/testsuite/g++.dg/template/cond2.C @@ -3,8 +3,8 @@ template<int X> class c; -template<int X, int Y> int test(c<X ? : Y>&); +template<int X, int Y> int test(c<X ? : Y>&); // { dg-error "omitted" } void test(c<2>*c2) { - test<0, 2>(*c2); // { dg-error "omitted" } + test<0, 2>(*c2); } diff --git a/gcc/testsuite/g++.dg/template/pr35240.C b/gcc/testsuite/g++.dg/template/pr35240.C index de82897..1972cf73 100644 --- a/gcc/testsuite/g++.dg/template/pr35240.C +++ b/gcc/testsuite/g++.dg/template/pr35240.C @@ -4,9 +4,9 @@ template<int> struct A {}; -template<int N> A<sizeof(new int[N][N])> foo(); +template<int N> A<sizeof(new int[N][N])> foo(); // { dg-message "unimplemented" } void bar() { - foo<1>(); // { dg-message "unimplemented" } + foo<1>(); } diff --git a/gcc/testsuite/g++.dg/tree-prof/inline_mismatch_args.C b/gcc/testsuite/g++.dg/tree-prof/inline_mismatch_args.C index a0d4882..352e176 100644 --- a/gcc/testsuite/g++.dg/tree-prof/inline_mismatch_args.C +++ b/gcc/testsuite/g++.dg/tree-prof/inline_mismatch_args.C @@ -31,6 +31,6 @@ int main(void) baz.Bar(&baz, gid); return 0; } -/* { dg-final-use { scan-tree-dump "Inlining virtual void Super::Foo" "einline2"} } */ +/* { dg-final-use { scan-tree-dump "Inlining .*Super::Foo" "einline2"} } */ /* { dg-final-use { scan-tree-dump-not "mismatched arguments" "einline2"} } */ /* { dg-final-use { cleanup-tree-dump "einline2" } } */ diff --git a/gcc/testsuite/g++.dg/warn/unit-1.C b/gcc/testsuite/g++.dg/warn/unit-1.C index 9c09d3f..49bc231 100644 --- a/gcc/testsuite/g++.dg/warn/unit-1.C +++ b/gcc/testsuite/g++.dg/warn/unit-1.C @@ -4,7 +4,7 @@ struct a { int mode; }; int sys_msgctl (void) { - struct a setbuf; /* { dg-warning "'setbuf\.a::mode' is used" "" { xfail *-*-* } } */ + struct a setbuf; /* { dg-warning "'setbuf.mode' is used" "" { xfail *-*-* } } */ return setbuf.mode; } diff --git a/gcc/testsuite/gcc.dg/gomp/combined-1.c b/gcc/testsuite/gcc.dg/gomp/combined-1.c index 7e23465..dfed647 100644 --- a/gcc/testsuite/gcc.dg/gomp/combined-1.c +++ b/gcc/testsuite/gcc.dg/gomp/combined-1.c @@ -20,5 +20,5 @@ int foo (void) } } -/* { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel_loop_runtime_start" 3 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "GOMP_parallel_loop_runtime_start" 3 "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/timevar.def b/gcc/timevar.def index 0e704cb..7e3d702 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -46,6 +46,7 @@ DEFTIMEVAR (TV_IPA_REFERENCE , "ipa reference") DEFTIMEVAR (TV_IPA_PURE_CONST , "ipa pure const") DEFTIMEVAR (TV_IPA_TYPE_ESCAPE , "ipa type escape") DEFTIMEVAR (TV_IPA_PTA , "ipa points-to") +DEFTIMEVAR (TV_IPA_FREE_LANG_DATA , "ipa free lang data") /* Time spent by constructing CFG. */ DEFTIMEVAR (TV_CFG , "cfg construction") /* Time spent by cleaning up CFG. */ diff --git a/gcc/toplev.c b/gcc/toplev.c index b0e7039..1eaa893 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1576,8 +1576,8 @@ default_pch_valid_p (const void *data_p, size_t len) } /* Default tree printer. Handles declarations only. */ -static bool -default_tree_printer (pretty_printer * pp, text_info *text, const char *spec, +bool +default_tree_printer (pretty_printer *pp, text_info *text, const char *spec, int precision, bool wide, bool set_locus, bool hash) { tree t; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index bc1ebda..4bb3364 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -409,6 +409,7 @@ extern struct gimple_opt_pass pass_warn_unused_result; /* IPA Passes */ extern struct ipa_opt_pass_d pass_ipa_inline; +extern struct simple_ipa_opt_pass pass_ipa_free_lang_data; extern struct ipa_opt_pass_d pass_ipa_cp; extern struct ipa_opt_pass_d pass_ipa_reference; extern struct ipa_opt_pass_d pass_ipa_pure_const; @@ -52,6 +52,13 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "pointer-set.h" #include "fixed-value.h" +#include "tree-pass.h" +#include "langhooks-def.h" +#include "diagnostic.h" +#include "cgraph.h" +#include "timevar.h" +#include "except.h" +#include "debug.h" /* Tree code classes. */ @@ -4124,6 +4131,789 @@ build_type_attribute_variant (tree ttype, tree attribute) TYPE_QUALS (ttype)); } +/* Reset all language specific information still present in TYPE. */ + +static void +free_lang_data_in_type (tree type) +{ + gcc_assert (TYPE_P (type)); + + /* Fill in the alias-set. We need to at least track zeroness here + for correctness. */ + if (lang_hooks.get_alias_set (type) == 0) + TYPE_ALIAS_SET (type) = 0; + + /* Give the FE a chance to remove its own data first. */ + lang_hooks.free_lang_data (type); + + TREE_LANG_FLAG_0 (type) = 0; + TREE_LANG_FLAG_1 (type) = 0; + TREE_LANG_FLAG_2 (type) = 0; + TREE_LANG_FLAG_3 (type) = 0; + TREE_LANG_FLAG_4 (type) = 0; + TREE_LANG_FLAG_5 (type) = 0; + TREE_LANG_FLAG_6 (type) = 0; + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + /* Remove the const and volatile qualifiers from arguments. The + C++ front end removes them, but the C front end does not, + leading to false ODR violation errors when merging two + instances of the same function signature compiled by + different front ends. */ + tree p; + + for (p = TYPE_ARG_TYPES (type); p; p = TREE_CHAIN (p)) + { + tree arg_type = TREE_VALUE (p); + + if (TYPE_READONLY (arg_type) || TYPE_VOLATILE (arg_type)) + { + int quals = TYPE_QUALS (arg_type) + & ~TYPE_QUAL_CONST + & ~TYPE_QUAL_VOLATILE; + TREE_VALUE (p) = build_qualified_type (arg_type, quals); + free_lang_data_in_type (TREE_VALUE (p)); + } + } + } + + /* Remove members that are not actually FIELD_DECLs from the field + list of an aggregate. These occur in C++. */ + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + tree prev, member; + + /* Note that TYPE_FIELDS can be shared across distinct + TREE_TYPEs. Therefore, if the first field of TYPE_FIELDS is + to be removed, we cannot set its TREE_CHAIN to NULL. + Otherwise, we would not be able to find all the other fields + in the other instances of this TREE_TYPE. + + This was causing an ICE in testsuite/g++.dg/lto/20080915.C. */ + prev = NULL_TREE; + member = TYPE_FIELDS (type); + while (member) + { + if (TREE_CODE (member) == FIELD_DECL) + { + if (prev) + TREE_CHAIN (prev) = member; + else + TYPE_FIELDS (type) = member; + prev = member; + } + + member = TREE_CHAIN (member); + } + + if (prev) + TREE_CHAIN (prev) = NULL_TREE; + else + TYPE_FIELDS (type) = NULL_TREE; + + TYPE_METHODS (type) = NULL_TREE; + if (TYPE_BINFO (type)) + { + tree binfo = TYPE_BINFO (type); + + if (BINFO_VIRTUALS (binfo)) + { + /* If the virtual function table for BINFO contains + entries, these may be useful for folding OBJ_TYPE_REF + expressions (see gimple_fold_obj_type_ref). In that + case, we only clear the unused fields in the BINFO + structure. */ + BINFO_OFFSET (binfo) = NULL_TREE; + BINFO_VTABLE (binfo) = NULL_TREE; + BINFO_VPTR_FIELD (binfo) = NULL_TREE; + BINFO_BASE_ACCESSES (binfo) = NULL; + BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE; + BINFO_SUBVTT_INDEX (binfo) = NULL_TREE; + BINFO_VPTR_FIELD (binfo) = NULL_TREE; + } + else + { + /* Otherwise, get rid of the whole binfo data. */ + TYPE_BINFO (type) = NULL_TREE; + } + } + } + else + { + /* For non-aggregate types, clear out the language slot (which + overloads TYPE_BINFO). */ + TYPE_LANG_SLOT_1 (type) = NULL_TREE; + } + + TYPE_CONTEXT (type) = NULL_TREE; + TYPE_STUB_DECL (type) = NULL_TREE; + + /* Remove type variants other than the main variant. This is both + wasteful and it may introduce infinite loops when the types are + read from disk and merged (since the variant will be the same + type as the main variant, traversing type variants will get into + an infinite loop). */ + if (TYPE_MAIN_VARIANT (type)) + TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (type)) = NULL_TREE; + + TYPE_NEXT_VARIANT (type) = NULL_TREE; +} + + +/* Return true if DECL may need an assembler name to be set. */ + +static inline bool +need_assembler_name_p (tree decl) +{ + /* Only FUNCTION_DECLs and VAR_DECLs are considered. */ + if (TREE_CODE (decl) != FUNCTION_DECL + && TREE_CODE (decl) != VAR_DECL) + return false; + + /* If DECL already has its assembler name set, it does not need a + new one. */ + if (!HAS_DECL_ASSEMBLER_NAME_P (decl) + || DECL_ASSEMBLER_NAME_SET_P (decl)) + return false; + + /* For VAR_DECLs, only static, public and external symbols need an + assembler name. */ + if (TREE_CODE (decl) == VAR_DECL + && !TREE_STATIC (decl) + && !TREE_PUBLIC (decl) + && !DECL_EXTERNAL (decl)) + return false; + + /* Do not set assembler name on builtins. Allow RTL expansion to + decide whether to expand inline or via a regular call. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_BUILT_IN (decl) + && DECL_BUILT_IN_CLASS (decl) != BUILT_IN_FRONTEND) + return false; + + /* For FUNCTION_DECLs, only used functions and functions + represented in the callgraph need an assembler name. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && cgraph_node_for_decl (decl) == NULL + && !TREE_USED (decl)) + return false; + + return true; +} + + +/* Remove all the non-variable decls from BLOCK. LOCALS is the set of + variables in DECL_STRUCT_FUNCTION (FN)->local_decls. Every decl + in BLOCK that is not in LOCALS is removed. */ + +static void +free_lang_data_in_block (tree fn, tree block, struct pointer_set_t *locals) +{ + tree *tp, t; + + tp = &BLOCK_VARS (block); + while (*tp) + { + if (!pointer_set_contains (locals, *tp)) + *tp = TREE_CHAIN (*tp); + else + tp = &TREE_CHAIN (*tp); + } + + for (t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t)) + free_lang_data_in_block (fn, t, locals); +} + + +/* Reset all language specific information still present in symbol + DECL. */ + +static void +free_lang_data_in_decl (tree decl) +{ + gcc_assert (DECL_P (decl)); + + /* Give the FE a chance to remove its own data first. */ + lang_hooks.free_lang_data (decl); + + TREE_LANG_FLAG_0 (decl) = 0; + TREE_LANG_FLAG_1 (decl) = 0; + TREE_LANG_FLAG_2 (decl) = 0; + TREE_LANG_FLAG_3 (decl) = 0; + TREE_LANG_FLAG_4 (decl) = 0; + TREE_LANG_FLAG_5 (decl) = 0; + TREE_LANG_FLAG_6 (decl) = 0; + + /* Identifiers need not have a type. */ + if (DECL_NAME (decl)) + TREE_TYPE (DECL_NAME (decl)) = NULL_TREE; + + if (TREE_CODE (decl) == CONST_DECL) + DECL_CONTEXT (decl) = NULL_TREE; + + /* Ignore any intervening types, because we are going to clear their + TYPE_CONTEXT fields. */ + if (TREE_CODE (decl) != FIELD_DECL) + DECL_CONTEXT (decl) = decl_function_context (decl); + + if (DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL) + DECL_CONTEXT (decl) = NULL_TREE; + + if (TREE_CODE (decl) == VAR_DECL) + { + tree context = DECL_CONTEXT (decl); + + if (context) + { + enum tree_code code = TREE_CODE (context); + if (code == FUNCTION_DECL && DECL_ABSTRACT (context)) + { + /* Do not clear the decl context here, that will promote + all vars to global ones. */ + DECL_INITIAL (decl) = NULL_TREE; + } + + if (TREE_STATIC (decl)) + DECL_CONTEXT (decl) = NULL_TREE; + } + } + + if (TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == RESULT_DECL) + { + tree unit_size = DECL_SIZE_UNIT (decl); + tree size = DECL_SIZE (decl); + if ((unit_size && TREE_CODE (unit_size) != INTEGER_CST) + || (size && TREE_CODE (size) != INTEGER_CST)) + { + DECL_SIZE_UNIT (decl) = NULL_TREE; + DECL_SIZE (decl) = NULL_TREE; + } + + if (TREE_CODE (decl) == FIELD_DECL + && DECL_FIELD_OFFSET (decl) + && TREE_CODE (DECL_FIELD_OFFSET (decl)) != INTEGER_CST) + DECL_FIELD_OFFSET (decl) = NULL_TREE; + } + else if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (gimple_has_body_p (decl)) + { + tree t; + struct pointer_set_t *locals; + + /* If DECL has a gimple body, then the context for its + arguments must be DECL. Otherwise, it doesn't really + matter, as we will not be emitting any code for DECL. In + general, there may be other instances of DECL created by + the front end and since PARM_DECLs are generally shared, + their DECL_CONTEXT changes as the replicas of DECL are + created. The only time where DECL_CONTEXT is important + is for the FUNCTION_DECLs that have a gimple body (since + the PARM_DECL will be used in the function's body). */ + for (t = DECL_ARGUMENTS (decl); t; t = TREE_CHAIN (t)) + DECL_CONTEXT (t) = decl; + + /* Collect all the symbols declared in DECL. */ + locals = pointer_set_create (); + t = DECL_STRUCT_FUNCTION (decl)->local_decls; + for (; t; t = TREE_CHAIN (t)) + { + pointer_set_insert (locals, TREE_VALUE (t)); + + /* All the local symbols should have DECL as their + context. */ + DECL_CONTEXT (TREE_VALUE (t)) = decl; + } + + /* Get rid of any decl not in local_decls. */ + free_lang_data_in_block (decl, DECL_INITIAL (decl), locals); + + pointer_set_destroy (locals); + } + + /* DECL_SAVED_TREE holds the GENERIC representation for DECL. + At this point, it is not needed anymore. */ + DECL_SAVED_TREE (decl) = NULL_TREE; + } + else if (TREE_CODE (decl) == VAR_DECL) + { + tree expr = DECL_DEBUG_EXPR (decl); + if (expr + && TREE_CODE (expr) == VAR_DECL + && !TREE_STATIC (expr) && !DECL_EXTERNAL (expr)) + SET_DECL_DEBUG_EXPR (decl, NULL_TREE); + + if (DECL_EXTERNAL (decl)) + DECL_INITIAL (decl) = NULL_TREE; + } + else if (TREE_CODE (decl) == TYPE_DECL) + { + DECL_INITIAL (decl) = NULL_TREE; + + /* DECL_CONTEXT is overloaded as DECL_FIELD_CONTEXT for + FIELD_DECLs, which should be preserved. Otherwise, + we shouldn't be concerned with source-level lexical + nesting beyond this point. */ + DECL_CONTEXT (decl) = NULL_TREE; + } +} + + +/* Data used when collecting DECLs and TYPEs for language data removal. */ + +struct free_lang_data_d +{ + /* Set of traversed objects. Used to avoid duplicate visits. */ + struct pointer_set_t *pset; + + /* Array of symbols to process with free_lang_data_in_decl. */ + VEC(tree,heap) *decls; + + /* Array of types to process with free_lang_data_in_type. */ + VEC(tree,heap) *types; +}; + + +/* Save all language fields needed to generate proper debug information + for DECL. This saves most fields cleared out by free_lang_data_in_decl. */ + +static void +save_debug_info_for_decl (tree t) +{ + /*struct saved_debug_info_d *sdi;*/ + + gcc_assert (debug_info_level > DINFO_LEVEL_TERSE && t && DECL_P (t)); + + /* FIXME. Partial implementation for saving debug info removed. */ +} + + +/* Save all language fields needed to generate proper debug information + for TYPE. This saves most fields cleared out by free_lang_data_in_type. */ + +static void +save_debug_info_for_type (tree t) +{ + /*struct saved_debug_info_d *sdi;*/ + + gcc_assert (debug_info_level > DINFO_LEVEL_TERSE && t && TYPE_P (t)); + + /* FIXME. Partial implementation for saving debug info removed. */ +} + + +/* Add type or decl T to one of the list of tree nodes that need their + language data removed. The lists are held inside FLD. */ + +static void +add_tree_to_fld_list (tree t, struct free_lang_data_d *fld) +{ + if (DECL_P (t)) + { + VEC_safe_push (tree, heap, fld->decls, t); + if (debug_info_level > DINFO_LEVEL_TERSE) + save_debug_info_for_decl (t); + } + else if (TYPE_P (t)) + { + VEC_safe_push (tree, heap, fld->types, t); + if (debug_info_level > DINFO_LEVEL_TERSE) + save_debug_info_for_type (t); + } + else + gcc_unreachable (); +} + + +/* Operand callback helper for free_lang_data_in_node. *TP is the + subtree operand being considered. */ + +static tree +find_decls_types_r (tree *tp, int *ws ATTRIBUTE_UNUSED, void *data) +{ + tree t = *tp; + struct free_lang_data_d *fld = (struct free_lang_data_d *) data; + + if (DECL_P (t)) + { + /* Note that walk_tree does not traverse every possible field in + decls, so we have to do our own traversals here. */ + add_tree_to_fld_list (t, fld); + + walk_tree (&DECL_NAME (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_CONTEXT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_SIZE (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_INITIAL (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_ABSTRACT_ORIGIN (t), find_decls_types_r, fld, fld->pset); + + if (TREE_CODE (t) == FUNCTION_DECL) + { + walk_tree (&DECL_ARGUMENTS (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_RESULT (t), find_decls_types_r, fld, fld->pset); + } + else if (TREE_CODE (t) == TYPE_DECL) + { + walk_tree (&DECL_ARGUMENT_FLD (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_VINDEX (t), find_decls_types_r, fld, fld->pset); + } + else if (TREE_CODE (t) == FIELD_DECL) + { + walk_tree (&DECL_FIELD_OFFSET (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_BIT_FIELD_TYPE (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_QUALIFIER (t), find_decls_types_r, fld, fld->pset); + walk_tree (&DECL_FIELD_BIT_OFFSET (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_FCONTEXT (t), find_decls_types_r, fld, fld->pset); + } + else if (TREE_CODE (t) == VAR_DECL) + { + walk_tree (&DECL_SECTION_NAME (t), find_decls_types_r, fld, + fld->pset); + walk_tree (&DECL_COMDAT_GROUP (t), find_decls_types_r, fld, + fld->pset); + } + } + else if (TYPE_P (t)) + { + /* Note that walk_tree does not traverse every possible field in + types, so we have to do our own traversals here. */ + add_tree_to_fld_list (t, fld); + + walk_tree (&TYPE_CACHED_VALUES (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_SIZE (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_POINTER_TO (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_REFERENCE_TO (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_NAME (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_MINVAL (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_MAXVAL (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_NEXT_VARIANT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_MAIN_VARIANT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_CONTEXT (t), find_decls_types_r, fld, fld->pset); + walk_tree (&TYPE_CANONICAL (t), find_decls_types_r, fld, fld->pset); + } + + if (TREE_TYPE (t)) + walk_tree (&TREE_TYPE (t), find_decls_types_r, fld, fld->pset); + + /* Do not recurse into TREE_CHAIN to avoid blowing up the stack. */ + for (tp = &TREE_CHAIN (t); *tp; tp = &TREE_CHAIN (*tp)) + { + tree saved_chain = TREE_CHAIN (*tp); + TREE_CHAIN (*tp) = NULL_TREE; + walk_tree (tp, find_decls_types_r, fld, fld->pset); + TREE_CHAIN (*tp) = saved_chain; + } + + return NULL_TREE; +} + + +/* Translate all the types in LIST with the corresponding runtime + types. */ + +static tree +get_eh_types_for_runtime (tree list) +{ + tree head, prev; + + if (list == NULL_TREE) + return NULL_TREE; + + head = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list))); + prev = head; + list = TREE_CHAIN (list); + while (list) + { + tree n = build_tree_list (0, lookup_type_for_runtime (TREE_VALUE (list))); + TREE_CHAIN (prev) = n; + prev = TREE_CHAIN (prev); + list = TREE_CHAIN (list); + } + + return head; +} + + +/* Find decls and types referenced in EH region R and store them in + FLD->DECLS and FLD->TYPES. */ + +static void +find_decls_types_in_eh_region (eh_region r, struct free_lang_data_d *fld) +{ + if (r == NULL) + return; + + /* The types referenced in R must first be changed to the EH types + used at runtime. This removes references to FE types in the + region. */ + if (r->type == ERT_CATCH) + { + tree list = r->u.eh_catch.type_list; + r->u.eh_catch.type_list = get_eh_types_for_runtime (list); + walk_tree (&r->u.eh_catch.type_list, find_decls_types_r, fld, fld->pset); + } + else if (r->type == ERT_ALLOWED_EXCEPTIONS) + { + tree list = r->u.allowed.type_list; + r->u.allowed.type_list = get_eh_types_for_runtime (list); + walk_tree (&r->u.allowed.type_list, find_decls_types_r, fld, fld->pset); + } +} + + +/* Find decls and types referenced in cgraph node N and store them in + FLD->DECLS and FLD->TYPES. Unlike pass_referenced_vars, this will + look for *every* kind of DECL and TYPE node reachable from N, + including those embedded inside types and decls (i.e,, TYPE_DECLs, + NAMESPACE_DECLs, etc). */ + +static void +find_decls_types_in_node (struct cgraph_node *n, struct free_lang_data_d *fld) +{ + basic_block bb; + struct function *fn; + tree t; + + walk_tree (&n->decl, find_decls_types_r, fld, fld->pset); + + if (!gimple_has_body_p (n->decl)) + return; + + gcc_assert (current_function_decl == NULL_TREE && cfun == NULL); + + fn = DECL_STRUCT_FUNCTION (n->decl); + + /* Traverse locals. */ + for (t = fn->local_decls; t; t = TREE_CHAIN (t)) + { + tree *tp = &TREE_VALUE (t); + tree saved_chain = TREE_CHAIN (*tp); + TREE_CHAIN (*tp) = NULL_TREE; + walk_tree (tp, find_decls_types_r, fld, fld->pset); + TREE_CHAIN (*tp) = saved_chain; + } + + /* Traverse EH regions in FN. */ + if (fn->eh->region_array) + { + unsigned i; + eh_region r; + + for (i = 0; VEC_iterate (eh_region, fn->eh->region_array, i, r); i++) + find_decls_types_in_eh_region (r, fld); + } + + /* Traverse every statement in FN. */ + FOR_EACH_BB_FN (bb, fn) + { + gimple_stmt_iterator si; + unsigned i; + + for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) + { + gimple phi = gsi_stmt (si); + + for (i = 0; i < gimple_phi_num_args (phi); i++) + { + tree *arg_p = gimple_phi_arg_def_ptr (phi, i); + walk_tree (arg_p, find_decls_types_r, fld, fld->pset); + } + } + + for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) + { + gimple stmt = gsi_stmt (si); + + for (i = 0; i < gimple_num_ops (stmt); i++) + { + tree *arg_p = gimple_op_ptr (stmt, i); + walk_tree (arg_p, find_decls_types_r, fld, fld->pset); + } + } + } +} + + +/* Find decls and types referenced in varpool node N and store them in + FLD->DECLS and FLD->TYPES. Unlike pass_referenced_vars, this will + look for *every* kind of DECL and TYPE node reachable from N, + including those embedded inside types and decls (i.e,, TYPE_DECLs, + NAMESPACE_DECLs, etc). */ + +static void +find_decls_types_in_var (struct varpool_node *v, struct free_lang_data_d *fld) +{ + walk_tree (&v->decl, find_decls_types_r, fld, fld->pset); +} + + +/* Free language specific information for every operand and expression + in every node of the call graph. This process operates in three stages: + + 1- Every callgraph node and varpool node is traversed looking for + decls and types embedded in them. This is a more exhaustive + search than that done by find_referenced_vars, because it will + also collect individual fields, decls embedded in types, etc. + + 2- All the decls found are sent to free_lang_data_in_decl. + + 3- All the types found are sent to free_lang_data_in_type. + + The ordering between decls and types is important because + free_lang_data_in_decl sets assembler names, which includes + mangling. So types cannot be freed up until assembler names have + been set up. */ + +static void +free_lang_data_in_cgraph (void) +{ + struct cgraph_node *n; + struct varpool_node *v; + struct free_lang_data_d fld; + tree t; + unsigned i; + alias_pair *p; + + /* Initialize sets and arrays to store referenced decls and types. */ + fld.pset = pointer_set_create (); + fld.decls = VEC_alloc (tree, heap, 100); + fld.types = VEC_alloc (tree, heap, 100); + + /* Find decls and types in the body of every function in the callgraph. */ + for (n = cgraph_nodes; n; n = n->next) + find_decls_types_in_node (n, &fld); + + for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++) + walk_tree (&p->decl, find_decls_types_r, &fld, fld.pset); + + /* Find decls and types in every varpool symbol. */ + for (v = varpool_nodes_queue; v; v = v->next_needed) + find_decls_types_in_var (v, &fld); + + /* Set the assembler name on every decl found. We need to do this + now because free_lang_data_in_decl will invalidate data needed + for mangling. This breaks mangling on interdependent decls. */ + for (i = 0; VEC_iterate (tree, fld.decls, i, t); i++) + if (need_assembler_name_p (t)) + { + /* When setting DECL_ASSEMBLER_NAME, the C++ mangler may emit + diagnostics that use input_location to show locus + information. The problem here is that, at this point, + input_location is generally anchored to the end of the file + (since the parser is long gone), so we don't have a good + position to pin it to. + + To alleviate this problem, this uses the location of T's + declaration. Examples of this are + testsuite/g++.dg/template/cond2.C and + testsuite/g++.dg/template/pr35240.C. */ + location_t saved_location = input_location; + input_location = DECL_SOURCE_LOCATION (t); + + decl_assembler_name (t); + + input_location = saved_location; + } + + /* Traverse every decl found freeing its language data. */ + for (i = 0; VEC_iterate (tree, fld.decls, i, t); i++) + free_lang_data_in_decl (t); + + /* Traverse every type found freeing its language data. */ + for (i = 0; VEC_iterate (tree, fld.types, i, t); i++) + free_lang_data_in_type (t); + + pointer_set_destroy (fld.pset); + VEC_free (tree, heap, fld.decls); + VEC_free (tree, heap, fld.types); +} + + +/* Free resources that are used by FE but are not needed once they are done. */ + +static unsigned +free_lang_data (void) +{ + /* Traverse the IL resetting language specific information for + operands, expressions, etc. */ + free_lang_data_in_cgraph (); + + /* Create gimple variants for common types. */ + ptrdiff_type_node = integer_type_node; + fileptr_type_node = ptr_type_node; + if (TREE_CODE (boolean_type_node) != BOOLEAN_TYPE + || (TYPE_MODE (boolean_type_node) + != mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0)) + || TYPE_PRECISION (boolean_type_node) != 1 + || !TYPE_UNSIGNED (boolean_type_node)) + { + boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE); + TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE); + TYPE_MAX_VALUE (boolean_type_node) = build_int_cst (boolean_type_node, 1); + TYPE_PRECISION (boolean_type_node) = 1; + boolean_false_node = TYPE_MIN_VALUE (boolean_type_node); + boolean_true_node = TYPE_MAX_VALUE (boolean_type_node); + } + + /* Reset some langhooks. */ + lang_hooks.callgraph.analyze_expr = NULL; + lang_hooks.types_compatible_p = NULL; + lang_hooks.dwarf_name = lhd_dwarf_name; + lang_hooks.decl_printable_name = gimple_decl_printable_name; + lang_hooks.set_decl_assembler_name = lhd_set_decl_assembler_name; + lang_hooks.fold_obj_type_ref = gimple_fold_obj_type_ref; + + /* Reset diagnostic machinery. */ + diagnostic_starter (global_dc) = default_diagnostic_starter; + diagnostic_finalizer (global_dc) = default_diagnostic_finalizer; + diagnostic_format_decoder (global_dc) = default_tree_printer; + + return 0; +} + + +/* Gate function for free_lang_data. */ + +static bool +gate_free_lang_data (void) +{ + /* FIXME. Remove after save_debug_info is working. */ + return !flag_gtoggle && debug_info_level <= DINFO_LEVEL_TERSE; +} + + +struct simple_ipa_opt_pass pass_ipa_free_lang_data = +{ + { + SIMPLE_IPA_PASS, + NULL, /* name */ + gate_free_lang_data, /* gate */ + free_lang_data, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_IPA_FREE_LANG_DATA, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + } +}; + /* Return nonzero if IDENT is a valid name for attribute ATTR, or zero if not. @@ -5292,6 +6082,9 @@ tree_int_cst_compare (const_tree t1, const_tree t2) int host_integerp (const_tree t, int pos) { + if (t == NULL_TREE) + return 0; + return (TREE_CODE (t) == INTEGER_CST && ((TREE_INT_CST_HIGH (t) == 0 && (HOST_WIDE_INT) TREE_INT_CST_LOW (t) >= 0) @@ -183,6 +183,22 @@ DEF_VEC_P(tree); DEF_VEC_ALLOC_P(tree,gc); DEF_VEC_ALLOC_P(tree,heap); +/* We have to be able to tell cgraph about the needed-ness of the target + of an alias. This requires that the decl have been defined. Aliases + that precede their definition have to be queued for later processing. */ + +typedef struct GTY(()) alias_pair +{ + tree decl; + tree target; +} alias_pair; + +/* Define gc'd vector type. */ +DEF_VEC_O(alias_pair); +DEF_VEC_ALLOC_O(alias_pair,gc); + +extern GTY(()) VEC(alias_pair,gc) * alias_pairs; + /* Classify which part of the compiler has defined a given builtin function. Note that we assume below that this is no more than two bits. */ @@ -1259,7 +1275,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, This is interesting in an inline function, since it might not need to be compiled separately. Nonzero in a RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE or ENUMERAL_TYPE - if the sdb debugging info for the type has been written. + if the debugging info for the type has been written. In a BLOCK node, nonzero if reorder_blocks has already seen this block. In an SSA_NAME node, nonzero if the SSA_NAME occurs in an abnormal PHI node. */ @@ -2035,6 +2051,8 @@ struct GTY(()) tree_block { #define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK (NODE)->type.next_variant) #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type.main_variant) #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type.context) +#define TYPE_MAXVAL(NODE) (TYPE_CHECK (NODE)->type.maxval) +#define TYPE_MINVAL(NODE) (TYPE_CHECK (NODE)->type.minval) /* Vector types need to check target flags to determine type. */ extern enum machine_mode vector_type_mode (const_tree); @@ -2439,9 +2457,9 @@ struct function; /* For FIELD_DECLs, this is the RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node that the field is a member of. For VAR_DECL, - PARM_DECL, FUNCTION_DECL, LABEL_DECL, and CONST_DECL nodes, this - points to either the FUNCTION_DECL for the containing function, - the RECORD_TYPE or UNION_TYPE for the containing type, or + PARM_DECL, FUNCTION_DECL, LABEL_DECL, RESULT_DECL, and CONST_DECL + nodes, this points to either the FUNCTION_DECL for the containing + function, the RECORD_TYPE or UNION_TYPE for the containing type, or NULL_TREE or a TRANSLATION_UNIT_DECL if the given decl has "file scope". */ #define DECL_CONTEXT(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.context) @@ -4889,6 +4907,7 @@ extern hashval_t iterative_hash_exprs_commutative (const_tree, const_tree, hashval_t); extern hashval_t iterative_hash_host_wide_int (HOST_WIDE_INT, hashval_t); extern hashval_t iterative_hash_hashval_t (hashval_t, hashval_t); +extern hashval_t iterative_hash_host_wide_int (HOST_WIDE_INT, hashval_t); extern int compare_tree_int (const_tree, unsigned HOST_WIDE_INT); extern int type_list_equal (const_tree, const_tree); extern int chain_member (const_tree, const_tree); @@ -5047,6 +5066,7 @@ extern void process_pending_assemble_externals (void); extern void finish_aliases_1 (void); extern void finish_aliases_2 (void); extern tree emutls_decl (tree); +extern void remove_unreachable_alias_pairs (void); /* In stmt.c */ extern void expand_computed_goto (tree); diff --git a/gcc/varasm.c b/gcc/varasm.c index 2a8fb11..d7f8611 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -5369,20 +5369,7 @@ globalize_decl (tree decl) targetm.asm_out.globalize_decl_name (asm_out_file, decl); } -/* We have to be able to tell cgraph about the needed-ness of the target - of an alias. This requires that the decl have been defined. Aliases - that precede their definition have to be queued for later processing. */ - -typedef struct GTY(()) alias_pair { - tree decl; - tree target; -} alias_pair; - -/* Define gc'd vector type. */ -DEF_VEC_O(alias_pair); -DEF_VEC_ALLOC_O(alias_pair,gc); - -static GTY(()) VEC(alias_pair,gc) *alias_pairs; +VEC(alias_pair,gc) *alias_pairs; /* Given an assembly name, find the decl it is associated with. At the same time, mark it needed for cgraph. */ @@ -5526,6 +5513,39 @@ do_assemble_alias (tree decl, tree target) #endif } + +/* Remove the alias pairing for functions that are no longer in the call + graph. */ + +void +remove_unreachable_alias_pairs (void) +{ + unsigned i; + alias_pair *p; + + if (alias_pairs == NULL) + return; + + for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); ) + { + if (!DECL_EXTERNAL (p->decl)) + { + struct cgraph_node *fnode = NULL; + struct varpool_node *vnode = NULL; + fnode = cgraph_node_for_asm (p->target); + vnode = (fnode == NULL) ? varpool_node_for_asm (p->target) : NULL; + if (fnode == NULL && vnode == NULL) + { + VEC_unordered_remove (alias_pair, alias_pairs, i); + continue; + } + } + + i++; + } +} + + /* First pass of completing pending aliases. Make sure that cgraph knows which symbols will be required. */ @@ -5547,6 +5567,11 @@ finish_aliases_1 (void) p->decl, p->target); } else if (DECL_EXTERNAL (target_decl) + /* We use local aliases for C++ thunks to force the tailcall + to bind locally. Of course this is a hack - to keep it + working do the following (which is not strictly correct). */ + && (! TREE_CODE (target_decl) == FUNCTION_DECL + || ! TREE_STATIC (target_decl)) && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))) error ("%q+D aliased to external symbol %qE", p->decl, p->target); |