This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[LTO merge] gimplification of types and symbols [1/2]
- From: Diego Novillo <dnovillo at google dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Richard Guenther <rguenther at suse dot de>, Jason Merrill <jason at redhat dot com>, Mark Mitchell <mark at codesourcery dot com>
- Date: Wed, 2 Sep 2009 10:04:28 -0400
- Subject: [LTO merge] gimplification of types and symbols [1/2]
This patch adds a new IPA pass that converts all types and
symbols to gimple.
There is no conversion to a new data structure (yet). The pass
works by clearing out fields in the tree structure that are only
used by the front ends. Specifically, pass_ipa_free_lang_data
will:
1- Clear out language fields in types and symbols. The main use
of this is in the gimple streamer. When the compiler loads a
gimple bytecode file, it has no way of knowing what front end
generated that file, so it cannot interpret this data.
It should also provide some memory savings, but I have not
measured how much.
Another side-effect of this is that it disables debug info
generation. As I proposed previously
(http://gcc.gnu.org/ml/gcc/2009-08/msg00289.html), I'll fix
this in a follow-up patch. Right now, the pass is only
enabled only at -g0 and -g1.
2- Assign assembler names early. Since assembler names may
involve mangling, we need to invoke the FE's mangler before it
goes away. A new predicate need_assembler_name_p decides
whether a decl should get an assembler name. The predicate
tries to avoid assigning assembler names unless absolutely
necessary, but there are likely more assembler names generated
now.
3- Redirect lang_hooks to default and/or gimple variants. The
interesting redirections are:
lang_hooks.decl_printable_name -> gimple_decl_printable_name
This will invoke libiberty's demangler to handle mangled
names. The demangler produces slighlty different output
than cc1plus's expr_to_string(), so I adjusted a few
patterns in the testsuites.
lang_hooks.fold_obj_type_ref -> gimple_fold_obj_type_ref
When we clear out BINFO data, we only keep BINFO_VIRTUALS
so that we can fold OBJ_TYPE_REF during optimization.
This will require minor adjustments in the streamer to
handle BINFO_VIRTUALS in the bytecode.
4- Early thunk generation. After pass_ipa_free_lang_data, thunks
can no longer be generated. This is done by a call to
cgraph_emit_thunks in cgraph_optimize.
In terms of LTO, thunks are still a problem in that they are
sometimes generated as asm strings. Prior to the final LTO
merge, I will fix this by introducing a new GIMPLE_THUNK
instruction as outlined in
http://gcc.gnu.org/ml/gcc-patches/2008-12/msg00953.html
5- Early generation of Java hidden aliases. In
cp_write_global_declarations, we were emitting hidden aliases
which needed to access front end data cleared out by the call
to cgraph_finalize_compilation_unit. What we do now is
collect a set of functions candidate for hidden aliases before
removing language data and generate them afterwards.
I'm posting the hunk for #5 separately, together with the bits
needed for C++ to clear out its own language data. That part
needs approval from C++ maintainers.
The patch has been bootstrapped and tested on x86_64 on all
languages including Ada and Obj-C++.
I will wait for approval from C++ maintainers before committing.
(the C++ bits cannot go in separately).
Diego.
2009-09-01 Simon Baldwin <simonb@google.com>
Rafael Espindola <espindola@google.com>
Richard Guenther <rguenther@suse.de>
Doug Kwan <dougkwan@google.com>
Bill Maddox <maddox@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.
* Makefile.in (tree.o): Add dependencies on tree-pass.h,
langhooks-def.h, $(DIAGNOSTIC_H), $(CGRAPH_H),
$(TIMEVAR_H), except.h and debug.h.
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.
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.
cp/ChangeLog
* 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.
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.
Index: java/lang.c
===================================================================
--- java/lang.c (revision 151295)
+++ java/lang.c (working copy)
@@ -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
Index: cgraph.c
===================================================================
--- cgraph.c (revision 151295)
+++ cgraph.c (working copy)
@@ -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, bo
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)))
Index: cgraph.h
===================================================================
--- cgraph.h (revision 151295)
+++ cgraph.h (working copy)
@@ -391,7 +391,8 @@ struct cgraph_edge *cgraph_create_edge (
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);
Index: tree.c
===================================================================
--- tree.c (revision 151295)
+++ tree.c (working copy)
@@ -52,6 +52,13 @@ along with GCC; see the file COPYING3.
#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,780 @@ build_type_attribute_variant (tree ttype
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;
+
+ /* Although free_lang_data_in_cgraph will set the assembler name on
+ most DECLs, it refuses to do it on unused ones. For cgraph
+ nodes, we need to set it even if it's seemingly unused. */
+ if (!DECL_ASSEMBLER_NAME_SET_P (n->decl) && !DECL_BUILT_IN (n->decl))
+ {
+ gcc_assert (need_assembler_name_p (n->decl));
+ lang_hooks.set_decl_assembler_name (n->decl);
+ }
+
+ 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))
+ lang_hooks.set_decl_assembler_name (t);
+
+ /* 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 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 +6073,9 @@ tree_int_cst_compare (const_tree t1, con
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)
Index: tree.h
===================================================================
--- tree.h (revision 151295)
+++ tree.h (working copy)
@@ -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_faile
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. */
@@ -2032,6 +2048,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);
@@ -2436,9 +2454,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)
@@ -4882,6 +4900,7 @@ extern hashval_t iterative_hash_exprs_co
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);
@@ -5040,6 +5059,7 @@ extern void process_pending_assemble_ext
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);
Index: tree-pass.h
===================================================================
--- tree-pass.h (revision 151295)
+++ tree-pass.h (working copy)
@@ -409,6 +409,7 @@ extern struct gimple_opt_pass pass_warn_
/* 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;
Index: diagnostic.c
===================================================================
--- diagnostic.c (revision 151295)
+++ diagnostic.c (working copy)
@@ -48,11 +48,6 @@ along with GCC; see the file COPYING3.
/* 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 (diagno
}
}
-static void
+void
default_diagnostic_starter (diagnostic_context *context,
diagnostic_info *diagnostic)
{
@@ -274,7 +269,7 @@ default_diagnostic_starter (diagnostic_c
pp_set_prefix (context->printer, diagnostic_build_prefix (diagnostic));
}
-static void
+void
default_diagnostic_finalizer (diagnostic_context *context,
diagnostic_info *diagnostic ATTRIBUTE_UNUSED)
{
Index: diagnostic.h
===================================================================
--- diagnostic.h (revision 151295)
+++ diagnostic.h (working copy)
@@ -213,6 +213,8 @@ extern bool emit_diagnostic (diagnostic_
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 *, g
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 */
Index: objc/objc-lang.c
===================================================================
--- objc/objc-lang.c (revision 151295)
+++ objc/objc-lang.c (working copy)
@@ -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. */
Index: toplev.c
===================================================================
--- toplev.c (revision 151295)
+++ toplev.c (working copy)
@@ -1564,8 +1564,8 @@ default_pch_valid_p (const void *data_p,
}
/* 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;
Index: cgraphunit.c
===================================================================
--- cgraphunit.c (revision 151295)
+++ cgraphunit.c (working copy)
@@ -1108,9 +1108,6 @@ cgraph_expand_function (struct cgraph_no
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
Index: testsuite/gcc.dg/gomp/combined-1.c
===================================================================
--- testsuite/gcc.dg/gomp/combined-1.c (revision 151295)
+++ testsuite/gcc.dg/gomp/combined-1.c (working copy)
@@ -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" } } */
Index: testsuite/g++.dg/tree-prof/inline_mismatch_args.C
===================================================================
--- testsuite/g++.dg/tree-prof/inline_mismatch_args.C (revision 151295)
+++ testsuite/g++.dg/tree-prof/inline_mismatch_args.C (working copy)
@@ -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" } } */
Index: testsuite/g++.dg/warn/unit-1.C
===================================================================
--- testsuite/g++.dg/warn/unit-1.C (revision 151295)
+++ testsuite/g++.dg/warn/unit-1.C (working copy)
@@ -4,7 +4,7 @@
struct a { int mode; };
int sys_msgctl (void)
{
- struct a setbuf; /* { dg-warning "'setbuf\.a::mode' is used" } */
+ struct a setbuf; /* { dg-warning "'setbuf.mode' is used" } */
return setbuf.mode;
}
Index: testsuite/g++.dg/ipa/iinline-1.C
===================================================================
--- testsuite/g++.dg/ipa/iinline-1.C (revision 151295)
+++ testsuite/g++.dg/ipa/iinline-1.C (working copy)
@@ -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" } } */
Index: objcp/objcp-lang.c
===================================================================
--- objcp/objcp-lang.c (revision 151295)
+++ objcp/objcp-lang.c (working copy)
@@ -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. */
Index: timevar.def
===================================================================
--- timevar.def (revision 151295)
+++ timevar.def (working copy)
@@ -46,6 +46,7 @@ DEFTIMEVAR (TV_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. */
Index: ada/gcc-interface/misc.c
===================================================================
--- ada/gcc-interface/misc.c (revision 151295)
+++ ada/gcc-interface/misc.c (working copy)
@@ -131,7 +131,7 @@ static void gnat_get_subrange_bounds (co
#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
Index: fortran/f95-lang.c
===================================================================
--- fortran/f95-lang.c (revision 151295)
+++ fortran/f95-lang.c (working copy)
@@ -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
Index: langhooks.h
===================================================================
--- langhooks.h (revision 151295)
+++ langhooks.h (working copy)
@@ -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,
Index: ipa.c
===================================================================
--- ipa.c (revision 151295)
+++ ipa.c (working copy)
@@ -240,6 +240,11 @@ cgraph_remove_unreachable_nodes (bool be
#ifdef ENABLE_CHECKING
verify_cgraph ();
#endif
+
+ /* Reclaim alias pairs for functions that have disappeared from the
+ call graph. */
+ remove_unreachable_alias_pairs ();
+
return changed;
}
Index: except.c
===================================================================
--- except.c (revision 151295)
+++ except.c (working copy)
@@ -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
{
Index: varasm.c
===================================================================
--- varasm.c (revision 151295)
+++ varasm.c (working copy)
@@ -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 targe
#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);
Index: Makefile.in
===================================================================
--- Makefile.in (revision 151295)
+++ Makefile.in (working copy)
@@ -2164,7 +2164,8 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_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
Index: gimple.c
===================================================================
--- gimple.c (revision 151295)
+++ gimple.c (working copy)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.
#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[] = {
@@ -3398,4 +3399,75 @@ gimple_ior_addresses_taken (bitmap addre
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"
Index: gimple.h
===================================================================
--- gimple.h (revision 151295)
+++ gimple.h (working copy)
@@ -824,6 +824,8 @@ bool gimple_assign_rhs_could_trap_p (gim
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);
Index: passes.c
===================================================================
--- passes.c (revision 151295)
+++ passes.c (working copy)
@@ -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;
Index: c-lang.c
===================================================================
--- c-lang.c (revision 151295)
+++ c-lang.c (working copy)
@@ -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. */
Index: langhooks-def.h
===================================================================
--- langhooks-def.h (revision 151295)
+++ langhooks-def.h (working copy)
@@ -99,6 +99,7 @@ extern void lhd_omp_firstprivatize_type_
#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_cod
#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, \