From 2c430630da43fd1908fcb6c4b57d0a5221c86261 Mon Sep 17 00:00:00 2001
From: Roger Sayle <roger@eyesopen.com>
Date: Mon, 7 Jul 2003 18:54:28 +0000
Subject: [PATCH] re PR rtl-optimization/11059 (empty union optimization ice)

	PR optimization/11059
	* expr.c (can_store_by_pieces): Return true if length is zero.
	(store_by_pieces): If length is zero and endp is two, abort,
	othwerise, if length is zero and endp is not two, return "to".
	(clear_by_pieces): Do nothing if length is zero.
	(clear_storage): Do nothing if length is zero.
	(store_constructor): Simplify code when size is zero, or the
	target has already been cleared.  This avoids emitting a
	blockage instruction when initializing empty structures.

	* g++.dg/opt/emptyunion.C: New testcase.

From-SVN: r69049
---
 gcc/ChangeLog                         | 12 +++++++++
 gcc/expr.c                            | 35 +++++++++++++++++++--------
 gcc/testsuite/ChangeLog               |  5 ++++
 gcc/testsuite/g++.dg/opt/emptyunion.C | 13 ++++++++++
 4 files changed, 55 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/opt/emptyunion.C

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c214ee95d8d0..c5e3dfdb5f99 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2003-07-07  Roger Sayle  <roger@eyesopen.com>
+
+	PR optimization/11059
+	* expr.c (can_store_by_pieces): Return true if length is zero.
+	(store_by_pieces): If length is zero and endp is two, abort,
+	othwerise, if length is zero and endp is not two, return "to".
+	(clear_by_pieces): Do nothing if length is zero.
+	(clear_storage): Do nothing if length is zero.
+	(store_constructor): Simplify code when size is zero, or the
+	target has already been cleared.  This avoids emitting a
+	blockage instruction when initializing empty structures.
+
 2003-07-07  Andreas Jaeger  <aj@suse.de>
 
 	* mips-tfile.c: Convert prototypes to ISO C90.
diff --git a/gcc/expr.c b/gcc/expr.c
index c32925a6bb47..87ada15337e0 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -2669,6 +2669,9 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
   int reverse;
   rtx cst;
 
+  if (len == 0)
+    return 1;
+
   if (! STORE_BY_PIECES_P (len, align))
     return 0;
 
@@ -2744,6 +2747,13 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
 {
   struct store_by_pieces data;
 
+  if (len == 0)
+    {
+      if (endp == 2)
+	abort ();
+      return to;
+    }
+
   if (! STORE_BY_PIECES_P (len, align))
     abort ();
   to = protect_from_queue (to, 1);
@@ -2792,6 +2802,9 @@ clear_by_pieces (rtx to, unsigned HOST_WIDE_INT len, unsigned int align)
 {
   struct store_by_pieces data;
 
+  if (len == 0)
+    return;
+
   data.constfun = clear_by_pieces_1;
   data.constfundata = NULL;
   data.len = len;
@@ -2956,7 +2969,9 @@ clear_storage (rtx object, rtx size)
       object = protect_from_queue (object, 1);
       size = protect_from_queue (size, 0);
 
-      if (GET_CODE (size) == CONST_INT
+      if (GET_CODE (size) == CONST_INT && INTVAL (size) == 0)
+	;
+      else if (GET_CODE (size) == CONST_INT
 	  && CLEAR_BY_PIECES_P (INTVAL (size), align))
 	clear_by_pieces (object, INTVAL (size), align);
       else if (clear_storage_via_clrstr (object, size, align))
@@ -4892,11 +4907,13 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
     {
       tree elt;
 
+      /* If size is zero or the target is already cleared, do nothing.  */
+      if (size == 0 || cleared)
+	cleared = 1;
       /* We either clear the aggregate or indicate the value is dead.  */
-      if ((TREE_CODE (type) == UNION_TYPE
-	   || TREE_CODE (type) == QUAL_UNION_TYPE)
-	  && ! cleared
-	  && ! CONSTRUCTOR_ELTS (exp))
+      else if ((TREE_CODE (type) == UNION_TYPE
+		|| TREE_CODE (type) == QUAL_UNION_TYPE)
+	       && ! CONSTRUCTOR_ELTS (exp))
 	/* If the constructor is empty, clear the union.  */
 	{
 	  clear_storage (target, expr_size (exp));
@@ -4907,7 +4924,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 	 set the initial value as zero so we can fold the value into
 	 a constant.  But if more than one register is involved,
 	 this probably loses.  */
-      else if (! cleared && GET_CODE (target) == REG && TREE_STATIC (exp)
+      else if (GET_CODE (target) == REG && TREE_STATIC (exp)
 	       && GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
 	{
 	  emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
@@ -4919,10 +4936,8 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 	 clear the whole structure first.  Don't do this if TARGET is a
 	 register whose mode size isn't equal to SIZE since clear_storage
 	 can't handle this case.  */
-      else if (! cleared && size > 0
-	       && ((list_length (CONSTRUCTOR_ELTS (exp))
-		    != fields_length (type))
-		   || mostly_zeros_p (exp))
+      else if (((list_length (CONSTRUCTOR_ELTS (exp)) != fields_length (type))
+		|| mostly_zeros_p (exp))
 	       && (GET_CODE (target) != REG
 		   || ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
 		       == size)))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 683cb294952b..c81312a8ee2b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2003-07-07  Roger Sayle  <roger@eyesopen.com>
+
+	PR optimization/11059
+	* g++.dg/opt/emptyunion.C: New testcase.
+
 2003-07-07  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
             Eric Botcazou  <ebotcazou@libertysurf.fr>
 
diff --git a/gcc/testsuite/g++.dg/opt/emptyunion.C b/gcc/testsuite/g++.dg/opt/emptyunion.C
new file mode 100644
index 000000000000..105faed58440
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/emptyunion.C
@@ -0,0 +1,13 @@
+// PR optimization/11059
+// This testcase ICEd because clear_by_pieces was called with zero length.
+// { dg-do compile }
+// { dg-options "-O2" }
+
+union uni {};
+
+int main() {
+  uni *h;
+
+  h = (uni *)new uni();
+}
+
-- 
GitLab