From 26d44ae2fd4b65d6e256a3c4a0800b9ebd52f6ff Mon Sep 17 00:00:00 2001
From: Richard Henderson <rth@redhat.com>
Date: Tue, 29 Jun 2004 17:38:18 -0700
Subject: [PATCH] gimplify.c (gimplify_modify_expr_rhs): Move immediately
 before gimplify_modify_expr.

        * gimplify.c (gimplify_modify_expr_rhs): Move immediately before
        gimplify_modify_expr.
        (gimplify_init_constructor): Likewise.  Gimplify the null
        CONSTRUCTOR assignment.
        (gimplify_modify_expr_to_memcpy): New.
        (gimplify_modify_expr_to_memset): New.
        (gimplify_modify_expr): Use them.

From-SVN: r83888
---
 gcc/ChangeLog  |   10 +
 gcc/gimplify.c | 1163 +++++++++++++++++++++++++-----------------------
 2 files changed, 620 insertions(+), 553 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2851a5d929f7..441759fc88fe 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2004-06-29  Richard Henderson  <rth@redhat.com>
+
+	* gimplify.c (gimplify_modify_expr_rhs): Move immediately before
+	gimplify_modify_expr.
+	(gimplify_init_constructor): Likewise.  Gimplify the null
+	CONSTRUCTOR assignment.
+	(gimplify_modify_expr_to_memcpy): New.
+	(gimplify_modify_expr_to_memset): New.
+	(gimplify_modify_expr): Use them.
+
 2004-06-29  Roman Zippel <zippel@linux-m68k.org>
 
 	* web.c (union_defs): use all defs of an instruction to create a
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 7ef88b565b30..c596ad90428b 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1323,414 +1323,137 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
   return NULL_TREE;
 }
 
-/* Break out elements of a constructor used as an initializer into separate
-   MODIFY_EXPRs.
+/* *EXPR_P is a COMPONENT_REF being used as an rvalue.  If its type is
+   different from its canonical type, wrap the whole thing inside a
+   NOP_EXPR and force the type of the COMPONENT_REF to be the canonical
+   type.
 
-   Note that we still need to clear any elements that don't have explicit
-   initializers, so if not all elements are initialized we keep the
-   original MODIFY_EXPR, we just remove all of the constructor elements.  */
+   The canonical type of a COMPONENT_REF is the type of the field being
+   referenced--unless the field is a bit-field which can be read directly
+   in a smaller mode, in which case the canonical type is the
+   sign-appropriate type corresponding to that mode.  */
 
