diff mbox series

Fix a tree sharing bug in get_*_computation_at (PR tree-optimization/92262)

Message ID 20191030065649.GO4650@tucnak
State New
Headers show
Series Fix a tree sharing bug in get_*_computation_at (PR tree-optimization/92262) | expand

Commit Message

Jakub Jelinek Oct. 30, 2019, 6:56 a.m. UTC
Hi!

As mentioned in the PR, while get_computation_at calls unshare_aff_combination
and through that unshares the individual expressions, we then call
aff_combination_to_tree which uses the fold-const.c APIs, and those do not
guarantee the same non-shareable tree isn't used multiple times in the
result, e.g. (a ? b : c) + d can be folded into a ? b + d : c + d and when
say d is (cast) &whatever that will appear multiple times in the result.
For debug stmts we are putting these expressions directly into the IL and so
need to make sure there is no invalid tree sharing.  As since my patch we
can try to compute the expressions even in cases where it won't be then used
in the end, the following patch does the unsharing only immediately before
putting it into the IL, and removes unsharing in get_debug_computation_at
because it will be unshared anyway later.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-10-30  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/92262
	* tree-ssa-loop-ivopts.c (get_debug_computation_at): Don't unshare
	ubase or cbase here.
	(remove_unused_ivs): Unshare comp before using it.

	* g++.dg/opt/pr92262.C: New test.


	Jakub

Comments

Richard Biener Oct. 30, 2019, 9:43 a.m. UTC | #1
On Wed, 30 Oct 2019, Jakub Jelinek wrote:

> Hi!
> 
> As mentioned in the PR, while get_computation_at calls unshare_aff_combination
> and through that unshares the individual expressions, we then call
> aff_combination_to_tree which uses the fold-const.c APIs, and those do not
> guarantee the same non-shareable tree isn't used multiple times in the
> result, e.g. (a ? b : c) + d can be folded into a ? b + d : c + d and when
> say d is (cast) &whatever that will appear multiple times in the result.
> For debug stmts we are putting these expressions directly into the IL and so
> need to make sure there is no invalid tree sharing.  As since my patch we
> can try to compute the expressions even in cases where it won't be then used
> in the end, the following patch does the unsharing only immediately before
> putting it into the IL, and removes unsharing in get_debug_computation_at
> because it will be unshared anyway later.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Richard.

