OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index f65dd4c..669ec9f 100644 (file)
@@ -50,15 +50,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 static struct gimplify_ctx
 {
   tree current_bind_expr;
-  bool save_stack;
   tree temps;
   tree conditional_cleanups;
-  int conditions;
   tree exit_label;
   tree return_temp;
   varray_type case_labels;
   /* The formal temporary table.  Should this be persistent?  */
   htab_t temp_htab;
+  int conditions;
+  bool save_stack;
+  bool into_ssa;
 } *gimplify_ctxp;
 
 
@@ -72,78 +73,18 @@ 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 *);
+static bool cpt_same_type (tree a, tree b);
 #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 +93,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
@@ -165,8 +106,7 @@ gimple_tree_eq (const void *p1, const void *p2)
 
   /* Only allow them to compare equal if they also hash equal; otherwise
      results are nondeterminate, and we fail bootstrap comparison.  */
-  if (gimple_tree_hash (p1) != gimple_tree_hash (p2))
-    abort ();
+  gcc_assert (gimple_tree_hash (p1) == gimple_tree_hash (p2));
 
   return 1;
 }
@@ -176,12 +116,14 @@ gimple_tree_eq (const void *p1, const void *p2)
 void
 push_gimplify_context (void)
 {
-  if (gimplify_ctxp)
-    abort ();
+  gcc_assert (!gimplify_ctxp);
   gimplify_ctxp
     = (struct gimplify_ctx *) xcalloc (1, sizeof (struct gimplify_ctx));
-  gimplify_ctxp->temp_htab
-    = htab_create (1000, gimple_tree_hash, gimple_tree_eq, free);
+  if (optimize)
+    gimplify_ctxp->temp_htab
+      = htab_create (1000, gimple_tree_hash, gimple_tree_eq, free);
+  else
+    gimplify_ctxp->temp_htab = NULL;
 }
 
 /* Tear down a context for the gimplifier.  If BODY is non-null, then
@@ -191,8 +133,12 @@ push_gimplify_context (void)
 void
 pop_gimplify_context (tree body)
 {
-  if (!gimplify_ctxp || gimplify_ctxp->current_bind_expr)
-    abort ();
+  tree t;
+
+  gcc_assert (gimplify_ctxp && !gimplify_ctxp->current_bind_expr);
+
+  for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
+    DECL_GIMPLE_FORMAL_TEMP_P (t) = 0;
 
   if (body)
     declare_tmp_vars (gimplify_ctxp->temps, body);
@@ -200,12 +146,13 @@ pop_gimplify_context (tree body)
     record_vars (gimplify_ctxp->temps);
 
 #if 0
-  if (!quiet_flag)
+  if (!quiet_flag && optimize)
     fprintf (stderr, " collisions: %f ",
             htab_collisions (gimplify_ctxp->temp_htab));
 #endif
 
-  htab_delete (gimplify_ctxp->temp_htab);
+  if (optimize)
+    htab_delete (gimplify_ctxp->temp_htab);
   free (gimplify_ctxp);
   gimplify_ctxp = NULL;
 }
@@ -244,6 +191,10 @@ gimple_conditional_context (void)
 static void
 gimple_push_condition (void)
 {
+#ifdef ENABLE_CHECKING
+  if (gimplify_ctxp->conditions == 0)
+    gcc_assert (!gimplify_ctxp->conditional_cleanups);
+#endif
   ++(gimplify_ctxp->conditions);
 }
 
@@ -254,13 +205,13 @@ static void
 gimple_pop_condition (tree *pre_p)
 {
   int conds = --(gimplify_ctxp->conditions);
+
+  gcc_assert (conds >= 0);
   if (conds == 0)
     {
       append_to_statement_list (gimplify_ctxp->conditional_cleanups, pre_p);
       gimplify_ctxp->conditional_cleanups = NULL_TREE;
     }
-  else if (conds < 0)
-    abort ();
 }
 
 /* A subroutine of append_to_statement_list{,_force}.  */
@@ -314,20 +265,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 +292,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 +310,7 @@ create_tmp_var_name (const char *prefix)
   if (prefix)
     {
       char *preftmp = ASTRDUP (prefix);
+
       remove_suffix (preftmp, strlen (preftmp));
       prefix = preftmp;
     }
@@ -394,7 +333,8 @@ create_tmp_var_raw (tree type, const char *prefix)
   new_type = build_type_variant (type, 0, 0);
   TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type);
 
-  tmp_var = build_decl (VAR_DECL, create_tmp_var_name (prefix), type);
+  tmp_var = build_decl (VAR_DECL, prefix ? create_tmp_var_name (prefix) : NULL,
+                       type);
 
   /* The variable was declared by the compiler.  */
   DECL_ARTIFICIAL (tmp_var) = 1;
@@ -421,14 +361,11 @@ create_tmp_var (tree type, const char *prefix)
 {
   tree tmp_var;
 
-#if defined ENABLE_CHECKING
   /* We don't allow types that are addressable (meaning we can't make copies),
      incomplete, or of variable size.  */
-  if (TREE_ADDRESSABLE (type)
-      || !COMPLETE_TYPE_P (type)
-      || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
-    abort ();
-#endif
+  gcc_assert (!TREE_ADDRESSABLE (type)
+             && COMPLETE_TYPE_P (type)
+             && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST);
 
   tmp_var = create_tmp_var_raw (type, prefix);
   gimple_add_tmp_var (tmp_var);
@@ -476,8 +413,15 @@ create_tmp_from_val (tree val)
 static tree
 lookup_tmp_var (tree val, bool is_formal)
 {
-  if (!is_formal || TREE_SIDE_EFFECTS (val))
-    return create_tmp_from_val (val);
+  tree ret;
+
+  /* If not optimizing, never really reuse a temporary.  local-alloc
+     won't allocate any variable that is used in more than one basic
+     block, which means it will go into memory, causing much extra
+     work in reload and final and poorer code generation, outweighing
+     the extra memory allocation here.  */
+  if (!optimize || !is_formal || TREE_SIDE_EFFECTS (val))
+    ret = create_tmp_from_val (val);
   else
     {
       elt_t elt, *elt_p;
@@ -489,14 +433,20 @@ 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;
+         elt_p->temp = ret = create_tmp_from_val (val);
+         *slot = (void *) elt_p;
        }
       else
-       elt_p = (elt_t *) *slot;
-
-      return elt_p->temp;
+       {
+         elt_p = (elt_t *) *slot;
+          ret = elt_p->temp;
+       }
     }
+
+  if (is_formal)
+    DECL_GIMPLE_FORMAL_TEMP_P (ret) = 1;
+
+  return ret;
 }
 
 /* Returns a formal temporary variable initialized with VAL.  PRE_P is as
@@ -515,22 +465,25 @@ static tree
 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_formal_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);
+    SET_EXPR_LOCATION (mod, input_location);
+
   /* gimplify_modify_expr might want to reduce this further.  */
-  gimplify_stmt (&mod);
-  append_to_statement_list (mod, pre_p);
+  gimplify_and_add (mod, pre_p);
+
+  /* If we're gimplifying into ssa, gimplify_modify_expr will have
+     given our temporary an ssa name.  Find and return it.  */
+  if (gimplify_ctxp->into_ssa)
+    t = TREE_OPERAND (mod, 0);
 
   return t;
 }
@@ -550,18 +503,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,31 +513,26 @@ 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);
 
-      if (TREE_CODE (scope) != BIND_EXPR)
-       abort ();
+      gcc_assert (TREE_CODE (scope) == BIND_EXPR);
 
       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)
-    abort ();
+  gcc_assert (!TREE_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp));
 
   DECL_CONTEXT (tmp) = current_function_decl;
