OSDN Git Service

* tree.h (TREE_ADDRESSABLE): Document its effect for function types.
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index 66b6b52..bfe82dd 100644 (file)
@@ -27,11 +27,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "tree.h"
 #include "rtl.h"
+#include "varray.h"
 #include "gimple.h"
 #include "tree-iterator.h"
 #include "tree-inline.h"
 #include "diagnostic.h"
-#include "tree-pretty-print.h"
 #include "langhooks.h"
 #include "langhooks-def.h"
 #include "tree-flow.h"
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "except.h"
 #include "hashtab.h"
 #include "flags.h"
+#include "real.h"
 #include "function.h"
 #include "output.h"
 #include "expr.h"
@@ -74,10 +75,9 @@ enum gimplify_omp_var_data
 enum omp_region_type
 {
   ORT_WORKSHARE = 0,
+  ORT_TASK = 1,
   ORT_PARALLEL = 2,
-  ORT_COMBINED_PARALLEL = 3,
-  ORT_TASK = 4,
-  ORT_UNTIED_TASK = 5
+  ORT_COMBINED_PARALLEL = 3
 };
 
 struct gimplify_omp_ctx
@@ -158,7 +158,7 @@ gimple_tree_eq (const void *p1, const void *p2)
    During gimplification, we need to manipulate statement sequences
    before the def/use vectors have been constructed.  */
 
-void
+static void
 gimplify_seq_add_stmt (gimple_seq *seq_p, gimple gs)
 {
   gimple_stmt_iterator si;
@@ -319,7 +319,7 @@ new_omp_context (enum omp_region_type region_type)
   c->privatized_types = pointer_set_create ();
   c->location = input_location;
   c->region_type = region_type;
-  if ((region_type & ORT_TASK) == 0)
+  if (region_type != ORT_TASK)
     c->default_kind = OMP_CLAUSE_DEFAULT_SHARED;
   else
     c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
@@ -340,6 +340,47 @@ delete_omp_context (struct gimplify_omp_ctx *c)
 static void omp_add_variable (struct gimplify_omp_ctx *, tree, unsigned int);
 static bool omp_notice_variable (struct gimplify_omp_ctx *, tree, bool);
 
+/* A subroutine of append_to_statement_list{,_force}.  T is not NULL.  */
+
+static void
+append_to_statement_list_1 (tree t, tree *list_p)
+{
+  tree list = *list_p;
+  tree_stmt_iterator i;
+
+  if (!list)
+    {
+      if (t && TREE_CODE (t) == STATEMENT_LIST)
+       {
+         *list_p = t;
+         return;
+       }
+      *list_p = list = alloc_stmt_list ();
+    }
+
+  i = tsi_last (list);
+  tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
+}
+
+/* Add T to the end of the list container pointed to by LIST_P.
+   If T is an expression with no effects, it is ignored.  */
+
+void
+append_to_statement_list (tree t, tree *list_p)
+{
+  if (t && TREE_SIDE_EFFECTS (t))
+    append_to_statement_list_1 (t, list_p);
+}
+
+/* Similar, but the statement is always added, regardless of side effects.  */
+
+void
+append_to_statement_list_force (tree t, tree *list_p)
+{
+  if (t != NULL_TREE)
+    append_to_statement_list_1 (t, list_p);
+}
+
 /* Both gimplify the statement T and append it to *SEQ_P.  This function
    behaves exactly as gimplify_stmt, but you don't have to pass T as a
    reference.  */
@@ -467,23 +508,6 @@ create_tmp_var (tree type, const char *prefix)
   return tmp_var;
 }
 
-/* Create a new temporary variable declaration of type TYPE by calling
-   create_tmp_var and if TYPE is a vector or a complex number, mark the new
-   temporary as gimple register.  */
-
-tree
-create_tmp_reg (tree type, const char *prefix)
-{
-  tree tmp;
-
-  tmp = create_tmp_var (type, prefix);
-  if (TREE_CODE (type) == COMPLEX_TYPE
-      || TREE_CODE (type) == VECTOR_TYPE)
-    DECL_GIMPLE_REG_P (tmp) = 1;
-
-  return tmp;
-}
-
 /* Create a temporary with a name derived from VAL.  Subroutine of
    lookup_tmp_var; nobody else should call this function.  */
 
@@ -820,44 +844,9 @@ annotate_all_with_location (gimple_seq stmt_p, location_t location)
       annotate_one_with_location (gs, location);
     }
 }
-\f
-/* This page contains routines to unshare tree nodes, i.e. to duplicate tree
-   nodes that are referenced more than once in GENERIC functions.  This is
-   necessary because gimplification (translation into GIMPLE) is performed
-   by modifying tree nodes in-place, so gimplication of a shared node in a
-   first context could generate an invalid GIMPLE form in a second context.
-
-   This is achieved with a simple mark/copy/unmark algorithm that walks the
-   GENERIC representation top-down, marks nodes with TREE_VISITED the first
-   time it encounters them, duplicates them if they already have TREE_VISITED
-   set, and finally removes the TREE_VISITED marks it has set.
-
-   The algorithm works only at the function level, i.e. it generates a GENERIC
-   representation of a function with no nodes shared within the function when
-   passed a GENERIC function (except for nodes that are allowed to be shared).
-
-   At the global level, it is also necessary to unshare tree nodes that are
-   referenced in more than one function, for the same aforementioned reason.
-   This requires some cooperation from the front-end.  There are 2 strategies:
-
-     1. Manual unsharing.  The front-end needs to call unshare_expr on every
-        expression that might end up being shared across functions.
-
-     2. Deep unsharing.  This is an extension of regular unsharing.  Instead
-        of calling unshare_expr on expressions that might be shared across
-        functions, the front-end pre-marks them with TREE_VISITED.  This will
-        ensure that they are unshared on the first reference within functions
-        when the regular unsharing algorithm runs.  The counterpart is that
-        this algorithm must look deeper than for manual unsharing, which is
-        specified by LANG_HOOKS_DEEP_UNSHARING.
-
-  If there are only few specific cases of node sharing across functions, it is
-  probably easier for a front-end to unshare the expressions manually.  On the
-  contrary, if the expressions generated at the global level are as widespread
-  as expressions generated within functions, deep unsharing is very likely the
-  way to go.  */
-
-/* Similar to copy_tree_r but do not copy SAVE_EXPR or TARGET_EXPR nodes.
+
+
+/* Similar to copy_tree_r() but do not copy SAVE_EXPR or TARGET_EXPR nodes.
    These nodes model computations that should only be done once.  If we
    were to unshare something like SAVE_EXPR(i++), the gimplification
    process would create wrong code.  */