-static enum gimplify_status
-gimplify_init_constructor (tree *expr_p, tree *pre_p,
-			   tree *post_p, bool want_value)
+static void
+canonicalize_component_ref (tree *expr_p)
 {
-  tree object = TREE_OPERAND (*expr_p, 0);
-  tree ctor = TREE_OPERAND (*expr_p, 1);
-  tree type = TREE_TYPE (ctor);
-  enum gimplify_status ret;
-  tree elt_list;
+  tree expr = *expr_p;
+  tree type;
 
-  if (TREE_CODE (ctor) != CONSTRUCTOR)
-    return GS_UNHANDLED;
+  if (TREE_CODE (expr) != COMPONENT_REF)
+    abort ();
 
-  elt_list = CONSTRUCTOR_ELTS (ctor);
+  if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+    type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
+  else
+    type = TREE_TYPE (TREE_OPERAND (expr, 1));
 
-  ret = GS_ALL_DONE;
-  switch (TREE_CODE (type))
+  if (TREE_TYPE (expr) != type)
     {
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-    case ARRAY_TYPE:
-      {
-	HOST_WIDE_INT i, num_elements, num_nonzero_elements;
-	HOST_WIDE_INT num_nonconstant_elements;
-	bool cleared;
+      tree old_type = TREE_TYPE (expr);
 
-	/* Aggregate types must lower constructors to initialization of
-	   individual elements.  The exception is that a CONSTRUCTOR node
-	   with no elements indicates zero-initialization of the whole.  */
-	if (elt_list == NULL)
-	  {
-	    if (want_value)
-	      {
-		*expr_p = object;
-		return GS_OK;
-	      }
-	    else
-	      return GS_UNHANDLED;
-	  }
+      /* Set the type of the COMPONENT_REF to the underlying type.  */
+      TREE_TYPE (expr) = type;
 
-	categorize_ctor_elements (ctor, &num_nonzero_elements,
-				  &num_nonconstant_elements);
-	num_elements = count_type_elements (TREE_TYPE (ctor));
+      /* And wrap the whole thing inside a NOP_EXPR.  */
+      expr = build1 (NOP_EXPR, old_type, expr);
 
-	/* If a const aggregate variable is being initialized, then it
-	   should never be a lose to promote the variable to be static.  */
-	if (num_nonconstant_elements == 0
-	    && TREE_READONLY (object)
-	    && TREE_CODE (object) == VAR_DECL)
-	  {
-	    DECL_INITIAL (object) = ctor;
-	    TREE_STATIC (object) = 1;
-	    if (!DECL_NAME (object))
-	      DECL_NAME (object) = create_tmp_var_name ("C");
-	    walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL);
+      *expr_p = expr;
+    }
+}
 
-	    /* ??? C++ doesn't automatically append a .<number> to the
-	       assembler name, and even when it does, it looks a FE private
-	       data structures to figure out what that number should be,
-	       which are not set for this variable.  I suppose this is
-	       important for local statics for inline functions, which aren't
-	       "local" in the object file sense.  So in order to get a unique
-	       TU-local symbol, we must invoke the lhd version now.  */
-	    lhd_set_decl_assembler_name (object);
+/* If a NOP conversion is changing a pointer to array of foo to a pointer
+   to foo, embed that change in the ADDR_EXPR by converting 
+      T array[U];
+      (T *)&array
+   ==>
+      &array[L]
+   where L is the lower bound.  For simplicity, only do this for constant
+   lower bound.  */
 
-	    *expr_p = NULL_TREE;
-	    break;
-	  }
+static void
+canonicalize_addr_expr (tree *expr_p)
+{
+  tree expr = *expr_p;
+  tree ctype = TREE_TYPE (expr);
+  tree addr_expr = TREE_OPERAND (expr, 0);
+  tree atype = TREE_TYPE (addr_expr);
+  tree dctype, datype, ddatype, otype, obj_expr;
 
-	/* If there are "lots" of initialized elements, and all of them
-	   are valid address constants, then the entire initializer can
-	   be dropped to memory, and then memcpy'd out.  */
-	if (num_nonconstant_elements == 0)
-	  {
-	    HOST_WIDE_INT size = int_size_in_bytes (type);
-	    unsigned int align;
+  /* Both cast and addr_expr types should be pointers.  */
+  if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
+    return;
 
-	    /* ??? We can still get unbounded array types, at least
-	       from the C++ front end.  This seems wrong, but attempt
-	       to work around it for now.  */
-	    if (size < 0)
-	      {
-		size = int_size_in_bytes (TREE_TYPE (object));
-		if (size >= 0)
-		  TREE_TYPE (ctor) = type = TREE_TYPE (object);
-	      }
+  /* The addr_expr type should be a pointer to an array.  */
+  datype = TREE_TYPE (atype);
+  if (TREE_CODE (datype) != ARRAY_TYPE)
+    return;
 
-	    /* Find the maximum alignment we can assume for the object.  */
-	    /* ??? Make use of DECL_OFFSET_ALIGN.  */
-	    if (DECL_P (object))
-	      align = DECL_ALIGN (object);
-	    else
-	      align = TYPE_ALIGN (type);
+  /* Both cast and addr_expr types should address the same object type.  */
+  dctype = TREE_TYPE (ctype);
+  ddatype = TREE_TYPE (datype);
+  if (!lang_hooks.types_compatible_p (ddatype, dctype))
+    return;
 
-	    if (size > 0 && !can_move_by_pieces (size, align))
-	      {
-		tree new = create_tmp_var_raw (type, "C");
-		gimple_add_tmp_var (new);
-		TREE_STATIC (new) = 1;
-		TREE_READONLY (new) = 1;
-		DECL_INITIAL (new) = ctor;
-		if (align > DECL_ALIGN (new))
-		  {
-		    DECL_ALIGN (new) = align;
-		    DECL_USER_ALIGN (new) = 1;
-		  }
-	        walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
+  /* The addr_expr and the object type should match.  */
+  obj_expr = TREE_OPERAND (addr_expr, 0);
+  otype = TREE_TYPE (obj_expr);
+  if (!lang_hooks.types_compatible_p (otype, datype))
+    return;
 
-		TREE_OPERAND (*expr_p, 1) = new;
-		break;
-	      }
-	  }
+  /* The lower bound and element sizes must be constant.  */
+  if (TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
+      || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
+      || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
+    return;
 
-	/* If there are "lots" of initialized elements, even discounting
-	   those that are not address constants (and thus *must* be 
-	   computed at runtime), then partition the constructor into
-	   constant and non-constant parts.  Block copy the constant
-	   parts in, then generate code for the non-constant parts.  */
-	/* TODO.  There's code in cp/typeck.c to do this.  */
+  /* All checks succeeded.  Build a new node to merge the cast.  */
+  *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
+		    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+		    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+		    size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
+				size_int (TYPE_ALIGN (dctype)
+					  / BITS_PER_UNIT)));
+  *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
+}
 
-	/* If there are "lots" of zeros, then block clear the object first.  */
-	cleared = false;
-	if (num_elements - num_nonzero_elements > CLEAR_RATIO
-	    && num_nonzero_elements < num_elements/4)
-	  cleared = true;
+/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
+   underneath as appropriate.  */
 
-	/* ??? This bit ought not be needed.  For any element not present
-	   in the initializer, we should simply set them to zero.  Except
-	   we'd need to *find* the elements that are not present, and that
-	   requires trickery to avoid quadratic compile-time behavior in
-	   large cases or excessive memory use in small cases.  */
-	else
-	  {
-	    HOST_WIDE_INT len = list_length (elt_list);
-	    if (TREE_CODE (type) == ARRAY_TYPE)
-	      {
-		tree nelts = array_type_nelts (type);
-		if (!host_integerp (nelts, 1)
-		    || tree_low_cst (nelts, 1) != len)
-		  cleared = 1;;
-	      }
-	    else if (len != fields_length (type))
-	      cleared = 1;
-	  }
+static enum gimplify_status
+gimplify_conversion (tree *expr_p)
+{  
+  /* Strip away as many useless type conversions as possible
+     at the toplevel.  */
+  STRIP_USELESS_TYPE_CONVERSION (*expr_p);
 
-	if (cleared)
-	  {
-	    CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
-	    append_to_statement_list (*expr_p, pre_p);
-	  }
+  /* If we still have a conversion at the toplevel, then strip
+     away all but the outermost conversion.  */
+  if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
+    {
+      STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));
 
