re PR tree-optimization/71522 (Wrong optimization of memcpy through a var of type...
[platform/upstream/gcc.git] / gcc / bitmap.c
index c4d8158..6206535 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions to support general ended bitmaps.
-   Copyright (C) 1997-2014 Free Software Foundation, Inc.
+   Copyright (C) 1997-2016 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -20,116 +20,26 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "obstack.h"
-#include "ggc.h"
 #include "bitmap.h"
-#include "hash-table.h"
-#include "vec.h"
+#include "selftest.h"
 
-/* Store information about each particular bitmap, per allocation site.  */
-struct bitmap_descriptor_d
-{
-  int id;
-  const char *function;
-  const char *file;
-  int line;
-  int created;
-  unsigned HOST_WIDEST_INT allocated;
-  unsigned HOST_WIDEST_INT peak;
-  unsigned HOST_WIDEST_INT current;
-  unsigned HOST_WIDEST_INT nsearches;
-  unsigned HOST_WIDEST_INT search_iter;
-};
-
-typedef struct bitmap_descriptor_d *bitmap_descriptor;
-typedef const struct bitmap_descriptor_d *const_bitmap_descriptor;
-
-/* Next available unique id number for bitmap desciptors.  */
-static int next_bitmap_desc_id = 0;
-
-/* Vector mapping descriptor ids to descriptors.  */
-static vec<bitmap_descriptor> bitmap_descriptors;
-
-/* Hashtable helpers.  */
-
-struct loc
-{
-  const char *file;
-  const char *function;
-  int line;
-};
-
-struct bitmap_desc_hasher : typed_noop_remove <bitmap_descriptor_d>
-{
-  typedef bitmap_descriptor_d value_type;
-  typedef loc compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
-};
-
-inline hashval_t
-bitmap_desc_hasher::hash (const value_type *d)
-{
-  return htab_hash_pointer (d->file) + d->line;
-}
-
-inline bool
-bitmap_desc_hasher::equal (const value_type *d, const compare_type *l)
-{
-  return d->file == l->file && d->function == l->function && d->line == l->line;
-}
-
-/* Hashtable mapping bitmap names to descriptors.  */
-static hash_table <bitmap_desc_hasher> bitmap_desc_hash;
-
-/* For given file and line, return descriptor, create new if needed.  */
-static bitmap_descriptor
-get_bitmap_descriptor (const char *file, int line, const char *function)
-{
-  bitmap_descriptor_d **slot;
-  struct loc loc;
-
-  loc.file = file;
-  loc.function = function;
-  loc.line = line;
-
-  if (!bitmap_desc_hash.is_created ())
-    bitmap_desc_hash.create (10);
-
-  slot = bitmap_desc_hash.find_slot_with_hash (&loc,
-                                              htab_hash_pointer (file) + line,
-                                              INSERT);
-  if (*slot)
-    return *slot;
-
-  *slot = XCNEW (struct bitmap_descriptor_d);
-  bitmap_descriptors.safe_push (*slot);
-  (*slot)->id = next_bitmap_desc_id++;
-  (*slot)->file = file;
-  (*slot)->function = function;
-  (*slot)->line = line;
-  return *slot;
-}
+/* Memory allocation statistics purpose instance.  */
+mem_alloc_description<bitmap_usage> bitmap_mem_desc;
 
 /* Register new bitmap.  */
 void
 bitmap_register (bitmap b MEM_STAT_DECL)
 {
-  bitmap_descriptor desc = get_bitmap_descriptor (ALONE_FINAL_PASS_MEM_STAT);
-  desc->created++;
-  b->descriptor_id = desc->id;
+  bitmap_mem_desc.register_descriptor (b, BITMAP_ORIGIN, false
+                                      FINAL_PASS_MEM_STAT);
 }
 
 /* Account the overhead.  */
 static void
-register_overhead (bitmap b, int amount)
+register_overhead (bitmap b, size_t amount)
 {
-  bitmap_descriptor desc = bitmap_descriptors[b->descriptor_id];
-  desc->current += amount;
-  if (amount > 0)
-    desc->allocated += amount;
-  if (desc->peak < desc->current)
-    desc->peak = desc->current;
+  if (bitmap_mem_desc.contains_descriptor_for_instance (b))
+    bitmap_mem_desc.register_instance_overhead (amount, b);
 }
 
 /* Global data */
@@ -244,7 +154,7 @@ bitmap_element_allocate (bitmap head)
          /*  Inner list was just a singleton.  */
          bitmap_ggc_free = element->prev;
       else
-       element = ggc_alloc_bitmap_element ();
+       element = ggc_alloc<bitmap_element> ();
     }
 
   if (GATHER_STATISTICS)