@@ -865,39 +854,21 @@ annotate_all_with_location (gimple_seq stmt_p, location_t location)
 static tree
 mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
 {
-  tree t = *tp;
-  enum tree_code code = TREE_CODE (t);
-
-  /* Do not copy SAVE_EXPR or TARGET_EXPR nodes themselves, but copy
-     their subtrees if we can make sure to do it only once.  */
-  if (code == SAVE_EXPR || code == TARGET_EXPR)
-    {
-      if (data && !pointer_set_insert ((struct pointer_set_t *)data, t))
-       ;
-      else
-       *walk_subtrees = 0;
-    }
-
-  /* Stop at types, decls, constants like copy_tree_r.  */
-  else if (TREE_CODE_CLASS (code) == tcc_type
-          || TREE_CODE_CLASS (code) == tcc_declaration
-          || TREE_CODE_CLASS (code) == tcc_constant
-          /* We can't do anything sensible with a BLOCK used as an
-             expression, but we also can't just die when we see it
-             because of non-expression uses.  So we avert our eyes
-             and cross our fingers.  Silly Java.  */
-          || code == BLOCK)
+  enum tree_code code = TREE_CODE (*tp);
+  /* Don't unshare types, decls, constants and SAVE_EXPR nodes.  */
+  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 just die 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;
-
-  /* Cope with the statement expression extension.  */
-  else if (code == STATEMENT_LIST)
-    ;
-
-  /* Leave the bulk of the work to copy_tree_r itself.  */
   else
     {
       gcc_assert (code != BIND_EXPR);
-      copy_tree_r (tp, walk_subtrees, NULL);
+      copy_tree_r (tp, walk_subtrees, data);
     }
 
   return NULL_TREE;
@@ -905,10 +876,16 @@ mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
 
 /* 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 mostly_copy_tree_r.  */
+   then *TP is deep copied by calling copy_tree_r.
+
+   This unshares the same trees as copy_tree_r with the exception of
+   SAVE_EXPR nodes.  These nodes model computations that should only be
+   done once.  If we were to unshare something like SAVE_EXPR(i++), the
+   gimplification process would create wrong code.  */
 
 static tree
-copy_if_shared_r (tree *tp, int *walk_subtrees, void *data)
+copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+                 void *data ATTRIBUTE_UNUSED)
 {
   tree t = *tp;
   enum tree_code code = TREE_CODE (t);
@@ -931,29 +908,27 @@ copy_if_shared_r (tree *tp, int *walk_subtrees, void *data)
      any deeper.  */
   else if (TREE_VISITED (t))
     {
-      walk_tree (tp, mostly_copy_tree_r, data, NULL);
+      walk_tree (tp, mostly_copy_tree_r, NULL, NULL);
       *walk_subtrees = 0;
     }
 
-  /* Otherwise, mark the node as visited and keep looking.  */
+  /* Otherwise, mark the tree as visited and keep looking.  */
   else
     TREE_VISITED (t) = 1;
 
   return NULL_TREE;
 }
 
-/* Unshare most of the shared trees rooted at *TP. */
-
-static inline void
-copy_if_shared (tree *tp)
+static tree
+unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+                 void *data ATTRIBUTE_UNUSED)
 {
-  /* If the language requires deep unsharing, we need a pointer set to make
-     sure we don't repeatedly unshare subtrees of unshareable nodes.  */
-  struct pointer_set_t *visited
-    = lang_hooks.deep_unsharing ? pointer_set_create () : NULL;
-  walk_tree (tp, copy_if_shared_r, visited, NULL);
-  if (visited)
-    pointer_set_destroy (visited);
+  if (TREE_VISITED (*tp))
+    TREE_VISITED (*tp) = 0;
+  else
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
 }
 
 /* Unshare all the trees in BODY_P, a pointer into the body of FNDECL, and the
@@ -965,40 +940,12 @@ unshare_body (tree *body_p, tree fndecl)
 {
   struct cgraph_node *cgn = cgraph_node (fndecl);
 
-  copy_if_shared (body_p);
-
+  walk_tree (body_p, copy_if_shared_r, NULL, NULL);
   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);
 }
 
-/* Callback for walk_tree to unmark the visited trees rooted at *TP.
-   Subtrees are walked until the first unvisited node is encountered.  */
-
-static tree
-unmark_visited_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
-{
-  tree t = *tp;
-
-  /* If this node has been visited, unmark it and keep looking.  */
-  if (TREE_VISITED (t))
-    TREE_VISITED (t) = 0;
-
-  /* Otherwise, don't look any deeper.  */
-  else
-    *walk_subtrees = 0;
-
-  return NULL_TREE;
-}
-
-/* Unmark the visited trees rooted at *TP.  */
-
-static inline void
-unmark_visited (tree *tp)
-{
-  walk_tree (tp, unmark_visited_r, NULL, NULL);
-}
-
 /* Likewise, but mark all trees as not visited.  */
 
 static void