-	for (i = 0; elt_list; i++, elt_list = TREE_CHAIN (elt_list))
-	  {
-	    tree purpose, value, cref, init;
+      /* And remove the outermost conversion if it's useless.  */
+      if (tree_ssa_useless_type_conversion (*expr_p))
+	*expr_p = TREE_OPERAND (*expr_p, 0);
+    }
 
-	    purpose = TREE_PURPOSE (elt_list);
-	    value = TREE_VALUE (elt_list);
+  /* If we still have a conversion at the toplevel,
+     then canonicalize some constructs.  */
+  if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
+    {
+      tree sub = TREE_OPERAND (*expr_p, 0);
 
-	    if (cleared && initializer_zerop (value))
-	      continue;
+      /* If a NOP conversion is changing the type of a COMPONENT_REF
+	 expression, then canonicalize its type now in order to expose more
+	 redundant conversions.  */
+      if (TREE_CODE (sub) == COMPONENT_REF)
+	canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0));
 
-	    if (TREE_CODE (type) == ARRAY_TYPE)
-	      {
-		tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
-
-		/* ??? Here's to hoping the front end fills in all of the
-		   indicies, so we don't have to figure out what's missing
-		   ourselves.  */
-		if (!purpose)
-		  abort ();
-		/* ??? Need to handle this.  */
-		if (TREE_CODE (purpose) == RANGE_EXPR)
-		  abort ();
-
-		cref = build (ARRAY_REF, t, object, purpose, NULL_TREE, NULL_TREE);
-	      }
-	    else
-	      cref = build (COMPONENT_REF, TREE_TYPE (purpose), object,
-			    purpose, NULL_TREE);
-
-	    init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
-
-	    /* Each member initialization is a full-expression.  */
-	    gimplify_and_add (init, pre_p);
-	  }
-
-	*expr_p = NULL_TREE;
-      }
-      break;
-
-    case COMPLEX_TYPE:
-      {
-	tree r, i;
-
-	/* Extract the real and imaginary parts out of the ctor.  */
-	r = i = NULL_TREE;
-	if (elt_list)
-	  {
-	    r = TREE_VALUE (elt_list);
-	    elt_list = TREE_CHAIN (elt_list);
-	    if (elt_list)
-	      {
-		i = TREE_VALUE (elt_list);
-		if (TREE_CHAIN (elt_list))
-		  abort ();
-	      }
-	  }
-	if (r == NULL || i == NULL)
-	  {
-	    tree zero = convert (TREE_TYPE (type), integer_zero_node);
-	    if (r == NULL)
-	      r = zero;
-	    if (i == NULL)
-	      i = zero;
-	  }
-
-	/* Complex types have either COMPLEX_CST or COMPLEX_EXPR to
-	   represent creation of a complex value.  */
-	if (TREE_CONSTANT (r) && TREE_CONSTANT (i))
-	  {
-	    ctor = build_complex (type, r, i);
-	    TREE_OPERAND (*expr_p, 1) = ctor;
-	  }
-	else
-	  {
-	    ctor = build (COMPLEX_EXPR, type, r, i);
-	    TREE_OPERAND (*expr_p, 1) = ctor;
-	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
-				 is_gimple_rhs, fb_rvalue);
-	  }
-      }
-      break;
-
-    case VECTOR_TYPE:
-      /* Go ahead and simplify constant constructors to VECTOR_CST.  */
-      if (TREE_CONSTANT (ctor))
-	TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
-      else
-	{
-	  /* Vector types use CONSTRUCTOR all the way through gimple
-	     compilation as a general initializer.  */
-	  for (; elt_list; elt_list = TREE_CHAIN (elt_list))
-	    {
-	      enum gimplify_status tret;
-	      tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
-				    is_gimple_constructor_elt, fb_rvalue);
-	      if (tret == GS_ERROR)
-		ret = GS_ERROR;
-	    }
-	}
-      break;
-
-    default:
-      /* So how did we get a CONSTRUCTOR for a scalar type?  */
-      abort ();
-    }
-
-  if (ret == GS_ERROR)
-    return GS_ERROR;
-  else if (want_value)
-    {
-      append_to_statement_list (*expr_p, pre_p);
-      *expr_p = object;
-      return GS_OK;
-    }
-  else
-    return GS_ALL_DONE;
-}
-
-/* *EXPR_P is a COMPONENT_REF being used as an rvalue.  If its type is
-   different from its canonical type, wrap the whole thing inside a
-   NOP_EXPR and force the type of the COMPONENT_REF to be the canonical
-   type.
-
-   The canonical type of a COMPONENT_REF is the type of the field being
-   referenced--unless the field is a bit-field which can be read directly
-   in a smaller mode, in which case the canonical type is the
-   sign-appropriate type corresponding to that mode.  */
-
-static void
-canonicalize_component_ref (tree *expr_p)
-{
-  tree expr = *expr_p;
-  tree type;
-
-  if (TREE_CODE (expr) != COMPONENT_REF)
-    abort ();
-
-  if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
-    type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
-  else
-    type = TREE_TYPE (TREE_OPERAND (expr, 1));
-
-  if (TREE_TYPE (expr) != type)
-    {
-      tree old_type = TREE_TYPE (expr);
-
-      /* Set the type of the COMPONENT_REF to the underlying type.  */
-      TREE_TYPE (expr) = type;
-
-      /* And wrap the whole thing inside a NOP_EXPR.  */
-      expr = build1 (NOP_EXPR, old_type, expr);
-
-      *expr_p = expr;
-    }
-}
-
-/* If a NOP conversion is changing a pointer to array of foo to a pointer
-   to foo, embed that change in the ADDR_EXPR by converting 
-      T array[U];
-      (T *)&array
-   ==>
-      &array[L]
-   where L is the lower bound.  For simplicity, only do this for constant
-   lower bound.  */
-
-static void
-canonicalize_addr_expr (tree *expr_p)
-{
-  tree expr = *expr_p;
-  tree ctype = TREE_TYPE (expr);
-  tree addr_expr = TREE_OPERAND (expr, 0);
-  tree atype = TREE_TYPE (addr_expr);
-  tree dctype, datype, ddatype, otype, obj_expr;
-
-  /* Both cast and addr_expr types should be pointers.  */
-  if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
-    return;
-
-  /* The addr_expr type should be a pointer to an array.  */
-  datype = TREE_TYPE (atype);
-  if (TREE_CODE (datype) != ARRAY_TYPE)
-    return;
-
-  /* Both cast and addr_expr types should address the same object type.  */
-  dctype = TREE_TYPE (ctype);
-  ddatype = TREE_TYPE (datype);
-  if (!lang_hooks.types_compatible_p (ddatype, dctype))
-    return;
-
-  /* The addr_expr and the object type should match.  */
-  obj_expr = TREE_OPERAND (addr_expr, 0);
-  otype = TREE_TYPE (obj_expr);
-  if (!lang_hooks.types_compatible_p (otype, datype))
-    return;
-
-  /* The lower bound and element sizes must be constant.  */
-  if (TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
-      || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
-      || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
-    return;
-
-  /* All checks succeeded.  Build a new node to merge the cast.  */
-  *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
-		    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
-		    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
-		    size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
-				size_int (TYPE_ALIGN (dctype)
-					  / BITS_PER_UNIT)));
-  *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
-}
-
-/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
-   underneath as appropriate.  */
-
-static enum gimplify_status
-gimplify_conversion (tree *expr_p)
-{  
-  /* Strip away as many useless type conversions as possible
-     at the toplevel.  */
-  STRIP_USELESS_TYPE_CONVERSION (*expr_p);
-
-  /* If we still have a conversion at the toplevel, then strip
-     away all but the outermost conversion.  */
-  if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
-    {
-      STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));
-
-      /* And remove the outermost conversion if it's useless.  */
-      if (tree_ssa_useless_type_conversion (*expr_p))
-	*expr_p = TREE_OPERAND (*expr_p, 0);
-    }
-
-  /* If we still have a conversion at the toplevel,
-     then canonicalize some constructs.  */
-  if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
-    {
-      tree sub = TREE_OPERAND (*expr_p, 0);
-
-      /* If a NOP conversion is changing the type of a COMPONENT_REF
-	 expression, then canonicalize its type now in order to expose more
-	 redundant conversions.  */
-      if (TREE_CODE (sub) == COMPONENT_REF)
-	canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0));
-
-      /* If a NOP conversion is changing a pointer to array of foo
-	 to a pointer to foo, embed that change in the ADDR_EXPR.  */
-      else if (TREE_CODE (sub) == ADDR_EXPR)
-	canonicalize_addr_expr (expr_p);
-    }
+      /* If a NOP conversion is changing a pointer to array of foo
+	 to a pointer to foo, embed that change in the ADDR_EXPR.  */
+      else if (TREE_CODE (sub) == ADDR_EXPR)
+	canonicalize_addr_expr (expr_p);
+    }
 
   return GS_OK;
 }
