diff mbox series

Fix PR89150, GC of tree-form bitmaps

Message ID alpine.LSU.2.20.1902041413310.23386@zhemvz.fhfr.qr
State New
Headers show
Series Fix PR89150, GC of tree-form bitmaps | expand

Commit Message

Richard Biener Feb. 4, 2019, 1:15 p.m. UTC
When I introduced tree-form bitmaps I forgot to think about GC.
The following drops the chain_prev annotation to make the marker
work for trees.  I've also maked the obstack member GTY skip
(and prevent bitmap_obstack from gengtype processing) because
the obstack isn't used for GC allocated bitmaps.

Bootstrap & regtest running on x86_64-unknown-linux-gnu.

Richard.

2019-02-04  Richard Biener  <rguenther@suse.de>

	PR middle-end/89150
	* bitmap.h (struct bitmap_obstack): Do not mark GTY.
	(struct bitmap_element): Drop chain_prev so we properly recurse on
	the prev member, supporting tree views.
	(struct bitmap_head): GTY skip the obstack member.

Comments

Steven Bosscher Feb. 4, 2019, 2:25 p.m. UTC | #1
On Mon, Feb 4, 2019 at 2:16 PM Richard Biener <rguenther@suse.de> wrote:
> When I introduced tree-form bitmaps I forgot to think about GC.
> The following drops the chain_prev annotation to make the marker
> work for trees.

I don't understand this patch. How are the nodes in a bitmap tree now
to be found for marking?

This patch should cause an ICE on test cases with bitmaps as trees
with ENABLE_GC_ALWAYS_COLLECT.

Ciao!
Steven
Richard Biener Feb. 4, 2019, 2:35 p.m. UTC | #2
On Mon, 4 Feb 2019, Steven Bosscher wrote:

> On Mon, Feb 4, 2019 at 2:16 PM Richard Biener <rguenther@suse.de> wrote:
> > When I introduced tree-form bitmaps I forgot to think about GC.
> > The following drops the chain_prev annotation to make the marker
> > work for trees.
> 
> I don't understand this patch. How are the nodes in a bitmap tree now
> to be found for marking?
> 
> This patch should cause an ICE on test cases with bitmaps as trees
> with ENABLE_GC_ALWAYS_COLLECT.

After the patch the marker routines look like

void
gt_ggc_mx_bitmap_head (void *x_p)
{
  struct bitmap_head * const x = (struct bitmap_head *)x_p;
  if (ggc_test_and_set_mark (x))
    {
      gt_ggc_m_14bitmap_element ((*x).first);
    }
}

void
gt_ggc_mx_bitmap_element (void *x_p)
{
  struct bitmap_element * x = (struct bitmap_element *)x_p;
  struct bitmap_element * xlimit = x;
  while (ggc_test_and_set_mark (xlimit))
   xlimit = ((*xlimit).next);
  while (x != xlimit)
    {
      gt_ggc_m_14bitmap_element ((*x).next);
      gt_ggc_m_14bitmap_element ((*x).prev);
      x = ((*x).next);
    }
}

gt_ggc_m_14bitmap_element just is a NULL protected call to
gt_ggc_mx_bitmap_element.  So bitmap elements are marked
by marking the ->next chain until we hit an already marked
node and then recurse on all prev and next members
(where the recursion will not chain ->next because we've
already marked it).

Previously it was

void
gt_ggc_mx_bitmap_element (void *x_p)
{
  struct bitmap_element * x = (struct bitmap_element *)x_p;
  struct bitmap_element * xlimit = x;
  while (ggc_test_and_set_mark (xlimit))
   xlimit = ((*xlimit).next);
  if (x != xlimit)
    for (;;)
      {
        struct bitmap_element * const xprev = ((*x).prev);
        if (xprev == NULL) break;
        x = xprev;
        (void) ggc_test_and_set_mark (xprev);
      }
  while (x != xlimit)
    {
      gt_ggc_m_14bitmap_element ((*x).next);
      gt_ggc_m_14bitmap_element ((*x).prev);
      x = ((*x).next);
    }
}

