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]

[PATCH][committed] Make LTO type merging (re-)compute TYPE_CANONICAL


This turns LTO type merging into what it is - re-computing TYPE_CANONICAL.
This allows us to cache most gimple_register_type queries, basically
using that only if TYPE_STRUCTURAL_EQUALITY_P is set.

Further improvements on the LTO side could be to leverage the
hashes tree.c has for types to avoid the hack in lto-streamer.c
and eventually merge basic types on-the-fly when streaming them
in.

Well, as previously measured this patch reduces the htab load
on the WPA phase of WHOPR bootstrap of cc1 significanlty.

The i386 parts were approved by Honza.  Re-bootstrapped and tested
on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2010-06-13  Richard Guenther  <rguenther@suse.de>

	* lto-streamer-in.c (lto_input_ts_type_tree_pointers):
	Do not stream but initialize TYPE_CANONICAL to NULL.
	(lto_output_ts_type_tree_pointers): Do not stream TYPE_CANONICAL.
	* gimple.c (gimple_types_compatible_p): Disregard
	TYPE_STRUCTURAL_EQUALITY_P.
	(gimple_register_type): Use TYPE_CANONICAL as cache.
	* lto-streamer.c (lto_record_common_node): Zero TYPE_CANONICAL
	before registering common types.
	* config/i386/i386.c (ix86_function_arg_boundary): Do not
	use TYPE_CANONICAL, instead use TYPE_MAIN_VARIANT.
	* tree.h (TYPE_CANONICAL): Clarify documentation.

	lto/
	* lto.c (lto_fixup_type): Do not register or fixup TYPE_CANONICAL.

Index: gcc/lto-streamer-in.c
===================================================================
*** gcc/lto-streamer-in.c.orig	2010-06-12 22:58:55.000000000 +0200
--- gcc/lto-streamer-in.c	2010-06-13 12:45:16.000000000 +0200
*************** lto_input_ts_type_tree_pointers (struct
*** 2192,2198 ****
    if (RECORD_OR_UNION_TYPE_P (expr))
      TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
    TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
!   TYPE_CANONICAL (expr) = lto_input_tree (ib, data_in);
    TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
  }
  
--- 2192,2199 ----
    if (RECORD_OR_UNION_TYPE_P (expr))
      TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
    TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
!   /* TYPE_CANONICAL gets re-computed during type merging.  */
!   TYPE_CANONICAL (expr) = NULL_TREE;
    TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
  }
  
Index: gcc/lto-streamer-out.c
===================================================================
*** gcc/lto-streamer-out.c.orig	2010-06-12 22:58:55.000000000 +0200
--- gcc/lto-streamer-out.c	2010-06-13 12:45:16.000000000 +0200
*************** lto_output_ts_type_tree_pointers (struct
*** 986,992 ****
    if (RECORD_OR_UNION_TYPE_P (expr))
      lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
    lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
!   lto_output_tree_or_ref (ob, TYPE_CANONICAL (expr), ref_p);
    lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
  }
  
--- 986,993 ----
    if (RECORD_OR_UNION_TYPE_P (expr))
      lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
    lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
!   /* TYPE_CANONICAL is re-computed during type merging, so no need
!      to stream it here.  */
    lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
  }
  
Index: gcc/gimple.c
===================================================================
*** gcc/gimple.c.orig	2010-06-12 11:35:39.000000000 +0200
--- gcc/gimple.c	2010-06-13 12:45:16.000000000 +0200
*************** gimple_types_compatible_p (tree t1, tree
*** 3593,3604 ****
        {
  	tree f1, f2;
  
- 	/* If one type requires structural equality checks and the
- 	   other doesn't, do not merge the types.  */
- 	if (TYPE_STRUCTURAL_EQUALITY_P (t1)
- 	    != TYPE_STRUCTURAL_EQUALITY_P (t2))
- 	  goto different_types;
- 
  	/* The struct tags shall compare equal.  */
  	if (!compare_type_names_p (TYPE_MAIN_VARIANT (t1),
  				   TYPE_MAIN_VARIANT (t2), false))
--- 3593,3598 ----
*************** gimple_register_type (tree t)
*** 3955,3960 ****
--- 3949,3959 ----
  
    gcc_assert (TYPE_P (t));
  
+   /* In TYPE_CANONICAL we cache the result of gimple_register_type.
+      It is initially set to NULL during LTO streaming.  */
+   if (TYPE_CANONICAL (t))
+     return TYPE_CANONICAL (t);
+ 
    /* Always register the main variant first.  This is important so we
       pick up the non-typedef variants as canonical, otherwise we'll end
       up taking typedef ids for structure tags during comparison.  */
*************** gimple_register_type (tree t)
*** 4018,4027 ****
  	  TYPE_NEXT_REF_TO (t) = NULL_TREE;
  	}
  
        t = new_type;
      }
    else