@@ -1006,8 +953,7 @@ unvisit_body (tree *body_p, tree fndecl)
 {
   struct cgraph_node *cgn = cgraph_node (fndecl);
 
-  unmark_visited (body_p);
-
+  walk_tree (body_p, unmark_visited_r, NULL, NULL);
   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);
@@ -1266,27 +1212,17 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
      hard_function_value generates a PARALLEL, we'll die during normal
      expansion of structure assignments; there's special code in expand_return
      to handle this case that does not exist in expand_expr.  */
-  if (!result_decl)
-    result = NULL_TREE;
-  else if (aggregate_value_p (result_decl, TREE_TYPE (current_function_decl)))
-    {
-      if (TREE_CODE (DECL_SIZE (result_decl)) != INTEGER_CST)
-       {
-         if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (result_decl)))
-           gimplify_type_sizes (TREE_TYPE (result_decl), pre_p);
-         /* Note that we don't use gimplify_vla_decl because the RESULT_DECL
-            should be effectively allocated by the caller, i.e. all calls to
-            this function must be subject to the Return Slot Optimization.  */
-         gimplify_one_sizepos (&DECL_SIZE (result_decl), pre_p);
-         gimplify_one_sizepos (&DECL_SIZE_UNIT (result_decl), pre_p);
-       }
-      result = result_decl;
-    }
+  if (!result_decl
+      || aggregate_value_p (result_decl, TREE_TYPE (current_function_decl)))
+    result = result_decl;
   else if (gimplify_ctxp->return_temp)
     result = gimplify_ctxp->return_temp;
   else
     {
-      result = create_tmp_reg (TREE_TYPE (result_decl), NULL);
+      result = create_tmp_var (TREE_TYPE (result_decl), NULL);
+      if (TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
+          || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
+        DECL_GIMPLE_REG_P (result) = 1;
 
       /* ??? With complex control flow (usually involving abnormal edges),
         we can wind up warning about an uninitialized value for this.  Due
@@ -1952,10 +1888,9 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 {
   tree *p;
   VEC(tree,heap) *stack;
-  enum gimplify_status ret = GS_ALL_DONE, tret;
+  enum gimplify_status ret = GS_OK, tret;
   int i;
   location_t loc = EXPR_LOCATION (*expr_p);
-  tree expr = *expr_p;
 
   /* Create a stack of the subexpressions so later we can walk them in
      order from inner to outer.  */
@@ -2109,12 +2044,11 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
   if ((fallback & fb_rvalue) && TREE_CODE (*expr_p) == COMPONENT_REF)
     {
       canonicalize_component_ref (expr_p);
+      ret = MIN (ret, GS_OK);
     }
 
   VEC_free (tree, heap, stack);
 
-  gcc_assert (*expr_p == expr || ret != GS_ALL_DONE);
-
   return ret;
 }
 
@@ -2919,67 +2853,71 @@ static enum gimplify_status
 gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
 {
   tree expr = *expr_p;
-  tree type = TREE_TYPE (expr);
-  location_t loc = EXPR_LOCATION (expr);
-  tree tmp, arm1, arm2;
+  tree tmp, type, arm1, arm2;
   enum gimplify_status ret;
   tree label_true, label_false, label_cont;
   bool have_then_clause_p, have_else_clause_p;
   gimple gimple_cond;
   enum tree_code pred_code;
   gimple_seq seq = NULL;
+  location_t loc = EXPR_LOCATION (*expr_p);
+
+  type = TREE_TYPE (expr);
 
   /* If this COND_EXPR has a value, copy the values into a temporary within
      the arms.  */
-  if (!VOID_TYPE_P (type))
+  if (! VOID_TYPE_P (type))
     {
-      tree then_ = TREE_OPERAND (expr, 1), else_ = TREE_OPERAND (expr, 2);
       tree result;
 
-      /* If either an rvalue is ok or we do not require an lvalue, create the
-        temporary.  But we cannot do that if the type is addressable.  */
-      if (((fallback & fb_rvalue) || !(fallback & fb_lvalue))
+      /* If an rvalue is ok or we do not require an lvalue, avoid creating
+        an addressable temporary.  */
+      if (((fallback & fb_rvalue)
+          || !(fallback & fb_lvalue))
          && !TREE_ADDRESSABLE (type))
        {
          if (gimplify_ctxp->allow_rhs_cond_expr
              /* If either branch has side effects or could trap, it can't be
                 evaluated unconditionally.  */
-             && !TREE_SIDE_EFFECTS (then_)
-             && !generic_expr_could_trap_p (then_)
-             && !TREE_SIDE_EFFECTS (else_)
-             && !generic_expr_could_trap_p (else_))
+             && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 1))
+             && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 1))
+             && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 2))
+             && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 2)))
            return gimplify_pure_cond_expr (expr_p, pre_p);
 
-         tmp = create_tmp_var (type, "iftmp");
-         result = tmp;
+         result = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+         ret = GS_ALL_DONE;
        }
