OSDN Git Service

2004-08-17 Paul Brook <paul@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 308f3e9..21d8f45 100644 (file)
@@ -72,78 +72,15 @@ typedef struct gimple_temp_hash_elt
 } elt_t;
 
 /* Forward declarations.  */
-static hashval_t gimple_tree_hash (const void *);
-static int gimple_tree_eq (const void *, const void *);
-static bool gimple_conditional_context (void);
-static void gimple_push_condition (void);
-static void gimple_pop_condition (tree *);
-static void append_to_statement_list_1 (tree, tree *, bool);
-static inline void remove_suffix (char *, int);
-static inline tree create_tmp_from_val (tree);
-static tree lookup_tmp_var (tree, bool);
-static tree internal_get_tmp_var (tree, tree *, tree *, bool);
-static bool should_carry_locus_p (tree);
-static tree mostly_copy_tree_r (tree *, int *, void *);
-static tree mark_decls_volatile_r (tree *, int *, void *);
-static tree copy_if_shared_r (tree *, int *, void *);
-static tree unmark_visited_r (tree *, int *, void *);
-static void unshare_body (tree *, tree);
-static void unvisit_body (tree *, tree);
-static void build_stack_save_restore (tree *, tree *);
-static enum gimplify_status gimplify_bind_expr (tree *, tree, tree *);
-static enum gimplify_status gimplify_return_expr (tree, tree *);
-static enum gimplify_status gimplify_loop_expr (tree *, tree *);
-static int compare_case_labels (const void *, const void *);
-static enum gimplify_status gimplify_switch_expr (tree *, tree *);
-static enum gimplify_status gimplify_case_label_expr (tree *);
-static enum gimplify_status gimplify_labeled_block_expr (tree *);
-static enum gimplify_status gimplify_exit_block_expr (tree *);
-static enum gimplify_status gimplify_exit_expr (tree *);
-static enum gimplify_status gimplify_init_constructor (tree *, tree *, tree *,
-                                                      bool);
-static void canonicalize_component_ref (tree *);
-static void canonicalize_addr_expr (tree *);
-static enum gimplify_status gimplify_conversion (tree *);
-static enum gimplify_status gimplify_minimax_expr (tree *, tree *, tree *);
-static enum gimplify_status gimplify_array_ref_to_plus (tree *, tree *,
-                                                       tree *);
-static tree build_addr_expr_with_type (tree, tree);
-static tree build_addr_expr (tree);
-static enum gimplify_status gimplify_compound_lval (tree *, tree *, tree *,
-                                                   bool);
-static enum gimplify_status gimplify_self_mod_expr (tree *, tree *, tree *,
-                                                   bool);
-static enum gimplify_status gimplify_call_expr (tree *, tree *,
-                                               bool (*) (tree));
-static tree shortcut_cond_r (tree, tree *, tree *);
-static tree shortcut_cond_expr (tree);
-static tree gimple_boolify (tree);
-static enum gimplify_status gimplify_cond_expr (tree *, tree *, tree);
-static enum gimplify_status gimplify_modify_expr (tree *, tree *, tree *,
-                                                 bool);
-static enum gimplify_status gimplify_modify_expr_rhs (tree *, tree *, tree *,
-                                                     tree *, tree *, bool);
-static enum gimplify_status gimplify_variable_sized_compare (tree *);
-static enum gimplify_status gimplify_boolean_expr (tree *);
 static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
-static enum gimplify_status gimplify_statement_list (tree *);
-static enum gimplify_status gimplify_save_expr (tree *, tree *, tree *);
-static enum gimplify_status gimplify_addr_expr (tree *, tree *, tree *);
-static enum gimplify_status gimplify_asm_expr (tree *, tree *, tree *);
-static enum gimplify_status gimplify_cleanup_point_expr (tree *, tree *);
-static void gimple_push_cleanup (tree, tree, tree *);
-static enum gimplify_status gimplify_target_expr (tree *, tree *, tree *);
-#ifdef ENABLE_CHECKING
-static bool cpt_same_type (tree, tree);
-static tree check_pointer_types_r (tree *, int *, void *);
-#endif
+
 
 /* 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);
 }
 
@@ -152,8 +89,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
@@ -254,6 +191,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);
@@ -314,20 +252,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
@@ -355,6 +279,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;
@@ -372,6 +297,7 @@ create_tmp_var_name (const char *prefix)
   if (prefix)
     {
       char *preftmp = ASTRDUP (prefix);
+
       remove_suffix (preftmp, strlen (preftmp));
       prefix = preftmp;
     }
@@ -490,7 +416,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;
@@ -517,21 +444,20 @@ internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
   tree t, mod;
   char class;
 
-  gimplify_expr (&val, pre_p, post_p, is_gimple_rhs, fb_rvalue);
+  gimplify_expr (&val, pre_p, post_p, is_gimple_tmp_rhs, fb_rvalue);
 
   t = lookup_tmp_var (val, 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;
 }
 
@@ -550,18 +476,7 @@ get_initialized_tmp_var (tree val, tree *pre_p, tree *post_p)
   return internal_get_tmp_var (val, pre_p, post_p, false);
 }
 
-/*  Returns true if T is a GIMPLE temporary variable, false otherwise.  */
-
-bool
-is_gimple_tmp_var (tree t)
-{
-  /* FIXME this could trigger for other local artificials, too.  */
-  return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (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)
@@ -571,7 +486,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);
@@ -582,20 +497,17 @@ declare_tmp_vars (tree vars, tree scope)
       temps = nreverse (last);
       TREE_CHAIN (last) = BIND_EXPR_VARS (scope);
       BIND_EXPR_VARS (scope) = temps;
-
-      /* We don't add the temps to the block for this BIND_EXPR, as we're
-        not interested in debugging info for them.  */
     }
 }
 
 void
 gimple_add_tmp_var (tree tmp)
 {
-  if (TREE_CHAIN (tmp) || tmp->decl.seen_in_bind_expr)
+  if (TREE_CHAIN (tmp) || DECL_SEEN_IN_BIND_EXPR_P (tmp))
     abort ();
 
   DECL_CONTEXT (tmp) = current_function_decl;
-  tmp->decl.seen_in_bind_expr = 1;
+  DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1;
 
   if (gimplify_ctxp)
     {
@@ -632,7 +544,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
@@ -686,20 +598,6 @@ mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
   return NULL_TREE;
 }
 
-/* Mark all the _DECL nodes under *TP as volatile.  FIXME: This must die
-   after VA_ARG_EXPRs are properly lowered.  */
-
-static tree
-mark_decls_volatile_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-                      void *data ATTRIBUTE_UNUSED)
-{
-  if (SSA_VAR_P (*tp))
-    TREE_THIS_VOLATILE (*tp) = 1;
-
-  return NULL_TREE;
-}
-
-
 /* Callback for walk_tree to unshare most of the shared trees rooted at
    *TP.  If *TP has been visited already (i.e., TREE_VISITED (*TP) == 1),
    then *TP is deep copied by calling copy_tree_r.
@@ -730,19 +628,6 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
        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.  */
-  else if (code == BIND_EXPR)
-    {
-      if (TREE_VISITED (t))
-       abort ();
-      TREE_VISITED (t) = 1;
-      *walk_subtrees = 0;
-      walk_tree (&BIND_EXPR_BODY (t), copy_if_shared_r, NULL, NULL);
-    }
-
   /* If this node has been visited already, unshare it and don't look
      any deeper.  */
   else if (TREE_VISITED (t))
@@ -753,23 +638,7 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
 
   /* Otherwise, mark the tree as visited and keep looking.  */
   else
-    {
-      TREE_VISITED (t) = 1;
-      if (TREE_CODE (*tp) == VA_ARG_EXPR
-         && targetm.calls.gimplify_va_arg_expr == NULL)
-       {
-         /* Mark any _DECL inside the operand as volatile to avoid
-            the optimizers messing around with it. We have to do this
-            early, otherwise we might mark a variable as volatile
-            after we gimplify other statements that use the variable
-            assuming it's not volatile.  */
-
-         /* FIXME once most targets define the above hook, this should
-            go away (perhaps along with the #include "target.h").  */
-         walk_tree (&TREE_OPERAND (*tp, 0), mark_decls_volatile_r,
-                    NULL, NULL);
-       }
-    }
+    TREE_VISITED (t) = 1;
 
   return NULL_TREE;
 }
