OSDN Git Service

* tree.h (TREE_ADDRESSABLE): Document its effect for function types.
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 8 Apr 2010 20:16:36 +0000 (20:16 +0000)
committerMasaki Muranaka <monaka@monami-software.com>
Sun, 23 May 2010 00:52:22 +0000 (09:52 +0900)
* calls.c (expand_call): Pass the function type to aggregate_value_p.
* function.c (aggregate_value_p): Do not honor DECL_BY_REFERENCE on
the target function of a CALL_EXPR.  Honor TREE_ADDRESSABLE on the
function type instead.  Reorder and simplify checks.

* gimplify.c (gimplify_modify_expr_rhs) <WITH_SIZE_EXPR>: New case.
ada/
* gcc-interface/ada-tree.h (TYPE_RETURNS_UNCONSTRAINED_P): Rename into.
(TYPE_RETURN_UNCONSTRAINED_P): ...this.
(TYPE_RETURNS_BY_REF_P): Rename into.
(TYPE_RETURN_BY_DIRECT_REF_P): ...this.
(TYPE_RETURNS_BY_TARGET_PTR_P): Delete.
* gcc-interface/gigi.h (create_subprog_type): Adjust parameter names.
(build_return_expr): Likewise.
* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Subprogram_Type>:
Rename local variables.  If the return Mechanism is By_Reference, pass
return_by_invisible_ref_p to create_subprog_type instead of toggling
TREE_ADDRESSABLE.  Test return_by_invisible_ref_p in order to annotate
the mechanism.  Use regular return for contrained types with non-static
size and return by invisible reference for unconstrained return types
with default discriminants.  Update comment.
* gcc-interface/trans.c (Subprogram_Body_to_gnu): If the function
returns by invisible reference, turn the RESULT_DECL into a pointer.
Do not handle DECL_BY_REF_P in the CICO case here.
(call_to_gnu): Remove code handling return by target pointer.  For a
function call, if the return type has non-constant size, generate the
assignment with an INIT_EXPR.
(gnat_to_gnu) <N_Return_Statement>: Remove dead code in the CICO case.
If the function returns by invisible reference, build the copy return
operation manually.
(add_decl_expr): Initialize the variable with an INIT_EXPR.
* gcc-interface/utils.c (create_subprog_type): Adjust parameter names.
Adjust for renaming of macros.  Copy the node only when necessary.
(create_subprog_decl): Do not toggle TREE_ADDRESSABLE on the return
type, only change DECL_BY_REFERENCE on the RETURN_DECL.
(convert_from_reference): Delete.
(is_byref_result): Likewise.
(gnat_genericize_r): Likewise.
(gnat_genericize): Likewise.
(end_subprog_body): Do not call gnat_genericize.
* gcc-interface/utils2.c (build_binary_op) <INIT_EXPR>: New case.
(build_return_expr): Adjust parameter names, logic and comment.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158139 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/ada/ChangeLog
gcc/ada/gcc-interface/decl.c
gcc/ada/gcc-interface/trans.c
gcc/gimplify.c

index 8d2578f..9b1c69e 100644 (file)
@@ -1,3 +1,13 @@
+2010-04-08  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * tree.h (TREE_ADDRESSABLE): Document its effect for function types.
+       * calls.c (expand_call): Pass the function type to aggregate_value_p.
+       * function.c (aggregate_value_p): Do not honor DECL_BY_REFERENCE on
+       the target function of a CALL_EXPR.  Honor TREE_ADDRESSABLE on the
+       function type instead.  Reorder and simplify checks.
+
+       * gimplify.c (gimplify_modify_expr_rhs) <WITH_SIZE_EXPR>: New case.
+
 2010-04-08  Jing Yu  <jingyu@google.com>
            Zdenek Dvorak  <ook@ucw.cz>
 