-
-      /* Otherwise, only create and copy references to the values.  */
       else
        {
-         type = build_pointer_type (type);
+         tree type = build_pointer_type (TREE_TYPE (expr));
 
-         if (!VOID_TYPE_P (TREE_TYPE (then_)))
-           then_ = build_fold_addr_expr_loc (loc, then_);
+         if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
+           TREE_OPERAND (expr, 1) =
+             build_fold_addr_expr_loc (loc, TREE_OPERAND (expr, 1));
 
-         if (!VOID_TYPE_P (TREE_TYPE (else_)))
-           else_ = build_fold_addr_expr_loc (loc, else_);
-         expr
-           = build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_);
+         if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
+           TREE_OPERAND (expr, 2) =
+             build_fold_addr_expr_loc (loc, TREE_OPERAND (expr, 2));
 
          tmp = create_tmp_var (type, "iftmp");
+
+         expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
+                        TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
+
          result = build_fold_indirect_ref_loc (loc, tmp);
        }
 
-      /* Build the new then clause, `tmp = then_;'.  But don't build the
-        assignment if the value is void; in C++ it can be if it's a throw.  */
-      if (!VOID_TYPE_P (TREE_TYPE (then_)))
-       TREE_OPERAND (expr, 1) = build2 (MODIFY_EXPR, type, tmp, then_);
+      /* Build the then clause, 't1 = a;'.  But don't build an assignment
+        if this branch is void; in C++ it can be, if it's a throw.  */
+      if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
+       TREE_OPERAND (expr, 1)
+         = build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, TREE_OPERAND (expr, 1));
 
-      /* Similarly, build the new else clause, `tmp = else_;'.  */
-      if (!VOID_TYPE_P (TREE_TYPE (else_)))
-       TREE_OPERAND (expr, 2) = build2 (MODIFY_EXPR, type, tmp, else_);
+      /* Build the else clause, 't1 = b;'.  */
+      if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
+       TREE_OPERAND (expr, 2)
+         = build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, TREE_OPERAND (expr, 2));
 
       TREE_TYPE (expr) = void_type_node;
       recalculate_side_effects (expr);
@@ -3810,14 +3748,25 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                && num_nonzero_elements > 1
                && !can_move_by_pieces (size, align))
              {
+               tree new_tree;
+
                if (notify_temp_creation)
                  return GS_ERROR;
 
-               walk_tree (&ctor, force_labels_r, NULL, NULL);
-               ctor = tree_output_constant_def (ctor);
-               if (!useless_type_conversion_p (type, TREE_TYPE (ctor)))
-                 ctor = build1 (VIEW_CONVERT_EXPR, type, ctor);
-               TREE_OPERAND (*expr_p, 1) = ctor;
+               new_tree = create_tmp_var_raw (type, "C");
+
+               gimple_add_tmp_var (new_tree);
+               TREE_STATIC (new_tree) = 1;
+               TREE_READONLY (new_tree) = 1;
+               DECL_INITIAL (new_tree) = ctor;
+               if (align > DECL_ALIGN (new_tree))
+                 {
+                   DECL_ALIGN (new_tree) = align;
+                   DECL_USER_ALIGN (new_tree) = 1;
+                 }
+               walk_tree (&DECL_INITIAL (new_tree), force_labels_r, NULL, NULL);
+
+               TREE_OPERAND (*expr_p, 1) = new_tree;
 
                /* This is no longer an assignment of a CONSTRUCTOR, but
                   we still may have processing to do on the LHS.  So
@@ -3844,10 +3793,10 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
        if (notify_temp_creation)
          return GS_OK;
 
-       /* If there are nonzero elements and if needed, pre-evaluate to capture
-          elements overlapping with the lhs into temporaries.  We must do this
-          before clearing to fetch the values before they are zeroed-out.  */
-       if (num_nonzero_elements > 0 && TREE_CODE (*expr_p) != INIT_EXPR)
+       /* If there are nonzero elements, pre-evaluate to capture elements
+          overlapping with the lhs into temporaries.  We must do this before
+          clearing to fetch the values before they are zeroed-out.  */
+       if (num_nonzero_elements > 0)
          {
            preeval_data.lhs_base_decl = get_base_address (object);
            if (!DECL_P (preeval_data.lhs_base_decl))
@@ -4145,255 +4094,253 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
                          gimple_seq *pre_p, gimple_seq *post_p,
                          bool want_value)
 {
-  enum gimplify_status ret = GS_UNHANDLED;
-  bool changed;
+  enum gimplify_status ret = GS_OK;
 
-  do
-    {
-      changed = false;
-      switch (TREE_CODE (*from_p))
-       {
-       case VAR_DECL:
-         /* If we're assigning from a read-only variable initialized with
-            a constructor, do the direct assignment from the constructor,
-            but only if neither source nor target are volatile since this
-            latter assignment might end up being done on a per-field basis.  */
-         if (DECL_INITIAL (*from_p)
-             && TREE_READONLY (*from_p)
-             && !TREE_THIS_VOLATILE (*from_p)
-             && !TREE_THIS_VOLATILE (*to_p)
-             && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR)
-           {
-             tree old_from = *from_p;
-             enum gimplify_status subret;
-
-             /* Move the constructor into the RHS.  */
-             *from_p = unshare_expr (DECL_INITIAL (*from_p));
-
-             /* Let's see if gimplify_init_constructor will need to put
-                it in memory.  */
-             subret = gimplify_init_constructor (expr_p, NULL, NULL,
-                                                 false, true);
-             if (subret == GS_ERROR)
-               {
-                 /* If so, revert the change.  */
-                 *from_p = old_from;
-               }
-             else
-               {
-                 ret = GS_OK;
-                 changed = true;
-               }
-           }
-         break;
-       case INDIRECT_REF:
+  while (ret != GS_UNHANDLED)
+    switch (TREE_CODE (*from_p))
+      {
+      case VAR_DECL:
+       /* If we're assigning from a read-only variable initialized with
+          a constructor, do the direct assignment from the constructor,
+          but only if neither source nor target are volatile since this
+          latter assignment might end up being done on a per-field basis.  */
+       if (DECL_INITIAL (*from_p)
+           && TREE_READONLY (*from_p)
+           && !TREE_THIS_VOLATILE (*from_p)
+           && !TREE_THIS_VOLATILE (*to_p)
+           && TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR)
          {
-           /* If we have code like
+           tree old_from = *from_p;
 
-            *(const A*)(A*)&x
+           /* Move the constructor into the RHS.  */
+           *from_p = unshare_expr (DECL_INITIAL (*from_p));
 
-            where the type of "x" is a (possibly cv-qualified variant
-            of "A"), treat the entire expression as identical to "x".
-            This kind of code arises in C++ when an object is bound
-            to a const reference, and if "x" is a TARGET_EXPR we want
-            to take advantage of the optimization below.  */
-           tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
-           if (t)
+           /* Let's see if gimplify_init_constructor will need to put
+              it in memory.  If so, revert the change.  */
+           ret = gimplify_init_constructor (expr_p, NULL, NULL, false, true);
+           if (ret == GS_ERROR)
              {
-               *from_p = t;
-               ret = GS_OK;
-               changed = true;
+               *from_p = old_from;
+               /* Fall through.  */
              }
-           break;
-         }
-
-       case TARGET_EXPR:
-         {
-           /* If we are initializing something from a TARGET_EXPR, strip the
-              TARGET_EXPR and initialize it directly, if possible.  This can't
-              be done if the initializer is void, since that implies that the
-              temporary is set in some non-trivial way.
-
-              ??? What about code that pulls out the temp and uses it
-              elsewhere? I think that such code never uses the TARGET_EXPR as
-              an initializer.  If I'm wrong, we'll die because the temp won't
-              have any RTL.  In that case, I guess we'll need to replace
-              references somehow.  */
-           tree init = TARGET_EXPR_INITIAL (*from_p);
-
-           if (init
-               && !VOID_TYPE_P (TREE_TYPE (init)))
+           else
              {
-               *from_p = init;
                ret = GS_OK;
-               changed = true;
+               break;
              }
          }
-         break;
-
-       case COMPOUND_EXPR:
-         /* Remove any COMPOUND_EXPR in the RHS so the following cases will be
-            caught.  */
-         gimplify_compound_expr (from_p, pre_p, true);
-         ret = GS_OK;
-         changed = true;
-         break;
+       ret = GS_UNHANDLED;
+       break;
+      case INDIRECT_REF:
+       {
+         /* If we have code like
 
-       case CONSTRUCTOR:
-         /* If we're initializing from a CONSTRUCTOR, break this into
-            individual MODIFY_EXPRs.  */
-         return gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
-                                           false);
+               *(const A*)(A*)&x
 
-       case COND_EXPR:
-         /* If we're assigning to a non-register type, push the assignment
-            down into the branches.  This is mandatory for ADDRESSABLE types,
-            since we cannot generate temporaries for such, but it saves a
-            copy in other cases as well.  */
-         if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
+            where the type of "x" is a (possibly cv-qualified variant
+            of "A"), treat the entire expression as identical to "x".
+            This kind of code arises in C++ when an object is bound
+            to a const reference, and if "x" is a TARGET_EXPR we want
+            to take advantage of the optimization below.  */
+         tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
+         if (t)
            {
-             /* This code should mirror the code in gimplify_cond_expr. */
-             enum tree_code code = TREE_CODE (*expr_p);
-             tree cond = *from_p;
-             tree result = *to_p;
-
-             ret = gimplify_expr (&result, pre_p, post_p,
-                                  is_gimple_lvalue, fb_lvalue);
-             if (ret != GS_ERROR)
-               ret = GS_OK;
-
-             if (TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node)
-               TREE_OPERAND (cond, 1)
-                 = build2 (code, void_type_node, result,
-                           TREE_OPERAND (cond, 1));
-             if (TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node)
-               TREE_OPERAND (cond, 2)
-                 = build2 (code, void_type_node, unshare_expr (result),
-                           TREE_OPERAND (cond, 2));
-
-             TREE_TYPE (cond) = void_type_node;
-             recalculate_side_effects (cond);
-
-             if (want_value)
-               {
-                 gimplify_and_add (cond, pre_p);
-                 *expr_p = unshare_expr (result);
-               }
-             else
-               *expr_p = cond;
-             return ret;
+             *from_p = t;
+             ret = GS_OK;
            }
+         else
+           ret = GS_UNHANDLED;
          break;
+       }
 
-       case CALL_EXPR:
-         /* For calls that return in memory, give *to_p as the CALL_EXPR's
-            return slot so that we don't generate a temporary.  */
-         if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p)
-             && aggregate_value_p (*from_p, *from_p))
+      case TARGET_EXPR:
+       {
+         /* If we are initializing something from a TARGET_EXPR, strip the
+            TARGET_EXPR and initialize it directly, if possible.  This can't
+            be done if the initializer is void, since that implies that the
+            temporary is set in some non-trivial way.
+
+            ??? What about code that pulls out the temp and uses it
+            elsewhere? I think that such code never uses the TARGET_EXPR as
+            an initializer.  If I'm wrong, we'll die because the temp won't
+            have any RTL.  In that case, I guess we'll need to replace
+            references somehow.  */
+         tree init = TARGET_EXPR_INITIAL (*from_p);
+
+         if (init
+             && !VOID_TYPE_P (TREE_TYPE (init)))
            {
-             bool use_target;
-
-             if (!(rhs_predicate_for (*to_p))(*from_p))
-               /* If we need a temporary, *to_p isn't accurate.  */
-               use_target = false;
-             else if (TREE_CODE (*to_p) == RESULT_DECL
-                      && DECL_NAME (*to_p) == NULL_TREE
-                      && needs_to_live_in_memory (*to_p))
-               /* It's OK to use the return slot directly unless it's an NRV. */
-               use_target = true;
-             else if (is_gimple_reg_type (TREE_TYPE (*to_p))
-                      || (DECL_P (*to_p) && DECL_REGISTER (*to_p)))
-               /* Don't force regs into memory.  */
-               use_target = false;
-             else if (TREE_CODE (*expr_p) == INIT_EXPR)
-               /* It's OK to use the target directly if it's being
-                  initialized. */
-               use_target = true;
-             else if (!is_gimple_non_addressable (*to_p))
-               /* Don't use the original target if it's already addressable;
-                  if its address escapes, and the called function uses the
-                  NRV optimization, a conforming program could see *to_p
-                  change before the called function returns; see c++/19317.
-                  When optimizing, the return_slot pass marks more functions
-                  as safe after we have escape info.  */
-               use_target = false;
-             else
-               use_target = true;
-
-             if (use_target)
-               {
-                 CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1;
-                 mark_addressable (*to_p);
-               }
+             *from_p = init;
+             ret = GS_OK;
            }
-         break;
+         else
+           ret = GS_UNHANDLED;
+       }
+       break;
 
-       case WITH_SIZE_EXPR:
-         /* Likewise for calls that return an aggregate of non-constant size,
-            since we would not be able to generate a temporary at all.  */
-         if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR)
-           {
-             *from_p = TREE_OPERAND (*from_p, 0);
-             /* We don't change ret in this case because the
-                WITH_SIZE_EXPR might have been added in
-                gimplify_modify_expr, so returning GS_OK would lead to an
-                infinite loop.  */
-             changed = true;
-           }
-         break;
+      case COMPOUND_EXPR:
+       /* Remove any COMPOUND_EXPR in the RHS so the following cases will be
+          caught.  */
+       gimplify_compound_expr (from_p, pre_p, true);
+       ret = GS_OK;
+       break;
 
-         /* If we're initializing from a container, push the initialization
-            inside it.  */
-       case CLEANUP_POINT_EXPR:
-       case BIND_EXPR:
-       case STATEMENT_LIST:
+      case CONSTRUCTOR:
+       /* If we're initializing from a CONSTRUCTOR, break this into
+          individual MODIFY_EXPRs.  */
+       return gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
+                                         false);
+
+      case COND_EXPR:
+       /* If we're assigning to a non-register type, push the assignment
+          down into the branches.  This is mandatory for ADDRESSABLE types,
+          since we cannot generate temporaries for such, but it saves a
+          copy in other cases as well.  */
+       if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
          {
-           tree wrap = *from_p;
-           tree t;
+           /* This code should mirror the code in gimplify_cond_expr. */
+           enum tree_code code = TREE_CODE (*expr_p);
+           tree cond = *from_p;
+           tree result = *to_p;
 
-           ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval,
-                                fb_lvalue);
+           ret = gimplify_expr (&result, pre_p, post_p,
+                                is_gimple_lvalue, fb_lvalue);
            if (ret != GS_ERROR)
              ret = GS_OK;
 
