[lto] make more things go

Nathan Froyd froydnj@codesourcery.com
Wed Nov 21 22:10:00 GMT 2007


The patch below fixes several things:

- The DWARF for global variables is now nearly exactly what it is for -g
  compiles.  Moving closer to -g is a good thing and as a bonus, the LTO
  reader no longer gets confused by the DWARF for global variables.  The
  LTO writer removed a bogus assert for TYPE_DECLs a couple patches
  ago.  We now remove the equivalent assert in the DWARF machinery, too;

- The LTO reader is smarter about static variables.  It is also less
  smart about builtins--the current state (prior to this patch) was that
  we'd handle things like alloca, but bomb on cases like memcpy.  This
  patch reverses that (bomb on alloca, handle memcpy).  Hopefully both
  will be fixed in a future patch; I need to do a bit more investigating
  as to exactly how GCC represents and recognizes calls to builtin
  functions;

- The LTO symtab code handles a few more cases properly;

This patch doesn't produce any spectacular results on testsuite
numbers--it may actually regress slightly due to the builtin change--
but (with minor tweaks to the SPEC code to properly declare
functions[*]) we now can compile 164.gzip, 175.vpr, 181.mcf, 197.parser,
256.bzip2, and 300.twolf from SPECint 2000 with -flto.  The resulting
executables are not functional (they crash immediately or they spin
their wheels for a very long time), but it does show that we are
reaching a point where real programs can be compiled with LTO.

Committed to the LTO branch.

-Nathan

[*] Yes, I know you're not allowed to do this.  What do people think is
the right thing to do here?  Entirely ignore function types for the
purposes of merging decls?

gcc/
	* dwarf2out.c (gen_subprogram_die): Inhibit generation of labels
	if we are being called for LTO's purposes.
	(gen_variable_die): Don't generate multiple DIEs for and equate
	the generated DIE with the decl for global variables.
	(force_decl_die): Don't play games with DECL_EXTERNAL if we are
	forcing a DIE for a global variable.
	(lto_typedecl_ref): Remove assert.

