Hi,

while I was happy using obstacks in other parts of the compiler I thought they would provide a handy solution for the XNEWVECs/XRESIZEVECs in df-scan.c, especially df_install_refs() which is the heaviest malloc() user after the rest of my patches.

In the process I realised that obstacks weren't exactly suitable (thanks matz for helping on IRC), nevertheless I have a patch which is stable, a bit faster and more memory friendly (don't know why, but RSS memory for common non-pathological compilations, was smaller). However after trying various incorrect changes I'm aware that there are leaks in there that can't be closed without dirty hacks, so I gave up.

I'm posting the simplest but stable version of my changes and would really like to hear ideas. There are "holes" in the obstack that should have been free'd, but in the end I didn't see memory increase. I don't know what would happen for huge functions that keep the obstack alive for long, I didn't have such testcase. Finally, I think my next try will involve converting the chains to pool_alloc'ed linked list, do you think that makes sense?


Thanks,
Dimitris
=== modified file 'gcc/df-scan.c'
--- gcc/df-scan.c       2012-07-16 11:32:42 +0000
+++ gcc/df-scan.c       2012-08-20 14:01:59 +0000
@@ -184,6 +184,17 @@ struct df_scan_problem_data
   bitmap_obstack insn_bitmaps;
 };
 
+/* Obstack for storing all of all of
+   insn_info->{defs,uses,eq_uses,mw_hardregs} and
+   bb_info->artificial_{defs,uses}.  */
+static struct obstack df_refs_obstack;
+
+/* Keep the obstack initialised (only 4k overhead) and use this pointer to
+   actually empty it fast.  */
+static void *df_first_refs_obj;
+static int df_refs_obstack_is_init;
+
+
 typedef struct df_scan_bb_info *df_scan_bb_info_t;
 
 
@@ -193,36 +204,13 @@ df_scan_free_internal (void)
 {
   struct df_scan_problem_data *problem_data
     = (struct df_scan_problem_data *) df_scan->problem_data;
-  unsigned int i;
-  basic_block bb;
 
-  /* The vectors that hold the refs are not pool allocated because
-     they come in many sizes.  This makes them impossible to delete
-     all at once.  */
-  for (i = 0; i < DF_INSN_SIZE(); i++)
-    {
-      struct df_insn_info *insn_info = DF_INSN_UID_GET(i);
-      /* Skip the insns that have no insn_info or have been
-        deleted.  */
-      if (insn_info)
-       {
-         df_scan_free_ref_vec (insn_info->defs);
-         df_scan_free_ref_vec (insn_info->uses);
-         df_scan_free_ref_vec (insn_info->eq_uses);
-         df_scan_free_mws_vec (insn_info->mw_hardregs);
-       }
-    }
-
-  FOR_ALL_BB (bb)
-    {
-      unsigned int bb_index = bb->index;
-      struct df_scan_bb_info *bb_info = df_scan_get_bb_info (bb_index);
-      if (bb_info)
-       {
-         df_scan_free_ref_vec (bb_info->artificial_defs);
-         df_scan_free_ref_vec (bb_info->artificial_uses);
-       }
-    }
+  /* Delete at once all vectors that hold the refs (all of
+     insn_info->{defs,uses,eq_uses,mw_hardregs} and
+     bb_info->artificial_{defs,uses}) but keep the obstack initialised, so
+     that it's ready for more BBs.  */
+  obstack_free (&df_refs_obstack, df_first_refs_obj);
+  df_first_refs_obj = NULL;
 
   free (df->def_info.refs);
   free (df->def_info.begin);
@@ -364,6 +352,14 @@ df_scan_alloc (bitmap all_blocks ATTRIBU
       bb_info->artificial_uses = NULL;
     }
 
+  if (! df_refs_obstack_is_init)
+    {
+      obstack_init (&df_refs_obstack);
+      df_refs_obstack_is_init = 1;
+    }
+  gcc_assert (df_first_refs_obj == NULL);
+  df_first_refs_obj = XOBNEW (&df_refs_obstack, void *);
+
   bitmap_initialize (&df->hardware_regs_used, &problem_data->reg_bitmaps);
   bitmap_initialize (&df->regular_block_artificial_uses, 
&problem_data->reg_bitmaps);
   bitmap_initialize (&df->eh_block_artificial_uses, 
&problem_data->reg_bitmaps);
@@ -791,9 +787,15 @@ df_install_ref_incremental (df_ref ref)
     }
 
   ref_rec = *ref_rec_ptr;
+  /* fprintf (stderr, "count:%d ref_rec:%p\n", count, ref_rec); */
   if (count)
     {
-      ref_rec = XRESIZEVEC (df_ref, ref_rec, count+2);
+      /* Impossible to actually know if ref_rec was malloc'ed or obstack'ed
+        thus we might have a leak here!  */
+      df_ref *ref_rec2 = XOBNEWVEC (&df_refs_obstack, df_ref, count+2);
+      memcpy (ref_rec2, ref_rec, count*sizeof(df_ref));
+      /* free (ref_rec); */
+      ref_rec = ref_rec2;
       *ref_rec_ptr = ref_rec;
       ref_rec[count] = ref;
       ref_rec[count+1] = NULL;
@@ -801,7 +803,7 @@ df_install_ref_incremental (df_ref ref)
     }
   else
     {
-      df_ref *ref_rec = XNEWVEC (df_ref, 2);
+      ref_rec = XOBNEWVEC (&df_refs_obstack, df_ref, 2);
       ref_rec[0] = ref;
       ref_rec[1] = NULL;
       *ref_rec_ptr = ref_rec;
@@ -1070,8 +1072,9 @@ df_ref_chain_delete (df_ref *ref_rec)
 
   /* If the list is empty, it has a special shared element that is not
      to be deleted.  */
-  if (*start)
-    free (start);
+  /* if (*start) */
+  /*   free (start); */
+  /* obstack_free'd alltogether in the end of df pass.  */
 }
 
 
@@ -2611,7 +2615,7 @@ df_install_refs (basic_block bb,
   count = VEC_length (df_ref, old_vec);
   if (count)
     {
-      df_ref *new_vec = XNEWVEC (df_ref, count + 1);
+      df_ref *new_vec = XOBNEWVEC (&df_refs_obstack, df_ref, count + 1);
       bool add_to_table;
       df_ref this_ref;
       unsigned int ix;

Reply via email to