where the prev_chain handling "wrecked" things for trees
and didn't help for the list implementation (since we've
only come here via the bitmap_head->first link).

Richard.
Jeff Law Feb. 4, 2019, 4:07 p.m. UTC | #3
On 2/4/19 6:15 AM, Richard Biener wrote:
> 
> When I introduced tree-form bitmaps I forgot to think about GC.
> The following drops the chain_prev annotation to make the marker
> work for trees.  I've also maked the obstack member GTY skip
> (and prevent bitmap_obstack from gengtype processing) because
> the obstack isn't used for GC allocated bitmaps.
> 
> Bootstrap & regtest running on x86_64-unknown-linux-gnu.
> 
> Richard.
> 
> 2019-02-04  Richard Biener  <rguenther@suse.de>
> 
> 	PR middle-end/89150
> 	* bitmap.h (struct bitmap_obstack): Do not mark GTY.
> 	(struct bitmap_element): Drop chain_prev so we properly recurse on
> 	the prev member, supporting tree views.
> 	(struct bitmap_head): GTY skip the obstack member.
Was there a particular failure mode you observed or was this discovered
by inspection.

The reason I ask is my tester is showing occasional failures
bootstrapping hppa-linux-gnu with a segfault in ICF.

I'd rather not have to dig into it if it can be avoided :-)
Bootstrapping hppa via qemu is something like 6 hours...

Jeff
Richard Biener Feb. 4, 2019, 4:39 p.m. UTC | #4
On February 4, 2019 5:07:00 PM GMT+01:00, Jeff Law <law@redhat.com> wrote:
>On 2/4/19 6:15 AM, Richard Biener wrote:
>> 
>> When I introduced tree-form bitmaps I forgot to think about GC.
>> The following drops the chain_prev annotation to make the marker
>> work for trees.  I've also maked the obstack member GTY skip
>> (and prevent bitmap_obstack from gengtype processing) because
>> the obstack isn't used for GC allocated bitmaps.
>> 
>> Bootstrap & regtest running on x86_64-unknown-linux-gnu.
>> 
>> Richard.
>> 
>> 2019-02-04  Richard Biener  <rguenther@suse.de>
>> 
>> 	PR middle-end/89150
>> 	* bitmap.h (struct bitmap_obstack): Do not mark GTY.
>> 	(struct bitmap_element): Drop chain_prev so we properly recurse on
>> 	the prev member, supporting tree views.
>> 	(struct bitmap_head): GTY skip the obstack member.
>Was there a particular failure mode you observed or was this discovered
>by inspection.

It was discovered via an out of tree patch, the issue is only latent on trunk (together with another unfixed pch issue of bitmaps). 

>The reason I ask is my tester is showing occasional failures
>bootstrapping hppa-linux-gnu with a segfault in ICF.

Unlikely to fix this... 

>I'd rather not have to dig into it if it can be avoided :-)
>Bootstrapping hppa via qemu is something like 6 hours...
>
>Jeff
Jeff Law Feb. 5, 2019, 8:20 p.m. UTC | #5
On 2/4/19 9:07 AM, Jeff Law wrote:
> On 2/4/19 6:15 AM, Richard Biener wrote:
>>
>> When I introduced tree-form bitmaps I forgot to think about GC.
>> The following drops the chain_prev annotation to make the marker
>> work for trees.  I've also maked the obstack member GTY skip
>> (and prevent bitmap_obstack from gengtype processing) because
>> the obstack isn't used for GC allocated bitmaps.
>>
>> Bootstrap & regtest running on x86_64-unknown-linux-gnu.
>>
>> Richard.
>>
>> 2019-02-04  Richard Biener  <rguenther@suse.de>
>>
>> 	PR middle-end/89150
>> 	* bitmap.h (struct bitmap_obstack): Do not mark GTY.
>> 	(struct bitmap_element): Drop chain_prev so we properly recurse on
>> 	the prev member, supporting tree views.
>> 	(struct bitmap_head): GTY skip the obstack member.
> Was there a particular failure mode you observed or was this discovered
> by inspection.
> 
> The reason I ask is my tester is showing occasional failures
> bootstrapping hppa-linux-gnu with a segfault in ICF.
> 
> I'd rather not have to dig into it if it can be avoided :-)
> Bootstrapping hppa via qemu is something like 6 hours...
And just to follow-up.  I'm really starting to wonder if the hppa issue
is a qemu bug of some kind.

