summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2003-07-07 18:54:28 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2003-07-07 18:54:28 +0000
commit2c430630da43fd1908fcb6c4b57d0a5221c86261 (patch)
tree6db930741a1591471ed698ee5312a1c604315210
parentcf633f5be8e81fa2314c0cdf74476dc5823e5df2 (diff)
downloadgcc-2c430630da43fd1908fcb6c4b57d0a5221c86261.tar.gz
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
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/expr.c35
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/opt/emptyunion.C13
4 files changed, 55 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c214ee95d8d..c5e3dfdb5f9 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 c32925a6bb4..87ada15337e 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 683cb294952..c81312a8ee2 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 00000000000..105faed5844
--- /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();
+}
+