@@ -2490,107 +2213,526 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
   tree tmp, type;
   enum gimplify_status ret;
 
-  type = TREE_TYPE (expr);
-  if (!type)
-    TREE_TYPE (expr) = void_type_node;
+  type = TREE_TYPE (expr);
+  if (!type)
+    TREE_TYPE (expr) = void_type_node;
+
+  /* If this COND_EXPR has a value, copy the values into a temporary within
+     the arms.  */
+  else if (! VOID_TYPE_P (type))
+    {
+      if (target)
+	{
+	  tmp = target;
+	  ret = GS_OK;
+	}
+      else
+	{
+	  tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+	  ret = GS_ALL_DONE;
+	}
+
+      /* Build the then clause, 't1 = a;'.  But don't build an assignment
+	 if this branch is void; in C++ it can be, if it's a throw.  */
+      if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
+	TREE_OPERAND (expr, 1)
+	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
+
+      /* Build the else clause, 't1 = b;'.  */
+      if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
+	TREE_OPERAND (expr, 2)
+	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2));
+
+      TREE_TYPE (expr) = void_type_node;
+      recalculate_side_effects (expr);
+
+      /* Move the COND_EXPR to the prequeue and use the temp in its place.  */
+      gimplify_and_add (expr, pre_p);
+      *expr_p = tmp;
+
+      return ret;
+    }
+
+  /* Make sure the condition has BOOLEAN_TYPE.  */
+  TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+
+  /* Break apart && and || conditions.  */
+  if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
+      || TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
+    {
+      expr = shortcut_cond_expr (expr);
+
+      if (expr != *expr_p)
+	{
+	  *expr_p = expr;
+
+	  /* We can't rely on gimplify_expr to re-gimplify the expanded
+	     form properly, as cleanups might cause the target labels to be
+	     wrapped in a TRY_FINALLY_EXPR.  To prevent that, we need to
+	     set up a conditional context.  */
+	  gimple_push_condition ();
+	  gimplify_stmt (expr_p);
+	  gimple_pop_condition (pre_p);
+
+	  return GS_ALL_DONE;
+	}
+    }
+
+  /* Now do the normal gimplification.  */
+  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+		       is_gimple_condexpr, fb_rvalue);
+
+  gimple_push_condition ();
+
+  gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
+  gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
+  recalculate_side_effects (expr);
+
+  gimple_pop_condition (pre_p);
+
+  if (ret == GS_ERROR)
+    ;
+  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+    ret = GS_ALL_DONE;
+  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
+    /* Rewrite "if (a); else b" to "if (!a) b"  */
+    {
+      TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
+      ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+			   is_gimple_condexpr, fb_rvalue);
+
+      tmp = TREE_OPERAND (expr, 1);
+      TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
+      TREE_OPERAND (expr, 2) = tmp;
+    }
+  else
+    /* Both arms are empty; replace the COND_EXPR with its predicate.  */
+    expr = TREE_OPERAND (expr, 0);
+
+  *expr_p = expr;
+  return ret;
+}
+
+/* A subroutine of gimplify_modify_expr.  Replace a MODIFY_EXPR with
+   a call to __builtin_memcpy.  */
+
+static enum gimplify_status
+gimplify_modify_expr_to_memcpy (tree *expr_p, bool want_value)
+{
+  tree args, t, to, to_ptr, from;
+
+  to = TREE_OPERAND (*expr_p, 0);
+  from = TREE_OPERAND (*expr_p, 1);
+
+  t = TYPE_SIZE_UNIT (TREE_TYPE (to));
+  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
+  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, from);
+  t = unshare_expr (t);
+  args = tree_cons (NULL, t, NULL);
+
+  t = build_fold_addr_expr (from);
+  args = tree_cons (NULL, t, args);
+
+  to_ptr = build_fold_addr_expr (to);
+  args = tree_cons (NULL, to, args);
+  t = implicit_built_in_decls[BUILT_IN_MEMCPY];
+  t = build_function_call_expr (t, args);
+
+  if (want_value)
+    {
+      t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
+      t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
+    }
+
+  *expr_p = t;
+  return GS_OK;
+}
+
+/* A subroutine of gimplify_modify_expr.  Replace a MODIFY_EXPR with
+   a call to __builtin_memset.  In this case we know that the RHS is
+   a CONSTRUCTOR with an empty element list.  */
+
+static enum gimplify_status
+gimplify_modify_expr_to_memset (tree *expr_p, bool want_value)
+{
+  tree args, t, to, to_ptr;
+
+  to = TREE_OPERAND (*expr_p, 0);
+
+  t = TYPE_SIZE_UNIT (TREE_TYPE (to));
+  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
+  t = unshare_expr (t);
+  args = tree_cons (NULL, t, NULL);
+
+  args = tree_cons (NULL, integer_zero_node, args);
+
+  to_ptr = build_fold_addr_expr (to);
+  args = tree_cons (NULL, to, args);
+  t = implicit_built_in_decls[BUILT_IN_MEMSET];
+  t = build_function_call_expr (t, args);
+
+  if (want_value)
+    {
+      t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
+      t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
+    }
+
+  *expr_p = t;
+  return GS_OK;
+}
+
+/* A subroutine of gimplify_modify_expr.  Break out elements of a
+   CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs.
+
+   Note that we still need to clear any elements that don't have explicit
+   initializers, so if not all elements are initialized we keep the
+   original MODIFY_EXPR, we just remove all of the constructor elements.  */
+
+static enum gimplify_status
+gimplify_init_constructor (tree *expr_p, tree *pre_p,
+			   tree *post_p, bool want_value)
+{
+  tree object = TREE_OPERAND (*expr_p, 0);
+  tree ctor = TREE_OPERAND (*expr_p, 1);
+  tree type = TREE_TYPE (ctor);
+  enum gimplify_status ret;
+  tree elt_list;
+
+  if (TREE_CODE (ctor) != CONSTRUCTOR)
+    return GS_UNHANDLED;
+
+  elt_list = CONSTRUCTOR_ELTS (ctor);
+
+  ret = GS_ALL_DONE;
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+    case ARRAY_TYPE:
+      {
+	HOST_WIDE_INT i, num_elements, num_nonzero_elements;
+	HOST_WIDE_INT num_nonconstant_elements;
+	bool cleared;
+
+	/* Aggregate types must lower constructors to initialization of
+	   individual elements.  The exception is that a CONSTRUCTOR node
+	   with no elements indicates zero-initialization of the whole.  */
+	if (elt_list == NULL)
+	  {
+	    if (want_value)
+	      {
+		*expr_p = object;
+		return GS_OK;
+	      }
+	    else
+	      return GS_UNHANDLED;
+	  }
+
+	categorize_ctor_elements (ctor, &num_nonzero_elements,
+				  &num_nonconstant_elements);
+	num_elements = count_type_elements (TREE_TYPE (ctor));
+
+	/* If a const aggregate variable is being initialized, then it
+	   should never be a lose to promote the variable to be static.  */
+	if (num_nonconstant_elements == 0
+	    && TREE_READONLY (object)
+	    && TREE_CODE (object) == VAR_DECL)
+	  {
+	    DECL_INITIAL (object) = ctor;
+	    TREE_STATIC (object) = 1;
+	    if (!DECL_NAME (object))
+	      DECL_NAME (object) = create_tmp_var_name ("C");
+	    walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL);
+
+	    /* ??? C++ doesn't automatically append a .<number> to the
+	       assembler name, and even when it does, it looks a FE private
+	       data structures to figure out what that number should be,
+	       which are not set for this variable.  I suppose this is
+	       important for local statics for inline functions, which aren't
+	       "local" in the object file sense.  So in order to get a unique
+	       TU-local symbol, we must invoke the lhd version now.  */
+	    lhd_set_decl_assembler_name (object);
+
+	    *expr_p = NULL_TREE;
+	    break;
+	  }
+
+	/* If there are "lots" of initialized elements, and all of them
+	   are valid address constants, then the entire initializer can
+	   be dropped to memory, and then memcpy'd out.  */
+	if (num_nonconstant_elements == 0)
+	  {
+	    HOST_WIDE_INT size = int_size_in_bytes (type);
+	    unsigned int align;
+
+	    /* ??? We can still get unbounded array types, at least
+	       from the C++ front end.  This seems wrong, but attempt
+	       to work around it for now.  */
+	    if (size < 0)
+	      {
+		size = int_size_in_bytes (TREE_TYPE (object));
+		if (size >= 0)
+		  TREE_TYPE (ctor) = type = TREE_TYPE (object);
+	      }
+
+	    /* Find the maximum alignment we can assume for the object.  */
+	    /* ??? Make use of DECL_OFFSET_ALIGN.  */
+	    if (DECL_P (object))
+	      align = DECL_ALIGN (object);
+	    else
+	      align = TYPE_ALIGN (type);
+
+	    if (size > 0 && !can_move_by_pieces (size, align))
+	      {
+		tree new = create_tmp_var_raw (type, "C");
+		gimple_add_tmp_var (new);
+		TREE_STATIC (new) = 1;
+		TREE_READONLY (new) = 1;
+		DECL_INITIAL (new) = ctor;
+		if (align > DECL_ALIGN (new))
+		  {
+		    DECL_ALIGN (new) = align;
+		    DECL_USER_ALIGN (new) = 1;
+		  }
+	        walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
+
+		TREE_OPERAND (*expr_p, 1) = new;
+		break;
+	      }
+	  }
+
+	/* If there are "lots" of initialized elements, even discounting
+	   those that are not address constants (and thus *must* be 
+	   computed at runtime), then partition the constructor into
+	   constant and non-constant parts.  Block copy the constant
+	   parts in, then generate code for the non-constant parts.  */
+	/* TODO.  There's code in cp/typeck.c to do this.  */
+
+	/* If there are "lots" of zeros, then block clear the object first.  */
+	cleared = false;
+	if (num_elements - num_nonzero_elements > CLEAR_RATIO
+	    && num_nonzero_elements < num_elements/4)
+	  cleared = true;
+
+	/* ??? This bit ought not be needed.  For any element not present
+	   in the initializer, we should simply set them to zero.  Except
+	   we'd need to *find* the elements that are not present, and that
+	   requires trickery to avoid quadratic compile-time behavior in
+	   large cases or excessive memory use in small cases.  */
+	else
+	  {
+	    HOST_WIDE_INT len = list_length (elt_list);
+	    if (TREE_CODE (type) == ARRAY_TYPE)
+	      {
+		tree nelts = array_type_nelts (type);
+		if (!host_integerp (nelts, 1)
+		    || tree_low_cst (nelts, 1) != len)
+		  cleared = 1;;
+	      }
+	    else if (len != fields_length (type))
+	      cleared = 1;
+	  }
+
+	if (cleared)
+	  {
+	    /* Zap the CONSTRUCTOR element list, which simplifies this case.
+	       Note that we still have to gimplify, in order to handle the
+	       case of variable sized types.  */
+	    CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
+	    gimplify_stmt (expr_p);
+	    append_to_statement_list (*expr_p, pre_p);
+	  }
+
+	for (i = 0; elt_list; i++, elt_list = TREE_CHAIN (elt_list))
+	  {
+	    tree purpose, value, cref, init;
+
+	    purpose = TREE_PURPOSE (elt_list);
+	    value = TREE_VALUE (elt_list);
+
+	    if (cleared && initializer_zerop (value))
+	      continue;
+
+	    if (TREE_CODE (type) == ARRAY_TYPE)
+	      {
+		tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
+
+		/* ??? Here's to hoping the front end fills in all of the
+		   indicies, so we don't have to figure out what's missing
+		   ourselves.  */
+		if (!purpose)
+		  abort ();
+		/* ??? Need to handle this.  */
+		if (TREE_CODE (purpose) == RANGE_EXPR)
+		  abort ();
+
+		cref = build (ARRAY_REF, t, object, purpose,
+			      NULL_TREE, NULL_TREE);
+	      }
+	    else
+	      cref = build (COMPONENT_REF, TREE_TYPE (purpose), object,
+			    purpose, NULL_TREE);
+
+	    init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
+
+	    /* Each member initialization is a full-expression.  */
+	    gimplify_and_add (init, pre_p);
+	  }
+
+	*expr_p = NULL_TREE;
+      }
+      break;
+
+    case COMPLEX_TYPE:
+      {
+	tree r, i;
+
+	/* Extract the real and imaginary parts out of the ctor.  */
+	r = i = NULL_TREE;
+	if (elt_list)
+	  {
+	    r = TREE_VALUE (elt_list);
+	    elt_list = TREE_CHAIN (elt_list);
+	    if (elt_list)
+	      {
+		i = TREE_VALUE (elt_list);
+		if (TREE_CHAIN (elt_list))
+		  abort ();
+	      }
+	  }
+	if (r == NULL || i == NULL)
+	  {
+	    tree zero = convert (TREE_TYPE (type), integer_zero_node);
+	    if (r == NULL)
+	      r = zero;
+	    if (i == NULL)
+	      i = zero;
+	  }
+
+	/* Complex types have either COMPLEX_CST or COMPLEX_EXPR to
+	   represent creation of a complex value.  */
+	if (TREE_CONSTANT (r) && TREE_CONSTANT (i))
+	  {
+	    ctor = build_complex (type, r, i);
+	    TREE_OPERAND (*expr_p, 1) = ctor;
+	  }
+	else
+	  {
+	    ctor = build (COMPLEX_EXPR, type, r, i);
+	    TREE_OPERAND (*expr_p, 1) = ctor;
+	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+				 is_gimple_rhs, fb_rvalue);
+	  }
+      }
+      break;
 