!     *slot = (void *) t;
  
    return t;
  }
--- 4017,4030 ----
  	  TYPE_NEXT_REF_TO (t) = NULL_TREE;
  	}
  
+       TYPE_CANONICAL (t) = new_type;
        t = new_type;
      }
    else
!     {
!       TYPE_CANONICAL (t) = t;
!       *slot = (void *) t;
!     }
  
    return t;
  }
Index: gcc/lto-streamer.c
===================================================================
*** gcc/lto-streamer.c.orig	2010-06-12 22:58:55.000000000 +0200
--- gcc/lto-streamer.c	2010-06-13 12:45:16.000000000 +0200
*************** lto_record_common_node (tree *nodep, VEC
*** 674,680 ****
      return;
  
    if (TYPE_P (node))
!     *nodep = node = gimple_register_type (node);
  
    /* Return if node is already seen.  */
    if (pointer_set_insert (seen_nodes, node))
--- 674,685 ----
      return;
  
    if (TYPE_P (node))
!     {
!       /* Type merging will get confused by the canonical types as they
! 	 are set by the middle-end.  */
!       TYPE_CANONICAL (node) = NULL_TREE;
!       *nodep = node = gimple_register_type (node);
!     }
  
    /* Return if node is already seen.  */
    if (pointer_set_insert (seen_nodes, node))
Index: gcc/config/i386/i386.c
===================================================================
*** gcc/config/i386/i386.c.orig	2010-06-12 11:35:39.000000000 +0200
--- gcc/config/i386/i386.c	2010-06-13 12:45:16.000000000 +0200
*************** ix86_function_arg_boundary (enum machine
*** 6398,6407 ****
    int align;
    if (type)
      {
!       /* Since canonical type is used for call, we convert it to
! 	 canonical type if needed.  */
!       if (!TYPE_STRUCTURAL_EQUALITY_P (type))
! 	type = TYPE_CANONICAL (type);
        align = TYPE_ALIGN (type);
      }
    else
--- 6398,6406 ----
    int align;
    if (type)
      {
!       /* Since the main variant type is used for call, we convert it to
! 	 the main variant type.  */
!       type = TYPE_MAIN_VARIANT (type);
        align = TYPE_ALIGN (type);
      }
    else
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig	2010-06-13 12:45:32.000000000 +0200
--- gcc/lto/lto.c	2010-06-13 12:46:57.000000000 +0200
*************** lto_fixup_type (tree t, void *data)
*** 1087,1093 ****
        else
  	LTO_FIXUP_SUBTREE (TYPE_CONTEXT (t));
      }
!   LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CANONICAL (t));
  
    /* The following re-creates proper variant lists while fixing up
       the variant leaders.  We do not stream TYPE_NEXT_VARIANT so the
--- 1087,1097 ----
        else
  	LTO_FIXUP_SUBTREE (TYPE_CONTEXT (t));
      }
! 
!   /* TYPE_CANONICAL does not need to be fixed up, instead it should
!      always point to ourselves at this time as we never fixup
!      non-canonical ones.  */
!   gcc_assert (TYPE_CANONICAL (t) == t);
  
    /* The following re-creates proper variant lists while fixing up
       the variant leaders.  We do not stream TYPE_NEXT_VARIANT so the
Index: gcc/tree.h
===================================================================
*** gcc/tree.h.orig	2010-06-13 12:50:21.000000000 +0200
--- gcc/tree.h	2010-06-13 13:00:42.000000000 +0200
*************** extern enum machine_mode vector_type_mod
*** 2090,2115 ****
  #define SET_TYPE_MODE(NODE, MODE) \
    (TYPE_CHECK (NODE)->type.mode = (MODE))
  
! /* The "canonical" type for this type node, which can be used to
!    compare the type for equality with another type. If two types are
     equal (based on the semantics of the language), then they will have
     equivalent TYPE_CANONICAL entries.
  
!    As a special case, if TYPE_CANONICAL is NULL_TREE, then it cannot
!    be used for comparison against other types. Instead, the type is
     said to require structural equality checks, described in
!    TYPE_STRUCTURAL_EQUALITY_P. */
  #define TYPE_CANONICAL(NODE) (TYPE_CHECK (NODE)->type.canonical)
  /* Indicates that the type node requires structural equality
!    checks. The compiler will need to look at the composition of the
     type to determine whether it is equal to another type, rather than
!    just comparing canonical type pointers. For instance, we would need
     to look at the return and parameter types of a FUNCTION_TYPE
!    node. */
  #define TYPE_STRUCTURAL_EQUALITY_P(NODE) (TYPE_CANONICAL (NODE) == NULL_TREE)
  /* Sets the TYPE_CANONICAL field to NULL_TREE, indicating that the
!    type node requires structural equality. */
  #define SET_TYPE_STRUCTURAL_EQUALITY(NODE) (TYPE_CANONICAL (NODE) = NULL_TREE)
  #define TYPE_LANG_SPECIFIC(NODE) (TYPE_CHECK (NODE)->type.lang_specific)
  #define TYPE_IBIT(NODE) (GET_MODE_IBIT (TYPE_MODE (NODE)))
  #define TYPE_FBIT(NODE) (GET_MODE_FBIT (TYPE_MODE (NODE)))