-           t = voidify_wrapper_expr (wrap, *expr_p);
-           gcc_assert (t == *expr_p);
+           if (TREE_TYPE (TREE_OPERAND (cond, 1)) != void_type_node)
+             TREE_OPERAND (cond, 1)
+               = build2 (code, void_type_node, result,
+                         TREE_OPERAND (cond, 1));
+           if (TREE_TYPE (TREE_OPERAND (cond, 2)) != void_type_node)
+             TREE_OPERAND (cond, 2)
+               = build2 (code, void_type_node, unshare_expr (result),
+                         TREE_OPERAND (cond, 2));
+
+           TREE_TYPE (cond) = void_type_node;
+           recalculate_side_effects (cond);
 
            if (want_value)
              {
-               gimplify_and_add (wrap, pre_p);
-               *expr_p = unshare_expr (*to_p);
+               gimplify_and_add (cond, pre_p);
+               *expr_p = unshare_expr (result);
              }
            else
-             *expr_p = wrap;
-           return GS_OK;
+             *expr_p = cond;
+           return ret;
          }
+       else
+         ret = GS_UNHANDLED;
+       break;
 
-       case COMPOUND_LITERAL_EXPR:
+      case CALL_EXPR:
+       /* For calls that return in memory, give *to_p as the CALL_EXPR's
+          return slot so that we don't generate a temporary.  */
+       if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p)
+           && aggregate_value_p (*from_p, *from_p))
          {
-           tree complit = TREE_OPERAND (*expr_p, 1);
-           tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit);
-           tree decl = DECL_EXPR_DECL (decl_s);
-           tree init = DECL_INITIAL (decl);
-
-           /* struct T x = (struct T) { 0, 1, 2 } can be optimized
-              into struct T x = { 0, 1, 2 } if the address of the
-              compound literal has never been taken.  */
-           if (!TREE_ADDRESSABLE (complit)
-               && !TREE_ADDRESSABLE (decl)
-               && init)
+           bool use_target;
+
+           if (!(rhs_predicate_for (*to_p))(*from_p))
+             /* If we need a temporary, *to_p isn't accurate.  */
+             use_target = false;
+           else if (TREE_CODE (*to_p) == RESULT_DECL
+                    && DECL_NAME (*to_p) == NULL_TREE
+                    && needs_to_live_in_memory (*to_p))
+             /* It's OK to use the return slot directly unless it's an NRV. */
+             use_target = true;
+           else if (is_gimple_reg_type (TREE_TYPE (*to_p))
+                    || (DECL_P (*to_p) && DECL_REGISTER (*to_p)))
+             /* Don't force regs into memory.  */
+             use_target = false;
+           else if (TREE_CODE (*expr_p) == INIT_EXPR)
+             /* It's OK to use the target directly if it's being
+                initialized. */
+             use_target = true;
+           else if (!is_gimple_non_addressable (*to_p))
+             /* Don't use the original target if it's already addressable;
+                if its address escapes, and the called function uses the
+                NRV optimization, a conforming program could see *to_p
+                change before the called function returns; see c++/19317.
+                When optimizing, the return_slot pass marks more functions
+                as safe after we have escape info.  */
+             use_target = false;
+           else
+             use_target = true;
+
+           if (use_target)
              {
-               *expr_p = copy_node (*expr_p);
-               TREE_OPERAND (*expr_p, 1) = init;
-               return GS_OK;
+               CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1;
+               mark_addressable (*to_p);
              }
          }
 