-  /* If this COND_EXPR has a value, copy the values into a temporary within
-     the arms.  */
-  else if (! VOID_TYPE_P (type))
-    {
-      if (target)
-	{
-	  tmp = target;
-	  ret = GS_OK;
-	}
+    case VECTOR_TYPE:
+      /* Go ahead and simplify constant constructors to VECTOR_CST.  */
+      if (TREE_CONSTANT (ctor))
+	TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
       else
 	{
-	  tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
-	  ret = GS_ALL_DONE;
+	  /* Vector types use CONSTRUCTOR all the way through gimple
+	     compilation as a general initializer.  */
+	  for (; elt_list; elt_list = TREE_CHAIN (elt_list))
+	    {
+	      enum gimplify_status tret;
+	      tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
+				    is_gimple_constructor_elt, fb_rvalue);
+	      if (tret == GS_ERROR)
+		ret = GS_ERROR;
+	    }
 	}
+      break;
 
-      /* Build the then clause, 't1 = a;'.  But don't build an assignment
-	 if this branch is void; in C++ it can be, if it's a throw.  */
-      if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
-	TREE_OPERAND (expr, 1)
-	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
-
-      /* Build the else clause, 't1 = b;'.  */
-      if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
-	TREE_OPERAND (expr, 2)
-	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2));
-
-      TREE_TYPE (expr) = void_type_node;
-      recalculate_side_effects (expr);
-
-      /* Move the COND_EXPR to the prequeue and use the temp in its place.  */
-      gimplify_and_add (expr, pre_p);
-      *expr_p = tmp;
+    default:
+      /* So how did we get a CONSTRUCTOR for a scalar type?  */
+      abort ();
+    }
 