--- 2090,2123 ----
  #define SET_TYPE_MODE(NODE, MODE) \
    (TYPE_CHECK (NODE)->type.mode = (MODE))
  
! /* The "canonical" type for this type node, which is used by frontends to
!    compare the type for equality with another type.  If two types are
     equal (based on the semantics of the language), then they will have
     equivalent TYPE_CANONICAL entries.
  
!    As a special case, if TYPE_CANONICAL is NULL_TREE, and thus
!    TYPE_STRUCTURAL_EQUALITY_P is true, then it cannot
!    be used for comparison against other types.  Instead, the type is
     said to require structural equality checks, described in
!    TYPE_STRUCTURAL_EQUALITY_P.
! 
!    For unqualified aggregate and function types the middle-end relies on
!    TYPE_CANONICAL to tell whether two variables can be assigned
!    to each other without a conversion.  The middle-end also makes sure
!    to assign the same alias-sets to the type partition with equal
!    TYPE_CANONICAL of their unqualified variants.  */
  #define TYPE_CANONICAL(NODE) (TYPE_CHECK (NODE)->type.canonical)
  /* Indicates that the type node requires structural equality
!    checks.  The compiler will need to look at the composition of the
     type to determine whether it is equal to another type, rather than
!    just comparing canonical type pointers.  For instance, we would need
     to look at the return and parameter types of a FUNCTION_TYPE
!    node.  */
  #define TYPE_STRUCTURAL_EQUALITY_P(NODE) (TYPE_CANONICAL (NODE) == NULL_TREE)
  /* Sets the TYPE_CANONICAL field to NULL_TREE, indicating that the
!    type node requires structural equality.  */
  #define SET_TYPE_STRUCTURAL_EQUALITY(NODE) (TYPE_CANONICAL (NODE) = NULL_TREE)
+ 
  #define TYPE_LANG_SPECIFIC(NODE) (TYPE_CHECK (NODE)->type.lang_specific)
  #define TYPE_IBIT(NODE) (GET_MODE_IBIT (TYPE_MODE (NODE)))
  #define TYPE_FBIT(NODE) (GET_MODE_FBIT (TYPE_MODE (NODE)))


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