OSDN Git Service

2008-04-30 Martin Jambor <mjambor@suse.cz>
[pf3gnuchains/gcc-fork.git] / gcc / tree-nrv.c
1 /* Language independent return value optimizations
2    Copyright (C) 2004, 2005, 2007, 2008 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 };
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 nrv_data *dp = (struct nrv_data *)data;
78
79   /* No need to walk into types.  */
80   if (TYPE_P (*tp))
81     *walk_subtrees = 0;
82
83   /* Otherwise replace all occurrences of VAR with RESULT.  */
84   else if (*tp == dp->var)
85     *tp = dp->result;
86
87   /* Keep iterating.  */
88   return NULL_TREE;
89 }
90
91 /* Main entry point for return value optimizations.
92
93    If this function always returns the same local variable, and that
94    local variable is an aggregate type, then replace the variable with
95    the function's DECL_RESULT.
96
97    This is the equivalent of the C++ named return value optimization
98    applied to optimized trees in a language independent form.  If we
99    ever encounter languages which prevent this kind of optimization,
100    then we could either have the languages register the optimization or
101    we could change the gating function to check the current language.  */
102    
103 static unsigned int
104 tree_nrv (void)
105 {
106   tree result = DECL_RESULT (current_function_decl);
107   tree result_type = TREE_TYPE (result);
108   tree found = NULL;
109   basic_block bb;
110   block_stmt_iterator bsi;
111   struct nrv_data data;
112
113   /* If this function does not return an aggregate type in memory, then
114      there is nothing to do.  */
115   if (!aggregate_value_p (result, current_function_decl))
116     return 0;
117
118   /* If a GIMPLE type is returned in memory, finalize_nrv_r might create
119      non-GIMPLE.  */
120   if (is_gimple_reg_type (result_type))
121     return 0;
122
123   /* Look through each block for assignments to the RESULT_DECL.  */
124   FOR_EACH_BB (bb)
125     {
126       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
127         {
128           tree stmt = bsi_stmt (bsi);
129           tree ret_expr;
130
131           if (TREE_CODE (stmt) == RETURN_EXPR)
132             {
133               /* In a function with an aggregate return value, the
134                  gimplifier has changed all non-empty RETURN_EXPRs to
135                  return the RESULT_DECL.  */
136               ret_expr = TREE_OPERAND (stmt, 0);
137               if (ret_expr)
138                 gcc_assert (ret_expr == result);
139             }
140           else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
141                    && GIMPLE_STMT_OPERAND (stmt, 0) == result)
142             {
143               ret_expr = GIMPLE_STMT_OPERAND (stmt, 1);
144
145               /* Now verify that this return statement uses the same value
146                  as any previously encountered return statement.  */
147               if (found != NULL)
148                 {
149                   /* If we found a return statement using a different variable
150                      than previous return statements, then we can not perform
151                      NRV optimizations.  */
152                   if (found != ret_expr)
153                     return 0;
154                 }
155               else
156                 found = ret_expr;
157
158               /* The returned value must be a local automatic variable of the
159                  same type and alignment as the function's result.  */
160               if (TREE_CODE (found) != VAR_DECL
161                   || TREE_THIS_VOLATILE (found)
162                   || DECL_CONTEXT (found) != current_function_decl
163                   || TREE_STATIC (found)
164                   || TREE_ADDRESSABLE (found)
165                   || DECL_ALIGN (found) > DECL_ALIGN (result)
166                   || !useless_type_conversion_p (result_type,
167                                                 TREE_TYPE (found)))
168                 return 0;
169             }
170           else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
171             {
172               tree addr = get_base_address (GIMPLE_STMT_OPERAND (stmt, 0));
173                /* If there's any MODIFY of component of RESULT, 
174                   then bail out.  */
175               if (addr && addr == result)
176                 return 0;
177             }
178         }
179     }
180
181   if (!found)
182     return 0;
183
184   /* If dumping details, then note once and only the NRV replacement.  */
185   if (dump_file && (dump_flags & TDF_DETAILS))
186     {
187       fprintf (dump_file, "NRV Replaced: ");
188       print_generic_expr (dump_file, found, dump_flags);
189       fprintf (dump_file, "  with: ");
190       print_generic_expr (dump_file, result, dump_flags);
191       fprintf (dump_file, "\n");
192     }
193
194   /* At this point we know that all the return statements return the
195      same local which has suitable attributes for NRV.   Copy debugging
196      information from FOUND to RESULT.  */
197   DECL_NAME (result) = DECL_NAME (found);
198   DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
199   DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
200   TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);
201
202   /* Now walk through the function changing all references to VAR to be
203      RESULT.  */
204   data.var = found;
205   data.result = result;
206   FOR_EACH_BB (bb)
207     {
208       for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
209         {
210           tree *tp = bsi_stmt_ptr (bsi);
211           /* If this is a copy from VAR to RESULT, remove it.  */
212           if (TREE_CODE (*tp) == GIMPLE_MODIFY_STMT
213               && GIMPLE_STMT_OPERAND (*tp, 0) == result
214               && GIMPLE_STMT_OPERAND (*tp, 1) == found)
215             bsi_remove (&bsi, true);
216           else
217             {
218               walk_tree (tp, finalize_nrv_r, &data, 0);
219               bsi_next (&bsi);
220             }
221         }
222     }
223
224   /* FOUND is no longer used.  Ensure it gets removed.  */
225   var_ann (found)->used = 0;
226   return 0;
227 }
228
229 struct gimple_opt_pass pass_nrv = 
230 {
231  {
232   GIMPLE_PASS,
233   "nrv",                                /* name */
234   NULL,                                 /* gate */
235   tree_nrv,                             /* execute */
236   NULL,                                 /* sub */
237   NULL,                                 /* next */
238   0,                                    /* static_pass_number */
239   TV_TREE_NRV,                          /* tv_id */
240   PROP_cfg,                             /* properties_required */
241   0,                                    /* properties_provided */
242   0,                                    /* properties_destroyed */
243   0,                                    /* todo_flags_start */
244   TODO_dump_func | TODO_ggc_collect                     /* todo_flags_finish */
245  }
246 };
247
248 /* Determine (pessimistically) whether DEST is available for NRV
249    optimization, where DEST is expected to be the LHS of a modify
250    expression where the RHS is a function returning an aggregate.
251
252    We search for a base VAR_DECL and look to see if it, or any of its
253    subvars are clobbered.  Note that we could do better, for example, by
254    attempting to doing points-to analysis on INDIRECT_REFs.  */
255
256 static bool
257 dest_safe_for_nrv_p (tree dest)
258 {
259   subvar_t sv;
260   unsigned int i;
261   tree subvar;
262
263   while (handled_component_p (dest))
264     dest = TREE_OPERAND (dest, 0);
265
266   if (! SSA_VAR_P (dest))
267     return false;
268
269   if (TREE_CODE (dest) == SSA_NAME)
270     dest = SSA_NAME_VAR (dest);
271
272   if (is_call_clobbered (dest))
273     return false;
274
275   sv = get_subvars_for_var (dest);
276   for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
277     if (is_call_clobbered (subvar))
278       return false;
279
280   return true;
281 }
282
283 /* Walk through the function looking for GIMPLE_MODIFY_STMTs with calls that
284    return in memory on the RHS.  For each of these, determine whether it is
285    safe to pass the address of the LHS as the return slot, and mark the
286    call appropriately if so.
287
288    The NRV shares the return slot with a local variable in the callee; this
289    optimization shares the return slot with the target of the call within
290    the caller.  If the NRV is performed (which we can't know in general),
291    this optimization is safe if the address of the target has not
292    escaped prior to the call.  If it has, modifications to the local
293    variable will produce visible changes elsewhere, as in PR c++/19317.  */
294
295 static unsigned int
296 execute_return_slot_opt (void)
297 {
298   basic_block bb;
299
300   FOR_EACH_BB (bb)
301     {
302       block_stmt_iterator i;
303       for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
304         {
305           tree stmt = bsi_stmt (i);
306           tree call;
307
308           if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
309               && (call = GIMPLE_STMT_OPERAND (stmt, 1),
310                   TREE_CODE (call) == CALL_EXPR)
311               && !CALL_EXPR_RETURN_SLOT_OPT (call)
312               && aggregate_value_p (call, call))
313             /* Check if the location being assigned to is
314                call-clobbered.  */
315             CALL_EXPR_RETURN_SLOT_OPT (call) =
316               dest_safe_for_nrv_p (GIMPLE_STMT_OPERAND (stmt, 0)) ? 1 : 0;
317         }
318     }
319   return 0;
320 }
321
322 struct gimple_opt_pass pass_return_slot = 
323 {
324  {
325   GIMPLE_PASS,
326   "retslot",                            /* name */
327   NULL,                                 /* gate */
328   execute_return_slot_opt,              /* execute */
329   NULL,                                 /* sub */
330   NULL,                                 /* next */
331   0,                                    /* static_pass_number */
332   0,                                    /* tv_id */
333   PROP_ssa | PROP_alias,                /* properties_required */
334   0,                                    /* properties_provided */
335   0,                                    /* properties_destroyed */
336   0,                                    /* todo_flags_start */
337   0                                     /* todo_flags_finish */
338  }
339 };