Hi!

Jason's recent patch to turn reference vars initialized with invariant
addresses broke the first testcase below, because &self->singleton
is considered TREE_CONSTANT (because self is TREE_CONSTANT VAR_DECL and
singleton field has constant offset), but after going into SSA form
it is not supposed to be TREE_CONSTANT anymore (&self_2->singleton),
because SSA_NAMEs don't have TREE_CONSTANT set on them.

The following patch fixes it by gimplifying such vars into their
DECL_INITIAL unless in OpenMP regions, where such folding is deferred
until omplower pass finishes.

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

2016-11-16  Jakub Jelinek  <ja...@redhat.com>

        PR c++/78373
        * gimplify.c (gimplify_decl_expr): For TREE_CONSTANT reference
        vars with is_gimple_min_invariant initializer after stripping
        useless conversions keep non-NULL DECL_INITIAL.
        (gimplify_var_or_parm_decl): Add fallback argument.  Gimplify
        TREE_CONSTANT reference vars with is_gimple_min_invariant initializer
        outside of OpenMP contexts to the initializer if fb_rvalue is
        allowed.
        (gimplify_compound_lval, gimplify_expr): Pass through fallback
        argument to gimplify_var_or_parm_decl.
        * omp-low.c (lower_omp_regimplify_p): Return non-zero for
        TREE_CONSTANT reference vars with is_gimple_min_invariant
        initializer.

        * g++.dg/opt/pr78373.C: New test.
        * g++.dg/gomp/pr78373.C: New test.

