This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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, \


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]