diff mbox

Small type_hash_canon improvement

Message ID 20170504144345.GS1809@tucnak
State New
Headers show

Commit Message

Jakub Jelinek May 4, 2017, 2:43 p.m. UTC
Hi!

While type_hash_canon in case of reusing an already existing type
ggc_frees the freshly created type, we still waste one type uid
for each such case, this patch attempts to avoid that.
Furthermore, for INTEGER_TYPE we keep around the min and max value
INTEGER_CSTs and the cached values vector (until it is GCed).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2017-05-04  Jakub Jelinek  <jakub@redhat.com>

	* tree.c (next_type_uid): Change type to unsigned.
	(type_hash_canon): Decrement back next_type_uid if
	freeing a type node with the highest TYPE_UID.  For INTEGER_TYPEs
	also ggc_free TYPE_MIN_VALUE, TYPE_MAX_VALUE and TYPE_CACHED_VALUES
	if possible.


	Jakub

Comments

Richard Biener May 4, 2017, 3:54 p.m. UTC | #1
On May 4, 2017 4:43:45 PM GMT+02:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>While type_hash_canon in case of reusing an already existing type
>ggc_frees the freshly created type, we still waste one type uid
>for each such case, this patch attempts to avoid that.
>Furthermore, for INTEGER_TYPE we keep around the min and max value
>INTEGER_CSTs and the cached values vector (until it is GCed).
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
>2017-05-04  Jakub Jelinek  <jakub@redhat.com>
>
>	* tree.c (next_type_uid): Change type to unsigned.
>	(type_hash_canon): Decrement back next_type_uid if
>	freeing a type node with the highest TYPE_UID.  For INTEGER_TYPEs
>	also ggc_free TYPE_MIN_VALUE, TYPE_MAX_VALUE and TYPE_CACHED_VALUES
>	if possible.
>
>--- gcc/tree.c.jj	2017-05-03 16:55:39.688052581 +0200
>+++ gcc/tree.c	2017-05-03 18:49:30.662185944 +0200
>@@ -151,7 +151,7 @@ static const char * const tree_node_kind
> /* Unique id for next decl created.  */
> static GTY(()) int next_decl_uid;
> /* Unique id for next type created.  */
>-static GTY(()) int next_type_uid = 1;
>+static GTY(()) unsigned next_type_uid = 1;
> /* Unique id for next debug decl created.  Use negative numbers,
>    to catch erroneous uses.  */
> static GTY(()) int next_debug_decl_uid;
>@@ -7188,6 +7188,19 @@ type_hash_canon (unsigned int hashcode,
>     {
>       tree t1 = ((type_hash *) *loc)->type;
>       gcc_assert (TYPE_MAIN_VARIANT (t1) == t1);
>+      if (TYPE_UID (type) + 1 == next_type_uid)
>+	--next_type_uid;
>+      if (TREE_CODE (type) == INTEGER_TYPE)
>+	{
>+	  if (TYPE_MIN_VALUE (type)
>+	      && TREE_TYPE (TYPE_MIN_VALUE (type)) == type)
>+	    ggc_free (TYPE_MIN_VALUE (type));
>+	  if (TYPE_MAX_VALUE (type)
>+	      && TREE_TYPE (TYPE_MAX_VALUE (type)) == type)
>+	    ggc_free (TYPE_MAX_VALUE (type));
>+	  if (TYPE_CACHED_VALUES_P (type))
>+	    ggc_free (TYPE_CACHED_VALUES (type));
>+	}
>       free_node (type);

Shouldn't free_node handle this?  That said, is freeing min/max safe?  The constants are shared after all.

Richard.

>       return t1;
>     }
>
>	Jakub
Jakub Jelinek May 4, 2017, 4:03 p.m. UTC | #2
On Thu, May 04, 2017 at 05:54:47PM +0200, Richard Biener wrote:
> >2017-05-04  Jakub Jelinek  <jakub@redhat.com>
> >
> >	* tree.c (next_type_uid): Change type to unsigned.
> >	(type_hash_canon): Decrement back next_type_uid if
> >	freeing a type node with the highest TYPE_UID.  For INTEGER_TYPEs
> >	also ggc_free TYPE_MIN_VALUE, TYPE_MAX_VALUE and TYPE_CACHED_VALUES
> >	if possible.
> >
> >--- gcc/tree.c.jj	2017-05-03 16:55:39.688052581 +0200
> >+++ gcc/tree.c	2017-05-03 18:49:30.662185944 +0200
> >@@ -151,7 +151,7 @@ static const char * const tree_node_kind
> > /* Unique id for next decl created.  */
> > static GTY(()) int next_decl_uid;
> > /* Unique id for next type created.  */
> >-static GTY(()) int next_type_uid = 1;
> >+static GTY(()) unsigned next_type_uid = 1;
> > /* Unique id for next debug decl created.  Use negative numbers,
> >    to catch erroneous uses.  */
> > static GTY(()) int next_debug_decl_uid;
> >@@ -7188,6 +7188,19 @@ type_hash_canon (unsigned int hashcode,
> >     {
> >       tree t1 = ((type_hash *) *loc)->type;
> >       gcc_assert (TYPE_MAIN_VARIANT (t1) == t1);
> >+      if (TYPE_UID (type) + 1 == next_type_uid)
> >+	--next_type_uid;
> >+      if (TREE_CODE (type) == INTEGER_TYPE)
> >+	{
> >+	  if (TYPE_MIN_VALUE (type)
> >+	      && TREE_TYPE (TYPE_MIN_VALUE (type)) == type)
> >+	    ggc_free (TYPE_MIN_VALUE (type));
> >+	  if (TYPE_MAX_VALUE (type)
> >+	      && TREE_TYPE (TYPE_MAX_VALUE (type)) == type)
> >+	    ggc_free (TYPE_MAX_VALUE (type));
> >+	  if (TYPE_CACHED_VALUES_P (type))
> >+	    ggc_free (TYPE_CACHED_VALUES (type));
> >+	}
> >       free_node (type);
> 
> Shouldn't free_node handle this?  That said, is freeing min/max safe?  The constants are shared after all.

The next_type_uid handling, I think it is better in type_hash_canon, the
only other user after all calls free_node in a loop, so it is highly
unlikely it would do anything there.

If you mean the INTEGER_TYPE handling, then yes, I guess it could be
done in free_node too and can move it there.  If it was without
the && TREE_TYPE (TYPE_M*_VALUE (type)) == type extra checks, then it
is certainly unsafe and breaks bootstrap even, e.g. build_range_type
and other spots happily create INTEGER_TYPEs with min/max value that
have some other type.  But when the type of the INTEGER_CSTs is the
type we are ggc_freeing, anything that would refer to those constants
afterwards would be necessarily broken (as their TREE_TYPE would be
ggc_freed, possibly reused for something completely unrelated).
Thus I think it should be safe even in the LTO case and thus doable
in free_node.

	Jakub
Richard Biener May 4, 2017, 4:21 p.m. UTC | #3
On May 4, 2017 6:03:46 PM GMT+02:00, Jakub Jelinek <jakub@redhat.com> wrote:
>On Thu, May 04, 2017 at 05:54:47PM +0200, Richard Biener wrote:
>> >2017-05-04  Jakub Jelinek  <jakub@redhat.com>
>> >
>> >	* tree.c (next_type_uid): Change type to unsigned.
>> >	(type_hash_canon): Decrement back next_type_uid if
>> >	freeing a type node with the highest TYPE_UID.  For INTEGER_TYPEs
>> >	also ggc_free TYPE_MIN_VALUE, TYPE_MAX_VALUE and TYPE_CACHED_VALUES
>> >	if possible.
>> >
>> >--- gcc/tree.c.jj	2017-05-03 16:55:39.688052581 +0200
>> >+++ gcc/tree.c	2017-05-03 18:49:30.662185944 +0200
>> >@@ -151,7 +151,7 @@ static const char * const tree_node_kind
>> > /* Unique id for next decl created.  */
>> > static GTY(()) int next_decl_uid;
>> > /* Unique id for next type created.  */
>> >-static GTY(()) int next_type_uid = 1;
>> >+static GTY(()) unsigned next_type_uid = 1;
>> > /* Unique id for next debug decl created.  Use negative numbers,
>> >    to catch erroneous uses.  */
>> > static GTY(()) int next_debug_decl_uid;
>> >@@ -7188,6 +7188,19 @@ type_hash_canon (unsigned int hashcode,
>> >     {
>> >       tree t1 = ((type_hash *) *loc)->type;
>> >       gcc_assert (TYPE_MAIN_VARIANT (t1) == t1);
>> >+      if (TYPE_UID (type) + 1 == next_type_uid)
>> >+	--next_type_uid;
>> >+      if (TREE_CODE (type) == INTEGER_TYPE)
>> >+	{
>> >+	  if (TYPE_MIN_VALUE (type)
>> >+	      && TREE_TYPE (TYPE_MIN_VALUE (type)) == type)
>> >+	    ggc_free (TYPE_MIN_VALUE (type));
>> >+	  if (TYPE_MAX_VALUE (type)
>> >+	      && TREE_TYPE (TYPE_MAX_VALUE (type)) == type)
>> >+	    ggc_free (TYPE_MAX_VALUE (type));
>> >+	  if (TYPE_CACHED_VALUES_P (type))
>> >+	    ggc_free (TYPE_CACHED_VALUES (type));
>> >+	}
>> >       free_node (type);
>> 
>> Shouldn't free_node handle this?  That said, is freeing min/max safe?
> The constants are shared after all.
>
>The next_type_uid handling, I think it is better in type_hash_canon,

Agreed.

>the
>only other user after all calls free_node in a loop, so it is highly
>unlikely it would do anything there.
>
>If you mean the INTEGER_TYPE handling, then yes, I guess it could be
>done in free_node too and can move it there.  If it was without
>the && TREE_TYPE (TYPE_M*_VALUE (type)) == type extra checks, then it
>is certainly unsafe and breaks bootstrap even, e.g. build_range_type
>and other spots happily create INTEGER_TYPEs with min/max value that
>have some other type.  But when the type of the INTEGER_CSTs is the
>type we are ggc_freeing, anything that would refer to those constants
>afterwards would be necessarily broken (as their TREE_TYPE would be
>ggc_freed, possibly reused for something completely unrelated).
>Thus I think it should be safe even in the LTO case and thus doable
>in free_node.

OK.  OTOH LTO frees the whole SCC and thus doesn't expect any pointed to stuff to be freed.  Not sure if we allow double ggc_free of stuff.

Richard.

>
>	Jakub
Jakub Jelinek May 4, 2017, 4:27 p.m. UTC | #4
On Thu, May 04, 2017 at 06:21:17PM +0200, Richard Biener wrote:
> >the
> >only other user after all calls free_node in a loop, so it is highly
> >unlikely it would do anything there.
> >
> >If you mean the INTEGER_TYPE handling, then yes, I guess it could be
> >done in free_node too and can move it there.  If it was without
> >the && TREE_TYPE (TYPE_M*_VALUE (type)) == type extra checks, then it
> >is certainly unsafe and breaks bootstrap even, e.g. build_range_type
> >and other spots happily create INTEGER_TYPEs with min/max value that
> >have some other type.  But when the type of the INTEGER_CSTs is the
> >type we are ggc_freeing, anything that would refer to those constants
> >afterwards would be necessarily broken (as their TREE_TYPE would be
> >ggc_freed, possibly reused for something completely unrelated).
> >Thus I think it should be safe even in the LTO case and thus doable
> >in free_node.
> 
> OK.  OTOH LTO frees the whole SCC and thus doesn't expect any pointed to stuff
> to be freed.  Not sure if we allow double ggc_free of stuff.

We don't, that crashes miserably.

	Jakub
Jakub Jelinek May 5, 2017, 7:09 a.m. UTC | #5
On Thu, May 04, 2017 at 06:27:00PM +0200, Jakub Jelinek wrote:
> On Thu, May 04, 2017 at 06:21:17PM +0200, Richard Biener wrote:
> > >the
> > >only other user after all calls free_node in a loop, so it is highly
> > >unlikely it would do anything there.
> > >
> > >If you mean the INTEGER_TYPE handling, then yes, I guess it could be
> > >done in free_node too and can move it there.  If it was without
> > >the && TREE_TYPE (TYPE_M*_VALUE (type)) == type extra checks, then it
> > >is certainly unsafe and breaks bootstrap even, e.g. build_range_type
> > >and other spots happily create INTEGER_TYPEs with min/max value that
> > >have some other type.  But when the type of the INTEGER_CSTs is the
> > >type we are ggc_freeing, anything that would refer to those constants
> > >afterwards would be necessarily broken (as their TREE_TYPE would be
> > >ggc_freed, possibly reused for something completely unrelated).
> > >Thus I think it should be safe even in the LTO case and thus doable
> > >in free_node.
> > 
> > OK.  OTOH LTO frees the whole SCC and thus doesn't expect any pointed to stuff
> > to be freed.  Not sure if we allow double ggc_free of stuff.
> 
> We don't, that crashes miserably.

Tried that patch (moving the INTEGRAL_TYPE handling into free_node), and got
246 new FAILs in -flto testcases.

	Jakub
Richard Biener May 5, 2017, 7:10 a.m. UTC | #6
On Thu, 4 May 2017, Jakub Jelinek wrote:

> On Thu, May 04, 2017 at 06:21:17PM +0200, Richard Biener wrote:
> > >the
> > >only other user after all calls free_node in a loop, so it is highly
> > >unlikely it would do anything there.
> > >
> > >If you mean the INTEGER_TYPE handling, then yes, I guess it could be
> > >done in free_node too and can move it there.  If it was without
> > >the && TREE_TYPE (TYPE_M*_VALUE (type)) == type extra checks, then it
> > >is certainly unsafe and breaks bootstrap even, e.g. build_range_type
> > >and other spots happily create INTEGER_TYPEs with min/max value that
> > >have some other type.  But when the type of the INTEGER_CSTs is the
> > >type we are ggc_freeing, anything that would refer to those constants
> > >afterwards would be necessarily broken (as their TREE_TYPE would be
> > >ggc_freed, possibly reused for something completely unrelated).
> > >Thus I think it should be safe even in the LTO case and thus doable
> > >in free_node.
> > 
> > OK.  OTOH LTO frees the whole SCC and thus doesn't expect any pointed to stuff
> > to be freed.  Not sure if we allow double ggc_free of stuff.
> 
> We don't, that crashes miserably.

Ok, so then keep it in type_hash_canon (with a comment).

Otherwise the patch is ok.

Thanks,
Richard.
diff mbox

Patch

--- gcc/tree.c.jj	2017-05-03 16:55:39.688052581 +0200
+++ gcc/tree.c	2017-05-03 18:49:30.662185944 +0200
@@ -151,7 +151,7 @@  static const char * const tree_node_kind
 /* Unique id for next decl created.  */
 static GTY(()) int next_decl_uid;
 /* Unique id for next type created.  */
-static GTY(()) int next_type_uid = 1;
+static GTY(()) unsigned next_type_uid = 1;
 /* Unique id for next debug decl created.  Use negative numbers,
    to catch erroneous uses.  */
 static GTY(()) int next_debug_decl_uid;
@@ -7188,6 +7188,19 @@  type_hash_canon (unsigned int hashcode,
     {
       tree t1 = ((type_hash *) *loc)->type;
       gcc_assert (TYPE_MAIN_VARIANT (t1) == t1);
+      if (TYPE_UID (type) + 1 == next_type_uid)
+	--next_type_uid;
+      if (TREE_CODE (type) == INTEGER_TYPE)
+	{
+	  if (TYPE_MIN_VALUE (type)
+	      && TREE_TYPE (TYPE_MIN_VALUE (type)) == type)
+	    ggc_free (TYPE_MIN_VALUE (type));
+	  if (TYPE_MAX_VALUE (type)
+	      && TREE_TYPE (TYPE_MAX_VALUE (type)) == type)
+	    ggc_free (TYPE_MAX_VALUE (type));
+	  if (TYPE_CACHED_VALUES_P (type))
+	    ggc_free (TYPE_CACHED_VALUES (type));
+	}
       free_node (type);
       return t1;
     }