Message ID | 20160310170351.GX3017@tucnak.redhat.com |
---|---|
State | New |
Headers | show |
OK. Jason
On Thu, Mar 10, 2016 at 12:03 PM, Jakub Jelinek <jakub@redhat.com> wrote: > Hi! > > As mentioned in the PR, the compile time and compile memory are wasted > if a large array is is using value or default initialization, and > if the resulting initializer value is simple enough, we can just share > it by all the elements. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2016-03-10 Patrick Palka <ppalka@gcc.gnu.org> > Jakub Jelinek <jakub@redhat.com> > > PR c++/70001 > * constexpr.c (cxx_eval_vec_init_1): For pre_init case, reuse > return value from cxx_eval_constant_expression from earlier > elements if it is valid constant initializer requiring no > relocations. > > * g++.dg/cpp0x/constexpr-70001-1.C: New test. > * g++.dg/cpp0x/constexpr-70001-2.C: New test. > * g++.dg/cpp0x/constexpr-70001-3.C: New test. > > --- gcc/cp/constexpr.c.jj 2016-03-08 21:04:43.050564671 +0100 > +++ gcc/cp/constexpr.c 2016-03-10 12:52:04.016852313 +0100 > @@ -2340,6 +2340,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx > vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor); > vec_alloc (*p, max + 1); > bool pre_init = false; > + tree pre_init_elt = NULL_TREE; > unsigned HOST_WIDE_INT i; > > /* For the default constructor, build up a call to the default > @@ -2389,9 +2390,18 @@ cxx_eval_vec_init_1 (const constexpr_ctx > { > /* Initializing an element using value or default initialization > we just pre-built above. */ > - eltinit = (cxx_eval_constant_expression > - (&new_ctx, init, > - lval, non_constant_p, overflow_p)); > + if (pre_init_elt == NULL_TREE) > + pre_init_elt > + = cxx_eval_constant_expression (&new_ctx, init, lval, > + non_constant_p, overflow_p); > + eltinit = pre_init_elt; > + /* Don't reuse the result of cxx_eval_constant_expression > + call if it isn't a constant initializer or if it requires > + relocations. */ > + if (initializer_constant_valid_p (pre_init_elt, > + TREE_TYPE (pre_init_elt)) > + != null_pointer_node) > + pre_init_elt = NULL_TREE; Doesn't this mean that we call initializer_constant_valid_p at each iteration? This would slow down the non-constant case even further. So I wonder if the return value of initializer_constant_valid_p could be cached or something, since it seems like a potentially expensive predicate.
On Thu, Mar 10, 2016 at 12:34:40PM -0500, Patrick Palka wrote: > Doesn't this mean that we call initializer_constant_valid_p at each > iteration? This would slow down the non-constant case even further. > So I wonder if the return value of initializer_constant_valid_p could > be cached or something, since it seems like a potentially expensive > predicate. You're right, but I've already committed the patch. I'll write an incremental patch and test it. Jakub
--- gcc/cp/constexpr.c.jj 2016-03-08 21:04:43.050564671 +0100 +++ gcc/cp/constexpr.c 2016-03-10 12:52:04.016852313 +0100 @@ -2340,6 +2340,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor); vec_alloc (*p, max + 1); bool pre_init = false; + tree pre_init_elt = NULL_TREE; unsigned HOST_WIDE_INT i; /* For the default constructor, build up a call to the default @@ -2389,9 +2390,18 @@ cxx_eval_vec_init_1 (const constexpr_ctx { /* Initializing an element using value or default initialization we just pre-built above. */ - eltinit = (cxx_eval_constant_expression - (&new_ctx, init, - lval, non_constant_p, overflow_p)); + if (pre_init_elt == NULL_TREE) + pre_init_elt + = cxx_eval_constant_expression (&new_ctx, init, lval, + non_constant_p, overflow_p); + eltinit = pre_init_elt; + /* Don't reuse the result of cxx_eval_constant_expression + call if it isn't a constant initializer or if it requires + relocations. */ + if (initializer_constant_valid_p (pre_init_elt, + TREE_TYPE (pre_init_elt)) + != null_pointer_node) + pre_init_elt = NULL_TREE; } else { --- gcc/testsuite/g++.dg/cpp0x/constexpr-70001-1.C.jj 2016-03-10 13:08:58.732932160 +0100 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-70001-1.C 2016-03-10 13:05:53.000000000 +0100 @@ -0,0 +1,13 @@ +// PR c++/70001 +// { dg-do compile { target c++11 } } + +struct B +{ + int a; + constexpr B () : a (0) { } +}; + +struct A +{ + B b[1 << 19]; +} c; --- gcc/testsuite/g++.dg/cpp0x/constexpr-70001-2.C.jj 2016-03-10 13:09:01.866889167 +0100 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-70001-2.C 2016-03-10 13:07:27.000000000 +0100 @@ -0,0 +1,19 @@ +// PR c++/70001 +// { dg-do run { target c++11 } } + +struct B +{ + struct B *a; + constexpr B () : a (this) { } +}; + +constexpr int N = 1 << 4; +struct A { B c[N]; } d; + +int +main () +{ + for (int i = 0; i < N; ++i) + if (d.c[i].a != &d.c[i]) + __builtin_abort (); +} --- gcc/testsuite/g++.dg/cpp0x/constexpr-70001-3.C.jj 2016-03-10 13:09:04.700850290 +0100 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-70001-3.C 2016-03-10 13:09:53.199184977 +0100 @@ -0,0 +1,26 @@ +// PR c++/70001 +// { dg-do compile { target c++11 } } + +#include <array> +#include <complex> + +typedef std::complex<double> cd; + +const int LOG = 17; +const int N = (1 << LOG); + +std::array<cd, N> a; +std::array<cd, N> b; + +void +foo (std::array<cd, N> &arr) +{ + std::array<std::array<cd, N>, LOG + 1> f; +} + +int +main () +{ + foo (a); + foo (b); +}