-      return ret;
+  if (ret == GS_ERROR)
+    return GS_ERROR;
+  else if (want_value)
+    {
+      append_to_statement_list (*expr_p, pre_p);
+      *expr_p = object;
+      return GS_OK;
     }
+  else
+    return GS_ALL_DONE;
+}
 
-  /* Make sure the condition has BOOLEAN_TYPE.  */
-  TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+/* Subroutine of gimplify_modify_expr to do simplifications of MODIFY_EXPRs
+   based on the code of the RHS.  We loop for as long as something changes.  */
 
-  /* Break apart && and || conditions.  */
-  if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
-      || TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
-    {
-      expr = shortcut_cond_expr (expr);
+static enum gimplify_status
+gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
+			  tree *post_p, bool want_value)
+{
+  enum gimplify_status ret = GS_OK;
 
-      if (expr != *expr_p)
+  while (ret != GS_UNHANDLED)
+    switch (TREE_CODE (*from_p))
+      {
+      case TARGET_EXPR:
 	{
-	  *expr_p = expr;
+	  /* If we are initializing something from a TARGET_EXPR, strip the
+	     TARGET_EXPR and initialize it directly, if possible.  This can't
+	     be done if the initializer is void, since that implies that the
+	     temporary is set in some non-trivial way.
 
-	  /* We can't rely on gimplify_expr to re-gimplify the expanded
-	     form properly, as cleanups might cause the target labels to be
-	     wrapped in a TRY_FINALLY_EXPR.  To prevent that, we need to
-	     set up a conditional context.  */
-	  gimple_push_condition ();
-	  gimplify_stmt (expr_p);
-	  gimple_pop_condition (pre_p);
+	     ??? What about code that pulls out the temp and uses it
+	     elsewhere? I think that such code never uses the TARGET_EXPR as
+	     an initializer.  If I'm wrong, we'll abort because the temp won't
+	     have any RTL.  In that case, I guess we'll need to replace
+	     references somehow.  */
+	  tree init = TARGET_EXPR_INITIAL (*from_p);
 
-	  return GS_ALL_DONE;
+	  if (!VOID_TYPE_P (TREE_TYPE (init)))
+	    {
+	      *from_p = init;
+	      ret = GS_OK;
+	    }
+	  else
+	    ret = GS_UNHANDLED;
 	}
-    }
-
-  /* Now do the normal gimplification.  */
-  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
-		       is_gimple_condexpr, fb_rvalue);
-
-  gimple_push_condition ();
+	break;
 