--- gcc/gimplify.c.jj   2016-11-10 12:34:12.000000000 +0100
+++ gcc/gimplify.c      2016-11-16 16:15:13.496510476 +0100
@@ -1645,10 +1645,23 @@ gimplify_decl_expr (tree *stmt_p, gimple
        {
          if (!TREE_STATIC (decl))
            {
+             tree new_init = NULL_TREE;
+             if (TREE_CONSTANT (decl)
+                 && TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
+               {
+                 new_init = init;
+                 STRIP_USELESS_TYPE_CONVERSION (new_init);
+                 if (is_gimple_min_invariant (new_init))
+                   new_init = unshare_expr (new_init);
+                 else
+                   new_init = NULL_TREE;
+               }
              DECL_INITIAL (decl) = NULL_TREE;
              init = build2 (INIT_EXPR, void_type_node, decl, init);
              gimplify_and_add (init, seq_p);
              ggc_free (init);
+             if (new_init && DECL_INITIAL (decl) == NULL_TREE)
+               DECL_INITIAL (decl) = new_init;
            }
          else
            /* We must still examine initializers for static variables
@@ -2546,7 +2559,7 @@ static tree nonlocal_vla_vars;
    DECL_VALUE_EXPR, and it's worth re-examining things.  */
 
 static enum gimplify_status
-gimplify_var_or_parm_decl (tree *expr_p)
+gimplify_var_or_parm_decl (tree *expr_p, fallback_t fallback)
 {
   tree decl = *expr_p;
 
@@ -2607,6 +2620,29 @@ gimplify_var_or_parm_decl (tree *expr_p)
       return GS_OK;
     }
 
+  /* Gimplify TREE_CONSTANT C++ reference vars as their DECL_INITIAL.  */
+  if (VAR_P (decl)
+      && TREE_CONSTANT (decl)
+      && TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+      && DECL_INITIAL (decl)
+      && (fallback & fb_rvalue) != 0
+      && is_gimple_min_invariant (DECL_INITIAL (decl)))
+    {
+      if (gimplify_omp_ctxp)
+       {
+         /* Don't do this in OpenMP regions, see e.g. libgomp.c++/target-14.C
+            testcase.  We'll do that in the omplower pass later instead.  */
+         if ((gimplify_omp_ctxp->region_type != ORT_TARGET
+              || gimplify_omp_ctxp->outer_context != NULL
+              || !lookup_attribute ("omp declare target",
+                                    DECL_ATTRIBUTES (cfun->decl)))
+             && gimplify_omp_ctxp->region_type != ORT_NONE)
+           return GS_ALL_DONE;
+       }
+      *expr_p = unshare_expr (DECL_INITIAL (decl));
+      return GS_OK;
+    }
+
   return GS_ALL_DONE;
 }
 
@@ -2712,7 +2748,7 @@ gimplify_compound_lval (tree *expr_p, gi
       /* Expand DECL_VALUE_EXPR now.  In some cases that may expose
         additional COMPONENT_REFs.  */
       else if ((VAR_P (*p) || TREE_CODE (*p) == PARM_DECL)
-              && gimplify_var_or_parm_decl (p) == GS_OK)
+              && gimplify_var_or_parm_decl (p, fallback) == GS_OK)
        goto restart;
       else
        break;
@@ -11624,7 +11660,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 
        case VAR_DECL:
        case PARM_DECL:
-         ret = gimplify_var_or_parm_decl (expr_p);
+         ret = gimplify_var_or_parm_decl (expr_p, fallback);
          break;
 
        case RESULT_DECL:
--- gcc/omp-low.c.jj    2016-11-16 09:23:46.000000000 +0100
+++ gcc/omp-low.c       2016-11-16 15:44:35.071617469 +0100
@@ -16963,6 +16963,14 @@ lower_omp_regimplify_p (tree *tp, int *w
       && bitmap_bit_p (task_shared_vars, DECL_UID (t)))
     return t;
 
+  /* And C++ references with TREE_CONSTANT set too.  */
+  if (VAR_P (t)
+      && TREE_CONSTANT (t)
+      && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
+      && DECL_INITIAL (t)
+      && is_gimple_min_invariant (DECL_INITIAL (t)))
+    return t;
+
   /* If a global variable has been privatized, TREE_CONSTANT on
      ADDR_EXPR might be wrong.  */
   if (data == NULL && TREE_CODE (t) == ADDR_EXPR)
--- gcc/testsuite/g++.dg/opt/pr78373.C.jj       2016-11-16 16:26:14.706204090 
+0100
+++ gcc/testsuite/g++.dg/opt/pr78373.C  2016-11-16 16:25:46.000000000 +0100
@@ -0,0 +1,22 @@
+// PR c++/78373
+// { dg-do compile { target c++11 } }
+
+struct A {
+  static A singleton;
+};
+struct B {
+  void m_fn2();
+  virtual int m_fn1();
+};
+struct D : B {
+  static int m_fn3(int, int, int, A) {
+    D &self = singleton;
+    self.m_fn2();
+  }
+  static D singleton;
+};
+template <typename, typename> struct C { bool m_fn4() const; };
+template <typename Base, typename Traits> bool C<Base, Traits>::m_fn4() const {
+  Traits::m_fn3(0, 0, 0, Base::singleton);
+}
+template struct C<A, D>;
--- gcc/testsuite/g++.dg/gomp/pr78373.C.jj      2016-11-16 16:26:39.971886570 
+0100
+++ gcc/testsuite/g++.dg/gomp/pr78373.C 2016-11-16 16:27:16.506427431 +0100
@@ -0,0 +1,53 @@
+// PR c++/78373
+// { dg-do compile }
+
+void fn ();
+
+const int a = 5;
+int c = 6;
+
+void
+foo (void)
+{
+  const int &b = a;
+  int &d = c;
+  fn ();
+  d += b;
+  fn ();
+  d += b;
+}
+
+void
+bar (void)
+{
+  #pragma omp parallel
+  {
+    const int &b = a;
+    int &d = c;
+    fn ();
+    d += b;
+    fn ();
+    d += b;
+  }
+}
+
+void
+baz (void)
+{
+  const int &b = a;
+  int &d = c;
+  #pragma omp parallel firstprivate (b, d)
+  {
+    fn ();
+    d += b;
+    fn ();
+    d += b;
+  }
+  #pragma omp parallel shared (b, d)
+  {
+    fn ();
+    d += b;
+    fn ();
+    d += b;
+  }
+}

        Jakub

Reply via email to