Implement the Named Return Value optimization.
authorJason Merrill <jason@redhat.com>
Mon, 18 Jun 2001 16:15:12 +0000 (12:15 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 18 Jun 2001 16:15:12 +0000 (12:15 -0400)
        * c-common.h (RETURN_NULLIFIED_P): New macro.
        * c-semantics.c (genrtl_return_stmt): Check it.
        * cp-tree.h (struct cp_language_function): Add x_return_value.
        (current_function_return_value): Now a macro.
        * decl.c: Don't define it.
        (define_label, finish_case_label): Don't clear it.
        (init_decl_processing): Don't register it with GC.
        * semantics.c (genrtl_finish_function): Don't check it for
        no_return_label.  Copy the RTL from the return value to
        current_function_return_value and walk, calling...
        (nullify_returns_r): ...this new fn.
        * typeck.c (check_return_expr): Set current_function_return_value.

        * expr.c (clear_storage): Set TREE_NOTHROW on the decl for memset.
        (emit_block_move): Likewise.

From-SVN: r43445

gcc/ChangeLog
gcc/c-common.h
gcc/c-semantics.c
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/expr.c

index 51c11e7acc2b56385ad4e1aaf857a72a06498d11..d8d0683abcc3639dd5d30ef72018b35a4aa8f9fa 100644 (file)
@@ -1,3 +1,11 @@
+2001-06-18  Jason Merrill  <jason_merrill@redhat.com>
+
+       * c-common.h (RETURN_NULLIFIED_P): New macro.
+       * c-semantics.c (genrtl_return_stmt): Check it.
+
+       * expr.c (clear_storage): Set TREE_NOTHROW on the decl for memset.
+       (emit_block_move): Likewise.
+
 Mon Jun 18 17:27:24 CEST 2001  Jan Hubicka  <jh@suse.cz>
 
        * unroll.c: Include predict.h.
index 3f766a7a179992be746d0176ba1dd33a22023a2f..05350c12fa2a40d4605f5602920a57e7d52d916f 100644 (file)
@@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA.  */
       SCOPE_BEGIN_P (in SCOPE_STMT)
       DECL_PRETTY_FUNCTION_P (in VAR_DECL)
       NEW_FOR_SCOPE_P (in FOR_STMT)
+      RETURN_NULLIFIED_P (in RETURN_STMT)
       ASM_INPUT_P (in ASM_STMT)
    1: C_DECLARED_LABEL_FLAG (in LABEL_DECL)
       STMT_IS_FULL_EXPR_P (in _STMT)
@@ -561,9 +562,11 @@ extern tree strip_array_types                   PARAMS ((tree));
 #define DO_COND(NODE)           TREE_OPERAND (DO_STMT_CHECK (NODE), 0)
 #define DO_BODY(NODE)           TREE_OPERAND (DO_STMT_CHECK (NODE), 1)
 
-/* RETURN_STMT accessor. This gives the expression associated with a
-   return statement. */
+/* RETURN_STMT accessors. These give the expression associated with a
+   return statement, and whether it should be ignored when expanding
+   (as opposed to inlining).  */
 #define RETURN_EXPR(NODE)       TREE_OPERAND (RETURN_STMT_CHECK (NODE), 0)
+#define RETURN_NULLIFIED_P(NODE) TREE_LANG_FLAG_0 (RETURN_STMT_CHECK (NODE))
 
 /* EXPR_STMT accessor. This gives the expression associated with an
    expression statement. */
index 6a963a9a10e20eda71ed84eb73de18e56e469560..eca64babe8d18b5f1fad708028d15b021877b762 100644 (file)
@@ -460,7 +460,15 @@ void
 genrtl_return_stmt (stmt)
      tree stmt;
 {
-  tree expr = RETURN_EXPR (stmt);
+  tree expr;
+
+  /* If RETURN_NULLIFIED_P is set, the frontend has arranged to set up
+     the return value separately, so just return the return value
+     itself.  This is used for the C++ named return value optimization.  */
+  if (RETURN_NULLIFIED_P (stmt))
+    expr = DECL_RESULT (current_function_decl);
+  else
+    expr = RETURN_EXPR (stmt);
 
   emit_line_note (input_filename, lineno);
   if (!expr)
index 342949eb00e552de77253e405b058ca33223205c..99643259c5115e526ea0082a0d5c842de6c43416 100644 (file)
@@ -1,3 +1,17 @@
+2001-06-18  Jason Merrill  <jason_merrill@redhat.com>
+
+       Implement the Named Return Value optimization.
+       * cp-tree.h (struct cp_language_function): Add x_return_value.
+       (current_function_return_value): Now a macro.
+       * decl.c: Don't define it.
+       (define_label, finish_case_label): Don't clear it.
+       (init_decl_processing): Don't register it with GC.
+       * semantics.c (genrtl_finish_function): Don't check it for
+       no_return_label.  Copy the RTL from the return value to
+       current_function_return_value and walk, calling...
+       (nullify_returns_r): ...this new fn.
+       * typeck.c (check_return_expr): Set current_function_return_value.
+
 2001-06-15  Jason Merrill  <jason_merrill@redhat.com>
 
        * class.c (dfs_accumulate_vtbl_inits): Just point to the base we're
index 5da11ee3151b127d8694edc8ec31243892c2952a..99106248b07a4defb79e2a8a93aec5a7ce7a8a50 100644 (file)
@@ -863,6 +863,7 @@ struct cp_language_function
   tree x_eh_spec_block;
   tree x_in_charge_parm;
   tree x_vtt_parm;
+  tree x_return_value;
 
   tree *x_vcalls_possible_p;
 
@@ -953,7 +954,12 @@ struct cp_language_function
 
 #define in_function_try_handler cp_function_chain->in_function_try_handler
 
-extern tree current_function_return_value;
+/* Expression always returned from function, or error_mark_node
+   otherwise, for use by the automatic named return value optimization.  */
+
+#define current_function_return_value \
+  (cp_function_chain->x_return_value)
+
 extern tree global_namespace;
 
 #define ansi_opname(CODE) \
index af9de43c559a4b85cef84581d7acd99d9bf93795..0968220b2fd0812ece312d60caa99944065a3487 100644 (file)
@@ -285,13 +285,6 @@ struct named_label_list
 
 #define named_labels cp_function_chain->x_named_labels
 
-/* Set to 0 at beginning of a function definition, and whenever
-   a label (case or named) is defined.  Set to value of expression
-   returned from function when that value can be transformed into
-   a named return value.  */
-
-tree current_function_return_value;
-
 /* Nonzero means use the ISO C94 dialect of C.  */
 
 int flag_isoc94;
@@ -5153,7 +5146,6 @@ define_label (filename, line, name)
          ent->binding_level = current_binding_level;
        }
       check_previous_gotos (decl);
-      current_function_return_value = NULL_TREE;
       return decl;
     }
 }