-  tmp->decl.seen_in_bind_expr = 1;
+  DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1;
 
   if (gimplify_ctxp)
     {
@@ -629,10 +566,8 @@ should_carry_locus_p (tree stmt)
 static void
 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);
+  if (EXPR_P (t) && ! EXPR_HAS_LOCATION (t) && should_carry_locus_p (t))
+    SET_EXPR_LOCATION (t, locus);
 }
 
 void
@@ -647,13 +582,10 @@ annotate_all_with_locus (tree *stmt_p, location_t locus)
     {
       tree t = tsi_stmt (i);
 
-#ifdef ENABLE_CHECKING
-         /* Assuming we've already been gimplified, we shouldn't
-            see nested chaining constructs anymore.  */
-         if (TREE_CODE (t) == STATEMENT_LIST
-             || TREE_CODE (t) == COMPOUND_EXPR)
-           abort ();
-#endif
+      /* Assuming we've already been gimplified, we shouldn't
+         see nested chaining constructs anymore.  */
+      gcc_assert (TREE_CODE (t) != STATEMENT_LIST
+                 && TREE_CODE (t) != COMPOUND_EXPR);
 
       annotate_one_with_locus (t, locus);
     }
@@ -669,37 +601,24 @@ mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
 {
   enum tree_code code = TREE_CODE (*tp);
   /* Don't unshare types, decls, constants and SAVE_EXPR nodes.  */
-  if (TREE_CODE_CLASS (code) == 't'
-      || TREE_CODE_CLASS (code) == 'd'
-      || TREE_CODE_CLASS (code) == 'c'
+  if (TREE_CODE_CLASS (code) == tcc_type
+      || TREE_CODE_CLASS (code) == tcc_declaration
+      || TREE_CODE_CLASS (code) == tcc_constant
       || code == SAVE_EXPR || code == TARGET_EXPR
       /* We can't do anything sensible with a BLOCK used as an expression,
         but we also can't abort when we see it because of non-expression
         uses.  So just avert our eyes and cross our fingers.  Silly Java.  */
       || code == BLOCK)
     *walk_subtrees = 0;
-  else if (code == BIND_EXPR)
-    abort ();
   else
-    copy_tree_r (tp, walk_subtrees, 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;
+    {
+      gcc_assert (code != BIND_EXPR);
+      copy_tree_r (tp, walk_subtrees, data);
+    }
 
   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.
@@ -720,9 +639,9 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
      types and the bounds of types.  Mark them as visited so we properly
      unmark their subtrees on the unmark pass.  If we've already seen them,
      don't look down further.  */
-  if (TREE_CODE_CLASS (code) == 't'
-      || TREE_CODE_CLASS (code) == 'd'
-      || TREE_CODE_CLASS (code) == 'c')
+  if (TREE_CODE_CLASS (code) == tcc_type
+      || TREE_CODE_CLASS (code) == tcc_declaration
+      || TREE_CODE_CLASS (code) == tcc_constant)
     {
       if (TREE_VISITED (t))
        *walk_subtrees = 0;
@@ -730,19 +649,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 +659,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 +676,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 +686,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 +699,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.  */
@@ -831,7 +724,7 @@ unshare_expr (tree expr)
   return expr;
 }
 
-/* A terser interface for building a representation of a exception
+/* A terser interface for building a representation of an exception
    specification.  */
 
 tree
@@ -883,7 +776,7 @@ voidify_wrapper_expr (tree wrapper, tree temp)
          p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i);
        }
       else
-       { 
+       {
          for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1))
            {
              TREE_SIDE_EFFECTS (*p) = 1;
@@ -901,7 +794,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 +856,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,30 +907,29 @@ 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);
-#ifdef ENABLE_CHECKING
-      if ((TREE_CODE (ret_expr) != MODIFY_EXPR
-          && TREE_CODE (ret_expr) != INIT_EXPR)
-         || TREE_CODE (result_decl) != RESULT_DECL)
-       abort ();
-#endif
+      if (TREE_CODE (result_decl) == INDIRECT_REF)
+       /* See through a return by reference.  */
+       result_decl = TREE_OPERAND (result_decl, 0);
+
+      gcc_assert ((TREE_CODE (ret_expr) == MODIFY_EXPR
+                  || TREE_CODE (ret_expr) == INIT_EXPR)
+                 && TREE_CODE (result_decl) == RESULT_DECL);
     }
 
   /* If aggregate_value_p is true, then we can return the bare RESULT_DECL.
      Recall that aggregate_value_p is FALSE for any aggregate type that is
      returned in registers.  If we're returning values in registers, then
      we don't want to extend the lifetime of the RESULT_DECL, particularly
-     across another call.  In addition, for those aggregates for which 
+     across another call.  In addition, for those aggregates for which
      hard_function_value generates a PARALLEL, we'll abort during normal
      expansion of structure assignments; there's special code in expand_return
      to handle this case that does not exist in expand_expr.  */
@@ -1062,8 +955,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 +969,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 occurrences 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 +1064,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 +1092,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)
@@ -1171,8 +1143,7 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p)
 
       /* If someone can be bothered to fill in the labels, they can
         be bothered to null out the body too.  */
-      if (SWITCH_LABELS (switch_expr))
-       abort ();
+      gcc_assert (!SWITCH_LABELS (switch_expr));
 
       saved_labels = gimplify_ctxp->case_labels;
       VARRAY_TREE_INIT (gimplify_ctxp->case_labels, 8, "case_labels");
@@ -1222,8 +1193,8 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p)
 
       SWITCH_BODY (switch_expr) = NULL;
     }
-  else if (!SWITCH_LABELS (switch_expr))
-    abort ();
+  else
+    gcc_assert (SWITCH_LABELS (switch_expr));
 
   return ret;
 }
@@ -1232,10 +1203,9 @@ static enum gimplify_status
 gimplify_case_label_expr (tree *expr_p)
 {
   tree expr = *expr_p;
-  if (gimplify_ctxp->case_labels)
-    VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, expr);
-  else
-    abort ();
+
+  gcc_assert (gimplify_ctxp->case_labels);
+  VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, expr);
   *expr_p = build (LABEL_EXPR, void_type_node, CASE_LABEL (expr));
   return GS_ALL_DONE;
 }
@@ -1269,10 +1239,7 @@ gimplify_exit_block_expr (tree *expr_p)
 
   /* First operand must be a LABELED_BLOCK_EXPR, which should
      already be lowered (or partially lowered) when we get here.  */
-#if defined ENABLE_CHECKING
-  if (TREE_CODE (labeled_block) != LABELED_BLOCK_EXPR)
-    abort ();
-#endif
+  gcc_assert (TREE_CODE (labeled_block) == LABELED_BLOCK_EXPR);
 
   label = LABELED_BLOCK_LABEL (labeled_block);
   *expr_p = build1 (GOTO_EXPR, void_type_node, label);
@@ -1288,7 +1255,7 @@ build_and_jump (tree *label_p)
 {
   if (label_p == NULL)
     /* If there's nowhere to jump, just fall through.  */
-    return alloc_stmt_list ();
+    return NULL_TREE;
 
   if (*label_p == NULL_TREE)
     {
@@ -1310,7 +1277,7 @@ gimplify_exit_expr (tree *expr_p)
   tree expr;
 
   expr = build_and_jump (&gimplify_ctxp->exit_label);
-  expr = build (COND_EXPR, void_type_node, cond, expr, alloc_stmt_list ());
+  expr = build (COND_EXPR, void_type_node, cond, expr, NULL_TREE);
   *expr_p = expr;
 
   return GS_OK;
@@ -1330,374 +1297,94 @@ 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;
+  gcc_assert (TREE_CODE (expr) == COMPONENT_REF);
 
-  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;
-
-       /* 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;
-         }
+      tree old_type = TREE_TYPE (expr);
 
-       categorize_ctor_elements (ctor, &num_nonzero_elements,
-                                 &num_nonconstant_elements);
-       num_elements = count_type_elements (TREE_TYPE (ctor));
+      /* Set the type of the COMPONENT_REF to the underlying type.  */
+      TREE_TYPE (expr) = type;
 
-       /* 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);
+      /* And wrap the whole thing inside a NOP_EXPR.  */
+      expr = build1 (NOP_EXPR, old_type, 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);
+      *expr_p = expr;
+    }
+}
 
-           *expr_p = alloc_stmt_list ();
-           break;
-         }
+/* 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.  */
 
-       /* 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;
+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;
 
-           /* ??? 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);
-             }
+  /* Both cast and addr_expr types should be pointers.  */
+  if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
+    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);
+  /* The addr_expr type should be a pointer to an array.  */
+  datype = TREE_TYPE (atype);
+  if (TREE_CODE (datype) != ARRAY_TYPE)
+    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);
+  /* 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;
 
-               TREE_OPERAND (*expr_p, 1) = new;
-               break;
-             }
-         }
+  /* 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;
 
-       /* If there are "lots" of initialized elements, even discounting
-          those that are not address constants (and thus *must* be 
-          computed at runtime), then partition the constructor into
-          constant and non-constant parts.  Block copy the constant
-          parts in, then generate code for the non-constant parts.  */
-       /* TODO.  There's code in cp/typeck.c to do this.  */
-
-       /* If there are "lots" of zeros, then block clear the object first.  */
-       cleared = false;
-       if (num_elements - num_nonzero_elements > CLEAR_RATIO
-           && num_nonzero_elements < num_elements/4)
-         cleared = true;
-
-       /* ??? This bit ought not be needed.  For any element not present
-          in the initializer, we should simply set them to zero.  Except
-          we'd need to *find* the elements that are not present, and that
-          requires trickery to avoid quadratic compile-time behavior in
-          large cases or excessive memory use in small cases.  */
-       else
-         {
-           HOST_WIDE_INT len = list_length (elt_list);
-           if (TREE_CODE (type) == ARRAY_TYPE)
-             {
-               tree nelts = array_type_nelts (type);
-               if (!host_integerp (nelts, 1)
-                   || tree_low_cst (nelts, 1) != len)
-                 cleared = 1;;
-             }
-           else if (len != fields_length (type))
-             cleared = 1;
-         }
-
-       if (cleared)
-         {
-           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 = alloc_stmt_list ();
-      }
-      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;
+  /* 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)));
+                               size_int (TYPE_ALIGN_UNIT (dctype))));
   *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
 }
 
@@ -1706,11 +1393,7 @@ canonicalize_addr_expr (tree *expr_p)
 
 static enum gimplify_status
 gimplify_conversion (tree *expr_p)
-{  
-  /* Strip away as many useless type conversions as possible
-     at the toplevel.  */
-  STRIP_USELESS_TYPE_CONVERSION (*expr_p);
-
+{
   /* If we still have a conversion at the toplevel, then strip
      away all but the outermost conversion.  */
   if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
@@ -1743,125 +1426,6 @@ gimplify_conversion (tree *expr_p)
   return GS_OK;
 }
 
-/* Reduce MIN/MAX_EXPR to a COND_EXPR for further gimplification.  */
-
-static enum gimplify_status
-gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
-{
-  tree op1 = TREE_OPERAND (*expr_p, 0);
-  tree op2 = TREE_OPERAND (*expr_p, 1);
-  enum tree_code code;
-  enum gimplify_status r0, r1;
-
-  if (TREE_CODE (*expr_p) == MIN_EXPR)
-    code = LE_EXPR;
-  else
-    code = GE_EXPR;
-
-  r0 = gimplify_expr (&op1, pre_p, post_p, is_gimple_val, fb_rvalue);
-  r1 = gimplify_expr (&op2, pre_p, post_p, is_gimple_val, fb_rvalue);
-
-  *expr_p = build (COND_EXPR, TREE_TYPE (*expr_p),
-                  build (code, boolean_type_node, op1, op2),
-                  op1, op2);
-
-  if (r0 == GS_ERROR || r1 == GS_ERROR)
-    return GS_ERROR;
-  else
-    return GS_OK;
-}
-
-/* Subroutine of gimplify_compound_lval.
-   Converts an ARRAY_REF to the equivalent *(&array + offset) form.  */
-
-static enum gimplify_status
-gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
-{
-  tree array = TREE_OPERAND (*expr_p, 0);
-  tree arrtype = TREE_TYPE (array);
-  tree elttype = TREE_TYPE (arrtype);
-  tree size = array_ref_element_size (*expr_p);
-  tree ptrtype = build_pointer_type (elttype);
-  enum tree_code add_code = PLUS_EXPR;
-  tree idx = TREE_OPERAND (*expr_p, 1);
-  tree minidx = unshare_expr (array_ref_low_bound (*expr_p));
-  tree offset, addr, result;
-  enum gimplify_status ret;
-
-  /* If the array domain does not start at zero, apply the offset.  */
-  if (!integer_zerop (minidx))
-    {
-      idx = convert (TREE_TYPE (minidx), idx);
-      idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
-    }
-  
-  /* If the index is negative -- a technically invalid situation now
-     that we've biased the index back to zero -- then casting it to
-     unsigned has ill effects.  In particular, -1*4U/4U != -1.
-     Represent this as a subtraction of a positive rather than addition
-     of a negative.  This will prevent any conversion back to ARRAY_REF
-     from getting the wrong results from the division.  */
-  if (TREE_CODE (idx) == INTEGER_CST && tree_int_cst_sgn (idx) < 0)
-    {
-      idx = fold (build1 (NEGATE_EXPR, TREE_TYPE (idx), idx));
-      add_code = MINUS_EXPR;
-    }
-
-  /* Pointer arithmetic must be done in sizetype.  */
-  idx = fold_convert (sizetype, idx);
-
-  /* Convert the index to a byte offset.  */
-  offset = size_binop (MULT_EXPR, size, idx);
-
-  ret = gimplify_expr (&array, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
-  if (ret == GS_ERROR)
-    return ret;
-
-  addr = build_fold_addr_expr_with_type (array, ptrtype);
-  result = fold (build (add_code, ptrtype, addr, offset));
-  *expr_p = build1 (INDIRECT_REF, elttype, result);
-
-  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,73 +1450,59 @@ 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);
+     order from inner to outer.
+
+     This array is very memory consuming.  Don't even think of making
+     it VARRAY_TREE.  */
+  VARRAY_GENERIC_PTR_NOGC_INIT (stack, 10, "stack");
+
+  /* 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_GENERIC_PTR_NOGC (stack, *p);
+
+  gcc_assert (VARRAY_ACTIVE_SIZE (stack));
 
   /* 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_GENERIC_PTR_NOGC (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.  */
          if (!TREE_OPERAND (t, 2))
            {
-             TREE_OPERAND (t, 2) = unshare_expr (array_ref_low_bound (t));
-             if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+             tree low = unshare_expr (array_ref_low_bound (t));
+             if (!is_gimple_min_invariant (low))
                {
+                 TREE_OPERAND (t, 2) = low;
                  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
-                                       is_gimple_tmp_var, fb_rvalue);
+                                       is_gimple_formal_tmp_reg, fb_rvalue);
                  ret = MIN (ret, tret);
                }
            }
@@ -1961,17 +1511,17 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
            {
              tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
              tree elmt_size = unshare_expr (array_ref_element_size (t));
-             tree factor = size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT);
+             tree factor = size_int (TYPE_ALIGN_UNIT (elmt_type));
 
              /* Divide the element size by the alignment of the element
                 type (above).  */
              elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor);
 
-             TREE_OPERAND (t, 3) = elmt_size;
-             if (!is_gimple_min_invariant (TREE_OPERAND (t, 3)))
+             if (!is_gimple_min_invariant (elmt_size))
                {
+                 TREE_OPERAND (t, 3) = elmt_size;
                  tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
-                                       is_gimple_tmp_var, fb_rvalue);
+                                       is_gimple_formal_tmp_reg, fb_rvalue);
                  ret = MIN (ret, tret);
                }
            }
@@ -1989,15 +1539,45 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
              /* Divide the offset by its alignment.  */
              offset = size_binop (EXACT_DIV_EXPR, offset, factor);
 
-             TREE_OPERAND (t, 2) = offset;
-             if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+             if (!is_gimple_min_invariant (offset))
                {
+                 TREE_OPERAND (t, 2) = offset;
                  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
-                                       is_gimple_tmp_var, fb_rvalue);
+                                       is_gimple_formal_tmp_reg, fb_rvalue);
                  ret = MIN (ret, tret);
                }
            }
        }
+    }
+
+  /* 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_formal_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,
@@ -2007,22 +1587,28 @@ gimplify_compound_lval (tree *expr_p, tree *pre_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);
     }
 
+  VARRAY_FREE (stack);
+
   return ret;
 }
 
@@ -2049,13 +1635,8 @@ gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
   code = TREE_CODE (*expr_p);
 
-#if defined ENABLE_CHECKING
-  if (code != POSTINCREMENT_EXPR
-      && code != POSTDECREMENT_EXPR
-      && code != PREINCREMENT_EXPR
-      && code != PREDECREMENT_EXPR)
-    abort ();
-#endif
+  gcc_assert (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR
+             || code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR);
 
   /* Prefix or postfix?  */
   if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
@@ -2094,8 +1675,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;
     }
@@ -2106,34 +1686,77 @@ 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;
+
+  /* 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;
+
+  /* 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);
+}
+
+/* Subroutine of gimplify_call_expr:  Gimplify a single argument.  */
+
+static enum gimplify_status
+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;
 
-      call_expr
-             : ID '(' arglist ')'
+  /* If this is a variable sized type, we must remember the size.  */
+  maybe_with_size_expr (expr_p);
 
-      arglist
-             : arglist ',' val
-             | val
+  /* 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);
+}
 
-    PRE_P points to the list where side effects that must happen before
-       *EXPR_P should be stored.  */
+/* Gimplify the CALL_EXPR node pointed by EXPR_P.  PRE_P points to the
+   list where side effects that must happen before *EXPR_P should be stored.
+   WANT_VALUE is true if the result of the call is desired.  */
 
 static enum gimplify_status
-gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
+gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
 {
   tree decl;
   tree arglist;
   enum gimplify_status ret;
 
-#if defined ENABLE_CHECKING
-  if (TREE_CODE (*expr_p) != CALL_EXPR)
-    abort ();
-#endif
+  gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR);
 
-  /* For reliable diagnostics during inlining, it is necessary that 
+  /* 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.
 
@@ -2150,20 +1773,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 = fold_builtin (*expr_p, !want_value);
 
       if (new && new != *expr_p)
        {
@@ -2173,6 +1783,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
@@ -2188,12 +1803,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;
@@ -2204,7 +1814,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 = fold_builtin (*expr_p, !want_value);
 
       if (new && new != *expr_p)
        {
@@ -2321,9 +1931,11 @@ shortcut_cond_expr (tree expr)
   tree *true_label_p;
   tree *false_label_p;
   bool emit_end, emit_false;
+  bool then_se = then_ && TREE_SIDE_EFFECTS (then_);
+  bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
 
   /* First do simple transformations.  */
-  if (!TREE_SIDE_EFFECTS (else_))
+  if (!else_se)
     {
       /* If there is no 'else', turn (a && b) into if (a) if (b).  */
       while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
@@ -2331,11 +1943,10 @@ shortcut_cond_expr (tree expr)
          TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
          then_ = shortcut_cond_expr (expr);
          pred = TREE_OPERAND (pred, 0);
-         expr = build (COND_EXPR, void_type_node, pred, then_,
-                       alloc_stmt_list ());
+         expr = build (COND_EXPR, void_type_node, pred, then_, NULL_TREE);
        }
     }