> 2019-10-30  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/92262
> 	* tree-ssa-loop-ivopts.c (get_debug_computation_at): Don't unshare
> 	ubase or cbase here.
> 	(remove_unused_ivs): Unshare comp before using it.
> 
> 	* g++.dg/opt/pr92262.C: New test.
> 
> --- gcc/tree-ssa-loop-ivopts.c.jj	2019-10-23 14:35:42.994753407 +0200
> +++ gcc/tree-ssa-loop-ivopts.c	2019-10-29 09:45:47.418217336 +0100
> @@ -4152,8 +4152,6 @@ get_debug_computation_at (class loop *lo
>        var = fold_convert (ctype, var);
>      }
>  
> -  ubase = unshare_expr (ubase);
> -  cbase = unshare_expr (cbase);
>    if (stmt_after_increment (loop, cand, at))
>      var = fold_build2 (MINUS_EXPR, TREE_TYPE (var), var,
>  		       unshare_expr (cstep));
> @@ -7648,6 +7646,7 @@ remove_unused_ivs (struct ivopts_data *d
>  	      if (!best_cand)
>  		continue;
>  
> +	      comp = unshare_expr (comp);
>  	      if (count > 1)
>  		{
>  		  tree vexpr = make_node (DEBUG_EXPR_DECL);
> --- gcc/testsuite/g++.dg/opt/pr92262.C.jj	2019-10-29 11:20:46.822901945 +0100
> +++ gcc/testsuite/g++.dg/opt/pr92262.C	2019-10-29 11:20:13.956410318 +0100
> @@ -0,0 +1,85 @@
> +// PR tree-optimization/92262
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-O2 -ftree-loop-distribution -g" }
> +
> +struct A;
> +struct B { template <typename T> using b = T *; };
> +template <typename, typename T> using c = B::b<T>;
> +void *operator new (__SIZE_TYPE__, void *p) { return p; }
> +struct C {
> +  template <typename T, typename... U> void
> +  foo (T *x, U... y) { new (x) T(y...); }
> +};
> +template <typename> class D : public C {};
> +template <typename> struct E;
> +template <typename T> struct E<D<T>> {
> +  using e = D<T>;
> +  template <typename U> using f = D<U>;
> +  template <typename U, typename... V>
> +  static void
> +  bar (e x, U y, V... z) { x.foo (y, z...); }
> +};
> +template <typename T> struct F : E<T> {
> +  template <typename U> struct G { typedef typename E<T>::template f<U> O; };
> +};
> +template <typename T, typename U, typename V> void
> +baz (T x, U y, V z)
> +{
> +  F<V>::bar (z, y, *x);
> +}
> +struct H {
> +  typedef c<int, A> I;
> +  typedef c<int, I> J;
> +  I i;
> +  J j;
> +  void qux (J x) { j = x; }
> +};
> +template <typename>
> +struct K {
> +  K(D<A> x) : k (x) {}
> +  typedef H::J L;
> +  struct M { L m; H n, o; };
> +  struct N : F<D<int>>::G<A>::O, M { N (F<D>::G<A>::O); };
> +  void quux ();
> +  N k;
> +};
> +template <typename T>
> +void
> +K<T>::quux ()
> +{
> +  L K (k.m - 1);
> +  k.n.qux (K);
> +}
> +template <typename, typename = int>
> +struct P : K<int> {
> +  template <typename T>
> +  P (T x, T, D<A> y = D<A> ()) : K (y) { corge (x); }
> +  template <typename T> void corge (T);
> +  typedef L L;
> +};
> +template <typename T, typename U>
> +template <typename V>
> +void P<T, U>::corge (V y)
> +{
> +  quux ();
> +  for (L x = k.n.j; x < k.o.j; ++x)
> +  {
> +    ++y;
> +    D<int> pv;
> +    baz (y, *x, pv);
> +  }
> +  D<int> z;
> +  baz (y, k.o.i, z);
> +}
> +struct A {
> +  A (int x) : a (x) {}
> +  int a;
> +};
> +int a[2]{};
> +
> +int
> +main ()
> +{
> +  P<int> (a, a);
> +  return 0;
> +}
> 
> 	Jakub
> 
>
diff mbox series

Patch

--- gcc/tree-ssa-loop-ivopts.c.jj	2019-10-23 14:35:42.994753407 +0200
+++ gcc/tree-ssa-loop-ivopts.c	2019-10-29 09:45:47.418217336 +0100
@@ -4152,8 +4152,6 @@  get_debug_computation_at (class loop *lo
       var = fold_convert (ctype, var);
     }
 
-  ubase = unshare_expr (ubase);
-  cbase = unshare_expr (cbase);
   if (stmt_after_increment (loop, cand, at))
     var = fold_build2 (MINUS_EXPR, TREE_TYPE (var), var,
 		       unshare_expr (cstep));
@@ -7648,6 +7646,7 @@  remove_unused_ivs (struct ivopts_data *d
 	      if (!best_cand)
 		continue;
 
+	      comp = unshare_expr (comp);
 	      if (count > 1)
 		{
 		  tree vexpr = make_node (DEBUG_EXPR_DECL);
--- gcc/testsuite/g++.dg/opt/pr92262.C.jj	2019-10-29 11:20:46.822901945 +0100
+++ gcc/testsuite/g++.dg/opt/pr92262.C	2019-10-29 11:20:13.956410318 +0100
@@ -0,0 +1,85 @@ 
+// PR tree-optimization/92262
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -ftree-loop-distribution -g" }
+
+struct A;
+struct B { template <typename T> using b = T *; };
+template <typename, typename T> using c = B::b<T>;
+void *operator new (__SIZE_TYPE__, void *p) { return p; }
+struct C {
+  template <typename T, typename... U> void
+  foo (T *x, U... y) { new (x) T(y...); }
+};
+template <typename> class D : public C {};
+template <typename> struct E;
+template <typename T> struct E<D<T>> {
+  using e = D<T>;
+  template <typename U> using f = D<U>;
+  template <typename U, typename... V>
+  static void
+  bar (e x, U y, V... z) { x.foo (y, z...); }
+};
+template <typename T> struct F : E<T> {
+  template <typename U> struct G { typedef typename E<T>::template f<U> O; };
+};
+template <typename T, typename U, typename V> void
+baz (T x, U y, V z)
+{
+  F<V>::bar (z, y, *x);
+}
+struct H {
+  typedef c<int, A> I;
+  typedef c<int, I> J;
+  I i;
+  J j;
+  void qux (J x) { j = x; }
+};
+template <typename>
+struct K {
+  K(D<A> x) : k (x) {}
+  typedef H::J L;
+  struct M { L m; H n, o; };
+  struct N : F<D<int>>::G<A>::O, M { N (F<D>::G<A>::O); };
+  void quux ();
+  N k;
+};
+template <typename T>
+void
+K<T>::quux ()
+{
+  L K (k.m - 1);
+  k.n.qux (K);
+}
+template <typename, typename = int>
+struct P : K<int> {
+  template <typename T>
+  P (T x, T, D<A> y = D<A> ()) : K (y) { corge (x); }
+  template <typename T> void corge (T);
+  typedef L L;
+};
+template <typename T, typename U>
+template <typename V>
+void P<T, U>::corge (V y)
+{
+  quux ();
+  for (L x = k.n.j; x < k.o.j; ++x)
+  {
+    ++y;
+    D<int> pv;
+    baz (y, *x, pv);
+  }
+  D<int> z;
+  baz (y, k.o.i, z);
+}
+struct A {
+  A (int x) : a (x) {}
+  int a;
+};
+int a[2]{};
+
+int
+main ()
+{
+  P<int> (a, a);
+  return 0;
+}