index c740fa8..e43a534 100644 (file)
@@ -1,3 +1,41 @@
+2010-04-08  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc-interface/ada-tree.h (TYPE_RETURNS_UNCONSTRAINED_P): Rename into.
+       (TYPE_RETURN_UNCONSTRAINED_P): ...this.
+       (TYPE_RETURNS_BY_REF_P): Rename into.
+       (TYPE_RETURN_BY_DIRECT_REF_P): ...this.
+       (TYPE_RETURNS_BY_TARGET_PTR_P): Delete.
+       * gcc-interface/gigi.h (create_subprog_type): Adjust parameter names.
+       (build_return_expr): Likewise.
+       * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Subprogram_Type>:
+       Rename local variables.  If the return Mechanism is By_Reference, pass
+       return_by_invisible_ref_p to create_subprog_type instead of toggling
+       TREE_ADDRESSABLE.  Test return_by_invisible_ref_p in order to annotate
+       the mechanism.  Use regular return for contrained types with non-static
+       size and return by invisible reference for unconstrained return types
+       with default discriminants.  Update comment.
+       * gcc-interface/trans.c (Subprogram_Body_to_gnu): If the function
+       returns by invisible reference, turn the RESULT_DECL into a pointer.
+       Do not handle DECL_BY_REF_P in the CICO case here.
+       (call_to_gnu): Remove code handling return by target pointer.  For a
+       function call, if the return type has non-constant size, generate the
+       assignment with an INIT_EXPR.
+       (gnat_to_gnu) <N_Return_Statement>: Remove dead code in the CICO case.
+       If the function returns by invisible reference, build the copy return
+       operation manually.
+       (add_decl_expr): Initialize the variable with an INIT_EXPR.
+       * gcc-interface/utils.c (create_subprog_type): Adjust parameter names.
+       Adjust for renaming of macros.  Copy the node only when necessary.
+       (create_subprog_decl): Do not toggle TREE_ADDRESSABLE on the return
+       type, only change DECL_BY_REFERENCE on the RETURN_DECL.
+       (convert_from_reference): Delete.
+       (is_byref_result): Likewise.
+       (gnat_genericize_r): Likewise.
+       (gnat_genericize): Likewise.
+       (end_subprog_body): Do not call gnat_genericize.
+       * gcc-interface/utils2.c (build_binary_op) <INIT_EXPR>: New case.
+       (build_return_expr): Adjust parameter names, logic and comment.
+
 2010-04-07  Eric Botcazou  <ebotcazou@adacore.com>
 
        * exp_pakd.adb (Create_Packed_Array_Type): Always use a modular type
index 6da9ce4..25b4c07 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *          Copyright (C) 1992-2009, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2010, Free Software Foundation, Inc.         *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
@@ -3799,13 +3799,13 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
        tree gnu_field_list = NULL_TREE;
        /* Non-null for subprograms containing parameters passed by copy-in
           copy-out (Ada In Out or Out parameters not passed by reference),
-          in which case it is the list of nodes used to specify the values of
-          the in out/out parameters that are returned as a record upon
+          in which case it is the list of nodes used to specify the values
+          of the In Out/Out parameters that are returned as a record upon
           procedure return.  The TREE_PURPOSE of an element of this list is
           a field of the record and the TREE_VALUE is the PARM_DECL
           corresponding to that field.  This list will be saved in the
           TYPE_CI_CO_LIST field of the FUNCTION_TYPE node we create.  */
-       tree gnu_return_list = NULL_TREE;
+       tree gnu_cico_list = NULL_TREE;
        /* If an import pragma asks to map this subprogram to a GCC builtin,
           this is the builtin DECL node.  */
        tree gnu_builtin_decl = NULL_TREE;
@@ -3831,9 +3831,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
             && Is_Pure (gnat_entity));
 
        bool volatile_flag = No_Return (gnat_entity);
-       bool returns_by_ref = false;
-       bool returns_unconstrained = false;
-       bool returns_by_target_ptr = false;
+       bool return_by_direct_ref_p = false;
+       bool return_by_invisi_ref_p = false;
+       bool return_unconstrained_p = false;
        bool has_copy_in_out = false;
        bool has_stub = false;
        int parmnum;
@@ -3885,37 +3885,39 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
        if (kind == E_Function || kind == E_Subprogram_Type)
          gnu_return_type = gnat_to_gnu_type (Etype (gnat_entity));
 
-       /* If this function returns by reference, make the actual
-          return type of this function the pointer and mark the decl.  */
+       /* If this function returns by reference, make the actual return
+          type of this function the pointer and mark the decl.  */
        if (Returns_By_Ref (gnat_entity))
          {
-           returns_by_ref = true;
            gnu_return_type = build_pointer_type (gnu_return_type);
+           return_by_direct_ref_p = true;
          }
 
-       /* If the Mechanism is By_Reference, ensure the return type uses
-          the machine's by-reference mechanism, which may not the same
-          as above (e.g., it might be by passing a fake parameter).  */
-       else if (kind == E_Function
-                && Mechanism (gnat_entity) == By_Reference)
-         {
-           TREE_ADDRESSABLE (gnu_return_type) = 1;
-
-           /* We expect this bit to be reset by gigi shortly, so can avoid a
-              type node copy here.  This actually also prevents troubles with
-              the generation of debug information for the function, because
-              we might have issued such info for this type already, and would
-              be attaching a distinct type node to the function if we made a
-              copy here.  */
-         }
-
-       /* If we are supposed to return an unconstrained array,
-          actually return a fat pointer and make a note of that.  Return
-          a pointer to an unconstrained record of variable size.  */
+       /* If the Mechanism is By_Reference, ensure this function uses the
+          target's by-invisible-reference mechanism, which may not be the
+          same as above (e.g. it might be passing an extra parameter).
+
+          Prior to GCC 4, this was handled by just setting TREE_ADDRESSABLE
+          on the result type.  Everything required to pass by invisible
+          reference using the target's mechanism (e.g. an extra parameter)
+          was handled at RTL expansion time.
+
+          This doesn't work with GCC 4 any more for several reasons.  First,
+          the gimplification process might need to create temporaries of this
+          type and the gimplifier ICEs on such attempts; that's why the flag
+          is now set on the function type instead.  Second, the middle-end
+          now also relies on a different attribute, DECL_BY_REFERENCE on the
+          RESULT_DECL, and expects the by-invisible-reference-ness to be made
+          explicit in the function body.  */
+       else if (kind == E_Function && Mechanism (gnat_entity) == By_Reference)
+         return_by_invisi_ref_p = true;
+
+       /* If we are supposed to return an unconstrained array, actually return
+          a fat pointer and make a note of that.  */
        else if (TREE_CODE (gnu_return_type) == UNCONSTRAINED_ARRAY_TYPE)
          {
            gnu_return_type = TREE_TYPE (gnu_return_type);
-           returns_unconstrained = true;
+           return_unconstrained_p = true;
          }
 
        /* If the type requires a transient scope, the result is allocated
@@ -3924,7 +3926,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
        else if (Requires_Transient_Scope (Etype (gnat_entity)))
          {
            gnu_return_type = build_pointer_type (gnu_return_type);
-           returns_unconstrained = true;
+           return_unconstrained_p = true;
          }
 
        /* If the type is a padded type and the underlying type would not
@@ -3936,20 +3938,17 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
                     || Has_Foreign_Convention (gnat_entity)))
          gnu_return_type = TREE_TYPE (TYPE_FIELDS (gnu_return_type));
 
-       /* If the return type has a non-constant size, we convert the function
-          into a procedure and its caller will pass a pointer to an object as
-          the first parameter when we call the function.  This can happen for
-          an unconstrained type with a maximum size or a constrained type with
-          a size not known at compile time.  */
-       if (TYPE_SIZE_UNIT (gnu_return_type)
-           && !TREE_CONSTANT (TYPE_SIZE_UNIT (gnu_return_type)))
+       /* If the return type is unconstrained, that means it must have a
+          maximum size.  Use the padded type as the effective return type.
+          And ensure the function uses the target's by-invisible-reference
+          mechanism to avoid copying too much data when it returns.  */
+       if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_return_type)))
          {
-           returns_by_target_ptr = true;
-           gnu_param_list
-             = create_param_decl (get_identifier ("TARGET"),
-                                  build_reference_type (gnu_return_type),
-                                  true);
-           gnu_return_type = void_type_node;
+           gnu_return_type
+             = maybe_pad_type (gnu_return_type,
+                               max_size (TYPE_SIZE (gnu_return_type), true),
+                               0, gnat_entity, false, false, false, true);
+           return_by_invisi_ref_p = true;
          }
 
        /* If the return type has a size that overflows, we cannot have
@@ -4091,8 +4090,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
                               &DECL_SOURCE_LOCATION (gnu_field));
                TREE_CHAIN (gnu_field) = gnu_field_list;
                gnu_field_list = gnu_field;
-               gnu_return_list = tree_cons (gnu_field, gnu_param,
-                                            gnu_return_list);
+               gnu_cico_list
+                 = tree_cons (gnu_field, gnu_param, gnu_cico_list);
              }
          }
 
@@ -4105,8 +4104,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
        /* If we have a CICO list but it has only one entry, we convert
           this function into a function that simply returns that one
           object.  */
