1169689Skan/* Language independent return value optimizations
2169689Skan   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3169689Skan
4169689SkanThis file is part of GCC.
5169689Skan
6169689SkanGCC is free software; you can redistribute it and/or modify
7169689Skanit under the terms of the GNU General Public License as published by
8169689Skanthe Free Software Foundation; either version 2, or (at your option)
9169689Skanany later version.
10169689Skan
11169689SkanGCC is distributed in the hope that it will be useful,
12169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
13169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14169689SkanGNU General Public License for more details.
15169689Skan
16169689SkanYou should have received a copy of the GNU General Public License
17169689Skanalong with GCC; see the file COPYING.  If not, write to
18169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
19169689SkanBoston, MA 02110-1301, USA.  */
20169689Skan
21169689Skan#include "config.h"
22169689Skan#include "system.h"
23169689Skan#include "coretypes.h"
24169689Skan#include "tm.h"
25169689Skan#include "tree.h"
26169689Skan#include "rtl.h"
27169689Skan#include "function.h"
28169689Skan#include "basic-block.h"
29169689Skan#include "expr.h"
30169689Skan#include "diagnostic.h"
31169689Skan#include "tree-flow.h"
32169689Skan#include "timevar.h"
33169689Skan#include "tree-dump.h"
34169689Skan#include "tree-pass.h"
35169689Skan#include "langhooks.h"
36169689Skan
37169689Skan/* This file implements return value optimizations for functions which
38169689Skan   return aggregate types.
39169689Skan
40169689Skan   Basically this pass searches the function for return statements which
41169689Skan   return a local aggregate.  When converted to RTL such statements will
42169689Skan   generate a copy from the local aggregate to final return value destination
43169689Skan   mandated by the target's ABI.
44169689Skan
45169689Skan   That copy can often be avoided by directly constructing the return value
46169689Skan   into the final destination mandated by the target's ABI.
47169689Skan
48169689Skan   This is basically a generic equivalent to the C++ front-end's
49169689Skan   Named Return Value optimization.  */
50169689Skan
51169689Skanstruct nrv_data
52169689Skan{
53169689Skan  /* This is the temporary (a VAR_DECL) which appears in all of
54169689Skan     this function's RETURN_EXPR statements.  */
55169689Skan  tree var;
56169689Skan
57169689Skan  /* This is the function's RESULT_DECL.  We will replace all occurrences
58169689Skan     of VAR with RESULT_DECL when we apply this optimization.  */
59169689Skan  tree result;
60169689Skan};
61169689Skan
62169689Skanstatic tree finalize_nrv_r (tree *, int *, void *);
63169689Skan
64169689Skan/* Callback for the tree walker.
65169689Skan
66169689Skan   If TP refers to a RETURN_EXPR, then set the expression being returned
67169689Skan   to nrv_data->result.
68169689Skan
69169689Skan   If TP refers to nrv_data->var, then replace nrv_data->var with
70169689Skan   nrv_data->result.
71169689Skan
72169689Skan   If we reach a node where we know all the subtrees are uninteresting,
73169689Skan   then set *WALK_SUBTREES to zero.  */
74169689Skan
75169689Skanstatic tree
76169689Skanfinalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
77169689Skan{
78169689Skan  struct nrv_data *dp = (struct nrv_data *)data;
79169689Skan
80169689Skan  /* No need to walk into types.  */
81169689Skan  if (TYPE_P (*tp))
82169689Skan    *walk_subtrees = 0;
83169689Skan
84169689Skan  /* Otherwise replace all occurrences of VAR with RESULT.  */
85169689Skan  else if (*tp == dp->var)
86169689Skan    *tp = dp->result;
87169689Skan
88169689Skan  /* Keep iterating.  */
89169689Skan  return NULL_TREE;
90169689Skan}
91169689Skan
92169689Skan/* Main entry point for return value optimizations.
93169689Skan
94169689Skan   If this function always returns the same local variable, and that
95169689Skan   local variable is an aggregate type, then replace the variable with
96169689Skan   the function's DECL_RESULT.
97169689Skan
98169689Skan   This is the equivalent of the C++ named return value optimization
99169689Skan   applied to optimized trees in a language independent form.  If we
100169689Skan   ever encounter languages which prevent this kind of optimization,
101169689Skan   then we could either have the languages register the optimization or
102169689Skan   we could change the gating function to check the current language.  */
103169689Skan
104169689Skanstatic unsigned int
105169689Skantree_nrv (void)
106169689Skan{
107169689Skan  tree result = DECL_RESULT (current_function_decl);
108169689Skan  tree result_type = TREE_TYPE (result);
109169689Skan  tree found = NULL;
110169689Skan  basic_block bb;
111169689Skan  block_stmt_iterator bsi;
112169689Skan  struct nrv_data data;
113169689Skan
114169689Skan  /* If this function does not return an aggregate type in memory, then
115169689Skan     there is nothing to do.  */
116169689Skan  if (!aggregate_value_p (result, current_function_decl))
117169689Skan    return 0;
118169689Skan
119169689Skan  /* Look through each block for assignments to the RESULT_DECL.  */
120169689Skan  FOR_EACH_BB (bb)
121169689Skan    {
122169689Skan      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
123169689Skan	{
124169689Skan	  tree stmt = bsi_stmt (bsi);
125169689Skan	  tree ret_expr;
126169689Skan
127169689Skan	  if (TREE_CODE (stmt) == RETURN_EXPR)
128169689Skan	    {
129169689Skan	      /* In a function with an aggregate return value, the
130169689Skan		 gimplifier has changed all non-empty RETURN_EXPRs to
131169689Skan		 return the RESULT_DECL.  */
132169689Skan	      ret_expr = TREE_OPERAND (stmt, 0);
133169689Skan	      if (ret_expr)
134169689Skan		gcc_assert (ret_expr == result);
135169689Skan	    }
136169689Skan	  else if (TREE_CODE (stmt) == MODIFY_EXPR
137169689Skan		   && TREE_OPERAND (stmt, 0) == result)
138169689Skan	    {
139169689Skan	      ret_expr = TREE_OPERAND (stmt, 1);
140169689Skan
141169689Skan	      /* Now verify that this return statement uses the same value
142169689Skan		 as any previously encountered return statement.  */
143169689Skan	      if (found != NULL)
144169689Skan		{
145169689Skan		  /* If we found a return statement using a different variable
146169689Skan		     than previous return statements, then we can not perform
147169689Skan		     NRV optimizations.  */
148169689Skan		  if (found != ret_expr)
149169689Skan		    return 0;
150169689Skan		}
151169689Skan	      else
152169689Skan		found = ret_expr;
153169689Skan
154169689Skan	      /* The returned value must be a local automatic variable of the
155169689Skan		 same type and alignment as the function's result.  */
156169689Skan	      if (TREE_CODE (found) != VAR_DECL
157169689Skan		  || TREE_THIS_VOLATILE (found)
158169689Skan		  || DECL_CONTEXT (found) != current_function_decl
159169689Skan		  || TREE_STATIC (found)
160169689Skan		  || TREE_ADDRESSABLE (found)
161169689Skan		  || DECL_ALIGN (found) > DECL_ALIGN (result)
162169689Skan		  || !lang_hooks.types_compatible_p (TREE_TYPE (found),
163169689Skan						     result_type))
164169689Skan		return 0;
165169689Skan	    }
166169689Skan	  else if (TREE_CODE (stmt) == MODIFY_EXPR)
167169689Skan	    {
168169689Skan	      tree addr = get_base_address (TREE_OPERAND (stmt, 0));
169169689Skan	       /* If there's any MODIFY of component of RESULT,
170169689Skan		  then bail out.  */
171169689Skan	      if (addr && addr == result)
172169689Skan		return 0;
173169689Skan	    }
174169689Skan	}
175169689Skan    }
176169689Skan
177169689Skan  if (!found)
178169689Skan    return 0;
179169689Skan
180169689Skan  /* If dumping details, then note once and only the NRV replacement.  */
181169689Skan  if (dump_file && (dump_flags & TDF_DETAILS))
182169689Skan    {
183169689Skan      fprintf (dump_file, "NRV Replaced: ");
184169689Skan      print_generic_expr (dump_file, found, dump_flags);
185169689Skan      fprintf (dump_file, "  with: ");
186169689Skan      print_generic_expr (dump_file, result, dump_flags);
187169689Skan      fprintf (dump_file, "\n");
188169689Skan    }
189169689Skan
190169689Skan  /* At this point we know that all the return statements return the
191169689Skan     same local which has suitable attributes for NRV.   Copy debugging
192169689Skan     information from FOUND to RESULT.  */
193169689Skan  DECL_NAME (result) = DECL_NAME (found);
194169689Skan  DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
195169689Skan  DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
196169689Skan  TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);
197169689Skan
198169689Skan  /* Now walk through the function changing all references to VAR to be
199169689Skan     RESULT.  */
200169689Skan  data.var = found;
201169689Skan  data.result = result;
202169689Skan  FOR_EACH_BB (bb)
203169689Skan    {
204169689Skan      for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
205169689Skan	{
206169689Skan	  tree *tp = bsi_stmt_ptr (bsi);
207169689Skan	  /* If this is a copy from VAR to RESULT, remove it.  */
208169689Skan	  if (TREE_CODE (*tp) == MODIFY_EXPR
209169689Skan	      && TREE_OPERAND (*tp, 0) == result
210169689Skan	      && TREE_OPERAND (*tp, 1) == found)
211169689Skan	    bsi_remove (&bsi, true);
212169689Skan	  else
213169689Skan	    {
214169689Skan	      walk_tree (tp, finalize_nrv_r, &data, 0);
215169689Skan	      bsi_next (&bsi);
216169689Skan	    }
217169689Skan	}
218169689Skan    }
219169689Skan
220169689Skan  /* FOUND is no longer used.  Ensure it gets removed.  */
221169689Skan  var_ann (found)->used = 0;
222169689Skan  return 0;
223169689Skan}
224169689Skan
225169689Skanstruct tree_opt_pass pass_nrv =
226169689Skan{
227169689Skan  "nrv",				/* name */
228169689Skan  NULL,					/* gate */
229169689Skan  tree_nrv,				/* execute */
230169689Skan  NULL,					/* sub */
231169689Skan  NULL,					/* next */
232169689Skan  0,					/* static_pass_number */
233169689Skan  TV_TREE_NRV,				/* tv_id */
234169689Skan  PROP_cfg,				/* properties_required */
235169689Skan  0,					/* properties_provided */
236169689Skan  0,					/* properties_destroyed */
237169689Skan  0,					/* todo_flags_start */
238169689Skan  TODO_dump_func | TODO_ggc_collect,			/* todo_flags_finish */
239169689Skan  0					/* letter */
240169689Skan};
241169689Skan
242169689Skan/* Determine (pessimistically) whether DEST is available for NRV
243169689Skan   optimization, where DEST is expected to be the LHS of a modify
244169689Skan   expression where the RHS is a function returning an aggregate.
245169689Skan
246169689Skan   We search for a base VAR_DECL and look to see if it, or any of its
247169689Skan   subvars are clobbered.  Note that we could do better, for example, by
248169689Skan   attempting to doing points-to analysis on INDIRECT_REFs.  */
249169689Skan
250169689Skanstatic bool
251169689Skandest_safe_for_nrv_p (tree dest)
252169689Skan{
253169689Skan  switch (TREE_CODE (dest))
254169689Skan    {
255169689Skan      case VAR_DECL:
256169689Skan	{
257169689Skan	  subvar_t subvar;
258169689Skan	  if (is_call_clobbered (dest))
259169689Skan	    return false;
260169689Skan	  for (subvar = get_subvars_for_var (dest);
261169689Skan	       subvar;
262169689Skan	       subvar = subvar->next)
263169689Skan	    if (is_call_clobbered (subvar->var))
264169689Skan	      return false;
265169689Skan	  return true;
266169689Skan	}
267169689Skan      case ARRAY_REF:
268169689Skan      case COMPONENT_REF:
269169689Skan	return dest_safe_for_nrv_p (TREE_OPERAND (dest, 0));
270169689Skan      default:
271169689Skan	return false;
272169689Skan    }
273169689Skan}
274169689Skan
275169689Skan/* Walk through the function looking for MODIFY_EXPRs with calls that
276169689Skan   return in memory on the RHS.  For each of these, determine whether it is
277169689Skan   safe to pass the address of the LHS as the return slot, and mark the
278169689Skan   call appropriately if so.
279169689Skan
280169689Skan   The NRV shares the return slot with a local variable in the callee; this
281169689Skan   optimization shares the return slot with the target of the call within
282169689Skan   the caller.  If the NRV is performed (which we can't know in general),
283169689Skan   this optimization is safe if the address of the target has not
284169689Skan   escaped prior to the call.  If it has, modifications to the local
285169689Skan   variable will produce visible changes elsewhere, as in PR c++/19317.  */
286169689Skan
287169689Skanstatic unsigned int
288169689Skanexecute_return_slot_opt (void)
289169689Skan{
290169689Skan  basic_block bb;
291169689Skan
292169689Skan  FOR_EACH_BB (bb)
293169689Skan    {
294169689Skan      block_stmt_iterator i;
295169689Skan      for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
296169689Skan	{
297169689Skan	  tree stmt = bsi_stmt (i);
298169689Skan	  tree call;
299169689Skan
300169689Skan	  if (TREE_CODE (stmt) == MODIFY_EXPR
301169689Skan	      && (call = TREE_OPERAND (stmt, 1),
302169689Skan		  TREE_CODE (call) == CALL_EXPR)
303169689Skan	      && !CALL_EXPR_RETURN_SLOT_OPT (call)
304169689Skan	      && aggregate_value_p (call, call))
305169689Skan	    /* Check if the location being assigned to is
306169689Skan	       call-clobbered.  */
307169689Skan	    CALL_EXPR_RETURN_SLOT_OPT (call) =
308169689Skan	      dest_safe_for_nrv_p (TREE_OPERAND (stmt, 0)) ? 1 : 0;
309169689Skan	}
310169689Skan    }
311169689Skan  return 0;
312169689Skan}
313169689Skan
314169689Skanstruct tree_opt_pass pass_return_slot =
315169689Skan{
316169689Skan  "retslot",				/* name */
317169689Skan  NULL,					/* gate */
318169689Skan  execute_return_slot_opt,		/* execute */
319169689Skan  NULL,					/* sub */
320169689Skan  NULL,					/* next */
321169689Skan  0,					/* static_pass_number */
322169689Skan  0,					/* tv_id */
323169689Skan  PROP_ssa | PROP_alias,		/* properties_required */
324169689Skan  0,					/* properties_provided */
325169689Skan  0,					/* properties_destroyed */
326169689Skan  0,					/* todo_flags_start */
327169689Skan  0,					/* todo_flags_finish */
328169689Skan  0					/* letter */
329169689Skan};
330