* cp-tree.h (enum cp_storage_class): Remove trailing comma.
[official-gcc.git] / gcc / tree-nrv.c
blob1768b3909b9092e621dbe12ecd88fe24ff8c0e97
1 /* Language independent return value optimizations
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GCC.
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 2, or (at your option)
9 any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
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"
37 /* This file implements return value optimizations for functions which
38 return aggregate types.
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.
45 That copy can often be avoided by directly constructing the return value
46 into the final destination mandated by the target's ABI.
48 This is basically a generic equivalent to the C++ front-end's
49 Named Return Value optimization. */
51 struct nrv_data
53 /* This is the temporary (a VAR_DECL) which appears in all of
54 this function's RETURN_EXPR statements. */
55 tree var;
57 /* This is the function's RESULT_DECL. We will replace all occurrences
58 of VAR with RESULT_DECL when we apply this optimization. */
59 tree result;
62 static tree finalize_nrv_r (tree *, int *, void *);
64 /* Callback for the tree walker.
66 If TP refers to a RETURN_EXPR, then set the expression being returned
67 to nrv_data->result.
69 If TP refers to nrv_data->var, then replace nrv_data->var with
70 nrv_data->result.
72 If we reach a node where we know all the subtrees are uninteresting,
73 then set *WALK_SUBTREES to zero. */
75 static tree
76 finalize_nrv_r (tree *tp, int *walk_subtrees, void *data)
78 struct nrv_data *dp = (struct nrv_data *)data;
80 /* No need to walk into types. */
81 if (TYPE_P (*tp))
82 *walk_subtrees = 0;
83 /* If this is a RETURN_EXPR, then set the expression being returned
84 to RESULT. */
85 else if (TREE_CODE (*tp) == RETURN_EXPR)
86 TREE_OPERAND (*tp, 0) = dp->result;
87 /* Replace all occurrences of VAR with RESULT. */
88 else if (*tp == dp->var)
89 *tp = dp->result;
91 /* Keep iterating. */
92 return NULL_TREE;
95 /* Main entry point for return value optimizations.
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.
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. */
107 static void
108 tree_nrv (void)
110 tree result = DECL_RESULT (current_function_decl);
111 tree result_type = TREE_TYPE (result);
112 tree found = NULL;
113 basic_block bb;
114 struct nrv_data data;
116 /* If this function does not return an aggregate type in memory, then
117 there is nothing to do. */
118 if (!aggregate_value_p (result, current_function_decl))
119 return;
121 /* Look through each block for suitable return expressions. RETURN_EXPRs
122 end basic blocks, so we only have to look at the last statement in
123 each block. That makes this very fast. */
124 FOR_EACH_BB (bb)
126 tree stmt = last_stmt (bb);
128 if (stmt && TREE_CODE (stmt) == RETURN_EXPR)
130 tree ret_expr = TREE_OPERAND (stmt, 0);
132 /* This probably should not happen, but just to be safe do
133 not perform NRV optimizations if only some of the return
134 statement return a value. */
135 if (!ret_expr
136 || TREE_CODE (ret_expr) != MODIFY_EXPR
137 || TREE_CODE (TREE_OPERAND (ret_expr, 0)) != RESULT_DECL)
138 return;
140 /* Now verify that this return statement uses the same value
141 as any previously encountered return statement. */
142 if (found != NULL)
144 /* If we found a return statement using a different variable
145 than previous return statements, then we can not perform
146 NRV optimizations. */
147 if (found != TREE_OPERAND (ret_expr, 1))
148 return;
150 else
151 found = TREE_OPERAND (ret_expr, 1);
153 /* The returned value must be a local automatic variable of the
154 same type and alignment as the function's result. */
155 if (TREE_CODE (found) != VAR_DECL
156 || DECL_CONTEXT (found) != current_function_decl
157 || TREE_STATIC (found)
158 || TREE_ADDRESSABLE (found)
159 || DECL_ALIGN (found) > DECL_ALIGN (result)
160 || !lang_hooks.types_compatible_p (TREE_TYPE (found),
161 result_type))
162 return;
166 if (!found)
167 return;
169 /* If dumping details, then note once and only the NRV replacement. */
170 if (dump_file && (dump_flags & TDF_DETAILS))
172 fprintf (dump_file, "NRV Replaced: ");
173 print_generic_expr (dump_file, found, dump_flags);
174 fprintf (dump_file, " with: ");
175 print_generic_expr (dump_file, result, dump_flags);
176 fprintf (dump_file, "\n");
179 /* At this point we know that all the return statements return the
180 same local which has suitable attributes for NRV. Copy debugging
181 information from FOUND to RESULT. */
182 DECL_NAME (result) = DECL_NAME (found);
183 DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
184 DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
185 TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);
187 /* Now walk through the function changing all references to VAR to be
188 RESULT. */
189 data.var = found;
190 data.result = result;
191 FOR_EACH_BB (bb)
193 block_stmt_iterator bsi;
195 for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
196 walk_tree (bsi_stmt_ptr (bsi), finalize_nrv_r, &data, 0);
199 /* FOUND is no longer used. Ensure it gets removed. */
200 var_ann (found)->used = 0;
203 struct tree_opt_pass pass_nrv =
205 "nrv", /* name */
206 NULL, /* gate */
207 tree_nrv, /* execute */
208 NULL, /* sub */
209 NULL, /* next */
210 0, /* static_pass_number */
211 TV_TREE_NRV, /* tv_id */
212 PROP_cfg, /* properties_required */
213 0, /* properties_provided */
214 0, /* properties_destroyed */
215 0, /* todo_flags_start */
216 TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */