OSDN Git Service

* gimplify.c (gimplify_compound_lval): Take fallback argument
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 92c52a9..e8fdbe9 100644 (file)
@@ -1,6 +1,5 @@
 /* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
    tree representation into the GIMPLE form.
-
    Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
    Major work done by Sebastian Pop <s.pop@laposte.net>,
    Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
@@ -36,6 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "langhooks.h"
 #include "langhooks-def.h"
 #include "tree-flow.h"
+#include "cgraph.h"
 #include "timevar.h"
 #include "except.h"
 #include "hashtab.h"
@@ -71,12 +71,18 @@ typedef struct gimple_temp_hash_elt
   tree temp;  /* Value */
 } elt_t;
 
+/* Forward declarations.  */
+static enum gimplify_status gimplify_modify_expr_rhs (tree *, tree *, tree *,
+                                                     tree *, tree *, bool);
+static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
+
+
 /* Return a hash value for a formal temporary table entry.  */
 
 static hashval_t
 gimple_tree_hash (const void *p)
 {
-  tree t = ((const elt_t *)p)->val;
+  tree t = ((const elt_t *) p)->val;
   return iterative_hash_expr (t, 0);
 }
 
@@ -85,8 +91,8 @@ gimple_tree_hash (const void *p)
 static int
 gimple_tree_eq (const void *p1, const void *p2)
 {
-  tree t1 = ((const elt_t *)p1)->val;
-  tree t2 = ((const elt_t *)p2)->val;
+  tree t1 = ((const elt_t *) p1)->val;
+  tree t2 = ((const elt_t *) p2)->val;
   enum tree_code code = TREE_CODE (t1);
 
   if (TREE_CODE (t2) != code
@@ -187,6 +193,7 @@ static void
 gimple_pop_condition (tree *pre_p)
 {
   int conds = --(gimplify_ctxp->conditions);
+
   if (conds == 0)
     {
       append_to_statement_list (gimplify_ctxp->conditional_cleanups, pre_p);
@@ -247,20 +254,6 @@ gimplify_and_add (tree t, tree *list_p)
   append_to_statement_list (t, list_p);
 }
 
-/* Add T to the end of a COMPOUND_EXPR pointed by LIST_P.  The type
-   of the result is the type of T.  */
-
-void
-append_to_compound_expr (tree t, tree *list_p)
-{
-  if (!t)
-    return;
-  if (!*list_p)
-    *list_p = t;
-  else
-    *list_p = build (COMPOUND_EXPR, TREE_TYPE (t), *list_p, t);
-}
-
 /* Strip off a legitimate source ending from the input string NAME of
    length LEN.  Rather than having to know the names used by all of
    our front ends, we strip off an ending of a period followed by
@@ -288,6 +281,7 @@ tree
 create_artificial_label (void)
 {
   tree lab = build_decl (LABEL_DECL, NULL_TREE, void_type_node);
+
   DECL_ARTIFICIAL (lab) = 1;
   DECL_CONTEXT (lab) = current_function_decl;
   return lab;
@@ -305,6 +299,7 @@ create_tmp_var_name (const char *prefix)
   if (prefix)
     {
       char *preftmp = ASTRDUP (prefix);
+
       remove_suffix (preftmp, strlen (preftmp));
       prefix = preftmp;
     }
@@ -355,15 +350,11 @@ create_tmp_var (tree type, const char *prefix)
   tree tmp_var;
 
 #if defined ENABLE_CHECKING
-  /* If the type is an array or a type which must be created by the
-     frontend, something is wrong.  */
-  if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type))
-    abort ();
-  if (!COMPLETE_TYPE_P (type))
-    abort ();
-  /* Variable sized types require lots of machinery to create; the
-     optimizers shouldn't be doing anything of the sort.  */
-  if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
+  /* We don't allow types that are addressable (meaning we can't make copies),
+     incomplete, or of variable size.  */
+  if (TREE_ADDRESSABLE (type)
+      || !COMPLETE_TYPE_P (type)
+      || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
     abort ();
 #endif
 
@@ -427,7 +418,8 @@ lookup_tmp_var (tree val, bool is_formal)
          elt_p = xmalloc (sizeof (*elt_p));
          elt_p->val = val;
          elt_p->temp = create_tmp_from_val (val);
-         *slot = (void *)elt_p;
+         TREE_READONLY (elt_p->temp) = 1;
+         *slot = (void *) elt_p;
        }
       else
        elt_p = (elt_t *) *slot;
@@ -461,14 +453,13 @@ internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
   mod = build (MODIFY_EXPR, TREE_TYPE (t), t, val);
 
   class = TREE_CODE_CLASS (TREE_CODE (val));
-  if (EXPR_LOCUS (val))
+  if (EXPR_HAS_LOCATION (val))
     SET_EXPR_LOCUS (mod, EXPR_LOCUS (val));
   else
-    annotate_with_locus (mod, input_location);
-  /* gimplify_modify_expr might want to reduce this further.  */
-  gimplify_stmt (&mod);
-  append_to_statement_list (mod, pre_p);
+    SET_EXPR_LOCATION (mod, input_location);
 
+  /* gimplify_modify_expr might want to reduce this further.  */
+  gimplify_and_add (mod, pre_p);
   return t;
 }
 
@@ -497,8 +488,7 @@ is_gimple_tmp_var (tree t)
          && !TREE_STATIC (t) && !DECL_EXTERNAL (t));
 }
 
-/* Declares all the variables in VARS in SCOPE.  Returns the last
-   DECL_STMT emitted.  */
+/* Declares all the variables in VARS in SCOPE.  */
 
 void
 declare_tmp_vars (tree vars, tree scope)
@@ -508,7 +498,7 @@ declare_tmp_vars (tree vars, tree scope)
     {
       tree temps;
 
-      /* C99 mode puts the default 'return 0;' for main() outside the outer
+      /* C99 mode puts the default 'return 0;' for main outside the outer
         braces.  So drill down until we find an actual scope.  */
       while (TREE_CODE (scope) == COMPOUND_EXPR)
        scope = TREE_OPERAND (scope, 0);
@@ -569,7 +559,7 @@ annotate_one_with_locus (tree t, location_t locus)
   if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t)))
       && ! EXPR_HAS_LOCATION (t)
       && should_carry_locus_p (t))
-    annotate_with_locus (t, locus);
+    SET_EXPR_LOCATION (t, locus);
 }
 
 void
@@ -653,16 +643,24 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
   tree t = *tp;
   enum tree_code code = TREE_CODE (t);
 
-  /* Skip types, decls, and constants.  */
+  /* Skip types, decls, and constants.  But we do want to look at their
+     types and the bounds of types.  Mark them as visited so we properly
+     unmark their subtrees on the unmark pass.  If we've already seen them,
+     don't look down further.  */
   if (TREE_CODE_CLASS (code) == 't'
       || TREE_CODE_CLASS (code) == 'd'
       || TREE_CODE_CLASS (code) == 'c')
-    *walk_subtrees = 0;
+    {
+      if (TREE_VISITED (t))
+       *walk_subtrees = 0;
+      else
+       TREE_VISITED (t) = 1;
+    }
 
   /* Special-case BIND_EXPR.  We should never be copying these, therefore
      we can omit examining BIND_EXPR_VARS.  Which also avoids problems with
      double processing of the DECL_INITIAL, which could be seen via both
-     the BIND_EXPR_VARS and a DECL_STMT.  */
+     the BIND_EXPR_VARS and a DECL_EXPR.  */
   else if (code == BIND_EXPR)
     {
       if (TREE_VISITED (t))
@@ -715,6 +713,31 @@ unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
   return NULL_TREE;
 }
 
+/* Unshare all the trees in BODY_P, a pointer to the body of FNDECL, and the
+   bodies of any nested functions.  */
+
+static void
+unshare_body (tree *body_p, tree fndecl)
+{
+  struct cgraph_node *cgn = cgraph_node (fndecl);
+
+  walk_tree (body_p, copy_if_shared_r, NULL, NULL);
+  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+    unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
+/* Likewise, but mark all trees as not visited.  */
+
+static void
+unvisit_body (tree *body_p, tree fndecl)
+{
+  struct cgraph_node *cgn = cgraph_node (fndecl);
+
+  walk_tree (body_p, unmark_visited_r, NULL, NULL);
+  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+    unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
 /* Unshare T and all the trees reached from T via TREE_CHAIN.  */
 
 void
@@ -805,7 +828,8 @@ voidify_wrapper_expr (tree wrapper, tree temp)
          goto restart;
        }
       /* The C++ frontend already did this for us.  */
-      else if (TREE_CODE (*p) == INIT_EXPR)
+      else if (TREE_CODE (*p) == INIT_EXPR
+              || TREE_CODE (*p) == TARGET_EXPR)
        temp = TREE_OPERAND (*p, 0);
       /* If we're returning a dereference, move the dereference
         outside the wrapper.  */
@@ -966,8 +990,8 @@ gimplify_return_expr (tree stmt, tree *pre_p)
      Then gimplify the whole thing.  */
   if (result != result_decl)
     TREE_OPERAND (ret_expr, 0) = result;
-  gimplify_stmt (&TREE_OPERAND (stmt, 0));
-  append_to_statement_list (TREE_OPERAND (stmt, 0), pre_p);
+
+  gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
 
   /* If we didn't use a temporary, then the result is just the result_decl.
      Otherwise we need a simple copy.  This should already be gimple.  */
@@ -980,6 +1004,72 @@ gimplify_return_expr (tree stmt, tree *pre_p)
   return GS_ALL_DONE;
 }
 
+/* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation
+   and initialization explicit.  */
+
+static enum gimplify_status
+gimplify_decl_expr (tree *stmt_p)
+{
+  tree stmt = *stmt_p;
+  tree decl = DECL_EXPR_DECL (stmt);
+
+  *stmt_p = NULL_TREE;
+
+  if (TREE_TYPE (decl) == error_mark_node)
+    return GS_ERROR;
+
+  else if (TREE_CODE (decl) == TYPE_DECL)
+    gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
+
+  else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+    {
+      tree init = DECL_INITIAL (decl);
+
+      if (!TREE_CONSTANT (DECL_SIZE (decl)))
+       {
+         /* This is a variable-sized decl.  Simplify its size and mark it
+            for deferred expansion.  Note that mudflap depends on the format
+            of the emitted code: see mx_register_decls().  */
+         tree t, args;
+
+         gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
+         gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
+         gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
+
+         args = tree_cons (NULL, DECL_SIZE_UNIT (decl), NULL);
+         t = build_fold_addr_expr (decl);
+         args = tree_cons (NULL, t, args);
+         t = implicit_built_in_decls[BUILT_IN_STACK_ALLOC];
+         t = build_function_call_expr (t, args);
+
+         gimplify_and_add (t, stmt_p);
+         DECL_DEFER_OUTPUT (decl) = 1;
+       }
+
+      if (init && init != error_mark_node)
+       {
+         if (!TREE_STATIC (decl))
+           {
+             DECL_INITIAL (decl) = NULL_TREE;
+             init = build (MODIFY_EXPR, void_type_node, decl, init);
+             gimplify_and_add (init, stmt_p);
+           }
+         else
+           /* We must still examine initializers for static variables
+              as they may contain a label address.  */
+           walk_tree (&init, force_labels_r, NULL, NULL);
+       }
+
+      /* This decl isn't mentioned in the enclosing block, so add it to the
+        list of temps.  FIXME it seems a bit of a kludge to say that
+        anonymous artificial vars aren't pushed, but everything else is.  */
+      if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
+       gimple_add_tmp_var (decl);
+    }
+
+  return GS_ALL_DONE;
+}
+
 /* Gimplify a LOOP_EXPR.  Normally this just involves gimplifying the body
    and replacing the LOOP_EXPR with goto, but if the loop contains an
    EXIT_EXPR, we need to append a label for it to jump to.  */
@@ -995,8 +1085,7 @@ gimplify_loop_expr (tree *expr_p, tree *pre_p)
 
   gimplify_ctxp->exit_label = NULL_TREE;
 
-  gimplify_stmt (&LOOP_EXPR_BODY (*expr_p));
-  append_to_statement_list (LOOP_EXPR_BODY (*expr_p), pre_p);
+  gimplify_and_add (LOOP_EXPR_BODY (*expr_p), pre_p);
 
   if (gimplify_ctxp->exit_label)
     {
@@ -1192,7 +1281,7 @@ build_and_jump (tree *label_p)
 {
   if (label_p == NULL)
     /* If there's nowhere to jump, just fall through.  */
-    return build_empty_stmt ();
+    return NULL_TREE;
 
   if (*label_p == NULL_TREE)
     {
@@ -1214,7 +1303,7 @@ gimplify_exit_expr (tree *expr_p)
   tree expr;
 
   expr = build_and_jump (&gimplify_ctxp->exit_label);
-  expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
+  expr = build (COND_EXPR, void_type_node, cond, expr, NULL_TREE);
   *expr_p = expr;
 
   return GS_OK;
@@ -1234,377 +1323,108 @@ 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, int 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_ALL_DONE;
-         }
+      /* 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 = build_empty_stmt ();
-           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;
-         }
-
-       if (cleared)
-         {
-           CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
-           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);
-             }
-           else
-             {
-               cref = build (COMPONENT_REF, TREE_TYPE (purpose),
-                             object, purpose);
-             }
-
-           init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
-           /* Each member initialization is a full-expression.  */
-           gimplify_stmt (&init);
-           append_to_statement_list (init, pre_p);
-         }
-
-       *expr_p = build_empty_stmt ();
-      }
-      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.  Lest we perturb the type
-   system too badly, we must take extra steps to ensure that the ADDR_EXPR
-   and the addressed object continue to agree on types.  */
-/* ??? We might could do better if we recognize
-       T array[N][M];
-       (T *)&array
-   ==>
-       &array[0][0];
-*/
-
-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;
-
-  /* All checks succeeded.  Build a new node to merge the cast.  */
-  *expr_p = build1 (ADDR_EXPR, ctype, obj_expr);
-}
-
-/* *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);
+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.  */
@@ -1666,7 +1486,7 @@ gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
     return GS_OK;
 }
 
-/* Subroutine of gimplify_compound_lval and gimplify_array_ref.
+/* Subroutine of gimplify_compound_lval.
    Converts an ARRAY_REF to the equivalent *(&array + offset) form.  */
 
 static enum gimplify_status
@@ -1675,25 +1495,21 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
   tree array = TREE_OPERAND (*expr_p, 0);
   tree arrtype = TREE_TYPE (array);
   tree elttype = TREE_TYPE (arrtype);
-  tree size = size_in_bytes (elttype);
+  tree size = array_ref_element_size (*expr_p);
   tree ptrtype = build_pointer_type (elttype);
   enum tree_code add_code = PLUS_EXPR;
   tree idx = TREE_OPERAND (*expr_p, 1);
-  tree minidx, offset, addr, result;
+  tree minidx = unshare_expr (array_ref_low_bound (*expr_p));
+  tree offset, addr, result;
   enum gimplify_status ret;
 
   /* If the array domain does not start at zero, apply the offset.  */
-  minidx = TYPE_DOMAIN (arrtype);
-  if (minidx)
+  if (!integer_zerop (minidx))
     {
-      minidx = TYPE_MIN_VALUE (minidx);
-      if (minidx && !integer_zerop (minidx))
-       {
-         idx = convert (TREE_TYPE (minidx), idx);
-         idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
-       }
+      idx = convert (TREE_TYPE (minidx), idx);
+      idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
     }
-
+  
   /* If the index is negative -- a technically invalid situation now
      that we've biased the index back to zero -- then casting it to
      unsigned has ill effects.  In particular, -1*4U/4U != -1.
@@ -1707,7 +1523,7 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
     }
 
   /* Pointer arithmetic must be done in sizetype.  */
-  idx = convert (sizetype, idx);
+  idx = fold_convert (sizetype, idx);
 
   /* Convert the index to a byte offset.  */
   offset = size_binop (MULT_EXPR, size, idx);
@@ -1747,63 +1563,124 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
 
 static enum gimplify_status
 gimplify_compound_lval (tree *expr_p, tree *pre_p,
-                       tree *post_p, int want_lvalue)
+                       tree *post_p, fallback_t fallback)
 {
   tree *p;
-  enum tree_code code;
   varray_type stack;
-  enum gimplify_status ret;
+  enum gimplify_status ret = GS_OK, tret;
+  int i;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (*expr_p) != ARRAY_REF
+      && TREE_CODE (*expr_p) != ARRAY_RANGE_REF
       && TREE_CODE (*expr_p) != COMPONENT_REF
+      && TREE_CODE (*expr_p) != BIT_FIELD_REF
       && TREE_CODE (*expr_p) != REALPART_EXPR
       && TREE_CODE (*expr_p) != IMAGPART_EXPR)
     abort ();
 #endif
 
-  code = ERROR_MARK;   /* [GIMPLE] Avoid uninitialized use warning.  */
-
   /* Create a stack of the subexpressions so later we can walk them in
      order from inner to outer.  */
   VARRAY_TREE_INIT (stack, 10, "stack");
 
+  /* We can either handle REALPART_EXPR, IMAGEPART_EXPR anything that
+     handled_components can deal with.  */
   for (p = expr_p;
-       TREE_CODE (*p) == ARRAY_REF
-       || TREE_CODE (*p) == COMPONENT_REF
-       || TREE_CODE (*p) == REALPART_EXPR
-       || TREE_CODE (*p) == IMAGPART_EXPR;
+       (handled_component_p (*p)
+       || TREE_CODE (*p) == REALPART_EXPR || TREE_CODE (*p) == IMAGPART_EXPR);
        p = &TREE_OPERAND (*p, 0))
+    VARRAY_PUSH_TREE (stack, *p);
+
+  /* Now STACK is a stack of pointers to all the refs we've walked through
+     and P points to the innermost expression.
+
+     Java requires that we elaborated nodes in source order.  That
+     means we must gimplify the inner expression followed by each of
+     the indices, in order.  But we can't gimplify the inner
+     expression until we deal with any variable bounds, sizes, or
+     positions in order to deal with PLACEHOLDER_EXPRs.
+
+     So we do this in three steps.  First we deal with the annotations
+     for any variables in the components, then we gimplify the base,
+     then we gimplify any indices, from left to right.  */
+  for (i = VARRAY_ACTIVE_SIZE (stack) - 1; i >= 0; i--)
     {
-      code = TREE_CODE (*p);
-      if (code == ARRAY_REF)
+      tree t = VARRAY_TREE (stack, i);
+
+      if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
        {
-         tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*p, 0)));
-         if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
-           /* If the size of the array elements is not constant,
-              computing the offset is non-trivial, so expose it.  */
-           break;
+         /* Gimplify the low bound and element type size and put them into
+            the ARRAY_REF.  If these values are set, they have already been
+            gimplified.  */
+         if (!TREE_OPERAND (t, 2))
+           {
+             tree low = unshare_expr (array_ref_low_bound (t));
+             if (!is_gimple_min_invariant (low))
+               {
+                 TREE_OPERAND (t, 2) = low;
+                 tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+                                       is_gimple_tmp_var, fb_rvalue);
+                 ret = MIN (ret, tret);
+               }
+           }
+
+         if (!TREE_OPERAND (t, 3))
+           {
+             tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
+             tree elmt_size = unshare_expr (array_ref_element_size (t));
+             tree factor = size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT);
+
+             /* Divide the element size by the alignment of the element
+                type (above).  */
+             elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor);
+
+             if (!is_gimple_min_invariant (elmt_size))
+               {
+                 TREE_OPERAND (t, 3) = elmt_size;
+                 tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
+                                       is_gimple_tmp_var, fb_rvalue);
+                 ret = MIN (ret, tret);
+               }
+           }
+       }
+      else if (TREE_CODE (t) == COMPONENT_REF)
+       {
+         /* Set the field offset into T and gimplify it.  */
+         if (!TREE_OPERAND (t, 2))
+           {
+             tree offset = unshare_expr (component_ref_field_offset (t));
+             tree field = TREE_OPERAND (t, 1);
+             tree factor
+               = size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT);
+
+             /* Divide the offset by its alignment.  */
+             offset = size_binop (EXACT_DIV_EXPR, offset, factor);
+
+             if (!is_gimple_min_invariant (offset))
+               {
+                 TREE_OPERAND (t, 2) = offset;
+                 tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+                                       is_gimple_tmp_var, fb_rvalue);
+                 ret = MIN (ret, tret);
+               }
+           }
        }
-      VARRAY_PUSH_TREE (stack, *p);
     }
 
-  /* Now 'p' points to the first bit that isn't a ref, 'code' is the
-     TREE_CODE of the last bit that was, and 'stack' is a stack of pointers
-     to all the refs we've walked through.
-
-     Gimplify the base, and then process each of the outer nodes from left
-     to right.  */
-  ret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
-                      code != ARRAY_REF ? fb_either : fb_lvalue);
+  /* Step 2 is to gimplify the base expression.  */
+  tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
+  ret = MIN (ret, tret);
 
+  /* And finally, the indices and operands to BIT_FIELD_REF.  */
   for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
     {
       tree t = VARRAY_TOP_TREE (stack);
-      if (TREE_CODE (t) == ARRAY_REF)
+
+      if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
        {
-         /* Gimplify the dimension.  */
-         enum gimplify_status tret;
-         /* Temporary fix for gcc.c-torture/execute/20040313-1.c.
+         /* Gimplify the dimension.
+            Temporary fix for gcc.c-torture/execute/20040313-1.c.
             Gimplify non-constant array indices into a temporary
             variable.
             FIXME - The real fix is to gimplify post-modify
@@ -1815,16 +1692,31 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
            {
              tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
                                    is_gimple_tmp_var, fb_rvalue);
-             if (tret == GS_ERROR)
-               ret = GS_ERROR;
+             ret = MIN (ret, tret);
            }
        }
+      else if (TREE_CODE (t) == BIT_FIELD_REF)
+       {
+         tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
+                               is_gimple_val, fb_rvalue);
+         ret = MIN (ret, tret);
+         tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+                               is_gimple_val, fb_rvalue);
+         ret = MIN (ret, tret);
+       }
+         
+      /* The innermost expression P may have originally had TREE_SIDE_EFFECTS
+        set which would have caused all the outer expressions in EXPR_P
+        leading to P to also have had TREE_SIDE_EFFECTS set.  */
       recalculate_side_effects (t);
       VARRAY_POP (stack);
     }
 
+  tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
+  ret = MIN (ret, tret);
+
   /* If the outermost expression is a COMPONENT_REF, canonicalize its type.  */
-  if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF)
+  if ((fallback & fb_rvalue) && TREE_CODE (*expr_p) == COMPONENT_REF)
     {
       canonicalize_component_ref (expr_p);
       ret = MIN (ret, GS_OK);
@@ -1833,33 +1725,6 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
   return ret;
 }
 
-/*  Re-write the ARRAY_REF node pointed by EXPR_P.
-
-    PRE_P points to the list where side effects that must happen before
-       *EXPR_P should be stored.
-
-    POST_P points to the list where side effects that must happen after
-       *EXPR_P should be stored.
-
-    FIXME: ARRAY_REF currently doesn't accept a pointer as the array
-    argument, so this gimplification uses an INDIRECT_REF of ARRAY_TYPE.
-    ARRAY_REF should be extended.  */
-
-static enum gimplify_status
-gimplify_array_ref (tree *expr_p, tree *pre_p,
-                   tree *post_p, int want_lvalue)
-{
-  tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*expr_p, 0)));
-  if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
-    /* If the size of the array elements is not constant,
-       computing the offset is non-trivial, so expose it.  */
-    return gimplify_array_ref_to_plus (expr_p, pre_p, post_p);
-  else
-    /* Handle array and member refs together for now.  When alias analysis
-       improves, we may want to go back to handling them separately.  */
-    return gimplify_compound_lval (expr_p, pre_p, post_p, want_lvalue);
-}
-
 /*  Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=).
 
     PRE_P points to the list where side effects that must happen before
@@ -1873,7 +1738,7 @@ gimplify_array_ref (tree *expr_p, tree *pre_p,
 
 static enum gimplify_status
 gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
-                       int want_value)
+                       bool want_value)
 {
   enum tree_code code;
   tree lhs, lvalue, rhs, t1;
@@ -1928,8 +1793,7 @@ gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
   if (postfix)
     {
-      gimplify_stmt (&t1);
-      append_to_statement_list (t1, post_p);
+      gimplify_and_add (t1, post_p);
       *expr_p = lhs;
       return GS_ALL_DONE;
     }
@@ -1940,20 +1804,12 @@ gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
     }
 }
 
-/*  Gimplify the CALL_EXPR node pointed by EXPR_P.
-
-      call_expr
-             : ID '(' arglist ')'
-
-      arglist
-             : arglist ',' val
-             | val
-
-    PRE_P points to the list where side effects that must happen before
-       *EXPR_P should be stored.  */
+/* Gimplify the CALL_EXPR node pointed by EXPR_P.  PRE_P points to the
+   list where side effects that must happen before *EXPR_P should be stored.
+   WANT_VALUE is true if the result of the call is desired.  */
 
 static enum gimplify_status
-gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
+gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
 {
   tree decl;
   tree arglist;
@@ -1966,8 +1822,8 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
 
   /* For reliable diagnostics during inlining, it is necessary that 
      every call_expr be annotated with file and line.  */
-  if (!EXPR_LOCUS (*expr_p))
-    annotate_with_locus (*expr_p, input_location);
+  if (! EXPR_HAS_LOCATION (*expr_p))
+    SET_EXPR_LOCATION (*expr_p, input_location);
 
   /* This may be a call to a builtin function.
 
@@ -1997,7 +1853,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
       if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_RESTORE)
        gimplify_ctxp->save_stack = false;
 
-      new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
+      new = simplify_builtin (*expr_p, !want_value);
 
       if (new && new != *expr_p)
        {
@@ -2013,7 +1869,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
      the calling expression must occur before the actual call.  Force
      gimplify_expr to use an internal post queue.  */
   ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL,
-                      is_gimple_val, fb_rvalue);
+                      is_gimple_call_addr, fb_rvalue);
 
   if (PUSH_ARGS_REVERSED)
     TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
@@ -2021,13 +1877,24 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
        arglist = TREE_CHAIN (arglist))
     {
       enum gimplify_status t;
+      bool (*test) (tree);
+      fallback_t fb;
+
+      /* In general, we allow lvalues for function arguments to avoid
+        extra overhead of copying large aggregates out of even larger
+        aggregates into temporaries only to copy the temporaries to
+        the argument list.  Make optimizers happy by pulling out to
+        temporaries those types that fit in registers.  */
+      if (is_gimple_reg_type (TREE_TYPE (TREE_VALUE (arglist))))
+       test = is_gimple_val, fb = fb_rvalue;
+      else
+       test = is_gimple_lvalue, fb = fb_either;
 
       /* There is a sequence point before a function call.  Side effects in
         the argument list must occur before the actual call. So, when
         gimplifying arguments, force gimplify_expr to use an internal
         post queue which is then appended to the end of PRE_P.  */
-      t = gimplify_expr (&TREE_VALUE (arglist), pre_p, NULL, is_gimple_val,
-                        fb_rvalue);
+      t = gimplify_expr (&TREE_VALUE (arglist), pre_p, NULL, test, fb);
 
       if (t == GS_ERROR)
        ret = GS_ERROR;
@@ -2038,7 +1905,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
   /* Try this again in case gimplification exposed something.  */
   if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
     {
-      tree new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
+      tree new = simplify_builtin (*expr_p, !want_value);
 
       if (new && new != *expr_p)
        {
@@ -2155,9 +2022,11 @@ shortcut_cond_expr (tree expr)
   tree *true_label_p;
   tree *false_label_p;
   bool emit_end, emit_false;
+  bool then_se = then_ && TREE_SIDE_EFFECTS (then_);
+  bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
 
   /* First do simple transformations.  */
-  if (!TREE_SIDE_EFFECTS (else_))
+  if (!else_se)
     {
       /* If there is no 'else', turn (a && b) into if (a) if (b).  */
       while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
@@ -2165,11 +2034,10 @@ shortcut_cond_expr (tree expr)
          TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
          then_ = shortcut_cond_expr (expr);
          pred = TREE_OPERAND (pred, 0);
-         expr = build (COND_EXPR, void_type_node, pred, then_,
-                       build_empty_stmt ());
+         expr = build (COND_EXPR, void_type_node, pred, then_, NULL_TREE);
        }
     }
-  if (!TREE_SIDE_EFFECTS (then_))
+  if (!then_se)
     {
       /* If there is no 'then', turn
           if (a || b); else d
@@ -2180,8 +2048,7 @@ shortcut_cond_expr (tree expr)
          TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
          else_ = shortcut_cond_expr (expr);
          pred = TREE_OPERAND (pred, 0);
-         expr = build (COND_EXPR, void_type_node, pred,
-                       build_empty_stmt (), else_);
+         expr = build (COND_EXPR, void_type_node, pred, NULL_TREE, else_);
        }
     }
 
@@ -2203,18 +2070,22 @@ shortcut_cond_expr (tree expr)
   /* If our arms just jump somewhere, hijack those labels so we don't
      generate jumps to jumps.  */
 
-  if (TREE_CODE (then_) == GOTO_EXPR
+  if (then_
+      && TREE_CODE (then_) == GOTO_EXPR
       && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
     {
       true_label = GOTO_DESTINATION (then_);
-      then_ = build_empty_stmt ();
+      then_ = NULL;
+      then_se = false;
     }
 
-  if (TREE_CODE (else_) == GOTO_EXPR
+  if (else_
+      && TREE_CODE (else_) == GOTO_EXPR
       && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
     {
       false_label = GOTO_DESTINATION (else_);
-      else_ = build_empty_stmt ();
+      else_ = NULL;
+      else_se = false;
     }
 
   /* If we aren't hijacking a label for the 'then' branch, it falls through.  */
@@ -2224,21 +2095,23 @@ shortcut_cond_expr (tree expr)
     true_label_p = NULL;
 
   /* The 'else' branch also needs a label if it contains interesting code.  */
-  if (false_label || TREE_SIDE_EFFECTS (else_))
+  if (false_label || else_se)
     false_label_p = &false_label;
   else
     false_label_p = NULL;
 
   /* If there was nothing else in our arms, just forward the label(s).  */
-  if (!TREE_SIDE_EFFECTS (then_) && !TREE_SIDE_EFFECTS (else_))
+  if (!then_se && !else_se)
     return shortcut_cond_r (pred, true_label_p, false_label_p);
 
   /* If our last subexpression already has a terminal label, reuse it.  */
-  if (TREE_SIDE_EFFECTS (else_))
+  if (else_se)
     expr = expr_last (else_);
-  else
+  else if (then_se)
     expr = expr_last (then_);
-  if (TREE_CODE (expr) == LABEL_EXPR)
+  else
+    expr = NULL;
+  if (expr && TREE_CODE (expr) == LABEL_EXPR)
     end_label = LABEL_EXPR_LABEL (expr);
 
   /* If we don't care about jumping to the 'else' branch, jump to the end
@@ -2256,7 +2129,7 @@ shortcut_cond_expr (tree expr)
   append_to_statement_list (pred, &expr);
 
   append_to_statement_list (then_, &expr);
-  if (TREE_SIDE_EFFECTS (else_))
+  if (else_se)
     {
       t = build_and_jump (&end_label);
       append_to_statement_list (t, &expr);
@@ -2329,114 +2202,538 @@ gimple_boolify (tree expr)
 
     The second form is used when *EXPR_P is of type void.
 
+    TARGET is the tree for T1 above.
+
     PRE_P points to the list where side effects that must happen before
        *EXPR_P should be stored.  */
 
-static enum gimplify_status
-gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
-{
-  tree expr = *expr_p;
-  tree tmp;
-  enum gimplify_status ret;
+static enum gimplify_status
+gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
+{
+  tree expr = *expr_p;
+  tree tmp, type;
+  enum gimplify_status ret;
+
+  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_ptr, 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.  */
-  if (! VOID_TYPE_P (TREE_TYPE (expr)))
-    {
-      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_stmt (&expr);
-      append_to_statement_list (expr, pre_p);
-      *expr_p = tmp;
-
-      return ret;
+    default:
+      /* So how did we get a CONSTRUCTOR for a scalar type?  */
+      abort ();
     }
 
-  /* 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)
+  if (ret == GS_ERROR)
+    return GS_ERROR;
+  else if (want_value)
     {
-      expr = shortcut_cond_expr (expr);
+      append_to_statement_list (*expr_p, pre_p);
+      *expr_p = object;
+      return GS_OK;
+    }
+  else
+    return GS_ALL_DONE;
+}
 
-      if (expr != *expr_p)
-       {
-         *expr_p = expr;
+/* 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.  */
 
-         /* 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);
+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;
 
-         return GS_ALL_DONE;
+  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;
        }
-    }
-
-  /* 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
@@ -2456,7 +2753,7 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
 {
   tree *from_p = &TREE_OPERAND (*expr_p, 1);
   tree *to_p = &TREE_OPERAND (*expr_p, 0);
-  enum gimplify_status ret;
+  enum gimplify_status ret = GS_UNHANDLED;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (*expr_p) != MODIFY_EXPR && TREE_CODE (*expr_p) != INIT_EXPR)
@@ -2467,34 +2764,35 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   if (TREE_CODE (*expr_p) == INIT_EXPR)
     TREE_SET_CODE (*expr_p, MODIFY_EXPR);
 
-  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
-  if (ret == GS_ERROR)
+  /* See if any simplifications can be done based on what the RHS is.  */
+  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+                                 want_value);
+  if (ret != GS_UNHANDLED)
     return ret;
 
-  /* If we are initializing something from a TARGET_EXPR, strip the
-     TARGET_EXPR and initialize it directly.  */
-  /* 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.  */
-  if (TREE_CODE (*from_p) == TARGET_EXPR)
-    *from_p = TARGET_EXPR_INITIAL (*from_p);
-
-  /* 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_CODE (*from_p) == COND_EXPR
-      && TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
+  /* If the value being copied is of variable width, expose the length
+     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)
     {
-      *expr_p = *from_p;
-      return gimplify_cond_expr (expr_p, pre_p, *to_p);
+      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);
+  if (ret == GS_ERROR)
+    return ret;
+
   ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_rhs, fb_rvalue);
   if (ret == GS_ERROR)
     return ret;
 
-  ret = gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
+  /* Now see if the above changed *from_p to something we handle specially.  */
+  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+                                 want_value);
   if (ret != GS_UNHANDLED)
     return ret;
 
@@ -2524,35 +2822,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
                   && !is_gimple_reg (*to_p)))
        gimplify_expr (from_p, pre_p, post_p, is_gimple_val, fb_rvalue);
 
-      /* If the value being copied is of variable width, expose the length
-        if the copy by converting the whole thing to a memcpy.  */
-      /* ??? Except that we can't manage this with VA_ARG_EXPR.  Yes, this
-        does leave us with an edge condition that doesn't work.  The only
-        way out is to rearrange how VA_ARG_EXPR works.  */
-      if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST
-         && TREE_CODE (*from_p) != VA_ARG_EXPR)
-       {
-         tree args, t, dest;
-
-         t = TYPE_SIZE_UNIT (TREE_TYPE (*to_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;
-       }
-
       ret = want_value ? GS_OK : GS_ALL_DONE;
     }
 
@@ -2565,6 +2834,32 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   return ret;
 }
 
+/*  Gimplify a comparison between two variable-sized objects.  Do this
+    with a call to BUILT_IN_MEMCMP.  */
+
+static enum gimplify_status
+gimplify_variable_sized_compare (tree *expr_p)
+{
+  tree op0 = TREE_OPERAND (*expr_p, 0);
+  tree op1 = TREE_OPERAND (*expr_p, 1);
+  tree args, t, dest;
+
+  t = TYPE_SIZE_UNIT (TREE_TYPE (op0));
+  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
+  t = unshare_expr (t);
+  args = tree_cons (NULL, t, NULL);
+  t = build_fold_addr_expr (op1);
+  args = tree_cons (NULL, t, args);
+  dest = build_fold_addr_expr (op0);
+  args = tree_cons (NULL, dest, args);
+  t = implicit_built_in_decls[BUILT_IN_MEMCMP];
+  t = build_function_call_expr (t, args);
+  *expr_p
+    = build (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node);
+
+  return GS_OK;
+}
+
 /*  Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions.  EXPR_P
     points to the expression to gimplify.
 
@@ -2646,7 +2941,9 @@ gimplify_statement_list (tree *expr_p)
       gimplify_stmt (tsi_stmt_ptr (i));
 
       t = tsi_stmt (i);
-      if (TREE_CODE (t) == STATEMENT_LIST)
+      if (t == NULL)
+       tsi_delink (&i);
+      else if (TREE_CODE (t) == STATEMENT_LIST)
        {
          tsi_link_before (&i, t, TSI_SAME_STMT);
          tsi_delink (&i);
@@ -2690,7 +2987,7 @@ gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p)
       tree body = TREE_OPERAND (*expr_p, 0);
       ret = gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none);
       append_to_statement_list (body, pre_p);
-      *expr_p = build_empty_stmt ();
+      *expr_p = NULL;
     }
   else
     *expr_p = TREE_OPERAND (*expr_p, 0)
@@ -2736,9 +3033,18 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
                                        pre_p, post_p);
 
       /* This added an INDIRECT_REF.  Fold it away.  */
-      op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+      *expr_p = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+      break;
 
-      *expr_p = op0;
+    case VIEW_CONVERT_EXPR:
+      /* Take the address of our operand and then convert it to the type of
+        this ADDR_EXPR.
+
+        ??? The interactions of VIEW_CONVERT_EXPR and aliasing is not at
+        all clear.  The impact of this transformation is even less clear.  */
+      *expr_p = fold_convert (TREE_TYPE (expr),
+                             build_fold_addr_expr (TREE_OPERAND (op0, 0)));
+      ret = GS_OK;
       break;
 
     default:
@@ -2986,8 +3292,7 @@ gimple_push_cleanup (tree var, tree cleanup, tree *pre_p)
                           boolean_false_node);
       tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
                          boolean_true_node);
-      cleanup = build (COND_EXPR, void_type_node, flag, cleanup,
-                      build_empty_stmt ());
+      cleanup = build (COND_EXPR, void_type_node, flag, cleanup, NULL);
       wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
                   cleanup, NULL_TREE);
       append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
@@ -3021,22 +3326,29 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
 
   if (init)
     {
-      /* TARGET_EXPR temps aren't part of the enclosing block, so add it to the
-        temps list.  */
+      /* TARGET_EXPR temps aren't part of the enclosing block, so add it
+        to the temps list.  */
       gimple_add_tmp_var (temp);
 
-      /* Build up the initialization and add it to pre_p.  Special handling
-        for BIND_EXPR can result in fewer temporaries created.  */
-      if (TREE_CODE (init) == BIND_EXPR)
-       gimplify_bind_expr (&init, temp, pre_p);
-      if (init != temp)
+      /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
+        expression is supposed to initialize the slot.  */
+      if (VOID_TYPE_P (TREE_TYPE (init)))
+       ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
+      else
        {
-         if (! VOID_TYPE_P (TREE_TYPE (init)))
-           init = build (MODIFY_EXPR, void_type_node, temp, init);
-         ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
-         if (ret == GS_ERROR)
-           return GS_ERROR;
+          /* Special handling for BIND_EXPR can result in fewer temps.  */
+         ret = GS_OK;
+          if (TREE_CODE (init) == BIND_EXPR)
+           gimplify_bind_expr (&init, temp, pre_p);
+          if (init != temp)
+           {
+             init = build (MODIFY_EXPR, void_type_node, temp, init);
+             ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
+                                  fb_none);
+           }
        }
+      if (ret == GS_ERROR)
+       return GS_ERROR;
       append_to_statement_list (init, pre_p);
 
       /* If needed, push the cleanup for the temp.  */
@@ -3067,8 +3379,6 @@ void
 gimplify_stmt (tree *stmt_p)
 {
   gimplify_expr (stmt_p, NULL, NULL, is_gimple_stmt, fb_none);
-  if (!*stmt_p)
-    *stmt_p = alloc_stmt_list ();
 }
 
 /* Similarly, but force the result to be a STATEMENT_LIST.  */
@@ -3077,7 +3387,9 @@ void
 gimplify_to_stmt_list (tree *stmt_p)
 {
   gimplify_stmt (stmt_p);
-  if (TREE_CODE (*stmt_p) != STATEMENT_LIST)
+  if (!*stmt_p)
+    *stmt_p = alloc_stmt_list ();
+  else if (TREE_CODE (*stmt_p) != STATEMENT_LIST)
     {
       tree t = *stmt_p;
       *stmt_p = alloc_stmt_list ();
@@ -3124,7 +3436,6 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
   tree internal_post = NULL_TREE;
   tree save_expr;
   int is_statement = (pre_p == NULL);
-  location_t *locus;
   location_t saved_location;
   enum gimplify_status ret;
 
@@ -3144,12 +3455,9 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
     post_p = &internal_post;
 
   saved_location = input_location;
-  if (save_expr == error_mark_node)
-    locus = NULL;
-  else
-    locus = EXPR_LOCUS (save_expr);
-  if (locus)
-    input_location = *locus;
+  if (save_expr != error_mark_node
+      && EXPR_HAS_LOCATION (*expr_p))
+    input_location = EXPR_LOCATION (*expr_p);
 
   /* Loop over the specific gimplifiers until the toplevel node
      remains the same.  */
@@ -3163,7 +3471,8 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
       /* Die, die, die, my darling.  */
       if (save_expr == error_mark_node
-         || TREE_TYPE (save_expr) == error_mark_node)
+         || (TREE_TYPE (save_expr)
+             && TREE_TYPE (save_expr) == error_mark_node))
        {
          ret = GS_ERROR;
          break;
@@ -3195,13 +3504,12 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        case ARRAY_REF:
-         ret = gimplify_array_ref (expr_p, pre_p, post_p,
-                                   fallback & fb_lvalue);
-         break;
-
+       case ARRAY_RANGE_REF:
+       case REALPART_EXPR:
+       case IMAGPART_EXPR:
        case COMPONENT_REF:
          ret = gimplify_compound_lval (expr_p, pre_p, post_p,
-                                       fallback & fb_lvalue);
+                                       fallback ? fallback : fb_rvalue);
          break;
 
        case COND_EXPR:
@@ -3209,7 +3517,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        case CALL_EXPR:
-         ret = gimplify_call_expr (expr_p, pre_p, gimple_test_f);
+         ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
          break;
 
        case TREE_LIST:
@@ -3219,12 +3527,6 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
          break;
 
-       case REALPART_EXPR:
-       case IMAGPART_EXPR:
-         ret = gimplify_compound_lval (expr_p, pre_p, post_p,
-                                       fallback & fb_lvalue);
-         break;
-
        case MODIFY_EXPR:
        case INIT_EXPR:
          ret = gimplify_modify_expr (expr_p, pre_p, post_p,
@@ -3252,6 +3554,39 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
          break;
 
+       case VIEW_CONVERT_EXPR:
+         if (VOID_TYPE_P (TREE_TYPE (*expr_p))
+             || fallback == fb_none)
+           {
+             /* Just strip a conversion to void (or in void context) and
+                try again.  */
+             *expr_p = TREE_OPERAND (*expr_p, 0);
+             break;
+           }
+
+         /* If both types are BLKmode or if one type is of variable size,
+            convert this into a pointer punning operation.  This avoids
+            copies of large data or making a variable-size temporary.
+
+            ??? The interactions of VIEW_CONVERT_EXPR and aliasing is not at
+            all clear.  The impact of this transformation is even less
+            clear.  */
+
+         if ((TYPE_MODE (TREE_TYPE (*expr_p)) == BLKmode
+              && TYPE_MODE (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) == BLKmode)
+             || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (*expr_p)))
+             || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE
+                                           (TREE_OPERAND (*expr_p,0)))))
+           {
+             tree restype = TREE_TYPE (*expr_p);
+             *expr_p = build1 (INDIRECT_REF, TREE_TYPE (*expr_p),
+                               fold_convert (build_pointer_type (restype),
+                                             build_fold_addr_expr
+                                             (TREE_OPERAND (*expr_p, 0))));
+             break;
+           }
+         goto unary;
+
        case CONVERT_EXPR:
        case NOP_EXPR:
          if (IS_EMPTY_STMT (*expr_p))
@@ -3280,6 +3615,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
        case FIX_CEIL_EXPR:
        case FIX_FLOOR_EXPR:
        case FIX_ROUND_EXPR:
+       unary:
          /* unary_expr: ... | '(' cast ')' val | ...  */
          ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
                               is_gimple_val, fb_rvalue);
@@ -3305,6 +3641,10 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          *expr_p = DECL_INITIAL (*expr_p);
          break;
 
+       case DECL_EXPR:
+         ret = gimplify_decl_expr (expr_p);
+         break;
+
        case EXC_PTR_EXPR:
          /* FIXME make this a decl.  */
          ret = GS_ALL_DONE;
@@ -3378,7 +3718,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
            enum gimplify_status r0, r1, r2;
 
            r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                               is_gimple_min_lval, fb_either);
+                               is_gimple_lvalue, fb_either);
            r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
                                is_gimple_val, fb_rvalue);
            r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p,
@@ -3423,12 +3763,15 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = GS_ALL_DONE;
          break;
 
-       case VTABLE_REF:
-         /* This moves much of the actual computation out of the
-            VTABLE_REF.  Perhaps this should be revisited once we want to
-            do clever things with VTABLE_REFs.  */
-         ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                              is_gimple_min_lval, fb_lvalue);
+       case OBJ_TYPE_REF:
+         {
+           enum gimplify_status r0, r1;
+           r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, post_p,
+                               is_gimple_val, fb_rvalue);
+           r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
+                               is_gimple_val, fb_rvalue);
+           ret = MIN (r0, r1);
+         }
          break;
 
        case MIN_EXPR:
@@ -3471,9 +3814,18 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        default:
+         /* If this is a comparison of objects of aggregate type, handle
+            it specially (by converting to a call to memcmp).  It would be
+            nice to only have to do this for variable-sized objects, but
+            then we'd have to allow the same nest of reference nodes we
+            allow for MODIFY_EXPR and that's too complex.  */
+         if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
+             && (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1)))))
+           ret = gimplify_variable_sized_compare (expr_p);
+
          /* If *EXPR_P does not need to be special-cased, handle it
             according to its class.  */
-         if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
+         else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
            ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
                                 post_p, is_gimple_val, fb_rvalue);
          else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2'
@@ -3516,7 +3868,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
   if (ret == GS_ERROR)
     {
       if (is_statement)
-       *expr_p = build_empty_stmt ();
+       *expr_p = NULL;
       goto out;
     }
 
@@ -3527,18 +3879,36 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
     abort ();
 #endif
 
-  if (!*expr_p)
-    *expr_p = build_empty_stmt ();
-  if (fallback == fb_none && !is_gimple_stmt (*expr_p))
+  if (fallback == fb_none && *expr_p && !is_gimple_stmt (*expr_p))
     {
       /* We aren't looking for a value, and we don't have a valid
         statement.  If it doesn't have side-effects, throw it away.  */
       if (!TREE_SIDE_EFFECTS (*expr_p))
-       *expr_p = build_empty_stmt ();
+       *expr_p = NULL;
       else if (!TREE_THIS_VOLATILE (*expr_p))
-       /* We only handle volatiles here; anything else with side-effects
-          must be converted to a valid statement before we get here.  */
-       abort ();
+       {
+         /* This is probably a _REF that contains something nested that
+            has side effects.  Recurse through the operands to find it.  */
+         enum tree_code code = TREE_CODE (*expr_p);
+
+         if (code == COMPONENT_REF
+             || code == REALPART_EXPR || code == IMAGPART_EXPR)
+           gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                          gimple_test_f, fallback);
+         else if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
+           {
+             gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                            gimple_test_f, fallback);
+             gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+                          gimple_test_f, fallback);
+           }
+         else
+           /* Anything else with side-effects
+              must be converted to a valid statement before we get here.  */
+           abort ();
+
+         *expr_p = NULL;
+       }
       else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
        {
          /* Historically, the compiler has treated a bare
@@ -3549,7 +3919,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
       else
        /* We can't do anything useful with a volatile reference to
           incomplete type, so just throw it away.  */
-       *expr_p = build_empty_stmt ();
+       *expr_p = NULL;
     }
 
   /* If we are gimplifying at the statement level, we're done.  Tack
@@ -3564,6 +3934,8 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          annotate_all_with_locus (&internal_pre, input_location);
          *expr_p = internal_pre;
        }
+      else if (!*expr_p)
+       ;
       else if (TREE_CODE (*expr_p) == STATEMENT_LIST)
        annotate_all_with_locus (expr_p, input_location);
       else
@@ -3647,6 +4019,64 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
   return ret;
 }
 
+/* Look through TYPE for variable-sized objects and gimplify each such
+   size that we find.  Add to LIST_P any statements generated.  */
+
+void
+gimplify_type_sizes (tree type, tree *list_p)
+{
+  tree field;
+
+  switch (TREE_CODE (type))
+    {
+    case ERROR_MARK:
+      return;
+
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case CHAR_TYPE:
+    case REAL_TYPE:
+      gimplify_one_sizepos (&TYPE_MIN_VALUE (type), list_p);
+      gimplify_one_sizepos (&TYPE_MAX_VALUE (type), list_p);
+      break;
+
+    case ARRAY_TYPE:
+      /* These anonymous types don't have declarations, so handle them here. */
+      gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
+      break;
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+       if (TREE_CODE (field) == FIELD_DECL)
+         gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
+      break;
+
+    default:
+      break;
+    }
+
+  gimplify_one_sizepos (&TYPE_SIZE (type), list_p);
+  gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), list_p);
+}
+
+/* Subroutine of the above to gimplify one size or position, *EXPR_P.
+   We add any required statements to STMT_P.  */
+
+void
+gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
+{
+  /* We don't do anything if the value isn't there, is constant, or contains
+     A PLACEHOLDER_EXPR.  */
+  if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)
+      || CONTAINS_PLACEHOLDER_P (*expr_p))
+    return;
+
+  gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
+}
+\f
 #ifdef ENABLE_CHECKING
 /* Compare types A and B for a "close enough" match.  */
 