-       if (list_length (gnu_return_list) == 1)
-         gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_return_list));
+       if (list_length (gnu_cico_list) == 1)
+         gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_cico_list));
 
        if (Has_Stdcall_Convention (gnat_entity))
          prepend_one_attribute_to
@@ -4131,22 +4130,25 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
        gnu_param_list = nreverse (gnu_param_list);
        if (has_stub)
          gnu_stub_param_list = nreverse (gnu_stub_param_list);
-       gnu_return_list = nreverse (gnu_return_list);
+       gnu_cico_list = nreverse (gnu_cico_list);
 
        if (Ekind (gnat_entity) == E_Function)
-         Set_Mechanism (gnat_entity,
-                        (returns_by_ref || returns_unconstrained
-                         ? By_Reference : By_Copy));
+         Set_Mechanism (gnat_entity, return_unconstrained_p
+                                     || return_by_direct_ref_p
+                                     || return_by_invisi_ref_p
+                                     ? By_Reference : By_Copy);
        gnu_type
          = create_subprog_type (gnu_return_type, gnu_param_list,
-                                gnu_return_list, returns_unconstrained,
-                                returns_by_ref, returns_by_target_ptr);
+                                gnu_cico_list, return_unconstrained_p,
+                                return_by_direct_ref_p,
+                                return_by_invisi_ref_p);
 
        if (has_stub)
          gnu_stub_type
            = create_subprog_type (gnu_return_type, gnu_stub_param_list,
-                                  gnu_return_list, returns_unconstrained,
-                                  returns_by_ref, returns_by_target_ptr);
+                                  gnu_cico_list, return_unconstrained_p,
+                                  return_by_direct_ref_p,
+                                  return_by_invisi_ref_p);
 
        /* A subprogram (something that doesn't return anything) shouldn't
           be considered const since there would be no reason for such a
index fb770e8..049c201 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                          C Implementation File                           *
  *                                                                          *
- *          Copyright (C) 1992-2009, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2010, Free Software Foundation, Inc.         *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
@@ -2196,6 +2196,8 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
        ? Corresponding_Spec (gnat_node) : Defining_Entity (gnat_node));
   /* The FUNCTION_DECL node corresponding to the subprogram spec.   */
   tree gnu_subprog_decl;
+  /* Its RESULT_DECL node.  */
+  tree gnu_result_decl;
   /* The FUNCTION_TYPE node corresponding to the subprogram spec.  */
   tree gnu_subprog_type;
   tree gnu_cico_list;
@@ -2219,9 +2221,18 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
     = gnat_to_gnu_entity (gnat_subprog_id, NULL_TREE,
                          Acts_As_Spec (gnat_node)
                          && !present_gnu_tree (gnat_subprog_id));
-
+  gnu_result_decl = DECL_RESULT (gnu_subprog_decl);
   gnu_subprog_type = TREE_TYPE (gnu_subprog_decl);
 
