Deal with CLOBBERs better in VN (PR92751)

Message ID nycvar.YFH.7.76.1912030958270.5566@zhemvz.fhfr.qr
State New
Headers show
Series
  • Deal with CLOBBERs better in VN (PR92751)
Related show

Commit Message

Richard Biener Dec. 3, 2019, 9:02 a.m.
The following fixes value-numbering being confused by the CLOBBERs
that appear in Skia vector constructors like

  <bb 2> :
  v ={v} {CLOBBER};
  MEM[(struct Vec *)&v] ={v} {CLOBBER};
  MEM[(struct Vec *)&v] ={v} {CLOBBER};
  MEM[(struct Vec *)&v].val = 1;
  MEM[(struct Vec *)&v + 4B] ={v} {CLOBBER};
  MEM[(struct Vec *)&v + 4B].val = 1;
  MEM[(struct Vec *)&v + 8B] ={v} {CLOBBER};
  MEM[(struct Vec *)&v + 8B] ={v} {CLOBBER};
  MEM[(struct Vec *)&v + 8B].val = 1;
  MEM[(struct Vec *)&v + 12B] ={v} {CLOBBER};
  MEM[(struct Vec *)&v + 12B].val = 1;
  _4 = MEM <__int128 unsigned> [(char * {ref-all})&v];

where we'd like to value-number _4 to { 1, 1, 1, 1 }.  Appearantly
the template obfuscation is necessary to trigger the CLOBBERs,
just a bunch of placement news to initialize array elements isn't
enough ;)

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

I didn't opt for the alternative to just skip over all clobbers
when value-numbering - "reads" from them would invoke undefined
behavior and so we could assume them to be not aliasing.  The
following works as well and is safer at this point.

The testcase depends on the improved memcpy folding which I had
to adjust a bit to avoid regressions in strlenopt pass testcases
(retesting at the moment).

Richard.

2019-12-03  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/92751
	* tree-ssa-sccvn.c (vn_walk_cb_data::push_partial_def): Fail
	when a clobber ends up in the partial-def vector.
	(vn_reference_lookup_3): Let clobbers be handled by the
	assignment from CTOR handling.

	* g++.dg/tree-ssa/pr92751.C: New testcase.

Patch

Index: gcc/tree-ssa-sccvn.c
===================================================================
--- gcc/tree-ssa-sccvn.c	(revision 278893)
+++ gcc/tree-ssa-sccvn.c	(working copy)
@@ -1761,6 +1761,9 @@  vn_walk_cb_data::push_partial_def (const
 
   if (partial_defs.is_empty ())
     {
+      /* If we get a clobber upfront, fail.  */
+      if (TREE_CLOBBER_P (pd.rhs))
+	return (void *)-1;
       partial_defs.safe_push (pd);
       first_range.offset = pd.offset;
       first_range.size = pd.size;
@@ -1792,7 +1795,8 @@  vn_walk_cb_data::push_partial_def (const
       && ranges_known_overlap_p (r->offset, r->size + 1,
 				 newr.offset, newr.size))
     {
-      /* Ignore partial defs already covered.  */
+      /* Ignore partial defs already covered.  Here we also drop shadowed
+         clobbers arriving here at the floor.  */
       if (known_subrange_p (newr.offset, newr.size, r->offset, r->size))
 	return NULL;
       r->size = MAX (r->offset + r->size, newr.offset + newr.size) - r->offset;
@@ -1817,6 +1821,9 @@  vn_walk_cb_data::push_partial_def (const
 		     rafter->offset + rafter->size) - r->offset;
       splay_tree_remove (known_ranges, (splay_tree_key)&rafter->offset);
     }
+  /* If we get a clobber, fail.  */
+  if (TREE_CLOBBER_P (pd.rhs))
+    return (void *)-1;
   partial_defs.safe_push (pd);
 
   /* Now we have merged newr into the range tree.  When we have covered
@@ -2355,10 +2362,6 @@  vn_reference_lookup_3 (ao_ref *ref, tree
   poly_int64 offset = ref->offset;
   poly_int64 maxsize = ref->max_size;
 
-  /* We can't deduce anything useful from clobbers.  */
-  if (gimple_clobber_p (def_stmt))
-    return (void *)-1;
-
   /* def_stmt may-defs *ref.  See if we can derive a value for *ref
      from that definition.
      1) Memset.  */
@@ -2508,6 +2511,10 @@  vn_reference_lookup_3 (ao_ref *ref, tree
 	  if (data->partial_defs.is_empty ()
 	      && known_subrange_p (offset, maxsize, offset2, size2))
 	    {
+	      /* While technically undefined behavior do not optimize
+	         a full read from a clobber.  */
+	      if (gimple_clobber_p (def_stmt))
+		return (void *)-1;
 	      tree val = build_zero_cst (vr->type);
 	      return vn_reference_lookup_or_insert_for_pieces
 		  (vuse, get_alias_set (lhs), vr->type, vr->operands, val);
@@ -2522,6 +2529,9 @@  vn_reference_lookup_3 (ao_ref *ref, tree
 		   && size2.is_constant (&size2i)
 		   && size2i % BITS_PER_UNIT == 0)
 	    {
+	      /* Let clobbers be consumed by the partial-def tracker
+	         which can choose to ignore them if they are shadowed
+		 by a later def.  */
 	      pd_data pd;
 	      pd.rhs = gimple_assign_rhs1 (def_stmt);
 	      pd.offset = (offset2i - offseti) / BITS_PER_UNIT;
Index: gcc/testsuite/g++.dg/tree-ssa/pr92751.C
===================================================================
--- gcc/testsuite/g++.dg/tree-ssa/pr92751.C	(nonexistent)
+++ gcc/testsuite/g++.dg/tree-ssa/pr92751.C	(working copy)
@@ -0,0 +1,26 @@ 
+// { dg-do compile }
+// { dg-options "-O -fdump-tree-fre1" }
+
+inline void* operator new(__SIZE_TYPE__, void* p) { return p; }
+template<int N>
+struct Vec {
+  Vec(int v) : lo(v), hi(v) {};
+  Vec<N/2> lo, hi;
+};
+template<>
+struct Vec<1> {
+  Vec(int v) : val(v) {}
+  int val;
+};
+
+typedef int v4si __attribute__((vector_size(16)));
+void foo (v4si *dst)
+{
+  Vec<4> v(1);
+  v4si tem;
+  __builtin_memcpy (&tem, &v, sizeof (tem));
+  *dst = tem;
+}
+
+// FRE should be able to value-number 'tem' to a constant.  */
+// { dg-final { scan-tree-dump "\\*dst_\[0-9\]*\\\(D\\\) = { 1, 1, 1, 1 };" "fre1" } }