@@ -786,8 +655,9 @@ 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.  */
+/* Unshare all the trees in BODY_P, a pointer into the body of FNDECL, and the
+   bodies of any nested functions if we are unsharing the entire body of
+   FNDECL.  */
 
 static void
 unshare_body (tree *body_p, tree fndecl)
@@ -795,8 +665,9 @@ 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);
+  if (body_p == &DECL_SAVED_TREE (fndecl))
+    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.  */
@@ -807,8 +678,9 @@ 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);
+  if (body_p == &DECL_SAVED_TREE (fndecl))
+    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.  */
@@ -901,7 +773,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.  */
@@ -962,7 +835,7 @@ gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p)
 
   /* Mark variables seen in this bind expr.  */
   for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
-    t->decl.seen_in_bind_expr = 1;
+    DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
 
   gimple_push_bind_expr (bind_expr);
   gimplify_ctxp->save_stack = false;
@@ -1013,17 +886,18 @@ gimplify_return_expr (tree stmt, tree *pre_p)
   tree ret_expr = TREE_OPERAND (stmt, 0);
   tree result_decl, result;
 
-  if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
+  if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL
+      || ret_expr == error_mark_node)
     return GS_ALL_DONE;
 
-  if (ret_expr == error_mark_node)
-    return GS_ERROR;
-
   if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
     result_decl = NULL_TREE;
   else
     {
       result_decl = TREE_OPERAND (ret_expr, 0);
+      if (TREE_CODE (result_decl) == INDIRECT_REF)
+       /* See through a return by reference.  */
+       result_decl = TREE_OPERAND (result_decl, 0);
 #ifdef ENABLE_CHECKING
       if ((TREE_CODE (ret_expr) != MODIFY_EXPR
           && TREE_CODE (ret_expr) != INIT_EXPR)
@@ -1062,8 +936,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.  */
@@ -1076,6 +950,86 @@ 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, addr, ptr_type;
+
+         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);
+
+         /* All occurences of this decl in final gimplified code will be
+            replaced by indirection.  Setting DECL_VALUE_EXPR does two
+            things: First, it lets the rest of the gimplifier know what
+            replacement to use.  Second, it lets the debug info know 
+            where to find the value.  */
+         ptr_type = build_pointer_type (TREE_TYPE (decl));
+         addr = create_tmp_var (ptr_type, get_name (decl));
+         DECL_IGNORED_P (addr) = 0;
+         t = build_fold_indirect_ref (addr);
+         DECL_VALUE_EXPR (decl) = t;
+
+         args = tree_cons (NULL, DECL_SIZE_UNIT (decl), NULL);
+         t = built_in_decls[BUILT_IN_ALLOCA];
+         t = build_function_call_expr (t, args);
+         t = fold_convert (ptr_type, t);
+         t = build2 (MODIFY_EXPR, void_type_node, addr, t);
+
+         gimplify_and_add (t, stmt_p);
+
+         /* Indicate that we need to restore the stack level when the
+            enclosing BIND_EXPR is exited.  */
+         gimplify_ctxp->save_stack = true;
+       }
+
+      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.  */
@@ -1091,8 +1045,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)
     {
@@ -1120,7 +1073,7 @@ compare_case_labels (const void *p1, const void *p2)
   return tree_int_cst_compare (CASE_LOW (case1), CASE_LOW (case2));
 }
 
-/* Sort the case labels in LABEL_VEC in ascending order.  */
+/* Sort the case labels in LABEL_VEC in place in ascending order.  */
 
 void
 sort_case_labels (tree label_vec)
@@ -1330,387 +1283,105 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
   return NULL_TREE;
 }
 
-/* Break out elements of a constructor used as an initializer into separate
-   MODIFY_EXPRs.
+/* *EXPR_P is a COMPONENT_REF being used as an rvalue.  If its type is
+   different from its canonical type, wrap the whole thing inside a
+   NOP_EXPR and force the type of the COMPONENT_REF to be the canonical
+   type.
 
-   Note that we still need to clear any elements that don't have explicit
-   initializers, so if not all elements are initialized we keep the
-   original MODIFY_EXPR, we just remove all of the constructor elements.  */
+   The canonical type of a COMPONENT_REF is the type of the field being
+   referenced--unless the field is a bit-field which can be read directly
+   in a smaller mode, in which case the canonical type is the
+   sign-appropriate type corresponding to that mode.  */
 
-static enum gimplify_status
-gimplify_init_constructor (tree *expr_p, tree *pre_p,
-                          tree *post_p, bool want_value)
+static void
+canonicalize_component_ref (tree *expr_p)
 {
-  tree object = TREE_OPERAND (*expr_p, 0);
-  tree ctor = TREE_OPERAND (*expr_p, 1);
-  tree type = TREE_TYPE (ctor);
-  enum gimplify_status ret;
-  tree elt_list;
+  tree expr = *expr_p;
+  tree type;
 
-  if (TREE_CODE (ctor) != CONSTRUCTOR)
-    return GS_UNHANDLED;
+  if (TREE_CODE (expr) != COMPONENT_REF)
+    abort ();
 
-  elt_list = CONSTRUCTOR_ELTS (ctor);
+  if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+    type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
+  else
+    type = TREE_TYPE (TREE_OPERAND (expr, 1));
 
-  ret = GS_ALL_DONE;
-  switch (TREE_CODE (type))
+  if (TREE_TYPE (expr) != type)
     {
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-    case ARRAY_TYPE:
-      {
-       HOST_WIDE_INT i, num_elements, num_nonzero_elements;
-       HOST_WIDE_INT num_nonconstant_elements;
-       bool cleared;
+      tree old_type = TREE_TYPE (expr);
 
-       /* Aggregate types must lower constructors to initialization of
-          individual elements.  The exception is that a CONSTRUCTOR node
-          with no elements indicates zero-initialization of the whole.  */
-       if (elt_list == NULL)
-         {
-           if (want_value)
-             {
-               *expr_p = object;
-               return GS_OK;
-             }
-           else
-             return GS_UNHANDLED;
-         }
+      /* Set the type of the COMPONENT_REF to the underlying type.  */
+      TREE_TYPE (expr) = type;
 
-       categorize_ctor_elements (ctor, &num_nonzero_elements,
-                                 &num_nonconstant_elements);
-       num_elements = count_type_elements (TREE_TYPE (ctor));
+      /* And wrap the whole thing inside a NOP_EXPR.  */
+      expr = build1 (NOP_EXPR, old_type, expr);
 
-       /* If a const aggregate variable is being initialized, then it
-          should never be a lose to promote the variable to be static.  */
-       if (num_nonconstant_elements == 0
-           && TREE_READONLY (object)
-           && TREE_CODE (object) == VAR_DECL)
-         {
-           DECL_INITIAL (object) = ctor;
-           TREE_STATIC (object) = 1;
-           if (!DECL_NAME (object))
-             DECL_NAME (object) = create_tmp_var_name ("C");
-           walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL);
+      *expr_p = expr;
+    }
+}
 
-           /* ??? C++ doesn't automatically append a .<number> to the
-              assembler name, and even when it does, it looks a FE private
-              data structures to figure out what that number should be,
-              which are not set for this variable.  I suppose this is
-              important for local statics for inline functions, which aren't
-              "local" in the object file sense.  So in order to get a unique
-              TU-local symbol, we must invoke the lhd version now.  */
-           lhd_set_decl_assembler_name (object);
+/* If a NOP conversion is changing a pointer to array of foo to a pointer
+   to foo, embed that change in the ADDR_EXPR by converting 
+      T array[U];
+      (T *)&array
+   ==>
+      &array[L]
+   where L is the lower bound.  For simplicity, only do this for constant
+   lower bound.  */
 
-           *expr_p = NULL_TREE;
-           break;
-         }
+static void
+canonicalize_addr_expr (tree *expr_p)
+{
+  tree expr = *expr_p;
+  tree ctype = TREE_TYPE (expr);
+  tree addr_expr = TREE_OPERAND (expr, 0);
+  tree atype = TREE_TYPE (addr_expr);
+  tree dctype, datype, ddatype, otype, obj_expr;
 
-       /* If there are "lots" of initialized elements, and all of them
-          are valid address constants, then the entire initializer can
-          be dropped to memory, and then memcpy'd out.  */
-       if (num_nonconstant_elements == 0)
-         {
-           HOST_WIDE_INT size = int_size_in_bytes (type);
-           unsigned int align;
+  /* Both cast and addr_expr types should be pointers.  */
+  if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
+    return;
 
-           /* ??? We can still get unbounded array types, at least
-              from the C++ front end.  This seems wrong, but attempt
-              to work around it for now.  */
-           if (size < 0)
-             {
-               size = int_size_in_bytes (TREE_TYPE (object));
-               if (size >= 0)
-                 TREE_TYPE (ctor) = type = TREE_TYPE (object);
-             }
+  /* The addr_expr type should be a pointer to an array.  */
+  datype = TREE_TYPE (atype);
+  if (TREE_CODE (datype) != ARRAY_TYPE)
+    return;
 
-           /* Find the maximum alignment we can assume for the object.  */
-           /* ??? Make use of DECL_OFFSET_ALIGN.  */
-           if (DECL_P (object))
-             align = DECL_ALIGN (object);
-           else
-             align = TYPE_ALIGN (type);
+  /* Both cast and addr_expr types should address the same object type.  */
+  dctype = TREE_TYPE (ctype);
+  ddatype = TREE_TYPE (datype);
+  if (!lang_hooks.types_compatible_p (ddatype, dctype))
+    return;
 
-           if (size > 0 && !can_move_by_pieces (size, align))
-             {
-               tree new = create_tmp_var_raw (type, "C");
-               gimple_add_tmp_var (new);
-               TREE_STATIC (new) = 1;
-               TREE_READONLY (new) = 1;
-               DECL_INITIAL (new) = ctor;
-               if (align > DECL_ALIGN (new))
-                 {
-                   DECL_ALIGN (new) = align;
-                   DECL_USER_ALIGN (new) = 1;
-                 }
-               walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
+  /* The addr_expr and the object type should match.  */
+  obj_expr = TREE_OPERAND (addr_expr, 0);
+  otype = TREE_TYPE (obj_expr);
+  if (!lang_hooks.types_compatible_p (otype, datype))
+    return;
 
-               TREE_OPERAND (*expr_p, 1) = new;
-               break;
-             }
-         }
+  /* The lower bound and element sizes must be constant.  */
+  if (TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
+      || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
+      || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
+    return;
 
-       /* If there are "lots" of initialized elements, even discounting
-          those that are not address constants (and thus *must* be 
-          computed at runtime), then partition the constructor into
-          constant and non-constant parts.  Block copy the constant
-          parts in, then generate code for the non-constant parts.  */
-       /* TODO.  There's code in cp/typeck.c to do this.  */
+  /* All checks succeeded.  Build a new node to merge the cast.  */
+  *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
+                   TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+                   TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+                   size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
+                               size_int (TYPE_ALIGN (dctype)
+                                         / BITS_PER_UNIT)));
+  *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
+}
 
-       /* If there are "lots" of zeros, then block clear the object first.  */
-       cleared = false;
-       if (num_elements - num_nonzero_elements > CLEAR_RATIO
-           && num_nonzero_elements < num_elements/4)
-         cleared = true;
-
-       /* ??? 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, 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_stmt (&init);
-           append_to_statement_list (init, pre_p);
-         }
-
-       *expr_p = NULL_TREE;
-      }
-      break;
-
-    case COMPLEX_TYPE:
-      {
-       tree r, i;
-
-       /* Extract the real and imaginary parts out of the ctor.  */
-       r = i = NULL_TREE;
-       if (elt_list)
-         {
-           r = TREE_VALUE (elt_list);
-           elt_list = TREE_CHAIN (elt_list);
-           if (elt_list)
-             {
-               i = TREE_VALUE (elt_list);
-               if (TREE_CHAIN (elt_list))
-                 abort ();
-             }
-         }
-       if (r == NULL || i == NULL)
-         {
-           tree zero = convert (TREE_TYPE (type), integer_zero_node);
-           if (r == NULL)
-             r = zero;
-           if (i == NULL)
-             i = zero;
-         }
-
-       /* Complex types have either COMPLEX_CST or COMPLEX_EXPR to
-          represent creation of a complex value.  */
-       if (TREE_CONSTANT (r) && TREE_CONSTANT (i))
-         {
-           ctor = build_complex (type, r, i);
-           TREE_OPERAND (*expr_p, 1) = ctor;
-         }
-       else
-         {
-           ctor = build (COMPLEX_EXPR, type, r, i);
-           TREE_OPERAND (*expr_p, 1) = ctor;
-           ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
-                                is_gimple_rhs, fb_rvalue);
-         }
-      }
-      break;
-
-    case VECTOR_TYPE:
-      /* Go ahead and simplify constant constructors to VECTOR_CST.  */
-      if (TREE_CONSTANT (ctor))
-       TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
-      else
-       {
-         /* Vector types use CONSTRUCTOR all the way through gimple
-            compilation as a general initializer.  */
-         for (; elt_list; elt_list = TREE_CHAIN (elt_list))
-           {
-             enum gimplify_status tret;
-             tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
-                                   is_gimple_constructor_elt, fb_rvalue);
-             if (tret == GS_ERROR)
-               ret = GS_ERROR;
-           }
-       }
-      break;
-
-    default:
-      /* So how did we get a CONSTRUCTOR for a scalar type?  */
-      abort ();
-    }
-
-  if (ret == GS_ERROR)
-    return GS_ERROR;
-  else if (want_value)
-    {
-      append_to_statement_list (*expr_p, pre_p);
-      *expr_p = object;
-      return GS_OK;
-    }
-  else
-    return GS_ALL_DONE;
-}
-
-/* *EXPR_P is a COMPONENT_REF being used as an rvalue.  If its type is
-   different from its canonical type, wrap the whole thing inside a
-   NOP_EXPR and force the type of the COMPONENT_REF to be the canonical
-   type.
-
-   The canonical type of a COMPONENT_REF is the type of the field being
-   referenced--unless the field is a bit-field which can be read directly
-   in a smaller mode, in which case the canonical type is the
-   sign-appropriate type corresponding to that mode.  */
-
-static void
-canonicalize_component_ref (tree *expr_p)
-{
-  tree expr = *expr_p;
-  tree type;
-
-  if (TREE_CODE (expr) != COMPONENT_REF)
-    abort ();
-
-  if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
-    type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
-  else
-    type = TREE_TYPE (TREE_OPERAND (expr, 1));
-
-  if (TREE_TYPE (expr) != type)
-    {
-      tree old_type = TREE_TYPE (expr);
-
-      /* Set the type of the COMPONENT_REF to the underlying type.  */
-      TREE_TYPE (expr) = type;
-
-      /* And wrap the whole thing inside a NOP_EXPR.  */
-      expr = build1 (NOP_EXPR, old_type, expr);
-
-      *expr_p = expr;
-    }
-}
-
-/* If a NOP conversion is changing a pointer to array of foo to a pointer
-   to foo, embed that change in the ADDR_EXPR by converting 
-      T array[U];
-      (T *)&array
-   ==>
-      &array[L]
-   where L is the lower bound.  Only do this for constant lower bound since
-   we have no place to put any statements made during gimplification of
-   the lower bound.  */
-
-static void
-canonicalize_addr_expr (tree *expr_p)
-{
-  tree expr = *expr_p;
-  tree ctype = TREE_TYPE (expr);
-  tree addr_expr = TREE_OPERAND (expr, 0);
-  tree atype = TREE_TYPE (addr_expr);
-  tree dctype, datype, ddatype, otype, obj_expr;
-
-  /* Both cast and addr_expr types should be pointers.  */
-  if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
-    return;
-
-  /* The addr_expr type should be a pointer to an array.  */
-  datype = TREE_TYPE (atype);
-  if (TREE_CODE (datype) != ARRAY_TYPE)
-    return;
-
-  /* Both cast and addr_expr types should address the same object type.  */
-  dctype = TREE_TYPE (ctype);
-  ddatype = TREE_TYPE (datype);
-  if (!lang_hooks.types_compatible_p (ddatype, dctype))
-    return;
-
-  /* The addr_expr and the object type should match.  */
-  obj_expr = TREE_OPERAND (addr_expr, 0);
-  otype = TREE_TYPE (obj_expr);
-  if (!lang_hooks.types_compatible_p (otype, datype))
-    return;
-
-  /* The lower bound and element sizes must be constant.  */
-  if (TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
-      || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
-      || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
-    return;
-
-  /* All checks succeeded.  Build a new node to merge the cast.  */
-  *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
-                   TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
-                   TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
-                   size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
-                               size_int (TYPE_ALIGN (dctype)
-                                         / BITS_PER_UNIT)));
-  *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
-}
-
-/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
-   underneath as appropriate.  */
+/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
+   underneath as appropriate.  */
 
 static enum gimplify_status
 gimplify_conversion (tree *expr_p)
 {  
-  /* Strip away as many useless type conversions as possible
-     at the toplevel.  */
-  STRIP_USELESS_TYPE_CONVERSION (*expr_p);
-
   /* If we still have a conversion at the toplevel, then strip
      away all but the outermost conversion.  */
   if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
@@ -1824,44 +1495,6 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
   return GS_OK;
 }
 
-/*  Build an expression for the address of T.  Folds away INDIRECT_REF to
-    avoid confusing the gimplify process.  */
-
-static tree
-build_addr_expr_with_type (tree t, tree ptrtype)
-{
-  if (TREE_CODE (t) == INDIRECT_REF)
-    {
-      t = TREE_OPERAND (t, 0);
-      if (TREE_TYPE (t) != ptrtype)
-       t = build1 (NOP_EXPR, ptrtype, t);
-    }
-  else
-    {
-      tree base = t;
-
-      if (TREE_CODE (base) == REALPART_EXPR
-         || TREE_CODE (base) == IMAGPART_EXPR)
-       base = TREE_OPERAND (base, 0);
-      else
-       while (handled_component_p (base))
-         base = TREE_OPERAND (base, 0);
-
-      if (DECL_P (base))
-       TREE_ADDRESSABLE (base) = 1;
-
-      t = build1 (ADDR_EXPR, ptrtype, t);
-    }
-
-  return t;
-}
-
-static tree
-build_addr_expr (tree t)
-{
-  return build_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
-}
-
 /* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
    node pointed by EXPR_P.
 
@@ -1886,63 +1519,48 @@ build_addr_expr (tree t)
 
 static enum gimplify_status
 gimplify_compound_lval (tree *expr_p, tree *pre_p,
-                       tree *post_p, bool want_lvalue)
+                       tree *post_p, fallback_t fallback)
 {
   tree *p;
   varray_type stack;
   enum gimplify_status ret = GS_OK, tret;
-
-#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
+  int i;
 
   /* 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 one REALPART_EXPR or IMAGEPART_EXPR or
-     nest of handled components.  */
-  if (TREE_CODE (*expr_p) == REALPART_EXPR
-      || TREE_CODE (*expr_p) == IMAGPART_EXPR)
-    p = &TREE_OPERAND (*expr_p, 0);
-  else
-    for (p = expr_p; handled_component_p (*p); p = &TREE_OPERAND (*p, 0))
-      VARRAY_PUSH_TREE (stack, *p);
+  /* We can either handle REALPART_EXPR, IMAGEPART_EXPR anything that
+     handled_components can deal with.  */
+  for (p = expr_p;
+       (handled_component_p (*p)
+       || TREE_CODE (*p) == REALPART_EXPR || TREE_CODE (*p) == IMAGPART_EXPR);
+       p = &TREE_OPERAND (*p, 0))
+    VARRAY_PUSH_TREE (stack, *p);
+
+#if defined ENABLE_CHECKING
+  if (VARRAY_ACTIVE_SIZE (stack) == 0)
+    abort ();
+#endif
 
   /* Now STACK is a stack of pointers to all the refs we've walked through
      and P points to the innermost expression.
 
-     Process each of the outer nodes from left to right, then gimplify the
-     base.  We need to do it in this order so that PLACEHOLDER_EXPRs
-     can be resolved.  */
-  for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
+     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--)
     {
-      tree t = VARRAY_TOP_TREE (stack);
+      tree t = VARRAY_TREE (stack, i);
 
       if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
        {
-         /* 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
-            expressions into a minimal gimple lvalue.  However, that
-            exposes bugs in alias analysis.  The alias analyzer does
-            not handle &PTR->FIELD very well.  Will fix after the
-            branch is merged into mainline (dnovillo 2004-05-03).  */
-         if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)))
-           {
-             tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
-                                   is_gimple_tmp_var, fb_rvalue);
-             ret = MIN (ret, tret);
-           }
-
          /* 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.  */
@@ -1953,7 +1571,7 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
                {
                  TREE_OPERAND (t, 2) = low;
                  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
-                                       is_gimple_tmp_var, fb_rvalue);
+                                       is_gimple_tmp_reg, fb_rvalue);
                  ret = MIN (ret, tret);
                }
            }
@@ -1972,7 +1590,7 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
                {
                  TREE_OPERAND (t, 3) = elmt_size;
                  tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
-                                       is_gimple_tmp_var, fb_rvalue);
+                                       is_gimple_tmp_reg, fb_rvalue);
                  ret = MIN (ret, tret);
                }
            }
@@ -1994,31 +1612,65 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
                {
                  TREE_OPERAND (t, 2) = offset;
                  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
-                                       is_gimple_tmp_var, fb_rvalue);
+                                       is_gimple_tmp_reg, fb_rvalue);
                  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);
+    }
+
+  /* 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.  During this
+     loop we also remove any useless conversions.  */
+  for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
+    {
+      tree t = VARRAY_TOP_TREE (stack);
+
+      if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
+       {
+         /* 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
+            expressions into a minimal gimple lvalue.  However, that
+            exposes bugs in alias analysis.  The alias analyzer does
+            not handle &PTR->FIELD very well.  Will fix after the
+            branch is merged into mainline (dnovillo 2004-05-03).  */
+         if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)))
+           {
+             tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
+                                   is_gimple_tmp_reg, fb_rvalue);
+             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);
        }
-         
+
+      STRIP_USELESS_TYPE_CONVERSION (TREE_OPERAND (t, 0));
+
+      /* 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,
-                       want_lvalue ? fb_lvalue : fb_rvalue);
+  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);
@@ -2095,8 +1747,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;
     }
@@ -2107,20 +1758,66 @@ gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
     }
 }
 
-/*  Gimplify the CALL_EXPR node pointed by EXPR_P.
+/* If *EXPR_P has a variable sized type, wrap it in a WITH_SIZE_EXPR.  */
+
+static void
+maybe_with_size_expr (tree *expr_p)
+{
+  tree expr = *expr_p;
+  tree type = TREE_TYPE (expr);
+  tree size;
+
+  /* If we've already wrapped this or the type is error_mark_node, we can't do
+     anything.  */
+  if (TREE_CODE (expr) == WITH_SIZE_EXPR
+      || type == error_mark_node)
+    return;
 
-      call_expr
-             : ID '(' arglist ')'
+  /* If the size isn't known or is a constant, we have nothing to do.  */
+  size = TYPE_SIZE_UNIT (type);
+  if (!size || TREE_CODE (size) == INTEGER_CST)
+    return;
 
-      arglist
-             : arglist ',' val
-             | val
+  /* Otherwise, make a WITH_SIZE_EXPR.  */
+  size = unshare_expr (size);
+  size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, expr);
+  *expr_p = build2 (WITH_SIZE_EXPR, type, expr, size);
+}
 
-    PRE_P points to the list where side effects that must happen before
-       *EXPR_P should be stored.  */
+/* Subroutine of gimplify_call_expr:  Gimplify a single argument.  */
 
 static enum gimplify_status
-gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
+gimplify_arg (tree *expr_p, tree *pre_p)
+{
+  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 (*expr_p)))
+    test = is_gimple_val, fb = fb_rvalue;
+  else
+    test = is_gimple_lvalue, fb = fb_either;
+
+  /* If this is a variable sized type, we must remember the size.  */
+  maybe_with_size_expr (expr_p);
+
+  /* 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.  */
+  return gimplify_expr (expr_p, pre_p, NULL, test, fb);
+}
+
+/* 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 want_value)
 {
   tree decl;
   tree arglist;
@@ -2133,8 +1830,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.
 
@@ -2151,20 +1848,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
   decl = get_callee_fndecl (*expr_p);
   if (decl && DECL_BUILT_IN (decl))
     {
-      tree new;
-
-      /* If it is allocation of stack, record the need to restore the memory
-        when the enclosing bind_expr is exited.  */
-      if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_ALLOC)
-       gimplify_ctxp->save_stack = true;
-
-      /* If it is restore of the stack, reset it, since it means we are
-        regimplifying the bind_expr.  Note that we use the fact that
-        for try_finally_expr, try part is processed first.  */
-      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);
+      tree new = simplify_builtin (*expr_p, !want_value);
 
       if (new && new != *expr_p)
        {
@@ -2174,6 +1858,11 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
          *expr_p = new;
          return GS_OK;
        }
+
+      if (DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
+       /* Avoid gimplifying the second argument to va_start, which needs
+          to be the plain PARM_DECL.  */
+       return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
     }
 
   /* There is a sequence point before the call, so any side effects in
@@ -2189,12 +1878,7 @@ gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
     {
       enum gimplify_status t;
 
-      /* 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_arg (&TREE_VALUE (arglist), pre_p);
 
       if (t == GS_ERROR)
        ret = GS_ERROR;
@@ -2205,7 +1889,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)
        {
@@ -2511,107 +2195,667 @@ static enum gimplify_status
 gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
 {
   tree expr = *expr_p;
-  tree tmp;
+  tree tmp, tmp2, 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.  */
-  if (! VOID_TYPE_P (TREE_TYPE (expr)))
+  else if (! VOID_TYPE_P (type))
     {
       if (target)
        {
+         ret = gimplify_expr (&target, pre_p, NULL,
+                              is_gimple_min_lval, fb_lvalue);
+         if (ret != GS_ERROR)
+           ret = GS_OK;
          tmp = target;
-         ret = GS_OK;
+         tmp2 = unshare_expr (target);
        }
       else
        {
-         tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+         tmp2 = 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_stmt (&expr);
-      append_to_statement_list (expr, pre_p);
-      *expr_p = tmp;
+      /* 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, tmp2, TREE_OPERAND (expr, 2));
+
+      TREE_TYPE (expr) = void_type_node;
+      recalculate_side_effects (expr);
+
+      /* Move the COND_EXPR to the prequeue.  */
+      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, tree size, bool want_value)
+{
+  tree args, t, to, to_ptr, from;
+
+  to = TREE_OPERAND (*expr_p, 0);
+  from = TREE_OPERAND (*expr_p, 1);
+
+  args = tree_cons (NULL, size, 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, tree size, bool want_value)
+{
+  tree args, t, to, to_ptr;
+
+  to = TREE_OPERAND (*expr_p, 0);
+
+  args = tree_cons (NULL, size, NULL);
+
+  args = tree_cons (NULL, integer_zero_node, args);
+
+  to_ptr = build_fold_addr_expr (to);
+  args = tree_cons (NULL, to_ptr, 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_init_ctor_preeval.  Called via walk_tree,
+   determine, cautiously, if a CONSTRUCTOR overlaps the lhs of an
+   assignment.  Returns non-null if we detect a potential overlap.  */
+
+struct gimplify_init_ctor_preeval_data
+{
+  /* The base decl of the lhs object.  May be NULL, in which case we
+     have to assume the lhs is indirect.  */
+  tree lhs_base_decl;
+
+  /* The alias set of the lhs object.  */
+  int lhs_alias_set;
+};
+
+static tree
+gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata)
+{
+  struct gimplify_init_ctor_preeval_data *data
+    = (struct gimplify_init_ctor_preeval_data *) xdata;
+  tree t = *tp;
+
+  /* If we find the base object, obviously we have overlap.  */
+  if (data->lhs_base_decl == t)
+    return t;
+
+  /* If the constructor component is indirect, determine if we have a
+     potential overlap with the lhs.  The only bits of information we
+     have to go on at this point are addressability and alias sets.  */
+  if (TREE_CODE (t) == INDIRECT_REF
+      && (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl))
+      && alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t)))
+    return t;
+
+  if (DECL_P (t) || TYPE_P (t))
+    *walk_subtrees = 0;
+  return NULL;
+}
+
+/* A subroutine of gimplify_init_constructor.  Pre-evaluate *EXPR_P,
+   force values that overlap with the lhs (as described by *DATA)
+   into temporaries.  */
+
+static void
+gimplify_init_ctor_preeval (tree *expr_p, tree *pre_p, tree *post_p,
+                           struct gimplify_init_ctor_preeval_data *data)
+{
+  enum gimplify_status one;
+
+  /* If the value is invariant, then there's nothing to pre-evaluate.
+     But ensure it doesn't have any side-effects since a SAVE_EXPR is
+     invariant but has side effects and might contain a reference to
+     the object we're initializing.  */
+  if (TREE_INVARIANT (*expr_p) && !TREE_SIDE_EFFECTS (*expr_p))
+    return;
+
+  /* If the type has non-trivial constructors, we can't pre-evaluate.  */
+  if (TREE_ADDRESSABLE (TREE_TYPE (*expr_p)))
+    return;
+
+  /* Recurse for nested constructors.  */
+  if (TREE_CODE (*expr_p) == CONSTRUCTOR)
+    {
+      tree list;
+      for (list = CONSTRUCTOR_ELTS (*expr_p); list ; list = TREE_CHAIN (list))
+       gimplify_init_ctor_preeval (&TREE_VALUE (list), pre_p, post_p, data);
+      return;
+    }
+
+  /* We can't preevaluate if the type contains a placeholder.  */
+  if (type_contains_placeholder_p (TREE_TYPE (*expr_p)))
+    return;
+
+  /* Gimplify the constructor element to something appropriate for the rhs
+     of a MODIFY_EXPR.  Given that we know the lhs is an aggregate, we know
+     the gimplifier will consider this a store to memory.  Doing this 
+     gimplification now means that we won't have to deal with complicated
+     language-specific trees, nor trees like SAVE_EXPR that can induce
+     exponential search behaviour.  */
+  one = gimplify_expr (expr_p, pre_p, post_p, is_gimple_mem_rhs, fb_rvalue);
+  if (one == GS_ERROR)
+    {
+      *expr_p = NULL;
+      return;
+    }
+
+  /* If we gimplified to a bare decl, we can be sure that it doesn't overlap
+     with the lhs, since "a = { .x=a }" doesn't make sense.  This will
+     always be true for all scalars, since is_gimple_mem_rhs insists on a
+     temporary variable for them.  */
+  if (DECL_P (*expr_p))
+    return;
+
+  /* If this is of variable size, we have no choice but to assume it doesn't
+     overlap since we can't make a temporary for it.  */
+  if (!TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (*expr_p))))
+    return;
+
+  /* Otherwise, we must search for overlap ...  */
+  if (!walk_tree (expr_p, gimplify_init_ctor_preeval_1, data, NULL))
+    return;
+
+  /* ... and if found, force the value into a temporary.  */
+  *expr_p = get_formal_tmp_var (*expr_p, pre_p);
+}
+
+/* A subroutine of gimplify_init_constructor.  Generate individual
+   MODIFY_EXPRs for a CONSTRUCTOR.  OBJECT is the LHS against which the
+   assignments should happen.  LIST is the CONSTRUCTOR_ELTS of the
+   CONSTRUCTOR.  CLEARED is true if the entire LHS object has been
+   zeroed first.  */
+
+static void
+gimplify_init_ctor_eval (tree object, tree list, tree *pre_p, bool cleared)
+{
+  tree array_elt_type = NULL;
+
+  if (TREE_CODE (TREE_TYPE (object)) == ARRAY_TYPE)
+    array_elt_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
+
+  for (; list; list = TREE_CHAIN (list))
+    {
+      tree purpose, value, cref, init;
+
+      purpose = TREE_PURPOSE (list);
+      value = TREE_VALUE (list);
+
+      /* NULL values are created above for gimplification errors.  */
+      if (value == NULL)
+       continue;
+
+      if (cleared && initializer_zerop (value))
+       continue;
+
+      if (array_elt_type)
+       {
+         /* ??? 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, array_elt_type, unshare_expr (object),
+                       purpose, NULL_TREE, NULL_TREE);
+       }
+      else
+       cref = build (COMPONENT_REF, TREE_TYPE (purpose),
+                     unshare_expr (object), purpose, NULL_TREE);
+
+      if (TREE_CODE (value) == CONSTRUCTOR)
+       gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
+                                pre_p, cleared);
+      else
+       {
+         init = build (MODIFY_EXPR, TREE_TYPE (cref), cref, value);
+         gimplify_and_add (init, pre_p);
+       }
+    }
+}
+
+/* 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 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;
+
+  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                      is_gimple_lvalue, fb_lvalue);
+  if (ret == GS_ERROR)
+    return ret;
+  object = TREE_OPERAND (*expr_p, 0);
+
+  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:
+      {
+       struct gimplify_init_ctor_preeval_data preeval_data;
+       HOST_WIDE_INT 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)
+         break;
+
+       categorize_ctor_elements (ctor, &num_nonzero_elements,
+                                 &num_nonconstant_elements);
+
+       /* 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;
+
+               /* This is no longer an assignment of a CONSTRUCTOR, but
+                  we still may have processing to do on the LHS.  So
+                  pretend we didn't do anything here to let that happen.  */
+               return GS_UNHANDLED;
+             }
+         }
+
+       /* 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.  */
+
+       num_elements = count_type_elements (TREE_TYPE (ctor));
+
+       /* 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) + 1 != len)
+                 cleared = true;
+             }
+           else if (len != fields_length (type))
+             cleared = true;
+         }
+
+       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.  Avoid shared tree structures.  */
+           CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
+           object = unshare_expr (object);
+           gimplify_stmt (expr_p);
+           append_to_statement_list (*expr_p, pre_p);
+         }
+
+       preeval_data.lhs_base_decl = get_base_address (object);
+       if (!DECL_P (preeval_data.lhs_base_decl))
+         preeval_data.lhs_base_decl = NULL;
+       preeval_data.lhs_alias_set = get_alias_set (object);
+
+       gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1),
+                                   pre_p, post_p, &preeval_data);
+       gimplify_init_ctor_eval (object, elt_list, pre_p, cleared);
+
+       *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_tmp_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 ();
+    }
 
-      return ret;
+  if (ret == GS_ERROR)
+    return GS_ERROR;
+  else if (want_value)
+    {
+      append_to_statement_list (*expr_p, pre_p);
+      *expr_p = object;
+      return GS_OK;
     }
+  else
+    return GS_ALL_DONE;
+}
 
-  /* Make sure the condition has BOOLEAN_TYPE.  */
-  TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+/* Subroutine of gimplify_modify_expr to do simplifications of MODIFY_EXPRs
+   based on the code of the RHS.  We loop for as long as something changes.  */
 
-  /* Break apart && and || conditions.  */
-  if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
-      || TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
-    {
-      expr = shortcut_cond_expr (expr);
+static enum gimplify_status
+gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
+                         tree *post_p, bool want_value)
+{
+  enum gimplify_status ret = GS_OK;
 
-      if (expr != *expr_p)
+  while (ret != GS_UNHANDLED)
+    switch (TREE_CODE (*from_p))
+      {
+      case TARGET_EXPR:
        {
-         *expr_p = expr;
+         /* If we are initializing something from a TARGET_EXPR, strip the
+            TARGET_EXPR and initialize it directly, if possible.  This can't
+            be done if the initializer is void, since that implies that the
+            temporary is set in some non-trivial way.
 
-         /* We can't rely on gimplify_expr to re-gimplify the expanded
-            form properly, as cleanups might cause the target labels to be
-            wrapped in a TRY_FINALLY_EXPR.  To prevent that, we need to
-            set up a conditional context.  */
-         gimple_push_condition ();
-         gimplify_stmt (expr_p);
-         gimple_pop_condition (pre_p);
+            ??? What about code that pulls out the temp and uses it
+            elsewhere? I think that such code never uses the TARGET_EXPR as
+            an initializer.  If I'm wrong, we'll abort because the temp won't
+            have any RTL.  In that case, I guess we'll need to replace
+            references somehow.  */
+         tree init = TARGET_EXPR_INITIAL (*from_p);
 
-         return GS_ALL_DONE;
+         if (!VOID_TYPE_P (TREE_TYPE (init)))
+           {
+             *from_p = init;
+             ret = GS_OK;
+           }
+         else
+           ret = GS_UNHANDLED;
        }
-    }
-
-  /* Now do the normal gimplification.  */
-  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
-                      is_gimple_condexpr, fb_rvalue);
-
-  gimple_push_condition ();
+       break;
 
-  gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
-  gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
-  recalculate_side_effects (expr);
+      case COMPOUND_EXPR:
+       /* Remove any COMPOUND_EXPR in the RHS so the following cases will be
+          caught.  */
+       gimplify_compound_expr (from_p, pre_p, true);
+       ret = GS_OK;
+       break;
 
-  gimple_pop_condition (pre_p);
+      case CONSTRUCTOR:
+       /* If we're initializing from a CONSTRUCTOR, break this into
+          individual MODIFY_EXPRs.  */
+       return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
 
-  if (ret == GS_ERROR)
-    ;
-  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
-    ret = GS_ALL_DONE;
-  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
-    /* Rewrite "if (a); else b" to "if (!a) b"  */
-    {
-      TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
-      ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
-                          is_gimple_condexpr, fb_rvalue);
+      case COND_EXPR:
+       /* If we're assigning to a non-register type, push the assignment
+          down into the branches.  This is mandatory for ADDRESSABLE types,
+          since we cannot generate temporaries for such, but it saves a 
+          copy in other cases as well.  */
+       if (!is_gimple_reg_type (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
@@ -2648,39 +2892,20 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   if (ret != GS_UNHANDLED)
     return ret;
 
-  /* If the value being copied is of variable width, expose the length
-     if the copy by converting the whole thing to a memcpy.  Note that
-     we need to do this before gimplifying any of the operands
-     so that we can resolve any PLACEHOLDER_EXPRs in the size.  */
-  if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST)
-    {
-      tree args, t, dest;
-
-      t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
-      t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *to_p);
-      t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *from_p);
-      t = unshare_expr (t);
-      args = tree_cons (NULL, t, NULL);
-      t = build_fold_addr_expr (*from_p);
-      args = tree_cons (NULL, t, args);
-      dest = build_fold_addr_expr (*to_p);
-      args = tree_cons (NULL, dest, args);
-      t = implicit_built_in_decls[BUILT_IN_MEMCPY];
-      t = build_function_call_expr (t, args);
-      if (want_value)
-       {
-         t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
-         t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
-       }
-      *expr_p = t;
-      return GS_OK;
-    }
+  /* If the value being copied is of variable width, compute the length
+     of the copy into a WITH_SIZE_EXPR.   Note that we need to do this
+     before gimplifying any of the operands so that we can resolve any
+     PLACEHOLDER_EXPRs in the size.  Also note that the RTL expander uses
+     the size of the expression to be copied, not of the destination, so
+     that is what we must here.  */
+  maybe_with_size_expr (from_p);
 
   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);