-  if (!TREE_SIDE_EFFECTS (then_))
+  if (!then_se)
     {
       /* If there is no 'then', turn
           if (a || b); else d
@@ -2346,8 +1957,7 @@ shortcut_cond_expr (tree expr)
          TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
          else_ = shortcut_cond_expr (expr);
          pred = TREE_OPERAND (pred, 0);
-         expr = build (COND_EXPR, void_type_node, pred,
-                       alloc_stmt_list (), else_);
+         expr = build (COND_EXPR, void_type_node, pred, NULL_TREE, else_);
        }
     }
 
@@ -2369,18 +1979,22 @@ shortcut_cond_expr (tree expr)
   /* If our arms just jump somewhere, hijack those labels so we don't
      generate jumps to jumps.  */
 
-  if (TREE_CODE (then_) == GOTO_EXPR
+  if (then_
+      && TREE_CODE (then_) == GOTO_EXPR
       && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
     {
       true_label = GOTO_DESTINATION (then_);
-      then_ = alloc_stmt_list ();
+      then_ = NULL;
+      then_se = false;
     }
 
-  if (TREE_CODE (else_) == GOTO_EXPR
+  if (else_
+      && TREE_CODE (else_) == GOTO_EXPR
       && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
     {
       false_label = GOTO_DESTINATION (else_);
-      else_ = alloc_stmt_list ();
+      else_ = NULL;
+      else_se = false;
     }
 
   /* If we aren't hijacking a label for the 'then' branch, it falls through.  */
@@ -2390,21 +2004,23 @@ shortcut_cond_expr (tree expr)
     true_label_p = NULL;
 
   /* The 'else' branch also needs a label if it contains interesting code.  */
-  if (false_label || TREE_SIDE_EFFECTS (else_))
+  if (false_label || else_se)
     false_label_p = &false_label;
   else
     false_label_p = NULL;
 
   /* If there was nothing else in our arms, just forward the label(s).  */
-  if (!TREE_SIDE_EFFECTS (then_) && !TREE_SIDE_EFFECTS (else_))
+  if (!then_se && !else_se)
     return shortcut_cond_r (pred, true_label_p, false_label_p);
 
   /* If our last subexpression already has a terminal label, reuse it.  */
-  if (TREE_SIDE_EFFECTS (else_))
+  if (else_se)
     expr = expr_last (else_);
-  else
+  else if (then_se)
     expr = expr_last (then_);
-  if (TREE_CODE (expr) == LABEL_EXPR)
+  else
+    expr = NULL;
+  if (expr && TREE_CODE (expr) == LABEL_EXPR)
     end_label = LABEL_EXPR_LABEL (expr);
 
   /* If we don't care about jumping to the 'else' branch, jump to the end
@@ -2422,7 +2038,7 @@ shortcut_cond_expr (tree expr)
   append_to_statement_list (pred, &expr);
 
   append_to_statement_list (then_, &expr);
-  if (TREE_SIDE_EFFECTS (else_))
+  if (else_se)
     {
       t = build_and_jump (&end_label);
       append_to_statement_list (t, &expr);
@@ -2476,7 +2092,7 @@ gimple_boolify (tree expr)
       /* These expressions always produce boolean results.  */
       TREE_TYPE (expr) = boolean_type_node;
       return expr;
-      
+
     default:
       /* Other expressions that get here must have boolean values, but
         might need to be converted to the appropriate mode.  */
@@ -2504,21 +2120,29 @@ 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;
        }
 
@@ -2531,16 +2155,15 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
       /* 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));
+         = 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 and use the temp in its place.  */
-      gimplify_stmt (&expr);
-      append_to_statement_list (expr, pre_p);
-      *expr_p = tmp;
+      /* Move the COND_EXPR to the prequeue.  */
+      gimplify_and_add (expr, pre_p);
 
+      *expr_p = tmp;
       return ret;
     }
 
@@ -2604,125 +2227,489 @@ gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
   return ret;
 }
 
-/*  Gimplify the MODIFY_EXPR node pointed by EXPR_P.
+/* A subroutine of gimplify_modify_expr.  Replace a MODIFY_EXPR with
+   a call to __builtin_memcpy.  */
 
-      modify_expr
-             : varname '=' rhs
-             | '*' ID '=' rhs
+static enum gimplify_status
+gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value)
+{
+  tree args, t, to, to_ptr, from;
 
-    PRE_P points to the list where side effects that must happen before
-       *EXPR_P should be stored.
+  to = TREE_OPERAND (*expr_p, 0);
+  from = TREE_OPERAND (*expr_p, 1);
 
-    POST_P points to the list where side effects that must happen after
-       *EXPR_P should be stored.
+  args = tree_cons (NULL, size, NULL);
 
-    WANT_VALUE is nonzero iff we want to use the value of this expression
-       in another expression.  */
+  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 (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
+gimplify_modify_expr_to_memset (tree *expr_p, tree size, bool want_value)
 {
-  tree *from_p = &TREE_OPERAND (*expr_p, 1);
-  tree *to_p = &TREE_OPERAND (*expr_p, 0);
-  enum gimplify_status ret = GS_UNHANDLED;
+  tree args, t, to, to_ptr;
 
-#if defined ENABLE_CHECKING
-  if (TREE_CODE (*expr_p) != MODIFY_EXPR && TREE_CODE (*expr_p) != INIT_EXPR)
-    abort ();
-#endif
+  to = TREE_OPERAND (*expr_p, 0);
 
-  /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful.  */
-  if (TREE_CODE (*expr_p) == INIT_EXPR)
-    TREE_SET_CODE (*expr_p, MODIFY_EXPR);
+  args = tree_cons (NULL, size, NULL);
 
-  /* See if any simplifications can be done based on what the RHS is.  */
-  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
-                                 want_value);
-  if (ret != GS_UNHANDLED)
+  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 (IS_TYPE_OR_DECL_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 behavior.  */
+  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.  */
+         gcc_assert (purpose);
+         /* ??? Need to handle this.  */
+         gcc_assert (TREE_CODE (purpose) != RANGE_EXPR);
+
+         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);
 
-  /* 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)
+  ret = GS_ALL_DONE;
+  switch (TREE_CODE (type))
     {
-      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)
+    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);
+               gcc_assert (!TREE_CHAIN (elt_list));
+             }
+         }
+       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,
+                                rhs_predicate_for (TREE_OPERAND (*expr_p, 0)),
+                                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
        {
-         t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
-         t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
+         /* 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_val, fb_rvalue);
+             if (tret == GS_ERROR)
+               ret = GS_ERROR;
+           }
        }
-      *expr_p = t;
-      return GS_OK;
-    }
-
-  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
-  if (ret == GS_ERROR)
-    return ret;
-
-  ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_rhs, fb_rvalue);
-  if (ret == GS_ERROR)
-    return ret;
-
-  /* Now see if the above changed *from_p to something we handle specially.  */
-  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
-                                 want_value);
-  if (ret != GS_UNHANDLED)
-    return ret;
+      break;
 
-  /* If the destination is already simple, nothing else needed.  */
-  if (is_gimple_tmp_var (*to_p))
-    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;
+    default:
+      /* So how did we get a CONSTRUCTOR for a scalar type?  */
+      gcc_unreachable ();
     }
 
-  if (want_value)
+  if (ret == GS_ERROR)
+    return GS_ERROR;
+  else if (want_value)
     {
       append_to_statement_list (*expr_p, pre_p);
-      *expr_p = *to_p;
+      *expr_p = object;
+      return GS_OK;
     }
-
-  return ret;
+  else
+    return GS_ALL_DONE;
 }
 
-/*  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.  */
+/* 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.  */
 
 static enum gimplify_status
 gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
@@ -2770,10 +2757,11 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
        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)))
+       /* 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);
@@ -2790,6 +2778,99 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
   return ret;
 }
 
+/* Gimplify the MODIFY_EXPR node pointed by EXPR_P.
+
+      modify_expr
+             : varname '=' rhs
+             | '*' ID '=' rhs
+
+    PRE_P points to the list where side effects that must happen before
+       *EXPR_P should be stored.
+
+    POST_P points to the list where side effects that must happen after
+       *EXPR_P should be stored.
+
+    WANT_VALUE is nonzero iff we want to use the value of this expression
+       in another expression.  */
+
+static enum gimplify_status
+gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
+{
+  tree *from_p = &TREE_OPERAND (*expr_p, 1);
+  tree *to_p = &TREE_OPERAND (*expr_p, 0);
+  enum gimplify_status ret = GS_UNHANDLED;
+
+  gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
+             || TREE_CODE (*expr_p) == INIT_EXPR);
+
+  /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful.  */
+  if (TREE_CODE (*expr_p) == INIT_EXPR)
+    TREE_SET_CODE (*expr_p, MODIFY_EXPR);
+
+  /* See if any simplifications can be done based on what the RHS is.  */
+  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+                                 want_value);
+  if (ret != GS_UNHANDLED)
+    return ret;
+
+  /* If 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,
+                      rhs_predicate_for (*to_p), fb_rvalue);
+  if (ret == GS_ERROR)
+    return ret;
+
+  /* Now see if the above changed *from_p to something we handle specially.  */
+  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+                                 want_value);
+  if (ret != GS_UNHANDLED)
+    return ret;
+
+  /* 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 (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
+    {
+      /* If we've somehow already got an SSA_NAME on the LHS, then
+        we're probably modifying it twice.  Not good.  */
+      gcc_assert (TREE_CODE (*to_p) != SSA_NAME);
+      *to_p = make_ssa_name (*to_p, *expr_p);
+    }
+
+  if (want_value)
+    {
+      append_to_statement_list (*expr_p, pre_p);
+      *expr_p = *to_p;
+      return GS_OK;
+    }
+
+  return GS_ALL_DONE;
+}
+
 /*  Gimplify a comparison between two variable-sized objects.  Do this
     with a call to BUILT_IN_MEMCMP.  */
 
@@ -2801,12 +2882,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);
@@ -2847,10 +2928,10 @@ gimplify_boolean_expr (tree *expr_p)
 
    PRE_P points to the list where the side effects for all the
        expressions in the sequence will be emitted.
-    
+
    WANT_VALUE is true when the result of the last COMPOUND_EXPR is used.  */
 /* ??? Should rearrange to share the pre-queue with all the indirect
-   invocations of gimplify_expr.  Would probably save on creations 
+   invocations of gimplify_expr.  Would probably save on creations
    of statement_list nodes.  */
 
 static enum gimplify_status
@@ -2897,7 +2978,9 @@ gimplify_statement_list (tree *expr_p)
       gimplify_stmt (tsi_stmt_ptr (i));
 
       t = tsi_stmt (i);
-      if (TREE_CODE (t) == STATEMENT_LIST)
+      if (t == NULL)
+       tsi_delink (&i);
+      else if (TREE_CODE (t) == STATEMENT_LIST)
        {
          tsi_link_before (&i, t, TSI_SAME_STMT);
          tsi_delink (&i);
@@ -2922,30 +3005,30 @@ gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p)
   enum gimplify_status ret = GS_ALL_DONE;
   tree val;
 
-#if defined ENABLE_CHECKING
-  if (TREE_CODE (*expr_p) != SAVE_EXPR)
-    abort ();
-#endif
-
+  gcc_assert (TREE_CODE (*expr_p) == SAVE_EXPR);
   val = TREE_OPERAND (*expr_p, 0);
 
