sbitmap.c (bitmap_bit_in_range_p): New function.
authorJeff Law <law@redhat.com>
Fri, 29 Sep 2017 18:20:41 +0000 (12:20 -0600)
committerJeff Law <law@gcc.gnu.org>
Fri, 29 Sep 2017 18:20:41 +0000 (12:20 -0600)
* sbitmap.c (bitmap_bit_in_range_p): New function.
* sbitmap.h (bitmap_bit_in_range_p): Prototype.
* tree-ssa-dse.c (live_bytes_read): New function.
(dse_classify_store): Ignore reads of dead bytes.

* testsuite/gcc.dg/tree-ssa/ssa-dse-26.c: New test.

From-SVN: r253305

gcc/ChangeLog
gcc/sbitmap.c
gcc/sbitmap.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-26.c [new file with mode: 0644]
gcc/tree-ssa-dse.c

index 16c9737f09a95c183295b2977508761162f52c4b..1932390dd0aaa714b91b5a4aad25bdeab298fb82 100644 (file)
@@ -1,5 +1,10 @@
 2017-09-29  Jeff Law  <law@redhat.com>
 
+       * sbitmap.c (bitmap_bit_in_range_p): New function.
+       * sbitmap.h (bitmap_bit_in_range_p): Prototype.
+       * tree-ssa-dse.c (live_bytes_read): New function.
+       (dse_classify_store): Ignore reads of dead bytes.
+
        * config/i386/i386.c (ix86_adjust_stack_and_probe_stack_clash): Fix
        typos and whitespace errors.
        * config/i386/predicates.md (address_no_seg_operand): Likewise.
index c065d1317675e5f47907400e14bf22953acb1cd1..4bf13a11a1d2070ebf924f2ec7850d9da99a0c59 100644 (file)
@@ -316,6 +316,59 @@ bitmap_set_range (sbitmap bmap, unsigned int start, unsigned int count)
   bmap->elms[start_word] |= mask;
 }
 
+/* Return TRUE if any bit between START and END inclusive is set within
+   the simple bitmap BMAP.  Return FALSE otherwise.  */
+
+bool
+bitmap_bit_in_range_p (const_sbitmap bmap, unsigned int start, unsigned int end)
+{
+  unsigned int start_word = start / SBITMAP_ELT_BITS;
+  unsigned int start_bitno = start % SBITMAP_ELT_BITS;
+
+  /* Testing within a word, starting at the beginning of a word.  */
+  if (start_bitno == 0 && (end - start) < SBITMAP_ELT_BITS)
+    {
+      SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << (end - start)) - 1;
+      return (bmap->elms[start_word] & mask) != 0;
+    }
+
+  unsigned int end_word = end / SBITMAP_ELT_BITS;
+  unsigned int end_bitno = end % SBITMAP_ELT_BITS;
+
+  /* Testing starts somewhere in the middle of a word.  Test up to the
+     end of the word or the end of the requested region, whichever comes
+     first.  */
+  if (start_bitno != 0)
+    {
+      unsigned int nbits = ((start_word == end_word)
+                           ? end_bitno - start_bitno
+                           : SBITMAP_ELT_BITS - start_bitno);
+      SBITMAP_ELT_TYPE mask = ((SBITMAP_ELT_TYPE)1 << nbits) - 1;
+      mask <<= start_bitno;
+      if (bmap->elms[start_word] & mask)
+       return true;
+      start_word++;
+    }
+
+  if (start_word > end_word)
+    return false;
+
+  /* Now test words at a time until we hit a partial word.  */
+  unsigned int nwords = (end_word - start_word);
+  while (nwords)
+    {
+      if (bmap->elms[start_word])
+       return true;
+      start_word++;
+      nwords--;
+    }
+
+  /* Now handle residuals in the last word.  */
+  SBITMAP_ELT_TYPE mask
+    = ((SBITMAP_ELT_TYPE)1 << (SBITMAP_ELT_BITS - end_bitno)) - 1;
+  return (bmap->elms[start_word] & mask) != 0;
+}
+
 #if GCC_VERSION < 3400
 /* Table of number of set bits in a character, indexed by value of char.  */
 static const unsigned char popcount_table[] =
index ce4d27d927c2b8553f54ea1baf5e5c6230d6f55b..ff52e939bf36c3e76fb40bc99f94c53debfacc8b 100644 (file)
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.  If not see
      * set_difference          : bitmap_and_compl
      * set_disjuction          : (not implemented)
      * set_compare             : bitmap_equal_p
+     * bit_in_range_p          : bitmap_bit_in_range_p
 
    Some operations on 3 sets that occur frequently in data flow problems
    are also implemented:
@@ -253,6 +254,7 @@ extern bool bitmap_and (sbitmap, const_sbitmap, const_sbitmap);
 extern bool bitmap_ior (sbitmap, const_sbitmap, const_sbitmap);
 extern bool bitmap_xor (sbitmap, const_sbitmap, const_sbitmap);
 extern bool bitmap_subset_p (const_sbitmap, const_sbitmap);