+  ret = gimplify_expr (from_p, pre_p, post_p,
+                      rhs_predicate_for (*to_p), fb_rvalue);
   if (ret == GS_ERROR)
     return ret;
 
@@ -2690,34 +2915,28 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   if (ret != GS_UNHANDLED)
     return ret;
 
+  /* If we've got a variable sized assignment between two lvalues (i.e. does
+     not involve a call), then we can make things a bit more straightforward
+     by converting the assignment to memcpy or memset.  */
+  if (TREE_CODE (*from_p) == WITH_SIZE_EXPR)
+    {
+      tree from = TREE_OPERAND (*from_p, 0);
+      tree size = TREE_OPERAND (*from_p, 1);
+
+      if (TREE_CODE (from) == CONSTRUCTOR)
+       return gimplify_modify_expr_to_memset (expr_p, size, want_value);
+      if (is_gimple_addressable (from))
+       {
+         *from_p = from;
+         return gimplify_modify_expr_to_memcpy (expr_p, size, want_value);
+       }
+    }
+
   /* If the destination is already simple, nothing else needed.  */
-  if (is_gimple_tmp_var (*to_p))
+  if (is_gimple_tmp_var (*to_p) || !want_value)
     ret = GS_ALL_DONE;
   else
-    {
-      /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto and
-        the LHS is a user variable, then we need to introduce a temporary.
-        ie temp = RHS; LHS = temp.
-
-        This way the optimizers can determine that the user variable is
-        only modified if evaluation of the RHS does not throw.
-
-        FIXME this should be handled by the is_gimple_rhs predicate.  */
-
-      if (aggregate_value_p (TREE_TYPE (*from_p), NULL_TREE))
-       /* Don't force a temp of a large aggregate type; the copy could be
-          arbitrarily expensive.  Instead we will generate a V_MAY_DEF for
-          the assignment.  */;
-      else if (TREE_CODE (*from_p) == CALL_EXPR
-              || (flag_non_call_exceptions && tree_could_trap_p (*from_p))
-              /* If we're dealing with a renamable type, either source or dest
-                 must be a renamed variable.  */
-              || (is_gimple_reg_type (TREE_TYPE (*from_p))
-                  && !is_gimple_reg (*to_p)))
-       gimplify_expr (from_p, pre_p, post_p, is_gimple_val, fb_rvalue);
-
-      ret = want_value ? GS_OK : GS_ALL_DONE;
-    }
+    ret = GS_OK;
 
   if (want_value)
     {
@@ -2728,75 +2947,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   return ret;
 }
 
-/*  Subroutine of above to do simplications of MODIFY_EXPRs based on
-    the code of the RHS.  We loop for as long as we can do something.  */
-
-static enum gimplify_status
-gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
-                         tree *post_p, bool want_value)
-{
-  enum gimplify_status ret = GS_OK;
-
-  while (ret != GS_UNHANDLED)
-    switch (TREE_CODE (*from_p))
-      {
-      case TARGET_EXPR:
-       {
-         /* If we are initializing something from a TARGET_EXPR, strip the
-            TARGET_EXPR and initialize it directly, if possible.  This can't
-            be done if the initializer is void, since that implies that the
-            temporary is set in some non-trivial way.
-
-            ??? What about code that pulls out the temp and uses it
-            elsewhere? I think that such code never uses the TARGET_EXPR as
-            an initializer.  If I'm wrong, we'll abort because the temp won't
-            have any RTL.  In that case, I guess we'll need to replace
-            references somehow.  */
-         tree init = TARGET_EXPR_INITIAL (*from_p);
-
-         if (!VOID_TYPE_P (TREE_TYPE (init)))
-           {
-             *from_p = init;
-             ret = GS_OK;
-           }
-         else
-           ret = GS_UNHANDLED;
-       }
-       break;
-
-      case COMPOUND_EXPR:
-       /* Remove any COMPOUND_EXPR in the RHS so the following cases will be
-          caught.  */
-       gimplify_compound_expr (from_p, pre_p, true);
-       ret = GS_OK;
-       break;
-
-      case CONSTRUCTOR:
-       /* If we're initializing from a CONSTRUCTOR, break this into
-          individual MODIFY_EXPRs.  */
-       return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
-
-      case COND_EXPR:
-       /* If we're assigning from a ?: expression with ADDRESSABLE type, push
-          the assignment down into the branches, since we can't generate a
-          temporary of such a type.  */
-       if (TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
-         {
-           *expr_p = *from_p;
-           return gimplify_cond_expr (expr_p, pre_p, *to_p);
-         }
-       else
-         ret = GS_UNHANDLED;
-       break;
-
-      default:
-       ret = GS_UNHANDLED;
-       break;
-      }
-
-  return ret;
-}
-
 /*  Gimplify a comparison between two variable-sized objects.  Do this
     with a call to BUILT_IN_MEMCMP.  */
 
@@ -2808,12 +2958,12 @@ gimplify_variable_sized_compare (tree *expr_p)
   tree args, t, dest;
 
   t = TYPE_SIZE_UNIT (TREE_TYPE (op0));
-  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
   t = unshare_expr (t);
+  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
   args = tree_cons (NULL, t, NULL);
-  t = build_addr_expr (op1);
+  t = build_fold_addr_expr (op1);
   args = tree_cons (NULL, t, args);
-  dest = build_addr_expr (op0);
+  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);
@@ -3001,25 +3151,35 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
 
     case VIEW_CONVERT_EXPR:
       /* Take the address of our operand and then convert it to the type of
-        this ADDR_EXPR.  */
+        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_addr_expr (TREE_OPERAND (op0, 0)));
+                             build_fold_addr_expr (TREE_OPERAND (op0, 0)));
       ret = GS_OK;
       break;
 
     default:
       /* We use fb_either here because the C frontend sometimes takes
-        the address of a call that returns a struct.  */
+        the address of a call that returns a struct; see
+        gcc.dg/c99-array-lval-1.c.  The gimplifier will correctly make
+        the implied temporary explicit.  */
       ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p,
-                          is_gimple_addr_expr_arg, fb_either);
+                          is_gimple_addressable, fb_either);
       if (ret != GS_ERROR)
        {
-         /* At this point, the argument of the ADDR_EXPR should be
-            sufficiently simple that there are never side effects.  */
-         /* ??? Could split out the decision code from build1 to verify.  */
-         TREE_SIDE_EFFECTS (expr) = 0;
+         /* The above may have made an INDIRECT_REF (e.g, Ada's NULL_EXPR),
+            so check for it here.  It's not worth checking for the other
+            cases above.  */
+         if (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF)
+           {
+             *expr_p = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+             break;
+           }
 
-         /* Make sure TREE_INVARIANT/TREE_CONSTANT is set properly.  */
+         /* Make sure TREE_INVARIANT, TREE_CONSTANT, and TREE_SIDE_EFFECTS
+            is set properly.  */
          recompute_tree_invarant_for_addr_expr (expr);
 
          /* Mark the RHS addressable.  */
@@ -3028,11 +3188,6 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
       break;
     }
 
-  /* If the operand is gimplified into a _DECL, mark the address expression
-     as TREE_INVARIANT.  */
-  if (DECL_P (TREE_OPERAND (expr, 0)))
-    TREE_INVARIANT (expr) = 1;
-
   return ret;
 }
 
