]> gcc.gnu.org Git - gcc.git/blame - gcc/tree-nrv.c
[multiple changes]
[gcc.git] / gcc / tree-nrv.c
CommitLineData
6de9cd9a
DN
1/* Language independent return value optimizations
2 Copyright (C) 2004 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "tree.h"
26#include "rtl.h"
27#include "function.h"
28#include "basic-block.h"
29#include "expr.h"
30#include "diagnostic.h"
31#include "tree-flow.h"
32#include "timevar.h"
33#include "tree-dump.h"
34#include "tree-pass.h"
35#include "langhooks.h"
36
37/* This file implements return value optimizations for functions which
38 return aggregate types.
39
40 Basically this pass searches the function for return statements which
41 return a local aggregate. When converted to RTL such statements will
42 generate a copy from the local aggregate to final return value destination
43 mandated by the target's ABI.
44
45 That copy can often be avoided by directly constructing the return value
46 into the final destination mandated by the target's ABI.
47
48 This is basically a generic equivalent to the C++ front-end's
49 Named Return Value optimization. */
50
51struct nrv_data
52{
53 /* This is the temporary (a VAR_DECL) which appears in all of
54 this function's RETURN_EXPR statements. */
55 tree var;
56
1ea7e6ad 57 /* This is the function's RESULT_DECL. We will replace all occurrences
6de9cd9a
DN
58 of VAR with RESULT_DECL when we apply this optimization. */
59 tree result;
60};
61
62static 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
75static tree
76finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
77{
78 struct nrv_data *dp = (struct nrv_data *)data;
79
80 /* No need to walk into types. */
81 if (TYPE_P (*tp))
82 *walk_subtrees = 0;
500b9b49
RK
83
84 /* If this is a RETURN_EXPR, set the expression being returned to RESULT. */
6de9cd9a
DN
85 else if (TREE_CODE (*tp) == RETURN_EXPR)
86 TREE_OPERAND (*tp, 0) = dp->result;
500b9b49 87
61ada8ae 88 /* Otherwise replace all occurrences of VAR with RESULT. */
6de9cd9a
DN
89 else if (*tp == dp->var)
90 *tp = dp->result;
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
108static void
109tree_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 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;
121
122 /* Look through each block for suitable return expressions. RETURN_EXPRs
123 end basic blocks, so we only have to look at the last statement in
124 each block. That makes this very fast. */
125 FOR_EACH_BB (bb)
126 {
127 tree stmt = last_stmt (bb);
128
129 if (stmt && TREE_CODE (stmt) == RETURN_EXPR)
130 {
131 tree ret_expr = TREE_OPERAND (stmt, 0);
132
133 /* This probably should not happen, but just to be safe do
134 not perform NRV optimizations if only some of the return
135 statement return a value. */
136 if (!ret_expr
137 || TREE_CODE (ret_expr) != MODIFY_EXPR
138 || TREE_CODE (TREE_OPERAND (ret_expr, 0)) != RESULT_DECL)
139 return;
140
141 /* Now verify that this return statement uses the same value
142 as any previously encountered return statement. */
143 if (found != NULL)
144 {
145 /* If we found a return statement using a different variable
146 than previous return statements, then we can not perform
147 NRV optimizations. */
148 if (found != TREE_OPERAND (ret_expr, 1))
149 return;
150 }
151 else
152 found = TREE_OPERAND (ret_expr, 1);
153
154 /* The returned value must be a local automatic variable of the
155 same type and alignment as the function's result. */
156 if (TREE_CODE (found) != VAR_DECL
e79b60a7 157 || TREE_THIS_VOLATILE (found)
6de9cd9a
DN
158 || DECL_CONTEXT (found) != current_function_decl
159 || TREE_STATIC (found)
160 || TREE_ADDRESSABLE (found)
161 || DECL_ALIGN (found) > DECL_ALIGN (result)
162 || !lang_hooks.types_compatible_p (TREE_TYPE (found),
163 result_type))
164 return;
165 }
166 }
167
168 if (!found)
169 return;
170
171 /* If dumping details, then note once and only the NRV replacement. */
172 if (dump_file && (dump_flags & TDF_DETAILS))
173 {
174 fprintf (dump_file, "NRV Replaced: ");
175 print_generic_expr (dump_file, found, dump_flags);
176 fprintf (dump_file, " with: ");
177 print_generic_expr (dump_file, result, dump_flags);
178 fprintf (dump_file, "\n");
179 }
180
181 /* At this point we know that all the return statements return the
182 same local which has suitable attributes for NRV. Copy debugging
183 information from FOUND to RESULT. */
184 DECL_NAME (result) = DECL_NAME (found);
185 DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
186 DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
187 TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);
188
189 /* Now walk through the function changing all references to VAR to be
190 RESULT. */
191 data.var = found;
192 data.result = result;
193 FOR_EACH_BB (bb)
194 {
195 block_stmt_iterator bsi;
196
197 for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
198 walk_tree (bsi_stmt_ptr (bsi), finalize_nrv_r, &data, 0);
199 }
200
201 /* FOUND is no longer used. Ensure it gets removed. */
202 var_ann (found)->used = 0;
203}
204
205struct tree_opt_pass pass_nrv =
206{
207 "nrv", /* name */
208 NULL, /* gate */
209 tree_nrv, /* execute */
210 NULL, /* sub */
211 NULL, /* next */
212 0, /* static_pass_number */
213 TV_TREE_NRV, /* tv_id */
214 PROP_cfg, /* properties_required */
215 0, /* properties_provided */
216 0, /* properties_destroyed */
217 0, /* todo_flags_start */
9f8628ba
PB
218 TODO_dump_func | TODO_ggc_collect, /* todo_flags_finish */
219 0 /* letter */
6de9cd9a 220};
This page took 0.471443 seconds and 5 git commands to generate.