@@ -388,7 +298,7 @@ bitmap_gc_alloc_stat (ALONE_MEM_STAT_DECL)
 {
   bitmap map;
 
-  map = ggc_alloc_bitmap_head ();
+  map = ggc_alloc<bitmap_head> ();
   bitmap_initialize_stat (map, NULL PASS_MEM_STAT);
 
   if (GATHER_STATISTICS)
@@ -559,6 +469,27 @@ bitmap_copy (bitmap to, const_bitmap from)
       to_ptr = to_elt;
     }
 }
+
+/* Move a bitmap to another bitmap.  */
+
+void
+bitmap_move (bitmap to, bitmap from)
+{
+  gcc_assert (to->obstack == from->obstack);
+
+  bitmap_clear (to);
+
+  *to = *from;
+
+  if (GATHER_STATISTICS)
+    {
+      size_t sz = 0;
+      for (bitmap_element *e = to->first; e; e = e->next)
+       sz += sizeof (bitmap_element);
+      register_overhead (to, sz);
+      register_overhead (from, -sz);
+    }
+}
 \f
 /* Find a bitmap element that would hold a bitmap's bit.
    Update the `current' field even if we can't find an element that
@@ -578,10 +509,16 @@ bitmap_find_bit (bitmap head, unsigned int bit)
       && head->first->next == NULL)
     return NULL;
 
+  /* Usage can be NULL due to allocated bitmaps for which we do not
+     call initialize function.  */
+  bitmap_usage *usage = NULL;
+  if (GATHER_STATISTICS)
+    usage = bitmap_mem_desc.get_descriptor_for_instance (head);
+
   /* This bitmap has more than one element, and we're going to look
      through the elements list.  Count that as a search.  */
-  if (GATHER_STATISTICS)
-    bitmap_descriptors[head->descriptor_id]->nsearches++;
+  if (GATHER_STATISTICS && usage)
+    usage->m_nsearches++;
 
   if (head->indx < indx)
     /* INDX is beyond head->indx.  Search from head->current
@@ -590,8 +527,8 @@ bitmap_find_bit (bitmap head, unsigned int bit)
         element->next != 0 && element->indx < indx;
         element = element->next)
       {
-       if (GATHER_STATISTICS)
-         bitmap_descriptors[head->descriptor_id]->search_iter++;
+       if (GATHER_STATISTICS && usage)
+         usage->m_search_iter++;
       }
 
   else if (head->indx / 2 < indx)
@@ -601,8 +538,8 @@ bitmap_find_bit (bitmap head, unsigned int bit)
         element->prev != 0 && element->indx > indx;
         element = element->prev)
       {
-       if (GATHER_STATISTICS)
-         bitmap_descriptors[head->descriptor_id]->search_iter++;
+       if (GATHER_STATISTICS && usage)
+         usage->m_search_iter++;
       }
 
   else
@@ -611,16 +548,16 @@ bitmap_find_bit (bitmap head, unsigned int bit)
     for (element = head->first;
         element->next != 0 && element->indx < indx;
         element = element->next)
-      if (GATHER_STATISTICS)
+      if (GATHER_STATISTICS && usage)
        {
-         bitmap_descriptors[head->descriptor_id]->search_iter++;
+         usage->m_search_iter++;
        }
 
   /* `element' is the nearest to the one we want.  If it's not the one we
      want, the one we want doesn't exist.  */
   head->current = element;
   head->indx = element->indx;
-  if (element != 0 && element->indx != indx)
+  if (element->indx != indx)
     element = 0;
 
   return element;
@@ -726,6 +663,26 @@ bitmap_popcount (BITMAP_WORD a)
   return ret;
 }
 #endif
+
+/* Count and return the number of bits set in the bitmap word BITS.  */
+static unsigned long
+bitmap_count_bits_in_word (const BITMAP_WORD *bits)
+{
+  unsigned long count = 0;
+
+  for (unsigned ix = 0; ix != BITMAP_ELEMENT_WORDS; ix++)
+    {
+#if GCC_VERSION >= 3400
+      /* Note that popcountl matches BITMAP_WORD in type, so the actual size
+        of BITMAP_WORD is not material.  */
+      count += __builtin_popcountl (bits[ix]);
+#else
+      count += bitmap_popcount (bits[ix]);
+#endif
+    }
+  return count;
+}
+
 /* Count the number of bits set in the bitmap, and return it.  */
 
 unsigned long