@@ -5255,7 +5247,6 @@ finish_case_label (low_value, high_value)
      own new (temporary) binding contour.  */
   for (p = current_binding_level; !(p->parm_flag); p = p->level_chain)
     p->more_cleanups_ok = 0;
-  current_function_return_value = NULL_TREE;
 
   return r;
 }
@@ -6624,7 +6615,6 @@ init_decl_processing ()
   ggc_add_tree_root (&lastiddecl, 1);
 
   ggc_add_tree_root (&last_function_parm_tags, 1);
-  ggc_add_tree_root (&current_function_return_value, 1);
   ggc_add_tree_root (&current_function_parm_tags, 1);
   ggc_add_tree_root (&last_function_parms, 1);
   ggc_add_tree_root (&error_mark_list, 1);
index 9dddf230ddd90a2d587bd906e5be0e78f398ef68..0dc392a9a894274cd4c889c4bf0dd32036922060 100644 (file)
@@ -49,6 +49,7 @@
 
 static tree maybe_convert_cond PARAMS ((tree));
 static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
+static tree nullify_returns_r PARAMS ((tree *, int *, void *));
 static void deferred_type_access_control PARAMS ((void));
 static void emit_associated_thunks PARAMS ((tree));
 static void genrtl_try_block PARAMS ((tree));
@@ -2464,6 +2465,25 @@ expand_body (fn)
   timevar_pop (TV_EXPAND);
 }
 
+/* Helper function for walk_tree, used by genrtl_start_function to override
+   all the RETURN_STMTs for the named return value optimization.  */
+
+static tree
+nullify_returns_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees;
+     void *data ATTRIBUTE_UNUSED;
+{
+  /* No need to walk into types.  */
+  if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+  else if (TREE_CODE (*tp) == RETURN_STMT)
+    RETURN_NULLIFIED_P (*tp) = 1;
+
+  /* Keep iterating.  */
+  return NULL_TREE;
+}
+
 /* Start generating the RTL for FN.  */
 
 static void