-  /* If the operand is already a GIMPLE temporary, just re-write the
-     SAVE_EXPR node.  */
-  if (is_gimple_tmp_var (val))
-    *expr_p = val;
-  /* The operand may be a void-valued expression such as SAVE_EXPRs
-     generated by the Java frontend for class initialization.  It is
-     being executed only for its side-effects.  */
-  else if (TREE_TYPE (val) == void_type_node)
+  /* If the SAVE_EXPR has not been resolved, then evaluate it once.  */
+  if (!SAVE_EXPR_RESOLVED_P (*expr_p))
     {
-      tree body = TREE_OPERAND (*expr_p, 0);
-      ret = gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none);
-      append_to_statement_list (body, pre_p);
-      *expr_p = alloc_stmt_list ();
+      /* The operand may be a void-valued expression such as SAVE_EXPRs
+        generated by the Java frontend for class initialization.  It is
+        being executed only for its side-effects.  */
+      if (TREE_TYPE (val) == void_type_node)
+       {
+         ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                              is_gimple_stmt, fb_none);
+         append_to_statement_list (TREE_OPERAND (*expr_p, 0), pre_p);
+         val = NULL;
+       }
+      else
+       val = get_initialized_tmp_var (val, pre_p, post_p);
+
+      TREE_OPERAND (*expr_p, 0) = val;
+      SAVE_EXPR_RESOLVED_P (*expr_p) = 1;
     }
-  else
-    *expr_p = TREE_OPERAND (*expr_p, 0)
-      = get_initialized_tmp_var (val, pre_p, post_p);
+
+  *expr_p = val;
 
   return ret;
 }
@@ -2973,44 +3056,73 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
   switch (TREE_CODE (op0))
     {
     case INDIRECT_REF:
+    case MISALIGNED_INDIRECT_REF:
+    do_indirect_ref:
       /* Check if we are dealing with an expression of the form '&*ptr'.
         While the front end folds away '&*ptr' into 'ptr', these
         expressions may be generated internally by the compiler (e.g.,
         builtins like __builtin_va_end).  */
-      *expr_p = TREE_OPERAND (op0, 0);
-      ret = GS_OK;
-      break;
-
-    case ARRAY_REF:
-      /* Fold &a[6] to (&a + 6).  */
-      ret = gimplify_array_ref_to_plus (&TREE_OPERAND (expr, 0),
-                                       pre_p, post_p);
+      /* Caution: the silent array decomposition semantics we allow for
+        ADDR_EXPR means we can't always discard the pair.  */
+      {
+       tree op00 = TREE_OPERAND (op0, 0);
+       tree t_expr = TREE_TYPE (expr);
+       tree t_op00 = TREE_TYPE (op00);
 
-      /* This added an INDIRECT_REF.  Fold it away.  */
-      *expr_p = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+        if (!lang_hooks.types_compatible_p (t_expr, t_op00))
+         {
+#ifdef ENABLE_CHECKING
+           tree t_op0 = TREE_TYPE (op0);
+           gcc_assert (TREE_CODE (t_op0) == ARRAY_TYPE
+                       && POINTER_TYPE_P (t_expr)
+                       && cpt_same_type (TREE_TYPE (t_op0),
+                                         TREE_TYPE (t_expr))
+                       && POINTER_TYPE_P (t_op00)
+                       && cpt_same_type (t_op0, TREE_TYPE (t_op00)));
+#endif
+           op00 = fold_convert (TREE_TYPE (expr), op00);
+         }
+        *expr_p = op00;
+        ret = GS_OK;
+      }
       break;
 
     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.  */
+
+      /* If the operand is a useless conversion, look through it.  Doing so
+        guarantees that the ADDR_EXPR and its operand will remain of the
+        same type.  */
+      if (tree_ssa_useless_type_conversion (TREE_OPERAND (op0, 0)))
+          op0 = TREE_OPERAND (op0, 0);
+
       *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;
+         op0 = TREE_OPERAND (expr, 0);
 
-         /* Make sure TREE_INVARIANT/TREE_CONSTANT is set properly.  */
+         /* For various reasons, the gimplification of the expression
+            may have made a new INDIRECT_REF.  */
+         if (TREE_CODE (op0) == INDIRECT_REF)
+           goto do_indirect_ref;
+
+         /* Make sure TREE_INVARIANT, TREE_CONSTANT, and TREE_SIDE_EFFECTS
+            is set properly.  */
          recompute_tree_invarant_for_addr_expr (expr);
 
          /* Mark the RHS addressable.  */
@@ -3019,11 +3131,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;
 }
 
@@ -3119,7 +3226,7 @@ gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
       else
        {
          tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
-                               is_gimple_val, fb_rvalue);
+                               is_gimple_asm_val, fb_rvalue);
          if (tret == GS_ERROR)
            ret = tret;
        }
@@ -3169,18 +3276,24 @@ 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;
            }
          else
            {
              tree sl, tfe;
+             enum tree_code code;
+
+             if (CLEANUP_EH_ONLY (wce))
+               code = TRY_CATCH_EXPR;
+             else
+               code = TRY_FINALLY_EXPR;
 
              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));
+             tfe = build (code, void_type_node, sl, NULL_TREE);
+             append_to_statement_list (TREE_OPERAND (wce, 0),
+                                       &TREE_OPERAND (tfe, 1));
              *wce_p = tfe;
              iter = tsi_start (sl);
            }
@@ -3206,7 +3319,7 @@ gimplify_cleanup_point_expr (tree *expr_p, tree *pre_p)
    is the cleanup action required.  */
 
 static void
-gimple_push_cleanup (tree var, tree cleanup, tree *pre_p)
+gimple_push_cleanup (tree var, tree cleanup, bool eh_only, tree *pre_p)
 {
   tree wce;
 
@@ -3243,10 +3356,8 @@ gimple_push_cleanup (tree var, tree cleanup, tree *pre_p)
                           boolean_false_node);
       tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
                          boolean_true_node);
-      cleanup = build (COND_EXPR, void_type_node, flag, cleanup,
-                      alloc_stmt_list ());
-      wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
-                  cleanup, NULL_TREE);
+      cleanup = build (COND_EXPR, void_type_node, flag, cleanup, NULL);
+      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);
@@ -3258,12 +3369,12 @@ 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);
+      CLEANUP_EH_ONLY (wce) = eh_only;
       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.  */
@@ -3307,16 +3418,17 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
       if (TARGET_EXPR_CLEANUP (targ))
        {
          gimplify_stmt (&TARGET_EXPR_CLEANUP (targ));
-         gimple_push_cleanup (temp, TARGET_EXPR_CLEANUP (targ), pre_p);
+         gimple_push_cleanup (temp, TARGET_EXPR_CLEANUP (targ),
+                              CLEANUP_EH_ONLY (targ), pre_p);
        }
 
       /* Only expand this once.  */
       TREE_OPERAND (targ, 3) = init;
       TARGET_EXPR_INITIAL (targ) = NULL_TREE;
     }
-  else if (!temp->decl.seen_in_bind_expr)
+  else
     /* We should have expanded this before.  */
-    abort ();
+    gcc_assert (DECL_SEEN_IN_BIND_EXPR_P (temp));
 
   *expr_p = temp;
   return GS_OK;
@@ -3331,8 +3443,6 @@ void
 gimplify_stmt (tree *stmt_p)
 {
   gimplify_expr (stmt_p, NULL, NULL, is_gimple_stmt, fb_none);
-  if (!*stmt_p)
-    *stmt_p = alloc_stmt_list ();
 }
 
 /* Similarly, but force the result to be a STATEMENT_LIST.  */