+  /* If the function returns by invisible reference, make it explicit in the
+     function body.  See gnat_to_gnu_entity, E_Subprogram_Type case.  */
+  if (TREE_ADDRESSABLE (gnu_subprog_type))
+    {
+      TREE_TYPE (gnu_result_decl)
+       = build_reference_type (TREE_TYPE (gnu_result_decl));
+      relayout_decl (gnu_result_decl);
+    }
+
   /* Propagate the debug mode.  */
   if (!Needs_Debug_Info (gnat_subprog_id))
     DECL_IGNORED_P (gnu_subprog_decl) = 1;
@@ -2319,9 +2330,18 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
       gnu_result = end_stmt_group ();
     }
 
-  /* If we made a special return label, we need to make a block that contains
-     the definition of that label and the copying to the return value.  That
-     block first contains the function, then the label and copy statement.  */
+    /* If we are dealing with a return from an Ada procedure with parameters
+       passed by copy-in/copy-out, we need to return a record containing the
+       final values of these parameters.  If the list contains only one entry,
+       return just that entry though.
+
+       For a full description of the copy-in/copy-out parameter mechanism, see
+       the part of the gnat_to_gnu_entity routine dealing with the translation
+       of subprograms.
+
+       We need to make a block that contains the definition of that label and
+       the copying of the return value.  It first contains the function, then
+       the label and copy statement.  */
   if (TREE_VALUE (gnu_return_label_stack))
     {
       tree gnu_retval;
@@ -2339,12 +2359,8 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
        gnu_retval = gnat_build_constructor (TREE_TYPE (gnu_subprog_type),
                                             gnu_cico_list);
 
-      if (DECL_P (gnu_retval) && DECL_BY_REF_P (gnu_retval))
-       gnu_retval = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_retval);
-
-      add_stmt_with_node
-       (build_return_expr (DECL_RESULT (gnu_subprog_decl), gnu_retval),
-        End_Label (Handled_Statement_Sequence (gnat_node)));
+      add_stmt_with_node (build_return_expr (gnu_result_decl, gnu_retval),
+                         End_Label (Handled_Statement_Sequence (gnat_node)));
       gnat_poplevel ();
       gnu_result = end_stmt_group ();
     }
@@ -2396,8 +2412,8 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
   tree gnu_subprog_node = gnat_to_gnu (Name (gnat_node));
   /* The FUNCTION_TYPE node giving the GCC type of the subprogram.  */
   tree gnu_subprog_type = TREE_TYPE (gnu_subprog_node);
-  tree gnu_subprog_addr = build_unary_op (ADDR_EXPR, NULL_TREE,
-                                         gnu_subprog_node);
+  tree gnu_subprog_addr
+    = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_subprog_node);
   Entity_Id gnat_formal;
   Node_Id gnat_actual;
   tree gnu_actual_list = NULL_TREE;
@@ -2433,51 +2449,6 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
       }
     }
 
