diff mbox

[C++] Reuse certain cxx_eval_constant_expression results in cxx_eval_vec_init_1 (PR c++/70001)

Message ID 20160310170351.GX3017@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek March 10, 2016, 5:03 p.m. UTC
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.


	Jakub

Comments

Jason Merrill March 10, 2016, 5:19 p.m. UTC | #1
OK.

Jason
Patrick Palka March 10, 2016, 5:34 p.m. UTC | #2
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.
Jakub Jelinek March 10, 2016, 5:37 p.m. UTC | #3
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
diff mbox

Patch

--- 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);
+}