@@ -733,19 +690,44 @@ bitmap_count_bits (const_bitmap a)
 {
   unsigned long count = 0;
   const bitmap_element *elt;
-  unsigned ix;
 
   for (elt = a->first; elt; elt = elt->next)
+    count += bitmap_count_bits_in_word (elt->bits);
+
+  return count;
+}
+
+/* Count the number of unique bits set in A and B and return it.  */
+
+unsigned long
+bitmap_count_unique_bits (const_bitmap a, const_bitmap b)
+{
+  unsigned long count = 0;
+  const bitmap_element *elt_a, *elt_b;
+
+  for (elt_a = a->first, elt_b = b->first; elt_a && elt_b; )
     {
-      for (ix = 0; ix != BITMAP_ELEMENT_WORDS; ix++)
+      /* If we're at different indices, then count all the bits
+        in the lower element.  If we're at the same index, then
+        count the bits in the IOR of the two elements.  */
+      if (elt_a->indx < elt_b->indx)
        {
-#if GCC_VERSION >= 3400
-         /* Note that popcountl matches BITMAP_WORD in type, so the actual size
-        of BITMAP_WORD is not material.  */
-         count += __builtin_popcountl (elt->bits[ix]);
-#else
-         count += bitmap_popcount (elt->bits[ix]);
-#endif
+         count += bitmap_count_bits_in_word (elt_a->bits);
+         elt_a = elt_a->next;
+       }
+      else if (elt_b->indx < elt_a->indx)
+       {
+         count += bitmap_count_bits_in_word (elt_b->bits);
+         elt_b = elt_b->next;
+       }
+      else
+       {
+         BITMAP_WORD bits[BITMAP_ELEMENT_WORDS];
+         for (unsigned ix = 0; ix != BITMAP_ELEMENT_WORDS; ix++)
+           bits[ix] = elt_a->bits[ix] | elt_b->bits[ix];
+         count += bitmap_count_bits_in_word (bits);
+         elt_a = elt_a->next;
+         elt_b = elt_b->next;
        }
     }
   return count;
@@ -1211,6 +1193,12 @@ bitmap_set_range (bitmap head, unsigned int start, unsigned int count)
   if (!count)
     return;
 
+  if (count == 1)
+    {
+      bitmap_set_bit (head, start);
+      return;
+    }
+
   first_index = start / BITMAP_ELEMENT_ALL_BITS;
   end_bit_plus1 = start + count;
   last_index = (end_bit_plus1 - 1) / BITMAP_ELEMENT_ALL_BITS;
@@ -1310,6 +1298,12 @@ bitmap_clear_range (bitmap head, unsigned int start, unsigned int count)
   if (!count)
     return;
 
+  if (count == 1)
+    {
+      bitmap_clear_bit (head, start);
+      return;
+    }
+
   first_index = start / BITMAP_ELEMENT_ALL_BITS;
   end_bit_plus1 = start + count;
   last_index = (end_bit_plus1 - 1) / BITMAP_ELEMENT_ALL_BITS;
@@ -1594,6 +1588,8 @@ bitmap_ior (bitmap dst, const_bitmap a, const_bitmap b)
   if (dst_elt)
     {
       changed = true;
+      /* Ensure that dst->current is valid.  */
+      dst->current = dst->first;
       bitmap_elt_clear_from (dst, dst_elt);
     }
   gcc_checking_assert (!dst->current == !dst->first);
@@ -1950,6 +1946,8 @@ bitmap_ior_and_compl (bitmap dst, const_bitmap a, const_bitmap b, const_bitmap k
   if (dst_elt)
     {
       changed = true;
+      /* Ensure that dst->current is valid.  */
+      dst->current = dst->first;
       bitmap_elt_clear_from (dst, dst_elt);
     }
   gcc_checking_assert (!dst->current == !dst->first);
@@ -2140,70 +2138,14 @@ bitmap_print (FILE *file, const_bitmap head, const char *prefix,
   fputs (suffix, file);
 }
 
-
-/* Used to accumulate statistics about bitmap sizes.  */
-struct output_info
-{
-  unsigned HOST_WIDEST_INT size;
-  unsigned HOST_WIDEST_INT count;
-};
-
-/* Called via hash_table::traverse.  Output bitmap descriptor pointed out by
-   SLOT and update statistics.  */
-int
-print_statistics (bitmap_descriptor_d **slot, output_info *i)
-{
-  bitmap_descriptor d = *slot;
-  char s[4096];
-
-  if (d->allocated)
-    {
-      const char *s1 = d->file;
-      const char *s2;
-      while ((s2 = strstr (s1, "gcc/")))
-       s1 = s2 + 4;
-      sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
-      s[41] = 0;
-      fprintf (stderr,
-              "%-41s %9u"
-              " %15"HOST_WIDEST_INT_PRINT"d %15"HOST_WIDEST_INT_PRINT"d"
-              " %15"HOST_WIDEST_INT_PRINT"d"
-              " %10"HOST_WIDEST_INT_PRINT"d %10"HOST_WIDEST_INT_PRINT"d\n",
-              s, d->created,
-              d->allocated, d->peak, d->current,
-              d->nsearches, d->search_iter);
-      i->size += d->allocated;
-      i->count += d->created;
-    }
-  return 1;
-}
-
 /* Output per-bitmap memory usage statistics.  */
 void
 dump_bitmap_statistics (void)
 {
-  struct output_info info;
-
-  if (! GATHER_STATISTICS)
+  if (!GATHER_STATISTICS)
     return;
 
-  if (!bitmap_desc_hash.is_created ())
-    return;
-
-  fprintf (stderr,
-          "\n%-41s %9s %15s %15s %15s %10s %10s\n",
-          "Bitmap", "Overall",
-          "Allocated", "Peak", "Leak",
-          "searched", "search_itr");
-  fprintf (stderr, "---------------------------------------------------------------------------------\n");
-  info.count = 0;
-  info.size = 0;
-  bitmap_desc_hash.traverse <output_info *, print_statistics> (&info);
-  fprintf (stderr, "---------------------------------------------------------------------------------\n");
-  fprintf (stderr,
-          "%-41s %9"HOST_WIDEST_INT_PRINT"d %15"HOST_WIDEST_INT_PRINT"d\n",
-          "Total", info.count, info.size);
-  fprintf (stderr, "---------------------------------------------------------------------------------\n");
+  bitmap_mem_desc.dump (BITMAP_ORIGIN);
 }
 
 DEBUG_FUNCTION void
@@ -2221,5 +2163,117 @@ debug (const bitmap_head *ptr)
     fprintf (stderr, "<nil>\n");
 }
 
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for bitmaps.  */
+
+/* Freshly-created bitmaps ought to be empty.  */
+
+static void
+test_gc_alloc ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+}
+
+/* Verify bitmap_set_range.  */
+
+static void
+test_set_range ()
+{
+  bitmap b = bitmap_gc_alloc ();
+  ASSERT_TRUE (bitmap_empty_p (b));
+
+  bitmap_set_range (b, 7, 5);
+  ASSERT_FALSE (bitmap_empty_p (b));
+  ASSERT_EQ (5, bitmap_count_bits (b));
+
+  /* Verify bitmap_bit_p at the boundaries.  */
+  ASSERT_FALSE (bitmap_bit_p (b, 6));
+  ASSERT_TRUE (bitmap_bit_p (b, 7));
+  ASSERT_TRUE (bitmap_bit_p (b, 11));
+  ASSERT_FALSE (bitmap_bit_p (b, 12));
+}
+
+/* Verify splitting a range into two pieces using bitmap_clear_bit.  */
+
+static void
+test_clear_bit_in_middle ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  /* Set b to [100..200].  */
+  bitmap_set_range (b, 100, 100);
+  ASSERT_EQ (100, bitmap_count_bits (b));
+
+  /* Clear a bit in the middle.  */
+  bool changed = bitmap_clear_bit (b, 150);
+  ASSERT_TRUE (changed);
+  ASSERT_EQ (99, bitmap_count_bits (b));
+  ASSERT_TRUE (bitmap_bit_p (b, 149));
+  ASSERT_FALSE (bitmap_bit_p (b, 150));
+  ASSERT_TRUE (bitmap_bit_p (b, 151));
+}
+
+/* Verify bitmap_copy.  */
+
+static void
+test_copying ()
+{
+  bitmap src = bitmap_gc_alloc ();
+  bitmap_set_range (src, 40, 10);
+
+  bitmap dst = bitmap_gc_alloc ();
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+  bitmap_copy (dst, src);
+  ASSERT_TRUE (bitmap_equal_p (src, dst));
+
+  /* Verify that we can make them unequal again...  */
+  bitmap_set_range (src, 70, 5);
+  ASSERT_FALSE (bitmap_equal_p (src, dst));
+
+  /* ...and that changing src after the copy didn't affect
+     the other: */
+  ASSERT_FALSE (bitmap_bit_p (dst, 70));
+}
+
+/* Verify bitmap_single_bit_set_p.  */
+
+static void
+test_bitmap_single_bit_set_p ()
+{
+  bitmap b = bitmap_gc_alloc ();
+
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+
+  bitmap_set_range (b, 42, 1);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_set_range (b, 1066, 1);
+  ASSERT_FALSE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (42, bitmap_first_set_bit (b));
+
+  bitmap_clear_range (b, 0, 100);
+  ASSERT_TRUE (bitmap_single_bit_set_p (b));
+  ASSERT_EQ (1066, bitmap_first_set_bit (b));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+bitmap_c_tests ()
+{
+  test_gc_alloc ();
+  test_set_range ();
+  test_clear_bit_in_middle ();
+  test_copying ();
+  test_bitmap_single_bit_set_p ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
 
 #include "gt-bitmap.h"