-  /* If we are calling by supplying a pointer to a target, set up that pointer
-     as the first argument.  Use GNU_TARGET if one was passed; otherwise, make
-     a target by building a variable and use the maximum size of the type if
-     it has self-referential size.  */
-  if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type))
-    {
-      tree gnu_ret_type
-       = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (gnu_subprog_type)));
-
-      if (!gnu_target)
-       {
-         tree gnu_obj_type;
-
-         if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_ret_type)))
-           gnu_obj_type
-             = maybe_pad_type (gnu_ret_type,
-                               max_size (TYPE_SIZE (gnu_ret_type), true),
-                               0, Etype (Name (gnat_node)), false, false,
-                               false, true);
-         else
-           gnu_obj_type = gnu_ret_type;
-
-         /* ??? We may be about to create a static temporary if we happen to
-            be at the global binding level.  That's a regression from what
-            the 3.x back-end would generate in the same situation, but we
-            don't have a mechanism in Gigi for creating automatic variables
-            in the elaboration routines.  */
-         gnu_target
-           = create_var_decl (create_tmp_var_name ("LR"), NULL, gnu_obj_type,
-                              NULL, false, false, false, false, NULL,
-                              gnat_node);
-
-         *gnu_result_type_p = gnu_ret_type;
-       }
-
-      gnu_actual_list
-       = tree_cons (NULL_TREE,
-                    build_unary_op (ADDR_EXPR, NULL_TREE,
-                                    unchecked_convert (gnu_ret_type,
-                                                       gnu_target,
-                                                       false)),
-                    NULL_TREE);
-
-    }
-
   /* The only way we can be making a call via an access type is if Name is an
      explicit dereference.  In that case, get the list of formal args from the
      type the access type is pointing to.  Otherwise, get the formals from
@@ -2784,53 +2755,43 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                                      nreverse (gnu_actual_list));
   set_expr_location_from_node (gnu_subprog_call, gnat_node);
 
-  /* If we return by passing a target, the result is the target after the
-     call.  We must not emit the call directly here because this might be
-     evaluated as part of an expression with conditions to control whether
-     the call should be emitted or not.  */
-  if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type))
-    {
-      /* Conceptually, what we need is a COMPOUND_EXPR of the call followed by
-        the target object.  Doing so would potentially be inefficient though,
-        as this expression might be wrapped up into a SAVE_EXPR later, which
-        would incur a pointless temporary copy of the whole object.
-
-        What we do instead is build a COMPOUND_EXPR returning the address of
-        the target, and then dereference.  Wrapping up the COMPOUND_EXPR into
-        a SAVE_EXPR then only incurs a mere pointer copy.  */
-      tree gnu_target_addr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_target);
-      set_expr_location_from_node (gnu_target_addr, gnat_node);
-      gnu_result = build2 (COMPOUND_EXPR, TREE_TYPE (gnu_target_addr),
-                          gnu_subprog_call, gnu_target_addr);
-      return build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result);
-    }
-
-  /* If it is a function call, the result is the call expression unless
-     a target is specified, in which case we copy the result into the target
-     and return the assignment statement.  */
-  else if (Nkind (gnat_node) == N_Function_Call)
+  /* If it's a function call, the result is the call expression unless a target
+     is specified, in which case we copy the result into the target and return
+     the assignment statement.  */
+  if (Nkind (gnat_node) == N_Function_Call)
     {
       gnu_result = gnu_subprog_call;
+      enum tree_code op_code;
 
-      /* If the function returns an unconstrained array or by reference,
-        we have to de-dereference the pointer.  */
-      if (TYPE_RETURNS_UNCONSTRAINED_P (gnu_subprog_type)
-         || TYPE_RETURNS_BY_REF_P (gnu_subprog_type))
+      /* If the function returns an unconstrained array or by direct reference,
+        we have to dereference the pointer.  */
+      if (TYPE_RETURN_UNCONSTRAINED_P (gnu_subprog_type)
+         || TYPE_RETURN_BY_DIRECT_REF_P (gnu_subprog_type))
        gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result);
 
       if (gnu_target)
-       gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
-                                     gnu_target, gnu_result);
+       {
+         /* ??? If the return type has non-constant size, then force the
+            return slot optimization as we would not be able to generate
+            a temporary.  That's what has been done historically.  */
+         if (TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (gnu_subprog_type))))
+           op_code = MODIFY_EXPR;
+         else
+           op_code = INIT_EXPR;
+
+         gnu_result
+           = build_binary_op (op_code, NULL_TREE, gnu_target, gnu_result);
+       }
       else
        *gnu_result_type_p = get_unpadded_type (Etype (gnat_node));
 
       return gnu_result;
     }
 
