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