xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/tree-nrv.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* Language independent return value optimizations
2    Copyright (C) 2004-2013 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10 
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "tm.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "tree-pretty-print.h"
28 #include "tree-flow.h"
29 #include "tree-pass.h"
30 #include "langhooks.h"
31 #include "flags.h"	/* For "optimize" in gate_pass_return_slot.
32 			   FIXME: That should be up to the pass manager,
33 			   but pass_nrv is not in pass_all_optimizations.  */
34 
35 /* This file implements return value optimizations for functions which
36    return aggregate types.
37 
38    Basically this pass searches the function for return statements which
39    return a local aggregate.  When converted to RTL such statements will
40    generate a copy from the local aggregate to final return value destination
41    mandated by the target's ABI.
42 
43    That copy can often be avoided by directly constructing the return value
44    into the final destination mandated by the target's ABI.
45 
46    This is basically a generic equivalent to the C++ front-end's
47    Named Return Value optimization.  */
48 
49 struct nrv_data
50 {
51   /* This is the temporary (a VAR_DECL) which appears in all of
52      this function's RETURN_EXPR statements.  */
53   tree var;
54 
55   /* This is the function's RESULT_DECL.  We will replace all occurrences
56      of VAR with RESULT_DECL when we apply this optimization.  */
57   tree result;
58   int modified;
59 };
60 
61 static tree finalize_nrv_r (tree *, int *, void *);
62 
63 /* Callback for the tree walker.
64 
65    If TP refers to a RETURN_EXPR, then set the expression being returned
66    to nrv_data->result.
67 
68    If TP refers to nrv_data->var, then replace nrv_data->var with
69    nrv_data->result.
70 
71    If we reach a node where we know all the subtrees are uninteresting,
72    then set *WALK_SUBTREES to zero.  */
73 
74 static tree
75 finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
76 {
77   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
78   struct nrv_data *dp = (struct nrv_data *) wi->info;
79 
80   /* No need to walk into types.  */
81   if (TYPE_P (*tp))
82     *walk_subtrees = 0;
83 
84   /* Otherwise replace all occurrences of VAR with RESULT.  */
85   else if (*tp == dp->var)
86     {
87       *tp = dp->result;
88       dp->modified = 1;
89     }
90 
91   /* Keep iterating.  */
92   return NULL_TREE;
93 }
94 
95 /* Main entry point for return value optimizations.
96 
97    If this function always returns the same local variable, and that
98    local variable is an aggregate type, then replace the variable with
99    the function's DECL_RESULT.
100 
101    This is the equivalent of the C++ named return value optimization
102    applied to optimized trees in a language independent form.  If we
103    ever encounter languages which prevent this kind of optimization,
104    then we could either have the languages register the optimization or
105    we could change the gating function to check the current language.  */
106 
107 static unsigned int
108 tree_nrv (void)
109 {
110   tree result = DECL_RESULT (current_function_decl);
111   tree result_type = TREE_TYPE (result);
112   tree found = NULL;
113   basic_block bb;
114   gimple_stmt_iterator gsi;
115   struct nrv_data data;
116 
117   /* If this function does not return an aggregate type in memory, then
118      there is nothing to do.  */
119   if (!aggregate_value_p (result, current_function_decl))
120     return 0;
121 
122   /* If a GIMPLE type is returned in memory, finalize_nrv_r might create
123      non-GIMPLE.  */
124   if (is_gimple_reg_type (result_type))
125     return 0;
126 
127   /* If the front end already did something like this, don't do it here.  */
128   if (DECL_NAME (result))
129     return 0;
130 
131   /* If the result has its address taken then it might be modified
132      by means not detected in the following loop.  Bail out in this
133      case.  */
134   if (TREE_ADDRESSABLE (result))
135     return 0;
136 
137   /* Look through each block for assignments to the RESULT_DECL.  */
138   FOR_EACH_BB (bb)
139     {
140       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
141 	{
142 	  gimple stmt = gsi_stmt (gsi);
143 	  tree ret_val;
144 
145 	  if (gimple_code (stmt) == GIMPLE_RETURN)
146 	    {
147 	      /* In a function with an aggregate return value, the
148 		 gimplifier has changed all non-empty RETURN_EXPRs to
149 		 return the RESULT_DECL.  */
150 	      ret_val = gimple_return_retval (stmt);
151 	      if (ret_val)
152 		gcc_assert (ret_val == result);
153 	    }
154 	  else if (gimple_has_lhs (stmt)
155 		   && gimple_get_lhs (stmt) == result)
156 	    {
157               tree rhs;
158 
159 	      if (!gimple_assign_copy_p (stmt))
160 		return 0;
161 
162 	      rhs = gimple_assign_rhs1 (stmt);
163 
164 	      /* Now verify that this return statement uses the same value
165 		 as any previously encountered return statement.  */
166 	      if (found != NULL)
167 		{
168 		  /* If we found a return statement using a different variable
169 		     than previous return statements, then we can not perform
170 		     NRV optimizations.  */
171 		  if (found != rhs)
172 		    return 0;
173 		}
174 	      else
175 		found = rhs;
176 
177 	      /* The returned value must be a local automatic variable of the
178 		 same type and alignment as the function's result.  */
179 	      if (TREE_CODE (found) != VAR_DECL
180 		  || TREE_THIS_VOLATILE (found)
181 		  || !auto_var_in_fn_p (found, current_function_decl)
182 		  || TREE_ADDRESSABLE (found)
183 		  || DECL_ALIGN (found) > DECL_ALIGN (result)
184 		  || !useless_type_conversion_p (result_type,
185 						 TREE_TYPE (found)))
186 		return 0;
187 	    }
188 	  else if (gimple_has_lhs (stmt))
189 	    {
190 	      tree addr = get_base_address (gimple_get_lhs (stmt));
191 	       /* If there's any MODIFY of component of RESULT,
192 		  then bail out.  */
193 	      if (addr && addr == result)
194 		return 0;
195 	    }
196 	}
197     }
198 
199   if (!found)
200     return 0;
201 
202   /* If dumping details, then note once and only the NRV replacement.  */
203   if (dump_file && (dump_flags & TDF_DETAILS))
204     {
205       fprintf (dump_file, "NRV Replaced: ");
206       print_generic_expr (dump_file, found, dump_flags);
207       fprintf (dump_file, "  with: ");
208       print_generic_expr (dump_file, result, dump_flags);
209       fprintf (dump_file, "\n");
210     }
211 
212   /* At this point we know that all the return statements return the
213      same local which has suitable attributes for NRV.   Copy debugging
214      information from FOUND to RESULT if it will be useful.  But don't set
215      DECL_ABSTRACT_ORIGIN to point at another function.  */
216   if (!DECL_IGNORED_P (found)
217       && !(DECL_ABSTRACT_ORIGIN (found)
218 	   && DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (found)) != current_function_decl))
219     {
220       DECL_NAME (result) = DECL_NAME (found);
221       DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
222       DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
223     }
224 
225   TREE_ADDRESSABLE (result) |= TREE_ADDRESSABLE (found);
226 
227   /* Now walk through the function changing all references to VAR to be
228      RESULT.  */
229   data.var = found;
230   data.result = result;
231   FOR_EACH_BB (bb)
232     {
233       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
234 	{
235 	  gimple stmt = gsi_stmt (gsi);
236 	  /* If this is a copy from VAR to RESULT, remove it.  */
237 	  if (gimple_assign_copy_p (stmt)
238 	      && gimple_assign_lhs (stmt) == result
239 	      && gimple_assign_rhs1 (stmt) == found)
240 	    {
241 	      unlink_stmt_vdef (stmt);
242 	      gsi_remove (&gsi, true);
243 	      release_defs (stmt);
244 	    }
245 	  else
246 	    {
247 	      struct walk_stmt_info wi;
248 	      memset (&wi, 0, sizeof (wi));
249 	      wi.info = &data;
250 	      data.modified = 0;
251 	      walk_gimple_op (stmt, finalize_nrv_r, &wi);
252 	      if (data.modified)
253 		update_stmt (stmt);
254 	      gsi_next (&gsi);
255 	    }
256 	}
257     }
258 
259   SET_DECL_VALUE_EXPR (found, result);
260   DECL_HAS_VALUE_EXPR_P (found) = 1;
261 
262   return 0;
263 }
264 
265 static bool
266 gate_pass_return_slot (void)
267 {
268   return optimize > 0;
269 }
270 
271 struct gimple_opt_pass pass_nrv =
272 {
273  {
274   GIMPLE_PASS,
275   "nrv",				/* name */
276   OPTGROUP_NONE,                        /* optinfo_flags */
277   gate_pass_return_slot,		/* gate */
278   tree_nrv,				/* execute */
279   NULL,					/* sub */
280   NULL,					/* next */
281   0,					/* static_pass_number */
282   TV_TREE_NRV,				/* tv_id */
283   PROP_ssa | PROP_cfg,				/* properties_required */
284   0,					/* properties_provided */
285   0,					/* properties_destroyed */
286   0,					/* todo_flags_start */
287   TODO_ggc_collect			/* todo_flags_finish */
288  }
289 };
290 
291 /* Determine (pessimistically) whether DEST is available for NRV
292    optimization, where DEST is expected to be the LHS of a modify
293    expression where the RHS is a function returning an aggregate.
294 
295    DEST is available if it is not clobbered or used by the call.  */
296 
297 static bool
298 dest_safe_for_nrv_p (gimple call)
299 {
300   tree dest = gimple_call_lhs (call);
301 
302   dest = get_base_address (dest);
303   if (! dest)
304     return false;
305 
306   if (TREE_CODE (dest) == SSA_NAME)
307     return true;
308 
309   if (call_may_clobber_ref_p (call, dest)
310       || ref_maybe_used_by_stmt_p (call, dest))
311     return false;
312 
313   return true;
314 }
315 
316 /* Walk through the function looking for GIMPLE_ASSIGNs with calls that
317    return in memory on the RHS.  For each of these, determine whether it is
318    safe to pass the address of the LHS as the return slot, and mark the
319    call appropriately if so.
320 
321    The NRV shares the return slot with a local variable in the callee; this
322    optimization shares the return slot with the target of the call within
323    the caller.  If the NRV is performed (which we can't know in general),
324    this optimization is safe if the address of the target has not
325    escaped prior to the call.  If it has, modifications to the local
326    variable will produce visible changes elsewhere, as in PR c++/19317.  */
327 
328 static unsigned int
329 execute_return_slot_opt (void)
330 {
331   basic_block bb;
332 
333   FOR_EACH_BB (bb)
334     {
335       gimple_stmt_iterator gsi;
336       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
337 	{
338 	  gimple stmt = gsi_stmt (gsi);
339 	  bool slot_opt_p;
340 
341 	  if (is_gimple_call (stmt)
342 	      && gimple_call_lhs (stmt)
343 	      && !gimple_call_return_slot_opt_p (stmt)
344 	      && aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)),
345 				    gimple_call_fndecl (stmt)))
346 	    {
347 	      /* Check if the location being assigned to is
348 	         clobbered by the call.  */
349 	      slot_opt_p = dest_safe_for_nrv_p (stmt);
350 	      gimple_call_set_return_slot_opt (stmt, slot_opt_p);
351 	    }
352 	}
353     }
354   return 0;
355 }
356 
357 struct gimple_opt_pass pass_return_slot =
358 {
359  {
360   GIMPLE_PASS,
361   "retslot",				/* name */
362   OPTGROUP_NONE,                        /* optinfo_flags */
363   NULL,					/* gate */
364   execute_return_slot_opt,		/* execute */
365   NULL,					/* sub */
366   NULL,					/* next */
367   0,					/* static_pass_number */
368   TV_NONE,				/* tv_id */
369   PROP_ssa,				/* properties_required */
370   0,					/* properties_provided */
371   0,					/* properties_destroyed */
372   0,					/* todo_flags_start */
373   0					/* todo_flags_finish */
374  }
375 };
376