@@ -3707,8 +4137,10 @@ check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
       dtype = TREE_TYPE (ptype);
       if (!cpt_same_type (otype, dtype))
        {
-         /* &array is allowed to produce a pointer to the element,
-            rather than a pointer to the array type.  */
+         /* &array is allowed to produce a pointer to the element, rather than
+            a pointer to the array type.  We must allow this in order to
+            properly represent assigning the address of an array in C into
+            pointer to the element type.  */
          if (TREE_CODE (otype) == ARRAY_TYPE
              && POINTER_TYPE_P (ptype)
              && cpt_same_type (TREE_TYPE (otype), dtype))
@@ -3738,8 +4170,12 @@ gimplify_body (tree *body_p, tree fndecl)
   timevar_push (TV_TREE_GIMPLIFY);
   push_gimplify_context ();
 
-  /* Unshare most shared trees in the body.  */
-  unshare_all_trees (*body_p);
+  /* Unshare most shared trees in the body and in that of any nested functions.
+     It would seem we don't have to do this for nested functions because
+     they are supposed to be output and then the outer function gimplified
+     first, but the g++ front end doesn't always do it that way.  */
+  unshare_body (body_p, fndecl);
+  unvisit_body (body_p, fndecl);
 
   /* Make sure input_location isn't set to something wierd.  */
   input_location = DECL_SOURCE_LOCATION (fndecl);
@@ -3751,13 +4187,16 @@ gimplify_body (tree *body_p, tree fndecl)
   /* Unshare again, in case gimplification was sloppy.  */
   unshare_all_trees (body);
 
-  /* If there isn't an outer BIND_EXPR, add one.  */
-  if (TREE_CODE (body) == STATEMENT_LIST)
+  if (!body)
+    body = alloc_stmt_list ();
+  else if (TREE_CODE (body) == STATEMENT_LIST)
     {
       tree t = expr_only (*body_p);
       if (t)
        body = t;
     }
+
+  /* If there isn't an outer BIND_EXPR, add one.  */
   if (TREE_CODE (body) != BIND_EXPR)
     {
       tree b = build (BIND_EXPR, void_type_node, NULL_TREE,