-       default:
-         break;
+       ret = GS_UNHANDLED;
+       break;
+
+      case WITH_SIZE_EXPR:
+       /* Likewise for calls that return an aggregate of non-constant size,
+          since we would not be able to generate a temporary at all.  */
+       if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR)
+         {
+           *from_p = TREE_OPERAND (*from_p, 0);
+           ret = GS_OK;
+         }
+       else
+         ret = GS_UNHANDLED;
+       break;
+
+       /* If we're initializing from a container, push the initialization
+          inside it.  */
+      case CLEANUP_POINT_EXPR:
+      case BIND_EXPR:
+      case STATEMENT_LIST:
+       {
+         tree wrap = *from_p;
+         tree t;
+
+         ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_min_lval,
+                              fb_lvalue);
+         if (ret != GS_ERROR)
+           ret = GS_OK;
+
+         t = voidify_wrapper_expr (wrap, *expr_p);
+         gcc_assert (t == *expr_p);
+
+         if (want_value)
+           {
+             gimplify_and_add (wrap, pre_p);
+             *expr_p = unshare_expr (*to_p);
+           }
+         else
+           *expr_p = wrap;
+         return GS_OK;
        }
-    }
-  while (changed);
+
+      case COMPOUND_LITERAL_EXPR:
+       {
+         tree complit = TREE_OPERAND (*expr_p, 1);
+         tree decl_s = COMPOUND_LITERAL_EXPR_DECL_EXPR (complit);
+         tree decl = DECL_EXPR_DECL (decl_s);
+         tree init = DECL_INITIAL (decl);
+
+         /* struct T x = (struct T) { 0, 1, 2 } can be optimized
+            into struct T x = { 0, 1, 2 } if the address of the
+            compound literal has never been taken.  */
+         if (!TREE_ADDRESSABLE (complit)
+             && !TREE_ADDRESSABLE (decl)
+             && init)
+           {
+             *expr_p = copy_node (*expr_p);
+             TREE_OPERAND (*expr_p, 1) = init;
+             return GS_OK;
+           }
+       }
+
+      default:
+       ret = GS_UNHANDLED;
+       break;
+      }
 
   return ret;
 }
@@ -5511,31 +5458,6 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags)
   splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags);
 }
 
-/* Notice a threadprivate variable DECL used in OpenMP context CTX.
-   This just prints out diagnostics about threadprivate variable uses
-   in untied tasks.  If DECL2 is non-NULL, prevent this warning
-   on that variable.  */
-
-static bool
-omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl,
-                                  tree decl2)
-{
-  splay_tree_node n;
-
-  if (ctx->region_type != ORT_UNTIED_TASK)
-    return false;
-  n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
-  if (n == NULL)
-    {
-      error ("threadprivate variable %qE used in untied task", DECL_NAME (decl));
-      error_at (ctx->location, "enclosing task");
-      splay_tree_insert (ctx->variables, (splay_tree_key)decl, 0);
-    }
-  if (decl2)
-    splay_tree_insert (ctx->variables, (splay_tree_key)decl2, 0);
-  return false;
-}
-
 /* Record the fact that DECL was used within the OpenMP context CTX.
    IN_CODE is true when real code uses DECL, and false when we should
    merely emit default(none) errors.  Return true if DECL is going to
@@ -5556,14 +5478,14 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
   if (is_global_var (decl))
     {
       if (DECL_THREAD_LOCAL_P (decl))
-       return omp_notice_threadprivate_variable (ctx, decl, NULL_TREE);
+       return false;
 
       if (DECL_HAS_VALUE_EXPR_P (decl))
        {
          tree value = get_base_address (DECL_VALUE_EXPR (decl));
 
          if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value))
-           return omp_notice_threadprivate_variable (ctx, decl, value);
+           return false;
        }
     }
 
@@ -5589,10 +5511,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
        case OMP_CLAUSE_DEFAULT_NONE:
          error ("%qE not specified in enclosing parallel",
                 DECL_NAME (decl));
-         if ((ctx->region_type & ORT_TASK) != 0)
-           error_at (ctx->location, "enclosing task");
-         else
-           error_at (ctx->location, "enclosing parallel");
+         error_at (ctx->location, "enclosing parallel");
          /* FALLTHRU */
        case OMP_CLAUSE_DEFAULT_SHARED:
          flags |= GOVD_SHARED;