+extern bool bitmap_bit_in_range_p (const_sbitmap, unsigned int, unsigned int);
 
 extern int bitmap_first_set_bit (const_sbitmap);
 extern int bitmap_last_set_bit (const_sbitmap);
index 94cedb737173257bd9e76ef7e1bc1adc6400f980..890063cf470db3b96ab305f7012c8b0c4484a08c 100644 (file)
@@ -1,3 +1,7 @@
+2017-09-29  Jeff Law  <law@redhat.com>
+
+       * testsuite/gcc.dg/tree-ssa/ssa-dse-26.c: New test.
+
 2017-09-29  Jakub Jelinek  <jakub@redhat.com>
 
        P0683R1 - default member initializers for bit-fields
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-26.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-26.c
new file mode 100644 (file)
index 0000000..6605dfe
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dse1-details" } */
+
+enum constraint_expr_type
+{
+  SCALAR, DEREF, ADDRESSOF
+};
+typedef struct constraint_expr
+{
+  enum constraint_expr_type type;
+  unsigned int var;
+  long offset;
+} constraint_expr ;
+typedef struct constraint
+{
+  struct constraint_expr lhs;
+  struct constraint_expr rhs;
+} constraint;
+static _Bool
+constraint_expr_equal (struct constraint_expr x, struct constraint_expr y)
+{
+  return x.type == y.type && x.var == y.var && x.offset == y.offset;
+}
+
+_Bool
+constraint_equal (struct constraint a, struct constraint b)
+{
+  return constraint_expr_equal (a.lhs, b.lhs)
+    && constraint_expr_equal (a.rhs, b.rhs);
+}
+
+/* { dg-final { scan-tree-dump-times "Deleted dead store" 2 "dse1" } } */
+
index 70c8b073359a75ff9ec7e5c7f32b21c96310bb59..1eca740598fc325554da3a359098268fa28fafac 100644 (file)
@@ -468,6 +468,36 @@ maybe_trim_partially_dead_store (ao_ref *ref, sbitmap live, gimple *stmt)
     }
 }
 
+/* Return TRUE if USE_REF reads bytes from LIVE where live is
+   derived from REF, a write reference.
+
+   While this routine may modify USE_REF, it's passed by value, not
+   location.  So callers do not see those modifications.  */
+
+static bool
+live_bytes_read (ao_ref use_ref, ao_ref *ref, sbitmap live)
+{
+  /* We have already verified that USE_REF and REF hit the same object.
+     Now verify that there's actually an overlap between USE_REF and REF.  */
+  if (ranges_overlap_p (use_ref.offset, use_ref.size, ref->offset, ref->size))
+    {
+      normalize_ref (&use_ref, ref);
+
+      /* If USE_REF covers all of REF, then it will hit one or more
+        live bytes.   This avoids useless iteration over the bitmap
+        below.  */
+      if (use_ref.offset <= ref->offset
+         && use_ref.offset + use_ref.size >= ref->offset + ref->size)
+       return true;
+
+      /* Now check if any of the remaining bits in use_ref are set in LIVE.  */
+      unsigned int start = (use_ref.offset - ref->offset) / BITS_PER_UNIT;
+      unsigned int end  = (use_ref.offset + use_ref.size) / BITS_PER_UNIT;
+      return bitmap_bit_in_range_p (live, start, end);
+    }
+  return true;
+}
+
 /* A helper of dse_optimize_stmt.
    Given a GIMPLE_ASSIGN in STMT that writes to REF, find a candidate
    statement *USE_STMT that may prove STMT to be dead.
@@ -547,6 +577,31 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
          /* If the statement is a use the store is not dead.  */
          else if (ref_maybe_used_by_stmt_p (use_stmt, ref))
            {
+             /* Handle common cases where we can easily build a ao_ref
+                structure for USE_STMT and in doing so we find that the
+                references hit non-live bytes and thus can be ignored.  */
+             if (live_bytes && (!gimple_vdef (use_stmt) || !temp))
+               {
+                 if (is_gimple_assign (use_stmt))
+                   {
+                     /* Other cases were noted as non-aliasing by
+                        the call to ref_maybe_used_by_stmt_p.  */
+                     ao_ref use_ref;
+                     ao_ref_init (&use_ref, gimple_assign_rhs1 (use_stmt));
+                     if (valid_ao_ref_for_dse (&use_ref)
+                         && use_ref.base == ref->base
+                         && use_ref.size == use_ref.max_size
+                         && !live_bytes_read (use_ref, ref, live_bytes))
+                       {
+                         /* If this statement has a VDEF, then it is the
+                            first store we have seen, so walk through it.  */
+                         if (gimple_vdef (use_stmt))
+                           temp = use_stmt;
+                         continue;
+                       }
+                   }
+               }
+
              fail = true;
              BREAK_FROM_IMM_USE_STMT (ui);
            }