While looking at another issue I noticed that in g++.dg/init/vbase1.C the Diamond(int) constructor was unnecessarily storing a CONSTRUCTOR into a stack temporary and then copying it into the SubB base subobject rather than directly storing the CONSTRUCTOR. It was doing this because the base subobject is smaller than a complete object of SubB, but we already know how to store a CONSTRUCTOR into a space smaller than it would normally take without needing to introduce an extra temporary. This patch fixes that.

Tested x86_64-pc-linux-gnu.  OK for trunk?
commit 3355a0973e15993812403c1cb2b122f010b1915b
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Oct 7 16:39:29 2015 -0400

    	* expr.c (store_field): Call store_constructor directly when
    	storing a CONSTRUCTOR into a target smaller than its type.

diff --git a/gcc/expr.c b/gcc/expr.c
index 6498a63..d82a10f 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6608,7 +6608,11 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
 	 operations.  */
       || (bitsize >= 0
 	  && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
-	  && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0)
+	  && compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0
+	  /* Except for initialization of full bytes from a CONSTRUCTOR, which
+	     we will handle specially below.  */
+	  && !(TREE_CODE (exp) == CONSTRUCTOR
+	       && bitsize % BITS_PER_UNIT == 0))
       /* If we are expanding a MEM_REF of a non-BLKmode non-addressable
          decl we must use bitfield operations.  */
       || (bitsize >= 0
@@ -6735,6 +6739,15 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
 	set_mem_alias_set (to_rtx, alias_set);
 
+      /* Above we avoided using bitfield operations for storing a CONSTRUCTOR
+	 into a target smaller than its type; handle that case now.  */
+      if (TREE_CODE (exp) == CONSTRUCTOR && bitsize >= 0)
+	{
+	  gcc_assert (bitsize % BITS_PER_UNIT == 0);
+	  store_constructor (exp, to_rtx, 0, bitsize/BITS_PER_UNIT);
+	  return to_rtx;
+	}
+
       return store_expr (exp, to_rtx, 0, nontemporal);
     }
 }
diff --git a/gcc/testsuite/g++.dg/init/vbase1.C b/gcc/testsuite/g++.dg/init/vbase1.C
index bbfd58f..bcd6b42 100644
--- a/gcc/testsuite/g++.dg/init/vbase1.C
+++ b/gcc/testsuite/g++.dg/init/vbase1.C
@@ -1,4 +1,5 @@
 // PR c++/50618
+// { dg-options "-fdump-rtl-expand" }
 // { dg-do run }
 
 struct Base
@@ -37,3 +38,8 @@ int main(int, char**)
     Diamond x(2);
     x.printText();
 }
+
+// Verify that the SubB() mem-initializer is storing 0 directly into
+// this->D.whatever rather than into a stack temp that is then copied into the
+// base field.
+// { dg-final { scan-rtl-dump "set \[^\n\]*\n\[^\n\]*this\[^\n\]*\n\[^\n\]*const_int 0" "expand" } }

Reply via email to