@@ -5605,7 +5524,7 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
          break;
        case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
          /* decl will be either GOVD_FIRSTPRIVATE or GOVD_SHARED.  */
-         gcc_assert ((ctx->region_type & ORT_TASK) != 0);
+         gcc_assert (ctx->region_type == ORT_TASK);
          if (ctx->outer_context)
            omp_notice_variable (ctx->outer_context, decl, in_code);
          for (octx = ctx->outer_context; octx; octx = octx->outer_context)
@@ -6108,10 +6027,7 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p)
   gimple_seq body = NULL;
   struct gimplify_ctx gctx;
 
-  gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p,
-                            find_omp_clause (OMP_TASK_CLAUSES (expr),
-                                             OMP_CLAUSE_UNTIED)
-                            ? ORT_UNTIED_TASK : ORT_TASK);
+  gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, ORT_TASK);
 
   push_gimplify_context (&gctx);
 
@@ -6435,7 +6351,9 @@ gimplify_omp_atomic (tree *expr_p, gimple_seq *pre_p)
   tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
   tree tmp_load;
 
-   tmp_load = create_tmp_reg (type, NULL);
+   tmp_load = create_tmp_var (type, NULL);
+   if (TREE_CODE (type) == COMPLEX_TYPE || TREE_CODE (type) == VECTOR_TYPE)
+     DECL_GIMPLE_REG_P (tmp_load) = 1;
    if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
      return GS_ERROR;
 
@@ -6641,8 +6559,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       else if (ret != GS_UNHANDLED)
        break;
 
-      /* Make sure that all the cases set 'ret' appropriately.  */
-      ret = GS_UNHANDLED;
+      ret = GS_OK;
       switch (TREE_CODE (*expr_p))
        {
          /* First deal with the special cases.  */
@@ -6676,7 +6593,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
              mark_addressable (*expr_p);
-             ret = GS_OK;
            }
          break;
 
@@ -6691,7 +6607,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
              mark_addressable (*expr_p);
-             ret = GS_OK;
            }
          break;
 
@@ -6753,7 +6668,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
              /* Just strip a conversion to void (or in void context) and
                 try again.  */
              *expr_p = TREE_OPERAND (*expr_p, 0);
-             ret = GS_OK;
              break;
            }
 
@@ -6774,10 +6688,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
        case INDIRECT_REF:
          *expr_p = fold_indirect_ref_loc (input_location, *expr_p);
          if (*expr_p != save_expr)
-           {
-             ret = GS_OK;
-             break;
-           }
+           break;
          /* else fall through.  */
        case ALIGN_INDIRECT_REF:
        case MISALIGNED_INDIRECT_REF:
@@ -6804,10 +6715,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          if (fallback & fb_lvalue)
            ret = GS_ALL_DONE;
          else
-           {
-             *expr_p = DECL_INITIAL (*expr_p);
-             ret = GS_OK;
-           }
+           *expr_p = DECL_INITIAL (*expr_p);
          break;
 
        case DECL_EXPR:
@@ -6842,7 +6750,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            }
          gimplify_seq_add_stmt (pre_p,
                          gimple_build_goto (GOTO_DESTINATION (*expr_p)));
-         ret = GS_ALL_DONE;
          break;
 
        case PREDICT_EXPR:
@@ -6885,7 +6792,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                  append_to_statement_list (ce->value, &temp);
 
              *expr_p = temp;
-             ret = temp ? GS_OK : GS_ALL_DONE;
+             ret = GS_OK;
            }
          /* C99 code may assign to an array in a constructed
             structure or union, and this has undefined behavior only
@@ -6895,7 +6802,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            {
              *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
              mark_addressable (*expr_p);
-             ret = GS_OK;
            }
          else
            ret = GS_ALL_DONE;
@@ -7043,7 +6949,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                           gimple_test_f, fallback);
            gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
                           is_gimple_val, fb_rvalue);
-           ret = GS_ALL_DONE;
          }
          break;
 
@@ -7131,7 +7036,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                   TREE_TYPE (*expr_p))))
            {
              *expr_p = tmp;
-             ret = GS_OK;
              break;
            }
          /* Convert (void *)&a + 4 into (void *)&a[1].  */
@@ -7147,7 +7051,6 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                                            0)))))
             {
                *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
-              ret = GS_OK;
               break;
             }
           /* FALLTHRU */
@@ -7217,7 +7120,9 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          break;
        }
 
-      gcc_assert (*expr_p || ret != GS_OK);
+      /* If we replaced *expr_p, gimplify again.  */
+      if (ret == GS_OK && (*expr_p == NULL || *expr_p == save_expr))
+       ret = GS_ALL_DONE;
     }
   while (ret == GS_OK);
 
@@ -7923,8 +7828,11 @@ gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p)
            }
          if (need_temp)
            {
-             tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL);
+             tree temp = create_tmp_var (TREE_TYPE (lhs), NULL);
 
+             if (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE
+                 || TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE)
+               DECL_GIMPLE_REG_P (temp) = 1;
              if (TREE_CODE (orig_lhs) == SSA_NAME)
                orig_lhs = SSA_NAME_VAR (orig_lhs);