@@ -3341,7 +3451,9 @@ void
 gimplify_to_stmt_list (tree *stmt_p)
 {
   gimplify_stmt (stmt_p);
-  if (TREE_CODE (*stmt_p) != STATEMENT_LIST)
+  if (!*stmt_p)
+    *stmt_p = alloc_stmt_list ();
+  else if (TREE_CODE (*stmt_p) != STATEMENT_LIST)
     {
       tree t = *stmt_p;
       *stmt_p = alloc_stmt_list ();
@@ -3388,7 +3500,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;
 
@@ -3408,26 +3519,25 @@ 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;
 
       /* Die, die, die, my darling.  */
       if (save_expr == error_mark_node
-         || TREE_TYPE (save_expr) == error_mark_node)
+         || (TREE_TYPE (save_expr)
+             && TREE_TYPE (save_expr) == error_mark_node))
        {
          ret = GS_ERROR;
          break;
@@ -3463,8 +3573,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:
@@ -3472,11 +3583,11 @@ 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:
-         abort ();
+         gcc_unreachable ();
 
        case COMPOUND_EXPR:
          ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
@@ -3509,34 +3620,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))
@@ -3565,13 +3648,14 @@ 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);
          recalculate_side_effects (*expr_p);
          break;
 
+       case ALIGN_INDIRECT_REF:
+       case MISALIGNED_INDIRECT_REF:
        case INDIRECT_REF:
          ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
                               is_gimple_reg, fb_rvalue);
@@ -3588,7 +3672,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 replaceable 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:
@@ -3630,10 +3725,8 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
        case LABEL_EXPR:
          ret = GS_ALL_DONE;
-#ifdef ENABLE_CHECKING
-         if (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) != current_function_decl)
-           abort ();
-#endif
+         gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
+                     == current_function_decl);
          break;
 
        case CASE_LABEL_EXPR:
@@ -3645,8 +3738,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;
 
@@ -3664,7 +3769,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,
@@ -3677,8 +3782,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 
        case NON_LVALUE_EXPR:
          /* This should have been stripped above.  */
-         abort ();
-         break;
+         gcc_unreachable ();
 
        case ASM_EXPR:
          ret = gimplify_asm_expr (expr_p, pre_p, post_p);
@@ -3720,11 +3824,6 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          }
          break;
 
-       case MIN_EXPR:
-       case MAX_EXPR:
-         ret = gimplify_minimax_expr (expr_p, pre_p, post_p);
-         break;
-
        case LABEL_DECL:
          /* We get here when taking the address of a label.  We mark
             the label as "forced"; meaning it can never be removed and
@@ -3737,69 +3836,101 @@ 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
             declaration, for which we've already issued an error.  It would
-            be really nice if the front end wouldn't leak these at all. 
+            be really nice if the front end wouldn't leak these at all.
             Currently the only known culprit is C++ destructors, as seen
             in g++.old-deja/g++.jason/binding.C.  */
          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
+             gcc_assert (errorcount || sorrycount);
              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:
-         /* If this is a comparison of objects of aggregate type, handle
-            it specially (by converting to a call to memcmp).  It would be
-            nice to only have to do this for variable-sized objects, but
-            then we'd have to allow the same nest of reference nodes we
-            allow for MODIFY_EXPR and that's too complex.  */
-         if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
-             && (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1)))))
-           ret = gimplify_variable_sized_compare (expr_p);
-
-         /* If *EXPR_P does not need to be special-cased, handle it
-            according to its class.  */
-         else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
-           ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
-                                post_p, is_gimple_val, fb_rvalue);
-         else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2'
-                  || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
-                  || TREE_CODE (*expr_p) == TRUTH_AND_EXPR
-                  || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
-                  || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR)
+         switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
            {
-             enum gimplify_status r0, r1;
+           case tcc_comparison:
+             /* If this is a comparison of objects of aggregate type,
+                handle it specially (by converting to a call to
+                memcmp).  It would be nice to only have to do this
+                for variable-sized objects, but then we'd have to
+                allow the same nest of reference nodes we allow for
+                MODIFY_EXPR and that's too complex.  */
+             if (!AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1))))
+               goto expr_2;
+             ret = gimplify_variable_sized_compare (expr_p);
+             break;
 
-             r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
-                                 post_p, is_gimple_val, fb_rvalue);
-             r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
-                                 post_p, is_gimple_val, fb_rvalue);
+           /* If *EXPR_P does not need to be special-cased, handle it
+              according to its class.  */
+           case tcc_unary:
+             ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+                                  post_p, is_gimple_val, fb_rvalue);
+             break;
 
-             ret = MIN (r0, r1);
-           }
-         else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'd'
-                  || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'c')
-           {
+           case tcc_binary:
+           expr_2:
+             {
+               enum gimplify_status r0, r1;
+
+               r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+                                   post_p, is_gimple_val, fb_rvalue);
+               r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
+                                   post_p, is_gimple_val, fb_rvalue);
+
+               ret = MIN (r0, r1);
+               break;
+             }
+
+           case tcc_declaration:
+           case tcc_constant:
              ret = GS_ALL_DONE;
-             break;
+             goto dont_recalculate;
+
+           default:
+             gcc_assert (TREE_CODE (*expr_p) == TRUTH_AND_EXPR
+                         || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
+                         || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR);
+             goto expr_2;
            }
-         else
-           /* Fail if we don't know how to handle this tree code.  */
-           abort ();
 
          recalculate_side_effects (*expr_p);
+       dont_recalculate:
          break;
        }
 
@@ -3814,48 +3945,48 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
   if (ret == GS_ERROR)
     {
       if (is_statement)
-       *expr_p = alloc_stmt_list ();
+       *expr_p = NULL;
       goto out;
     }
 
-#ifdef ENABLE_CHECKING
   /* This was only valid as a return value from the langhook, which
      we handled.  Make sure it doesn't escape from any other context.  */
-  if (ret == GS_UNHANDLED)
-    abort ();
-#endif
+  gcc_assert (ret != GS_UNHANDLED);
 
-  if (!*expr_p)
-    *expr_p = alloc_stmt_list ();
-  if (fallback == fb_none && !is_gimple_stmt (*expr_p))
+  if (fallback == fb_none && *expr_p && !is_gimple_stmt (*expr_p))
     {
       /* We aren't looking for a value, and we don't have a valid
         statement.  If it doesn't have side-effects, throw it away.  */
       if (!TREE_SIDE_EFFECTS (*expr_p))
-       *expr_p = alloc_stmt_list ();
+       *expr_p = NULL;
       else if (!TREE_THIS_VOLATILE (*expr_p))
        {
          /* This is probably a _REF that contains something nested that
             has side effects.  Recurse through the operands to find it.  */
          enum tree_code code = TREE_CODE (*expr_p);
 
-         if (code == COMPONENT_REF
-             || code == REALPART_EXPR || code == IMAGPART_EXPR)
-           gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                          gimple_test_f, fallback);
-         else if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
+         switch (code)
            {
+           case COMPONENT_REF:
+           case REALPART_EXPR: case IMAGPART_EXPR:
+             gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                            gimple_test_f, fallback);
+             break;
+
+           case ARRAY_REF: case ARRAY_RANGE_REF:
              gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
                             gimple_test_f, fallback);
              gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
-                          gimple_test_f, fallback);
+                            gimple_test_f, fallback);
+             break;
+
+           default:
+              /* Anything else with side-effects must be converted to
+                 a valid statement before we get here.  */
+             gcc_unreachable ();
            }
-         else
-           /* Anything else with side-effects
-              must be converted to a valid statement before we get here.  */
-           abort ();
 