@@ -3178,7 +3333,7 @@ gimplify_cleanup_point_expr (tree *expr_p, tree *pre_p)
        {
          if (tsi_one_before_end_p (iter))
            {
-             tsi_link_before (&iter, TREE_OPERAND (wce, 1), TSI_SAME_STMT);
+             tsi_link_before (&iter, TREE_OPERAND (wce, 0), TSI_SAME_STMT);
              tsi_delink (&iter);
              break;
            }
@@ -3188,8 +3343,8 @@ gimplify_cleanup_point_expr (tree *expr_p, tree *pre_p)
 
              sl = tsi_split_statement_list_after (&iter);
              tfe = build (TRY_FINALLY_EXPR, void_type_node, sl, NULL_TREE);
-             append_to_statement_list (TREE_OPERAND (wce, 1),
-                                    &TREE_OPERAND (tfe, 1));
+             append_to_statement_list (TREE_OPERAND (wce, 0),
+                                       &TREE_OPERAND (tfe, 1));
              *wce_p = tfe;
              iter = tsi_start (sl);
            }
@@ -3253,8 +3408,7 @@ gimple_push_cleanup (tree var, tree cleanup, tree *pre_p)
       tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
                          boolean_true_node);
       cleanup = build (COND_EXPR, void_type_node, flag, cleanup, NULL);
-      wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
-                  cleanup, NULL_TREE);
+      wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
       append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
       append_to_statement_list (wce, &gimplify_ctxp->conditional_cleanups);
       append_to_statement_list (ftrue, pre_p);
@@ -3266,12 +3420,11 @@ gimple_push_cleanup (tree var, tree cleanup, tree *pre_p)
     }
   else
     {
-      wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
-                  cleanup, NULL_TREE);
+      wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
       append_to_statement_list (wce, pre_p);
     }
 
-  gimplify_stmt (&TREE_OPERAND (wce, 1));
+  gimplify_stmt (&TREE_OPERAND (wce, 0));
 }
 
 /* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR.  */
@@ -3322,7 +3475,7 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
       TREE_OPERAND (targ, 3) = init;
       TARGET_EXPR_INITIAL (targ) = NULL_TREE;
     }
-  else if (!temp->decl.seen_in_bind_expr)
+  else if (!DECL_SEEN_IN_BIND_EXPR_P (temp))
     /* We should have expanded this before.  */
     abort ();
 
@@ -3396,7 +3549,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;
 
@@ -3416,19 +3568,17 @@ 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.  */
   do
     {
-      /* Strip any uselessness.  */
-      STRIP_MAIN_TYPE_NOPS (*expr_p);
+      /* Strip away as many useless type conversions as possible
+        at the toplevel.  */
+      STRIP_USELESS_TYPE_CONVERSION (*expr_p);
 
       /* Remember the expr.  */
       save_expr = *expr_p;
@@ -3472,8 +3622,9 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
        case REALPART_EXPR:
        case IMAGPART_EXPR:
        case COMPONENT_REF:
+       case VIEW_CONVERT_EXPR:
          ret = gimplify_compound_lval (expr_p, pre_p, post_p,
-                                       fallback & fb_lvalue);
+                                       fallback ? fallback : fb_rvalue);
          break;
 
        case COND_EXPR:
@@ -3481,7 +3632,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:
@@ -3518,34 +3669,6 @@ 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.  */
-         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_addr_expr
-                                             (TREE_OPERAND (*expr_p, 0))));
-             break;
-           }
-         goto unary;
-
        case CONVERT_EXPR:
        case NOP_EXPR:
          if (IS_EMPTY_STMT (*expr_p))
@@ -3574,7 +3697,6 @@ 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);
@@ -3597,7 +3719,18 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        case CONST_DECL:
-         *expr_p = DECL_INITIAL (*expr_p);
+         /* If we require an lvalue, such as for ADDR_EXPR, retain the
+            CONST_DECL node.  Otherwise the decl is replacable by its
+            value.  */
+         /* ??? Should be == fb_lvalue, but ADDR_EXPR passes fb_either.  */
+         if (fallback & fb_lvalue)
+           ret = GS_ALL_DONE;
+         else
+           *expr_p = DECL_INITIAL (*expr_p);
+         break;
+
+       case DECL_EXPR:
+         ret = gimplify_decl_expr (expr_p);
          break;
 
        case EXC_PTR_EXPR:
@@ -3654,8 +3787,20 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          break;
 
        case CONSTRUCTOR:
-         /* Don't reduce this in place; let gimplify_init_constructor work
-            its magic.  */
+         /* Don't reduce this in place; let gimplify_init_constructor work its
+            magic.  Buf if we're just elaborating this for side effects, just
+            gimplify any element that has side-effects.  */
+         if (fallback == fb_none)
+           {
+             for (tmp = CONSTRUCTOR_ELTS (*expr_p); tmp;
+                  tmp = TREE_CHAIN (tmp))
+               if (TREE_SIDE_EFFECTS (TREE_VALUE (tmp)))
+                 gimplify_expr (&TREE_VALUE (tmp), pre_p, post_p,
+                                gimple_test_f, fallback);
+
+             *expr_p = NULL_TREE;
+           }
+                 
          ret = GS_ALL_DONE;
          break;
 
@@ -3673,7 +3818,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,
@@ -3746,6 +3891,17 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = gimplify_statement_list (expr_p);
          break;
 
+       case WITH_SIZE_EXPR:
+         {
+           enum gimplify_status r0, r1;
+           r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, 
+                               post_p == &internal_post ? NULL : post_p,
+                               gimple_test_f, fallback);
+           r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+                               is_gimple_val, fb_rvalue);
+         }
+         break;
+
        case VAR_DECL:
          /* ??? If this is a local variable, and it has not been seen in any
             outer BIND_EXPR, then it's probably the result of a duplicate
@@ -3756,16 +3912,31 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          tmp = *expr_p;
          if (!TREE_STATIC (tmp) && !DECL_EXTERNAL (tmp)
              && decl_function_context (tmp) == current_function_decl
-             && !tmp->decl.seen_in_bind_expr)
+             && !DECL_SEEN_IN_BIND_EXPR_P (tmp))
            {
 #ifdef ENABLE_CHECKING
              if (!errorcount && !sorrycount)
                abort ();
 #endif
              ret = GS_ERROR;
+             break;
            }
-         else
-           ret = GS_ALL_DONE;
+
+         /* If this is a local variable sized decl, it must be accessed
+            indirectly.  Perform that substitution.  */
+         if (DECL_VALUE_EXPR (tmp))
+           {
+             *expr_p = unshare_expr (DECL_VALUE_EXPR (tmp));
+             ret = GS_OK;
+             break;
+           }
+
+         ret = GS_ALL_DONE;
+         break;
+
+       case SSA_NAME:
+         /* Allow callbacks into the gimplifier during optimization.  */
+         ret = GS_ALL_DONE;
          break;
 
        default:
@@ -3915,7 +4086,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
      postqueue; we need to copy the value out first, which means an
      rvalue.  */
   if ((fallback & fb_lvalue) && !internal_post
-      && is_gimple_addr_expr_arg (*expr_p))
+      && is_gimple_addressable (*expr_p))
     {
       /* An lvalue will do.  Take the address of the expression, store it
         in a temporary, and replace the expression with an INDIRECT_REF of
@@ -3924,7 +4095,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
       gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue);
       *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp);
     }
-  else if ((fallback & fb_rvalue) && is_gimple_rhs (*expr_p))
+  else if ((fallback & fb_rvalue) && is_gimple_tmp_rhs (*expr_p))
     {
 #if defined ENABLE_CHECKING
       if (VOID_TYPE_P (TREE_TYPE (*expr_p)))
@@ -4024,8 +4195,12 @@ 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.  */
+     A PLACEHOLDER_EXPR.  We also don't want to do anything if it's already
+     a VAR_DECL.  If it's a VAR_DECL from another function, the gimplfier
+     will want to replace it with a new variable, but that will cause problems
+     if this type is from outside the function.  It's OK to have that here.  */
   if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)
+      || TREE_CODE (*expr_p) == VAR_DECL
       || CONTAINS_PLACEHOLDER_P (*expr_p))
     return;