The faulting instruction, ACAICT, shouldn't be faulting.  It appears to
be loading from a valid address, it's a byte load (so no alignment
issues).  Furthermore, I can instruction-step over it in gdb.

Anyway, I think we can reasonably conclude the PA issue is unrelated to
your change.

jeff
Michael Ploujnikov Feb. 7, 2019, 8:04 p.m. UTC | #6
On 2019-02-04 11:39 a.m., Richard Biener wrote:
> On February 4, 2019 5:07:00 PM GMT+01:00, Jeff Law <law@redhat.com> wrote:
>> On 2/4/19 6:15 AM, Richard Biener wrote:
>>>
>>> When I introduced tree-form bitmaps I forgot to think about GC.
>>> The following drops the chain_prev annotation to make the marker
>>> work for trees.  I've also maked the obstack member GTY skip
>>> (and prevent bitmap_obstack from gengtype processing) because
>>> the obstack isn't used for GC allocated bitmaps.
>>>
>>> Bootstrap & regtest running on x86_64-unknown-linux-gnu.
>>>
>>> Richard.
>>>
>>> 2019-02-04  Richard Biener  <rguenther@suse.de>
>>>
>>> 	PR middle-end/89150
>>> 	* bitmap.h (struct bitmap_obstack): Do not mark GTY.
>>> 	(struct bitmap_element): Drop chain_prev so we properly recurse on
>>> 	the prev member, supporting tree views.
>>> 	(struct bitmap_head): GTY skip the obstack member.
>> Was there a particular failure mode you observed or was this discovered
>> by inspection.
> 
> It was discovered via an out of tree patch, the issue is only latent on trunk (together with another unfixed pch issue of bitmaps). 

My apologies for not noticing this thread/PR earlier. I originally discovered this issue while working on an experimental patch, but since then I've also come up with a test case for this specific issue. Is it worth adding it to trunk?

- Michael
From 9f1049a1e24cd1aa9852c5dddd1342dce0226416 Mon Sep 17 00:00:00 2001
From: Michael Ploujnikov <michael.ploujnikov@oracle.com>
Date: Thu, 7 Feb 2019 14:43:40 -0500
Subject: [PATCH] Add a test for GC marking bitmaps in tree view mode

gcc/ChangeLog:

2019-02-07  Michael Ploujnikov  <michael.ploujnikov@oracle.com>

	PR middle-end/89150
	* bitmap.c (test_bitmap_tree_marking): New test.
	(NOT_NULL_OR_GARBAGE): For shortening
	test_bitmap_tree_marking.
	(bitmap_c_tests): Add test_bitmap_tree_marking.
---
 gcc/bitmap.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git gcc/bitmap.c gcc/bitmap.c
index 5a8236de75..7e802a1600 100644
--- gcc/bitmap.c
+++ gcc/bitmap.c
@@ -2626,6 +2626,11 @@ bitmap_head::dump ()
 
 #if CHECKING_P
 
+static GTY(()) bitmap selftest_test_bitmap;
+
+/* From ggc-internal.h */
+extern bool ggc_force_collect;
+
 namespace selftest {
 
 /* Selftests for bitmaps.  */
@@ -2722,6 +2727,82 @@ test_bitmap_single_bit_set_p ()
   ASSERT_EQ (1066, bitmap_first_set_bit (b));
 }
 
