OSDN Git Service

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