@@ -2541,6 +2561,22 @@ genrtl_start_function (fn)
   /* Create a binding contour which can be used to catch
      cleanup-generated temporaries.  */
   expand_start_bindings (2);
+
+  /* Set up the named return value optimization, if we can.  */
+  if (current_function_return_value
+      && current_function_return_value != error_mark_node)
+    {
+      tree r = current_function_return_value;
+      /* This is only worth doing for fns that return in memory--and
+        simpler, since we don't have to worry about promoted modes.  */
+      if (aggregate_value_p (TREE_TYPE (TREE_TYPE (fn))))
+       {
+         COPY_DECL_RTL (DECL_RESULT (fn), r);
+         DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fn));
+         walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+                                       nullify_returns_r, NULL_TREE);
+       }
+    }
 }
 
 /* Finish generating the RTL for FN.  */
@@ -2579,7 +2615,6 @@ genrtl_finish_function (fn)
 
   if (!dtor_label && !DECL_CONSTRUCTOR_P (fn)
       && return_label != NULL_RTX
-      && current_function_return_value == NULL_TREE
       && ! DECL_NAME (DECL_RESULT (current_function_decl)))
     no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
 
index 38deeeecad0f2efa381753185e74ac8da8e98147..1256b6d1ca138ce150cd8c777e73619c44793ba2 100644 (file)
@@ -6679,6 +6679,32 @@ check_return_expr (retval)
       && retval != current_class_ref)
     cp_warning ("`operator=' should return a reference to `*this'");
 
+  /* The fabled Named Return Value optimization: If this is a
+     value-returning function that always returns the same local
+     variable, remember it.
+
+     It might be nice to be more flexible, and choose the first suitable
+     variable even if the function sometimes returns something else, but
+     then we run the risk of clobbering the variable we chose if the other
+     returned expression uses the chosen variable somehow.  And people expect
+     this restriction, anyway.  (jason 2000-11-19) */
+
+  if (fn_returns_value_p && optimize)
+    {
+      if (retval != NULL_TREE
+         && (current_function_return_value == NULL_TREE
+             || current_function_return_value == retval)
+         && TREE_CODE (retval) == VAR_DECL
+         && DECL_CONTEXT (retval) == current_function_decl
+         && ! TREE_STATIC (retval)
+         && ! DECL_USER_ALIGN (retval)
+         && same_type_p (TREE_TYPE (retval),
+                         TREE_TYPE (TREE_TYPE (current_function_decl))))
+       current_function_return_value = retval;
+      else
+       current_function_return_value = error_mark_node;
+    }
+
   /* We don't need to do any conversions when there's nothing being
      returned.  */
   if (!retval || retval == error_mark_node)
index 230cf9f1e6e498e6605aed598e7b4f6217f480f8..9b81988521bf70a2aa4e21ed906f8618ddcbe0d6 100644 (file)
@@ -1773,6 +1773,7 @@ emit_block_move (x, y, size, align)
          DECL_EXTERNAL (fn) = 1;
          TREE_PUBLIC (fn) = 1;
          DECL_ARTIFICIAL (fn) = 1;
+         TREE_NOTHROW (fn) = 1;
          make_decl_rtl (fn, NULL);
          assemble_external (fn);
        }
@@ -2659,7 +2660,7 @@ clear_storage (object, size, align)
 
             For targets where libcalls and normal calls have different
             conventions for returning pointers, we could end up generating
-             incorrect code.
+            incorrect code.
 
             So instead of using a libcall sequence we build up a suitable
             CALL_EXPR and expand the call in the normal fashion.  */
@@ -2677,6 +2678,7 @@ clear_storage (object, size, align)
              DECL_EXTERNAL (fn) = 1;
              TREE_PUBLIC (fn) = 1;
              DECL_ARTIFICIAL (fn) = 1;
+             TREE_NOTHROW (fn) = 1;
              make_decl_rtl (fn, NULL);
              assemble_external (fn);
            }
@@ -4547,7 +4549,7 @@ store_constructor (exp, target, align, cleared, size)
 
       /* If the constructor has fewer fields than the structure
         or if we are initializing the structure to mostly zeros,
-        clear the whole structure first.  Don't do this is TARGET is
+        clear the whole structure first.  Don't do this if TARGET is a
         register whose mode size isn't equal to SIZE since clear_storage
         can't handle this case.  */
       else if (size > 0