diff gcc/tree-nrv.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/tree-nrv.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/tree-nrv.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,6 +1,5 @@
 /* Language independent return value optimizations
-   Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2004-2017 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,19 +20,15 @@
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
 #include "tree.h"
-#include "function.h"
-#include "basic-block.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
 #include "tree-pretty-print.h"
-#include "tree-flow.h"
-#include "timevar.h"
-#include "tree-dump.h"
-#include "tree-pass.h"
-#include "langhooks.h"
-#include "flags.h"	/* For "optimize" in gate_pass_return_slot.
-			   FIXME: That should be up to the pass manager,
-			   but pass_nrv is not in pass_all_optimizations.  */
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "internal-fn.h"
 
 /* This file implements return value optimizations for functions which
    return aggregate types.
@@ -49,7 +44,7 @@
    This is basically a generic equivalent to the C++ front-end's
    Named Return Value optimization.  */
 
-struct nrv_data
+struct nrv_data_t
 {
   /* This is the temporary (a VAR_DECL) which appears in all of
      this function's RETURN_EXPR statements.  */
@@ -78,7 +73,7 @@
 finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct nrv_data *dp = (struct nrv_data *) wi->info;
+  struct nrv_data_t *dp = (struct nrv_data_t *) wi->info;
 
   /* No need to walk into types.  */
   if (TYPE_P (*tp))
@@ -107,15 +102,44 @@
    then we could either have the languages register the optimization or
    we could change the gating function to check the current language.  */
 
-static unsigned int
-tree_nrv (void)
+namespace {
+
+const pass_data pass_data_nrv =
+{
+  GIMPLE_PASS, /* type */
+  "nrv", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_NRV, /* tv_id */
+  ( PROP_ssa | PROP_cfg ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_nrv : public gimple_opt_pass
+{
+public:
+  pass_nrv (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_nrv, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return optimize > 0; }
+
+  virtual unsigned int execute (function *);
+
+}; // class pass_nrv
+
+unsigned int
+pass_nrv::execute (function *fun)
 {
   tree result = DECL_RESULT (current_function_decl);
   tree result_type = TREE_TYPE (result);
   tree found = NULL;
   basic_block bb;
   gimple_stmt_iterator gsi;
-  struct nrv_data data;
+  struct nrv_data_t data;
 
   /* If this function does not return an aggregate type in memory, then
      there is nothing to do.  */
@@ -138,19 +162,19 @@
     return 0;
 
   /* Look through each block for assignments to the RESULT_DECL.  */
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, fun)
     {
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
-	  gimple stmt = gsi_stmt (gsi);
+	  gimple *stmt = gsi_stmt (gsi);
 	  tree ret_val;
 
-	  if (gimple_code (stmt) == GIMPLE_RETURN)
+	  if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
 	    {
 	      /* In a function with an aggregate return value, the
 		 gimplifier has changed all non-empty RETURN_EXPRs to
 		 return the RESULT_DECL.  */
-	      ret_val = gimple_return_retval (stmt);
+	      ret_val = gimple_return_retval (return_stmt);
 	      if (ret_val)
 		gcc_assert (ret_val == result);
 	    }
@@ -179,10 +203,9 @@
 
 	      /* The returned value must be a local automatic variable of the
 		 same type and alignment as the function's result.  */
-	      if (TREE_CODE (found) != VAR_DECL
+	      if (!VAR_P (found)
 		  || TREE_THIS_VOLATILE (found)
-		  || DECL_CONTEXT (found) != current_function_decl
-		  || TREE_STATIC (found)
+		  || !auto_var_in_fn_p (found, current_function_decl)
 		  || TREE_ADDRESSABLE (found)
 		  || DECL_ALIGN (found) > DECL_ALIGN (result)
 		  || !useless_type_conversion_p (result_type,
@@ -232,11 +255,11 @@
      RESULT.  */
   data.var = found;
   data.result = result;
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, fun)
     {
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
 	{
-	  gimple stmt = gsi_stmt (gsi);
+	  gimple *stmt = gsi_stmt (gsi);
 	  /* If this is a copy from VAR to RESULT, remove it.  */
 	  if (gimple_assign_copy_p (stmt)
 	      && gimple_assign_lhs (stmt) == result
@@ -244,6 +267,7 @@
 	    {
 	      unlink_stmt_vdef (stmt);
 	      gsi_remove (&gsi, true);
+	      release_defs (stmt);
 	    }
 	  else
 	    {
@@ -262,35 +286,16 @@
   SET_DECL_VALUE_EXPR (found, result);
   DECL_HAS_VALUE_EXPR_P (found) = 1;
 
-  /* FOUND is no longer used.  Ensure it gets removed.  */
-  clear_is_used (found);
   return 0;
 }
 
-static bool
-gate_pass_return_slot (void)
-{
-  return optimize > 0;
-}
+} // anon namespace
 
-struct gimple_opt_pass pass_nrv =
+gimple_opt_pass *
+make_pass_nrv (gcc::context *ctxt)
 {
- {
-  GIMPLE_PASS,
-  "nrv",				/* name */
-  gate_pass_return_slot,		/* gate */
-  tree_nrv,				/* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  TV_TREE_NRV,				/* tv_id */
-  PROP_ssa | PROP_cfg,				/* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  0,					/* todo_flags_start */
-  TODO_dump_func | TODO_ggc_collect			/* todo_flags_finish */
- }
-};
+  return new pass_nrv (ctxt);
+}
 
 /* Determine (pessimistically) whether DEST is available for NRV
    optimization, where DEST is expected to be the LHS of a modify
@@ -299,7 +304,7 @@
    DEST is available if it is not clobbered or used by the call.  */
 
 static bool
-dest_safe_for_nrv_p (gimple call)
+dest_safe_for_nrv_p (gcall *call)
 {
   tree dest = gimple_call_lhs (call);
 
@@ -329,27 +334,61 @@
    escaped prior to the call.  If it has, modifications to the local
    variable will produce visible changes elsewhere, as in PR c++/19317.  */
 
-static unsigned int
-execute_return_slot_opt (void)
+namespace {
+
+const pass_data pass_data_return_slot =
+{
+  GIMPLE_PASS, /* type */
+  "retslot", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_return_slot : public gimple_opt_pass
+{
+public:
+  pass_return_slot (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_return_slot, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *);
+
+}; // class pass_return_slot
+
+unsigned int
+pass_return_slot::execute (function *fun)
 {
   basic_block bb;
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, fun)
     {
       gimple_stmt_iterator gsi;
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
-	  gimple stmt = gsi_stmt (gsi);
+	  gcall *stmt;
 	  bool slot_opt_p;
 
-	  if (is_gimple_call (stmt)
+	  stmt = dyn_cast <gcall *> (gsi_stmt (gsi));
+	  if (stmt
 	      && gimple_call_lhs (stmt)
 	      && !gimple_call_return_slot_opt_p (stmt)
+	      /* Ignore internal functions without direct optabs,
+		 those are expanded specially and aggregate_value_p
+		 on their result might result in undesirable warnings
+		 with some backends.  */
+	      && (!gimple_call_internal_p (stmt)
+		  || direct_internal_fn_p (gimple_call_internal_fn (stmt)))
 	      && aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)),
 				    gimple_call_fndecl (stmt)))
 	    {
 	      /* Check if the location being assigned to is
-	         clobbered by the call.  */
+		 clobbered by the call.  */
 	      slot_opt_p = dest_safe_for_nrv_p (stmt);
 	      gimple_call_set_return_slot_opt (stmt, slot_opt_p);
 	    }
@@ -358,21 +397,10 @@
   return 0;
 }
 
-struct gimple_opt_pass pass_return_slot =
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_return_slot (gcc::context *ctxt)
 {
- {
-  GIMPLE_PASS,
-  "retslot",				/* name */
-  NULL,					/* gate */
-  execute_return_slot_opt,		/* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  TV_NONE,				/* tv_id */
-  PROP_ssa,				/* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  0,					/* todo_flags_start */
-  0					/* todo_flags_finish */
- }
-};
+  return new pass_return_slot (ctxt);
+}