+#define NOT_NULL_OR_GARBAGE(NODE) \
+  (NODE != NULL && (unsigned long)(NODE) != 0xa5a5a5a5UL)
+
+static void
+test_bitmap_tree_marking ()
+{
+  selftest_test_bitmap = BITMAP_GGC_ALLOC ();
+  bitmap_tree_view (selftest_test_bitmap);
+
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 1*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 5*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 10*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 15*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 30*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 25*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 3*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 4*BITMAP_ELEMENT_ALL_BITS));
+  ASSERT_TRUE (bitmap_set_bit (selftest_test_bitmap, 26*BITMAP_ELEMENT_ALL_BITS));
+  /* At this point it should look like:
+              26
+             /  \
+            25  30
+           /
+          5
+         / \
+        4  15
+       /  /
+      3  10
+     /
+    1
+
+  */
+  ggc_force_collect = true;
+  ggc_collect ();
+  ggc_force_collect = false;
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first));
+  ASSERT_TRUE (selftest_test_bitmap->first->indx == 26);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->next));
+  ASSERT_TRUE (selftest_test_bitmap->first->next->indx == 30);
+  ASSERT_TRUE (selftest_test_bitmap->first->next->next == NULL);
+  ASSERT_TRUE (selftest_test_bitmap->first->next->prev == NULL);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->prev));
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->indx == 25);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->next == NULL);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->prev->prev));
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->indx == 5);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->prev->prev->next));
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->next->indx == 15);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->next->next == NULL);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->prev->prev->next->prev));
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->next->prev->indx == 10);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->next->prev->prev == NULL);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->next->prev->next == NULL);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->prev->prev->prev));
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->prev->indx == 4);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->prev->next == NULL);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->prev->prev->prev->prev));
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->prev->prev->indx == 3);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->prev->prev->next == NULL);
+
+  ASSERT_TRUE (NOT_NULL_OR_GARBAGE (selftest_test_bitmap->first->prev->prev->prev->prev->prev));
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->prev->prev->prev->indx == 1);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->prev->prev->prev->prev == NULL);
+  ASSERT_TRUE (selftest_test_bitmap->first->prev->prev->prev->prev->prev->next == NULL);
+
+  ASSERT_TRUE (bitmap_bit_p (selftest_test_bitmap, 15*BITMAP_ELEMENT_ALL_BITS));
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -2732,6 +2813,7 @@ bitmap_c_tests ()
   test_clear_bit_in_middle ();
   test_copying ();
   test_bitmap_single_bit_set_p ();
+  test_bitmap_tree_marking ();
 }
 
 } // namespace selftest
Jakub Jelinek Feb. 7, 2019, 8:09 p.m. UTC | #7
On Thu, Feb 07, 2019 at 03:04:21PM -0500, Michael Ploujnikov wrote:
> 2019-02-07  Michael Ploujnikov  <michael.ploujnikov@oracle.com>
> 
> 	PR middle-end/89150
> 	* bitmap.c (test_bitmap_tree_marking): New test.
> 	(NOT_NULL_OR_GARBAGE): For shortening
> 	test_bitmap_tree_marking.
> 	(bitmap_c_tests): Add test_bitmap_tree_marking.

Could you do that instead in a plugin in the testsuite?
I mean, the patch is adding garbage collection roots, so it will not affect
just -fself-tests run, but also any time the compiler will do GC.

	Jakub