-  /* If this is the case where the GNAT tree contains a procedure call
-     but the Ada procedure has copy in copy out parameters, the special
-     parameter passing mechanism must be used.  */
-  else if (TYPE_CI_CO_LIST (gnu_subprog_type) != NULL_TREE)
+  /* If this is the case where the GNAT tree contains a procedure call but the
+     Ada procedure has copy-in/copy-out parameters, then the special parameter
+     passing mechanism must be used.  */
+  if (TYPE_CI_CO_LIST (gnu_subprog_type))
     {
       /* List of FIELD_DECLs associated with the PARM_DECLs of the copy
         in copy out parameters.  */
@@ -4636,25 +4597,10 @@ gnat_to_gnu (Node_Id gnat_node)
 
     case N_Return_Statement:
       {
-       /* The gnu function type of the subprogram currently processed.  */
-       tree gnu_subprog_type = TREE_TYPE (current_function_decl);
-       /* The return value from the subprogram.  */
-       tree gnu_ret_val = NULL_TREE;
-       /* The place to put the return value.  */
-       tree gnu_lhs;
-
-       /* If we are dealing with a "return;" from an Ada procedure with
-          parameters passed by copy in copy out, we need to return a record
-          containing the final values of these parameters.  If the list
-          contains only one entry, return just that entry.
-
-          For a full description of the copy in copy out parameter mechanism,
-          see the part of the gnat_to_gnu_entity routine dealing with the
-          translation of subprograms.
-
-          But if we have a return label defined, convert this into
-          a branch to that label.  */
+       tree gnu_ret_val, gnu_ret_obj;
 
+       /* If we have a return label defined, convert this into a branch to
+          that label.  The return proper will be handled elsewhere.  */
        if (TREE_VALUE (gnu_return_label_stack))
          {
            gnu_result = build1 (GOTO_EXPR, void_type_node,
@@ -4662,90 +4608,69 @@ gnat_to_gnu (Node_Id gnat_node)
            break;
          }
 
-       else if (TYPE_CI_CO_LIST (gnu_subprog_type))
-         {
-           gnu_lhs = DECL_RESULT (current_function_decl);
-           if (list_length (TYPE_CI_CO_LIST (gnu_subprog_type)) == 1)
-             gnu_ret_val = TREE_VALUE (TYPE_CI_CO_LIST (gnu_subprog_type));
-           else
-             gnu_ret_val
-               = gnat_build_constructor (TREE_TYPE (gnu_subprog_type),
-                                         TYPE_CI_CO_LIST (gnu_subprog_type));
-         }
-
-       /* If the Ada subprogram is a function, we just need to return the
-          expression.   If the subprogram returns an unconstrained
-          array, we have to allocate a new version of the result and
-          return it.  If we return by reference, return a pointer.  */
-
-       else if (Present (Expression (gnat_node)))
+       /* If the subprogram is a function, we must return the expression.  */
+       if (Present (Expression (gnat_node)))
          {
-           /* If the current function returns by target pointer and we
-              are doing a call, pass that target to the call.  */
-           if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type)
-               && Nkind (Expression (gnat_node)) == N_Function_Call)
+           tree gnu_subprog_type = TREE_TYPE (current_function_decl);
+           tree gnu_result_decl = DECL_RESULT (current_function_decl);
+           gnu_ret_val = gnat_to_gnu (Expression (gnat_node));
+
+           /* Do not remove the padding from GNU_RET_VAL if the inner type is
+              self-referential since we want to allocate the fixed size.  */
+           if (TREE_CODE (gnu_ret_val) == COMPONENT_REF
+               && TYPE_IS_PADDING_P
+                  (TREE_TYPE (TREE_OPERAND (gnu_ret_val, 0)))
+               && CONTAINS_PLACEHOLDER_P
+                  (TYPE_SIZE (TREE_TYPE (gnu_ret_val))))
+             gnu_ret_val = TREE_OPERAND (gnu_ret_val, 0);
+
+           /* If the subprogram returns by direct reference, return a pointer
+              to the return value.  */
+           if (TYPE_RETURN_BY_DIRECT_REF_P (gnu_subprog_type)
+               || By_Ref (gnat_node))
+             gnu_ret_val = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_ret_val);
+
+           /* Otherwise, if it returns an unconstrained array, we have to
+              allocate a new version of the result and return it.  */
+           else if (TYPE_RETURN_UNCONSTRAINED_P (gnu_subprog_type))
              {
-               gnu_lhs
-                 = build_unary_op (INDIRECT_REF, NULL_TREE,
-                                   DECL_ARGUMENTS (current_function_decl));
-               gnu_result = call_to_gnu (Expression (gnat_node),
-                                         &gnu_result_type, gnu_lhs);
+               gnu_ret_val = maybe_unconstrained_array (gnu_ret_val);
+               gnu_ret_val = build_allocator (TREE_TYPE (gnu_ret_val),
+                                              gnu_ret_val,
+                                              TREE_TYPE (gnu_subprog_type),
+                                              Procedure_To_Call (gnat_node),
+                                              Storage_Pool (gnat_node),
+                                              gnat_node, false);
              }
-           else
+
+           /* If the subprogram returns by invisible reference, dereference
+              the pointer it is passed using the type of the return value
+              and build the copy operation manually.  This ensures that we
+              don't copy too much data, for example if the return type is
+              unconstrained with a maximum size.  */
+           if (TREE_ADDRESSABLE (gnu_subprog_type))
              {
-               gnu_ret_val = gnat_to_gnu (Expression (gnat_node));
-
-               if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type))
-                 /* The original return type was unconstrained so dereference
-                    the TARGET pointer in the actual return value's type.  */
-                 gnu_lhs
-                   = build_unary_op (INDIRECT_REF, TREE_TYPE (gnu_ret_val),
-                                     DECL_ARGUMENTS (current_function_decl));
-               else
-                 gnu_lhs = DECL_RESULT (current_function_decl);
-
-               /* Do not remove the padding from GNU_RET_VAL if the inner
-                  type is self-referential since we want to allocate the fixed
-                  size in that case.  */
-               if (TREE_CODE (gnu_ret_val) == COMPONENT_REF
-                   && TYPE_IS_PADDING_P
-                      (TREE_TYPE (TREE_OPERAND (gnu_ret_val, 0)))
-                   && CONTAINS_PLACEHOLDER_P
-                      (TYPE_SIZE (TREE_TYPE (gnu_ret_val))))
-                 gnu_ret_val = TREE_OPERAND (gnu_ret_val, 0);
-
-               if (TYPE_RETURNS_BY_REF_P (gnu_subprog_type)
-                   || By_Ref (gnat_node))
-                 gnu_ret_val
-                   = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_ret_val);
-
-               else if (TYPE_RETURNS_UNCONSTRAINED_P (gnu_subprog_type))
-                 {
-                   gnu_ret_val = maybe_unconstrained_array (gnu_ret_val);
-                   gnu_ret_val
-                     = build_allocator (TREE_TYPE (gnu_ret_val),
-                                        gnu_ret_val,
-                                        TREE_TYPE (gnu_subprog_type),
-                                        Procedure_To_Call (gnat_node),
-                                        Storage_Pool (gnat_node),
-                                        gnat_node, false);
-                 }
+               gnu_ret_obj
+                 = build_unary_op (INDIRECT_REF, TREE_TYPE (gnu_ret_val),
+                                   gnu_result_decl);
+               gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
+                                             gnu_ret_obj, gnu_ret_val);
+               add_stmt_with_node (gnu_result, gnat_node);
+               gnu_ret_val = NULL_TREE;
+               gnu_ret_obj = gnu_result_decl;
              }