-         *expr_p = alloc_stmt_list ();
+         *expr_p = NULL;
        }
       else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
        {
@@ -3867,7 +3998,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
       else
        /* We can't do anything useful with a volatile reference to
           incomplete type, so just throw it away.  */
-       *expr_p = alloc_stmt_list ();
+       *expr_p = NULL;
     }
 
   /* If we are gimplifying at the statement level, we're done.  Tack
@@ -3882,6 +4013,8 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          annotate_all_with_locus (&internal_pre, input_location);
          *expr_p = internal_pre;
        }
+      else if (!*expr_p)
+       ;
       else if (TREE_CODE (*expr_p) == STATEMENT_LIST)
        annotate_all_with_locus (expr_p, input_location);
       else
@@ -3906,7 +4039,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
@@ -3915,12 +4048,9 @@ 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_formal_tmp_rhs (*expr_p))
     {
-#if defined ENABLE_CHECKING
-      if (VOID_TYPE_P (TREE_TYPE (*expr_p)))
-       abort ();
-#endif
+      gcc_assert (!VOID_TYPE_P (TREE_TYPE (*expr_p)));
 
       /* An rvalue will do.  Assign the gimplified expression into a new
         temporary TMP and replace the original expression with TMP.  */
@@ -3932,27 +4062,31 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
        *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
       else
        *expr_p = get_formal_tmp_var (*expr_p, pre_p);
+
+      if (TREE_CODE (*expr_p) != SSA_NAME)
+       DECL_GIMPLE_FORMAL_TEMP_P (*expr_p) = 1;
     }
-  else if (fallback & fb_mayfail)
+  else
     {
-      /* If this is an asm statement, and the user asked for the impossible,
-        don't abort.  Fail and let gimplify_asm_expr issue an error.  */
+#ifdef ENABLE_CHECKING
+      if (!(fallback & fb_mayfail))
+       {
+         fprintf (stderr, "gimplification failed:\n");
+         print_generic_expr (stderr, *expr_p, 0);
+         debug_tree (*expr_p);
+         internal_error ("gimplification failed");
+       }
+#endif
+      gcc_assert (fallback & fb_mayfail);
+      /* If this is an asm statement, and the user asked for the
+        impossible, don't abort.  Fail and let gimplify_asm_expr
+        issue an error.  */
       ret = GS_ERROR;
       goto out;
     }
-  else
-    {
-      fprintf (stderr, "gimplification failed:\n");
-      print_generic_expr (stderr, *expr_p, 0);
-      debug_tree (*expr_p);
-      abort ();
-    }
 
-#if defined ENABLE_CHECKING
   /* Make sure the temporary matches our predicate.  */
-  if (!(*gimple_test_f) (*expr_p))
-    abort ();
-#endif
+  gcc_assert ((*gimple_test_f) (*expr_p));
 
   if (internal_post)
     {
@@ -3966,32 +4100,30 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 }
 
 /* Look through TYPE for variable-sized objects and gimplify each such
-   size that we find.  Return a STATEMENT_LIST containing the result.  */
+   size that we find.  Add to LIST_P any statements generated.  */
 
-tree
-gimplify_type_sizes (tree type)
+void
+gimplify_type_sizes (tree type, tree *list_p)
 {
-  tree stmts = NULL_TREE;
   tree field;
 
   switch (TREE_CODE (type))
     {
     case ERROR_MARK:
-      return alloc_stmt_list ();
+      return;
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case CHAR_TYPE:
     case REAL_TYPE:
-      gimplify_one_sizepos (&TYPE_MIN_VALUE (type), &stmts);
-      gimplify_one_sizepos (&TYPE_MAX_VALUE (type), &stmts);
+      gimplify_one_sizepos (&TYPE_MIN_VALUE (type), list_p);
+      gimplify_one_sizepos (&TYPE_MAX_VALUE (type), list_p);
       break;
 
     case ARRAY_TYPE:
-      /* These anonymous types don't have declarations, so handle them here. */
-      append_to_statement_list (gimplify_type_sizes (TYPE_DOMAIN (type)),
-                               &stmts);
+      /* These anonymous types don't have declarations, so handle them here.  */
+      gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
       break;
 
     case RECORD_TYPE:
@@ -3999,20 +4131,15 @@ gimplify_type_sizes (tree type)
     case QUAL_UNION_TYPE:
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
        if (TREE_CODE (field) == FIELD_DECL)
-         gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), &stmts);
+         gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
       break;
 
     default:
       break;
     }
 
-  gimplify_one_sizepos (&TYPE_SIZE (type), &stmts);
-  gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), &stmts);
-
-  if (!stmts)
-    stmts = alloc_stmt_list ();
-
-  return stmts;
+  gimplify_one_sizepos (&TYPE_SIZE (type), list_p);
+  gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), list_p);
 }
 
 /* Subroutine of the above to gimplify one size or position, *EXPR_P.
@@ -4021,20 +4148,17 @@ gimplify_type_sizes (tree type)
 void
 gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
 {
-  tree pre = NULL_TREE, post = NULL_TREE;
-
   /* 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;
 
-  gimplify_expr (expr_p, &pre, &post, is_gimple_val, fb_rvalue);
-
-  if (pre)
-    append_to_statement_list (pre, stmt_p);
-  if (post)
-    append_to_statement_list (post, stmt_p);
+  gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
 }
 \f
 #ifdef ENABLE_CHECKING
@@ -4087,8 +4211,7 @@ check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
       otype = TREE_TYPE (t);
       ptype = TREE_TYPE (TREE_OPERAND (t, 0));
       dtype = TREE_TYPE (ptype);
-      if (!cpt_same_type (otype, dtype))
-       abort ();
+      gcc_assert (cpt_same_type (otype, dtype));
       break;
 
     case ADDR_EXPR:
@@ -4101,11 +4224,10 @@ check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
             a pointer to the array type.  We must allow this in order to
             properly represent assigning the address of an array in C into
             pointer to the element type.  */
-         if (TREE_CODE (otype) == ARRAY_TYPE
-             && POINTER_TYPE_P (ptype)
-             && cpt_same_type (TREE_TYPE (otype), dtype))
-           break;
-         abort ();
+         gcc_assert (TREE_CODE (otype) == ARRAY_TYPE
+                     && POINTER_TYPE_P (ptype)
+                     && cpt_same_type (TREE_TYPE (otype), dtype));
+         break;
        }
       break;
 
@@ -4147,7 +4269,9 @@ gimplify_body (tree *body_p, tree fndecl)
   /* Unshare again, in case gimplification was sloppy.  */
   unshare_all_trees (body);
 
-  if (TREE_CODE (body) == STATEMENT_LIST)
+  if (!body)
+    body = alloc_stmt_list ();
+  else if (TREE_CODE (body) == STATEMENT_LIST)
     {
       tree t = expr_only (*body_p);
       if (t)
@@ -4218,4 +4342,42 @@ gimplify_function_tree (tree fndecl)
   current_function_decl = oldfn;
 }
 
+\f
+/* Expands EXPR to list of gimple statements STMTS.  If SIMPLE is true,
+   force the result to be either ssa_name or an invariant, otherwise
+   just force it to be a rhs expression.  If VAR is not NULL, make the
+   base variable of the final destination be VAR if suitable.  */
+
+tree
+force_gimple_operand (tree expr, tree *stmts, bool simple, tree var)
+{
+  tree t;
+  enum gimplify_status ret;
+  gimple_predicate gimple_test_f;
+
+  *stmts = NULL_TREE;
+
+  if (is_gimple_val (expr))
+    return expr;
+
+  gimple_test_f = simple ? is_gimple_val : is_gimple_reg_rhs;
+
+  push_gimplify_context ();
+  gimplify_ctxp->into_ssa = true;
+
+  if (var)
+    expr = build (MODIFY_EXPR, TREE_TYPE (var), var, expr);
+
+  ret = gimplify_expr (&expr, stmts, NULL,
+                      gimple_test_f, fb_rvalue);
+  gcc_assert (ret != GS_ERROR);
+
+  for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
+    add_referenced_tmp_var (t);
+
+  pop_gimplify_context (NULL);
+
+  return expr;
+}
+
 #include "gt-gimplify.h"