Michael Ploujnikov Feb. 8, 2019, 3:02 p.m. UTC | #8
On 2019-02-07 3:09 p.m., Jakub Jelinek wrote:
> On Thu, Feb 07, 2019 at 03:04:21PM -0500, Michael Ploujnikov wrote:
>> 2019-02-07  Michael Ploujnikov  <michael.ploujnikov@oracle.com>
>>
>> 	PR middle-end/89150
>> 	* bitmap.c (test_bitmap_tree_marking): New test.
>> 	(NOT_NULL_OR_GARBAGE): For shortening
>> 	test_bitmap_tree_marking.
>> 	(bitmap_c_tests): Add test_bitmap_tree_marking.
> 
> Could you do that instead in a plugin in the testsuite?
> I mean, the patch is adding garbage collection roots, so it will not affect
> just -fself-tests run, but also any time the compiler will do GC.
> 
> 	Jakub
> 

I'm not sure what I would need to do to get gengtype to process a test
plugin source file and I can't find examples of this.

Instead, shouldn't I just do something like what's at the bottom of
gcc/ggc-tests.c and not worry about the extra root added to
gt-bitmap.h?


- Michael
Jakub Jelinek Feb. 8, 2019, 3:11 p.m. UTC | #9
On Fri, Feb 08, 2019 at 10:02:27AM -0500, Michael Ploujnikov wrote:
> On 2019-02-07 3:09 p.m., Jakub Jelinek wrote:
> > On Thu, Feb 07, 2019 at 03:04:21PM -0500, Michael Ploujnikov wrote:
> >> 2019-02-07  Michael Ploujnikov  <michael.ploujnikov@oracle.com>
> >>
> >> 	PR middle-end/89150
> >> 	* bitmap.c (test_bitmap_tree_marking): New test.
> >> 	(NOT_NULL_OR_GARBAGE): For shortening
> >> 	test_bitmap_tree_marking.
> >> 	(bitmap_c_tests): Add test_bitmap_tree_marking.
> > 
> > Could you do that instead in a plugin in the testsuite?
> > I mean, the patch is adding garbage collection roots, so it will not affect
> > just -fself-tests run, but also any time the compiler will do GC.
> > 
> > 	Jakub
> > 
> 
> I'm not sure what I would need to do to get gengtype to process a test
> plugin source file and I can't find examples of this.
> 
> Instead, shouldn't I just do something like what's at the bottom of
> gcc/ggc-tests.c and not worry about the extra root added to
> gt-bitmap.h?

No, instead ggc-tests.c should be moved into a plugin too.  You can run
gengtype from within *.exp and the additional advantage is that you test how
plugins work better.

	Jakub
diff mbox series

Patch

Index: gcc/bitmap.h
===================================================================
--- gcc/bitmap.h	(revision 268509)
+++ gcc/bitmap.h	(working copy)
@@ -288,10 +288,10 @@  typedef unsigned long BITMAP_WORD;
 #define BITMAP_ELEMENT_ALL_BITS (BITMAP_ELEMENT_WORDS * BITMAP_WORD_BITS)
 
 /* Obstack for allocating bitmaps and elements from.  */
-struct GTY (()) bitmap_obstack {
+struct bitmap_obstack {
   struct bitmap_element *elements;
   struct bitmap_head *heads;
-  struct obstack GTY ((skip)) obstack;
+  struct obstack obstack;
 };
 
 /* Bitmap set element.  We use a linked list to hold only the bits that
@@ -306,7 +306,7 @@  struct GTY (()) bitmap_obstack {
    bitmap_elt_clear_from to be implemented in unit time rather than
    linear in the number of elements to be freed.  */
 
-struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) bitmap_element {
+struct GTY((chain_next ("%h.next"))) bitmap_element {
   /* In list form, the next element in the linked list;
      in tree form, the left child node in the tree.  */
   struct bitmap_element *next;
@@ -340,7 +340,7 @@  struct GTY(()) bitmap_head {
   /* Last element looked at.  */
   bitmap_element * GTY((skip(""))) current;
   /* Obstack to allocate elements from.  If NULL, then use GGC allocation.  */
-  bitmap_obstack *obstack;
+  bitmap_obstack * GTY((skip(""))) obstack;
   void dump ();
 };