+
+           /* Otherwise, build a regular return.  */
+           else
+             gnu_ret_obj = gnu_result_decl;
          }
        else
-         /* If the Ada subprogram is a regular procedure, just return.  */
-         gnu_lhs = NULL_TREE;
-
-       if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type))
          {
-           if (gnu_ret_val)
-             gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
-                                           gnu_lhs, gnu_ret_val);
-           add_stmt_with_node (gnu_result, gnat_node);
-           gnu_lhs = NULL_TREE;
+           gnu_ret_val = NULL_TREE;
+           gnu_ret_obj = NULL_TREE;
          }
 
-       gnu_result = build_return_expr (gnu_lhs, gnu_ret_val);
+       gnu_result = build_return_expr (gnu_ret_obj, gnu_ret_val);
       }
       break;
 
@@ -5605,7 +5530,7 @@ add_decl_expr (tree gnu_decl, Entity_Id gnat_entity)
       else
        t = gnu_decl;
 
-      gnu_stmt = build_binary_op (MODIFY_EXPR, NULL_TREE, t, gnu_init);
+      gnu_stmt = build_binary_op (INIT_EXPR, NULL_TREE, t, gnu_init);
 
       DECL_INITIAL (gnu_decl) = NULL_TREE;
       if (TREE_READONLY (gnu_decl))
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);