-  gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
-  gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
-  recalculate_side_effects (expr);
+      case COMPOUND_EXPR:
+	/* Remove any COMPOUND_EXPR in the RHS so the following cases will be
+	   caught.  */
+	gimplify_compound_expr (from_p, pre_p, true);
+	ret = GS_OK;
+	break;
 
-  gimple_pop_condition (pre_p);
+      case CONSTRUCTOR:
+	/* If we're initializing from a CONSTRUCTOR, break this into
+	   individual MODIFY_EXPRs.  */
+	return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
 
-  if (ret == GS_ERROR)
-    ;
-  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
-    ret = GS_ALL_DONE;
-  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
-    /* Rewrite "if (a); else b" to "if (!a) b"  */
-    {
-      TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
-      ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
-			   is_gimple_condexpr, fb_rvalue);
+      case COND_EXPR:
+	/* If we're assigning from a ?: expression with ADDRESSABLE type, push
+	   the assignment down into the branches, since we can't generate a
+	   temporary of such a type.  */
+	if (TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
+	  {
+	    *expr_p = *from_p;
+	    return gimplify_cond_expr (expr_p, pre_p, *to_p);
+	  }
+	else
+	  ret = GS_UNHANDLED;
+	break;
 
-      tmp = TREE_OPERAND (expr, 1);
-      TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
-      TREE_OPERAND (expr, 2) = tmp;
-    }
-  else
-    /* Both arms are empty; replace the COND_EXPR with its predicate.  */
-    expr = TREE_OPERAND (expr, 0);
+      default:
+	ret = GS_UNHANDLED;
+	break;
+      }
 
