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