gcc/lto/
	* lto.c (lto_read_variable_formal_parameter_constant_DIE): Don't
	set TREE_ADDRESSABLE.  Do set DECL_COMDAT.  Set TREE_READONLY if
	the type is a constant type.  Set the assembler name and inform
	the rest of the compiler about the new decl if the decl is not
	public.
	(lto_read_subroutine_type_subprogram_DIE): Don't check for equivalency
	of DECL_ASSEMBLER_NAME when determining if we have a builtin.  Don't
	try to read in function bodies for functions that already have bodies.
	* lto-symtab.c (lto_same_type_p): Check for unbounded array
	equivalency.
	(lto_symtab_merge_decl): Don't merge decls that aren't TREE_PUBLIC.
	Check for whether we matched a builtin function type before calling
	lto_same_type_p on the generated type.  Permit cases where the
	declaration of an array is unbounded, but the definition is bounded.
	Don't combine TREE_PUBLIC flags.  Copy over DECL_SIZE and
	DECL_SIZE_UNIT if necessary.

Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 130295)
+++ gcc/dwarf2out.c	(working copy)
@@ -12264,7 +12264,7 @@ gen_subprogram_die (tree decl, dw_die_re
       if (!old_die || !get_AT (old_die, DW_AT_inline))
 	equate_decl_number_to_die (decl, subr_die);
 
-      if (!flag_reorder_blocks_and_partition)
+      if (!flag_reorder_blocks_and_partition && !dwarf2_called_from_lto_p)
 	{
 	  ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
 				       current_function_funcdef_no);
@@ -12441,8 +12441,7 @@ static void
 gen_variable_die (tree decl, dw_die_ref context_die)
 {
   tree origin = decl_ultimate_origin (decl);
-  dw_die_ref var_die = new_die (DW_TAG_variable, context_die, decl);
-
+  dw_die_ref var_die;
   dw_die_ref old_die = lookup_decl_die (decl);
   int declaration = (DECL_EXTERNAL (decl)
 		     /* If DECL is COMDAT and has not actually been
@@ -12466,6 +12465,12 @@ gen_variable_die (tree decl, dw_die_ref 
 			 && DECL_COMDAT (decl) && !TREE_ASM_WRITTEN (decl))
 		     || class_or_namespace_scope_p (context_die));
 
+  /* Don't output multiple DIEs for global variables.  */
+  if (old_die && context_die == comp_unit_die)
+    return;
+
+  var_die = new_die (DW_TAG_variable, context_die, decl);
+
   if (origin != NULL)
     add_abstract_origin_attribute (var_die, origin);
 
@@ -12526,7 +12531,8 @@ gen_variable_die (tree decl, dw_die_ref 
   if (declaration)
     add_AT_flag (var_die, DW_AT_declaration, 1);
 
-  if (DECL_ABSTRACT (decl) || declaration)
+  if (context_die == comp_unit_die
+      || DECL_ABSTRACT (decl) || declaration)
     equate_decl_number_to_die (decl, var_die);
 
   if (! declaration && ! DECL_ABSTRACT (decl))
@@ -13546,12 +13552,22 @@ force_decl_die (tree decl)
 	  break;
 
 	case VAR_DECL:
-	  /* Set external flag to force declaration die. Restore it after
-	   gen_decl_die() call.  */
-	  saved_external_flag = DECL_EXTERNAL (decl);
-	  DECL_EXTERNAL (decl) = 1;
-	  gen_decl_die (decl, context_die);
-	  DECL_EXTERNAL (decl) = saved_external_flag;
+	  if (context_die == comp_unit_die)
+	    {
+	      /* Global variable.  gen_decl_die will always equate the
+		 generated DIE with this decl, so we don't have to cheat
+		 like we do below.  */
+	      gen_decl_die (decl, context_die);
+	    }
+	  else
+	    {
+	      /* Set external flag to force declaration die. Restore it after
+		 gen_decl_die() call.  */
+	      saved_external_flag = DECL_EXTERNAL (decl);
+	      DECL_EXTERNAL (decl) = 1;
+	      gen_decl_die (decl, context_die);
+	      DECL_EXTERNAL (decl) = saved_external_flag;
+	    }
 	  break;
 
 	case NAMESPACE_DECL:
@@ -15199,10 +15215,6 @@ lto_typedecl_ref (tree decl, lto_out_ref
 {
   gcc_assert (TREE_CODE (decl) == TYPE_DECL);
 
-  /* These should be nameless decls generated by the front-end for local
-     typedefs.  */
-  gcc_assert (!DECL_NAME (decl));
-
   /* Just use the reference to TREE_TYPE.  */
   lto_type_ref (TREE_TYPE (decl), ref);
 }
Index: gcc/lto/lto.c
===================================================================
--- gcc/lto/lto.c	(revision 130295)
+++ gcc/lto/lto.c	(working copy)
@@ -2090,7 +2090,20 @@ lto_read_variable_formal_parameter_const
 	  DECL_EXTERNAL (decl) = declaration;
 	  TREE_STATIC (decl) = 1;
 	  TREE_USED (decl) = 1;
-	  TREE_ADDRESSABLE (decl) = 1;
+	  DECL_COMDAT (decl) = 1;
+
+	  if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
+	    TREE_READONLY (decl) = 1;
+
+	  if (!TREE_PUBLIC (decl))
+	    {
+	      /* Need to ensure static variables between different files
+		 don't clash unexpectedly.  */
+	      lang_hooks.set_decl_assembler_name (decl);
+	      rest_of_decl_compilation (decl,
+					/*top_level=*/1,
+					/*at_end=*/0);
+	    }
 
 	  /* If there is an initializer, read it now.  */
 	  if (!declaration)
@@ -2597,9 +2610,7 @@ lto_read_subroutine_type_subprogram_DIE 
 
 	      /* Check to see if this builtin matches this function's
 		 DIE.  Use the builtin decl if so.  */
-	      if (name == DECL_NAME (candidate)
-		  || (DECL_ASSEMBLER_NAME (candidate)
-		      && name == DECL_ASSEMBLER_NAME (candidate)))
+	      if (name == DECL_NAME (candidate))
 		{
 		  result = candidate;
 
@@ -2637,8 +2648,11 @@ lto_read_subroutine_type_subprogram_DIE 
              resolved from the bodies of functions.  */
           lto_cache_store_DIE (fd, die, result);
 
-	  /* Save it for later.  */
-	  VEC_safe_push (tree, gc, fd->unmaterialized_fndecls, result);
+	  /* We want to read in its body from the LTO data only if we
+	     haven't already done so.  FIXME: we will need to handle
+	     multiple conflicting definitions one day... */
+	  if (!DECL_STRUCT_FUNCTION (result))
+	    VEC_safe_push (tree, gc, fd->unmaterialized_fndecls, result);
         }
     }
 
Index: gcc/lto/lto-symtab.c
===================================================================
--- gcc/lto/lto-symtab.c	(revision 130295)
+++ gcc/lto/lto-symtab.c	(working copy)
@@ -95,6 +95,13 @@ lto_same_type_p (tree type_1, tree type_
 	      tree min_2 = TYPE_MIN_VALUE (index_2);
 	      tree max_1 = TYPE_MAX_VALUE (index_1);
 	      tree max_2 = TYPE_MAX_VALUE (index_2);
+	      /* If the array types both have unspecified bounds, then
+		 MAX_{1,2} will be NULL_TREE.  */
+	      if (min_1 && min_2 && !max_1 && !max_2)
+		return (integer_zerop (min_1)
+			&& integer_zerop (min_2));
+	      /* Otherwise, we need the bounds to be fully
+		 specified.  */
 	      if (!min_1 || !min_2 || !max_1 || !max_2)
 		return false;
 	      if (TREE_CODE (min_1) != INTEGER_CST
@@ -236,6 +243,9 @@ lto_symtab_merge_decl (tree new_decl) 
 
   gcc_assert (TREE_CODE (new_decl) == VAR_DECL
 	      || TREE_CODE (new_decl) == FUNCTION_DECL);
+  /* Variables with internal linkage do not need to be merged.  */
+  if (!TREE_PUBLIC (new_decl))
+    return new_decl;
 
   /* Check that declarations reaching this function do not have
      properties inconsistent with having external linkage.  If any of
@@ -290,8 +300,12 @@ lto_symtab_merge_decl (tree new_decl) 
         {
           tree candidate = match_builtin_function_types (TREE_TYPE (new_decl),
                                                          TREE_TYPE (old_decl));
-          merged_type =
-            lto_same_type_p (candidate, TREE_TYPE (new_decl)) ? candidate : NULL_TREE;
+	  /* We don't really have source location information at this
+	     point, so the above matching was a bit of a gamble.  If we
+	     lose, then CANDIDATE will be NULL, so test for that.  */
+	  if (candidate)
+	    merged_type =
+	      lto_same_type_p (candidate, TREE_TYPE (new_decl)) ? candidate : NULL_TREE;
         }
 
       if (!merged_type)
@@ -312,9 +326,21 @@ lto_symtab_merge_decl (tree new_decl) 
       || !tree_int_cst_equal (DECL_SIZE_UNIT (old_decl),
 			      DECL_SIZE_UNIT (new_decl)))
     {
-      error ("size of %qD does not match original declaration", 
-	     new_decl);
-      return error_mark_node;
+      /* Permit cases where we are declaring arrays and at least one of
+	 the decls is external and one of the decls has a size whereas
+	 the other one does not.  */
+      if (!((DECL_EXTERNAL (old_decl) || DECL_EXTERNAL (new_decl))
+	    && ((DECL_SIZE (old_decl) == NULL_TREE
+		 && DECL_SIZE (new_decl) != NULL_TREE)
+		|| (DECL_SIZE (new_decl) == NULL_TREE
+		    && DECL_SIZE (old_decl) != NULL_TREE))
+	    && TREE_CODE (TREE_TYPE (old_decl)) == ARRAY_TYPE
+	    && TREE_CODE (TREE_TYPE (new_decl)) == ARRAY_TYPE))
+	{
+	  error ("size of %qD does not match original declaration", 
+		 new_decl);
+	  return error_mark_node;
+	}
     }
   if (DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
     {
@@ -376,7 +402,6 @@ lto_symtab_merge_decl (tree new_decl) 
   TREE_READONLY (old_decl) |= TREE_READONLY (new_decl);
   TREE_INVARIANT (old_decl) |= TREE_INVARIANT (new_decl);
   DECL_EXTERNAL (old_decl) &= DECL_EXTERNAL (new_decl);
-  TREE_PUBLIC (old_decl) &= TREE_PUBLIC (new_decl);
     
   DECL_WEAK (old_decl) &= DECL_WEAK (new_decl);
   DECL_PRESERVE_P (old_decl) |= DECL_PRESERVE_P (new_decl);
@@ -389,6 +414,11 @@ lto_symtab_merge_decl (tree new_decl) 
 	  gcc_assert (!DECL_INITIAL (old_decl));
 	  DECL_INITIAL (old_decl) = DECL_INITIAL (new_decl);
 	}
+      if (!DECL_SIZE (old_decl))
+	{
+	  DECL_SIZE (old_decl) = DECL_SIZE (new_decl);
+	  DECL_SIZE_UNIT (old_decl) = DECL_SIZE_UNIT (new_decl);
+	}
     }
   if (TREE_CODE (new_decl) == FUNCTION_DECL)
     {



More information about the Gcc-patches mailing list