-  *expr_p = expr;
   return ret;
 }
 
-/*  Gimplify the MODIFY_EXPR node pointed by EXPR_P.
+/* Gimplify the MODIFY_EXPR node pointed by EXPR_P.
 
       modify_expr
 	      : varname '=' rhs
@@ -2628,31 +2770,15 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
     return ret;
 
   /* If the value being copied is of variable width, expose the length
-     if the copy by converting the whole thing to a memcpy.  Note that
-     we need to do this before gimplifying any of the operands
+     if the copy by converting the whole thing to a memcpy/memset.
+     Note that we need to do this before gimplifying any of the operands
      so that we can resolve any PLACEHOLDER_EXPRs in the size.  */
   if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST)
     {
-      tree args, t, dest;
-
-      t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
-      t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *to_p);
-      t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *from_p);
-      t = unshare_expr (t);
-      args = tree_cons (NULL, t, NULL);
-      t = build_fold_addr_expr (*from_p);
-      args = tree_cons (NULL, t, args);
-      dest = build_fold_addr_expr (*to_p);
-      args = tree_cons (NULL, dest, args);
-      t = implicit_built_in_decls[BUILT_IN_MEMCPY];
-      t = build_function_call_expr (t, args);
-      if (want_value)
-	{
-	  t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
-	  t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
-	}
-      *expr_p = t;
-      return GS_OK;
+      if (TREE_CODE (*from_p) == CONSTRUCTOR)
+	return gimplify_modify_expr_to_memset (expr_p, want_value);
+      else
+	return gimplify_modify_expr_to_memcpy (expr_p, want_value);
     }
 
   ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
@@ -2707,75 +2833,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   return ret;
 }
 
-/*  Subroutine of above to do simplifications of MODIFY_EXPRs based on
-    the code of the RHS.  We loop for as long as we can do something.  */
-
-static enum gimplify_status
-gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
-			  tree *post_p, bool want_value)
-{
-  enum gimplify_status ret = GS_OK;
-
-  while (ret != GS_UNHANDLED)
-    switch (TREE_CODE (*from_p))
-      {
-      case TARGET_EXPR:
-	{
-	  /* If we are initializing something from a TARGET_EXPR, strip the
-	     TARGET_EXPR and initialize it directly, if possible.  This can't
-	     be done if the initializer is void, since that implies that the
-	     temporary is set in some non-trivial way.
-
-	     ??? What about code that pulls out the temp and uses it
-	     elsewhere? I think that such code never uses the TARGET_EXPR as
-	     an initializer.  If I'm wrong, we'll abort because the temp won't
-	     have any RTL.  In that case, I guess we'll need to replace
-	     references somehow.  */
-	  tree init = TARGET_EXPR_INITIAL (*from_p);
-
-	  if (!VOID_TYPE_P (TREE_TYPE (init)))
-	    {
-	      *from_p = init;
-	      ret = GS_OK;
-	    }
-	  else
-	    ret = GS_UNHANDLED;
-	}
-	break;
-
-      case COMPOUND_EXPR:
-	/* Remove any COMPOUND_EXPR in the RHS so the following cases will be
-	   caught.  */
-	gimplify_compound_expr (from_p, pre_p, true);
-	ret = GS_OK;
-	break;
-
-      case CONSTRUCTOR:
-	/* If we're initializing from a CONSTRUCTOR, break this into
-	   individual MODIFY_EXPRs.  */
-	return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
-
-      case COND_EXPR:
-	/* If we're assigning from a ?: expression with ADDRESSABLE type, push
-	   the assignment down into the branches, since we can't generate a
-	   temporary of such a type.  */
-	if (TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
-	  {
-	    *expr_p = *from_p;
-	    return gimplify_cond_expr (expr_p, pre_p, *to_p);
-	  }
-	else
-	  ret = GS_UNHANDLED;
-	break;
-
-      default:
-	ret = GS_UNHANDLED;
-	break;
-      }
-
-  return ret;
-}
-
 /*  Gimplify a comparison between two variable-sized objects.  Do this
     with a call to BUILT_IN_MEMCMP.  */
 
-- 
GitLab