Mercurial > hg > CbC > GCC_original
comparison gcc/tree-nrv.c @ 16:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
15:561a7518be6b | 16:04ced10e8804 |
---|---|
1 /* Language independent return value optimizations | 1 /* Language independent return value optimizations |
2 Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010 | 2 Copyright (C) 2004-2017 Free Software Foundation, Inc. |
3 Free Software Foundation, Inc. | |
4 | 3 |
5 This file is part of GCC. | 4 This file is part of GCC. |
6 | 5 |
7 GCC is free software; you can redistribute it and/or modify | 6 GCC is free software; you can redistribute it and/or modify |
8 it under the terms of the GNU General Public License as published by | 7 it under the terms of the GNU General Public License as published by |
19 <http://www.gnu.org/licenses/>. */ | 18 <http://www.gnu.org/licenses/>. */ |
20 | 19 |
21 #include "config.h" | 20 #include "config.h" |
22 #include "system.h" | 21 #include "system.h" |
23 #include "coretypes.h" | 22 #include "coretypes.h" |
24 #include "tm.h" | 23 #include "backend.h" |
25 #include "tree.h" | 24 #include "tree.h" |
26 #include "function.h" | 25 #include "gimple.h" |
27 #include "basic-block.h" | 26 #include "tree-pass.h" |
27 #include "ssa.h" | |
28 #include "tree-pretty-print.h" | 28 #include "tree-pretty-print.h" |
29 #include "tree-flow.h" | 29 #include "gimple-iterator.h" |
30 #include "timevar.h" | 30 #include "gimple-walk.h" |
31 #include "tree-dump.h" | 31 #include "internal-fn.h" |
32 #include "tree-pass.h" | |
33 #include "langhooks.h" | |
34 #include "flags.h" /* For "optimize" in gate_pass_return_slot. | |
35 FIXME: That should be up to the pass manager, | |
36 but pass_nrv is not in pass_all_optimizations. */ | |
37 | 32 |
38 /* This file implements return value optimizations for functions which | 33 /* This file implements return value optimizations for functions which |
39 return aggregate types. | 34 return aggregate types. |
40 | 35 |
41 Basically this pass searches the function for return statements which | 36 Basically this pass searches the function for return statements which |
47 into the final destination mandated by the target's ABI. | 42 into the final destination mandated by the target's ABI. |
48 | 43 |
49 This is basically a generic equivalent to the C++ front-end's | 44 This is basically a generic equivalent to the C++ front-end's |
50 Named Return Value optimization. */ | 45 Named Return Value optimization. */ |
51 | 46 |
52 struct nrv_data | 47 struct nrv_data_t |
53 { | 48 { |
54 /* This is the temporary (a VAR_DECL) which appears in all of | 49 /* This is the temporary (a VAR_DECL) which appears in all of |
55 this function's RETURN_EXPR statements. */ | 50 this function's RETURN_EXPR statements. */ |
56 tree var; | 51 tree var; |
57 | 52 |
76 | 71 |
77 static tree | 72 static tree |
78 finalize_nrv_r (tree *tp, int *walk_subtrees, void *data) | 73 finalize_nrv_r (tree *tp, int *walk_subtrees, void *data) |
79 { | 74 { |
80 struct walk_stmt_info *wi = (struct walk_stmt_info *) data; | 75 struct walk_stmt_info *wi = (struct walk_stmt_info *) data; |
81 struct nrv_data *dp = (struct nrv_data *) wi->info; | 76 struct nrv_data_t *dp = (struct nrv_data_t *) wi->info; |
82 | 77 |
83 /* No need to walk into types. */ | 78 /* No need to walk into types. */ |
84 if (TYPE_P (*tp)) | 79 if (TYPE_P (*tp)) |
85 *walk_subtrees = 0; | 80 *walk_subtrees = 0; |
86 | 81 |
105 applied to optimized trees in a language independent form. If we | 100 applied to optimized trees in a language independent form. If we |
106 ever encounter languages which prevent this kind of optimization, | 101 ever encounter languages which prevent this kind of optimization, |
107 then we could either have the languages register the optimization or | 102 then we could either have the languages register the optimization or |
108 we could change the gating function to check the current language. */ | 103 we could change the gating function to check the current language. */ |
109 | 104 |
110 static unsigned int | 105 namespace { |
111 tree_nrv (void) | 106 |
107 const pass_data pass_data_nrv = | |
108 { | |
109 GIMPLE_PASS, /* type */ | |
110 "nrv", /* name */ | |
111 OPTGROUP_NONE, /* optinfo_flags */ | |
112 TV_TREE_NRV, /* tv_id */ | |
113 ( PROP_ssa | PROP_cfg ), /* properties_required */ | |
114 0, /* properties_provided */ | |
115 0, /* properties_destroyed */ | |
116 0, /* todo_flags_start */ | |
117 0, /* todo_flags_finish */ | |
118 }; | |
119 | |
120 class pass_nrv : public gimple_opt_pass | |
121 { | |
122 public: | |
123 pass_nrv (gcc::context *ctxt) | |
124 : gimple_opt_pass (pass_data_nrv, ctxt) | |
125 {} | |
126 | |
127 /* opt_pass methods: */ | |
128 virtual bool gate (function *) { return optimize > 0; } | |
129 | |
130 virtual unsigned int execute (function *); | |
131 | |
132 }; // class pass_nrv | |
133 | |
134 unsigned int | |
135 pass_nrv::execute (function *fun) | |
112 { | 136 { |
113 tree result = DECL_RESULT (current_function_decl); | 137 tree result = DECL_RESULT (current_function_decl); |
114 tree result_type = TREE_TYPE (result); | 138 tree result_type = TREE_TYPE (result); |
115 tree found = NULL; | 139 tree found = NULL; |
116 basic_block bb; | 140 basic_block bb; |
117 gimple_stmt_iterator gsi; | 141 gimple_stmt_iterator gsi; |
118 struct nrv_data data; | 142 struct nrv_data_t data; |
119 | 143 |
120 /* If this function does not return an aggregate type in memory, then | 144 /* If this function does not return an aggregate type in memory, then |
121 there is nothing to do. */ | 145 there is nothing to do. */ |
122 if (!aggregate_value_p (result, current_function_decl)) | 146 if (!aggregate_value_p (result, current_function_decl)) |
123 return 0; | 147 return 0; |
136 case. */ | 160 case. */ |
137 if (TREE_ADDRESSABLE (result)) | 161 if (TREE_ADDRESSABLE (result)) |
138 return 0; | 162 return 0; |
139 | 163 |
140 /* Look through each block for assignments to the RESULT_DECL. */ | 164 /* Look through each block for assignments to the RESULT_DECL. */ |
141 FOR_EACH_BB (bb) | 165 FOR_EACH_BB_FN (bb, fun) |
142 { | 166 { |
143 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | 167 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) |
144 { | 168 { |
145 gimple stmt = gsi_stmt (gsi); | 169 gimple *stmt = gsi_stmt (gsi); |
146 tree ret_val; | 170 tree ret_val; |
147 | 171 |
148 if (gimple_code (stmt) == GIMPLE_RETURN) | 172 if (greturn *return_stmt = dyn_cast <greturn *> (stmt)) |
149 { | 173 { |
150 /* In a function with an aggregate return value, the | 174 /* In a function with an aggregate return value, the |
151 gimplifier has changed all non-empty RETURN_EXPRs to | 175 gimplifier has changed all non-empty RETURN_EXPRs to |
152 return the RESULT_DECL. */ | 176 return the RESULT_DECL. */ |
153 ret_val = gimple_return_retval (stmt); | 177 ret_val = gimple_return_retval (return_stmt); |
154 if (ret_val) | 178 if (ret_val) |
155 gcc_assert (ret_val == result); | 179 gcc_assert (ret_val == result); |
156 } | 180 } |
157 else if (gimple_has_lhs (stmt) | 181 else if (gimple_has_lhs (stmt) |
158 && gimple_get_lhs (stmt) == result) | 182 && gimple_get_lhs (stmt) == result) |
177 else | 201 else |
178 found = rhs; | 202 found = rhs; |
179 | 203 |
180 /* The returned value must be a local automatic variable of the | 204 /* The returned value must be a local automatic variable of the |
181 same type and alignment as the function's result. */ | 205 same type and alignment as the function's result. */ |
182 if (TREE_CODE (found) != VAR_DECL | 206 if (!VAR_P (found) |
183 || TREE_THIS_VOLATILE (found) | 207 || TREE_THIS_VOLATILE (found) |
184 || DECL_CONTEXT (found) != current_function_decl | 208 || !auto_var_in_fn_p (found, current_function_decl) |
185 || TREE_STATIC (found) | |
186 || TREE_ADDRESSABLE (found) | 209 || TREE_ADDRESSABLE (found) |
187 || DECL_ALIGN (found) > DECL_ALIGN (result) | 210 || DECL_ALIGN (found) > DECL_ALIGN (result) |
188 || !useless_type_conversion_p (result_type, | 211 || !useless_type_conversion_p (result_type, |
189 TREE_TYPE (found))) | 212 TREE_TYPE (found))) |
190 return 0; | 213 return 0; |
230 | 253 |
231 /* Now walk through the function changing all references to VAR to be | 254 /* Now walk through the function changing all references to VAR to be |
232 RESULT. */ | 255 RESULT. */ |
233 data.var = found; | 256 data.var = found; |
234 data.result = result; | 257 data.result = result; |
235 FOR_EACH_BB (bb) | 258 FOR_EACH_BB_FN (bb, fun) |
236 { | 259 { |
237 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) | 260 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) |
238 { | 261 { |
239 gimple stmt = gsi_stmt (gsi); | 262 gimple *stmt = gsi_stmt (gsi); |
240 /* If this is a copy from VAR to RESULT, remove it. */ | 263 /* If this is a copy from VAR to RESULT, remove it. */ |
241 if (gimple_assign_copy_p (stmt) | 264 if (gimple_assign_copy_p (stmt) |
242 && gimple_assign_lhs (stmt) == result | 265 && gimple_assign_lhs (stmt) == result |
243 && gimple_assign_rhs1 (stmt) == found) | 266 && gimple_assign_rhs1 (stmt) == found) |
244 { | 267 { |
245 unlink_stmt_vdef (stmt); | 268 unlink_stmt_vdef (stmt); |
246 gsi_remove (&gsi, true); | 269 gsi_remove (&gsi, true); |
270 release_defs (stmt); | |
247 } | 271 } |
248 else | 272 else |
249 { | 273 { |
250 struct walk_stmt_info wi; | 274 struct walk_stmt_info wi; |
251 memset (&wi, 0, sizeof (wi)); | 275 memset (&wi, 0, sizeof (wi)); |
260 } | 284 } |
261 | 285 |
262 SET_DECL_VALUE_EXPR (found, result); | 286 SET_DECL_VALUE_EXPR (found, result); |
263 DECL_HAS_VALUE_EXPR_P (found) = 1; | 287 DECL_HAS_VALUE_EXPR_P (found) = 1; |
264 | 288 |
265 /* FOUND is no longer used. Ensure it gets removed. */ | |
266 clear_is_used (found); | |
267 return 0; | 289 return 0; |
268 } | 290 } |
269 | 291 |
270 static bool | 292 } // anon namespace |
271 gate_pass_return_slot (void) | 293 |
272 { | 294 gimple_opt_pass * |
273 return optimize > 0; | 295 make_pass_nrv (gcc::context *ctxt) |
274 } | 296 { |
275 | 297 return new pass_nrv (ctxt); |
276 struct gimple_opt_pass pass_nrv = | 298 } |
277 { | |
278 { | |
279 GIMPLE_PASS, | |
280 "nrv", /* name */ | |
281 gate_pass_return_slot, /* gate */ | |
282 tree_nrv, /* execute */ | |
283 NULL, /* sub */ | |
284 NULL, /* next */ | |
285 0, /* static_pass_number */ | |
286 TV_TREE_NRV, /* tv_id */ | |
287 PROP_ssa | PROP_cfg, /* properties_required */ | |
288 0, /* properties_provided */ | |
289 0, /* properties_destroyed */ | |
290 0, /* todo_flags_start */ | |
291 TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ | |
292 } | |
293 }; | |
294 | 299 |
295 /* Determine (pessimistically) whether DEST is available for NRV | 300 /* Determine (pessimistically) whether DEST is available for NRV |
296 optimization, where DEST is expected to be the LHS of a modify | 301 optimization, where DEST is expected to be the LHS of a modify |
297 expression where the RHS is a function returning an aggregate. | 302 expression where the RHS is a function returning an aggregate. |
298 | 303 |
299 DEST is available if it is not clobbered or used by the call. */ | 304 DEST is available if it is not clobbered or used by the call. */ |
300 | 305 |
301 static bool | 306 static bool |
302 dest_safe_for_nrv_p (gimple call) | 307 dest_safe_for_nrv_p (gcall *call) |
303 { | 308 { |
304 tree dest = gimple_call_lhs (call); | 309 tree dest = gimple_call_lhs (call); |
305 | 310 |
306 dest = get_base_address (dest); | 311 dest = get_base_address (dest); |
307 if (! dest) | 312 if (! dest) |
327 the caller. If the NRV is performed (which we can't know in general), | 332 the caller. If the NRV is performed (which we can't know in general), |
328 this optimization is safe if the address of the target has not | 333 this optimization is safe if the address of the target has not |
329 escaped prior to the call. If it has, modifications to the local | 334 escaped prior to the call. If it has, modifications to the local |
330 variable will produce visible changes elsewhere, as in PR c++/19317. */ | 335 variable will produce visible changes elsewhere, as in PR c++/19317. */ |
331 | 336 |
332 static unsigned int | 337 namespace { |
333 execute_return_slot_opt (void) | 338 |
339 const pass_data pass_data_return_slot = | |
340 { | |
341 GIMPLE_PASS, /* type */ | |
342 "retslot", /* name */ | |
343 OPTGROUP_NONE, /* optinfo_flags */ | |
344 TV_NONE, /* tv_id */ | |
345 PROP_ssa, /* properties_required */ | |
346 0, /* properties_provided */ | |
347 0, /* properties_destroyed */ | |
348 0, /* todo_flags_start */ | |
349 0, /* todo_flags_finish */ | |
350 }; | |
351 | |
352 class pass_return_slot : public gimple_opt_pass | |
353 { | |
354 public: | |
355 pass_return_slot (gcc::context *ctxt) | |
356 : gimple_opt_pass (pass_data_return_slot, ctxt) | |
357 {} | |
358 | |
359 /* opt_pass methods: */ | |
360 virtual unsigned int execute (function *); | |
361 | |
362 }; // class pass_return_slot | |
363 | |
364 unsigned int | |
365 pass_return_slot::execute (function *fun) | |
334 { | 366 { |
335 basic_block bb; | 367 basic_block bb; |
336 | 368 |
337 FOR_EACH_BB (bb) | 369 FOR_EACH_BB_FN (bb, fun) |
338 { | 370 { |
339 gimple_stmt_iterator gsi; | 371 gimple_stmt_iterator gsi; |
340 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) | 372 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) |
341 { | 373 { |
342 gimple stmt = gsi_stmt (gsi); | 374 gcall *stmt; |
343 bool slot_opt_p; | 375 bool slot_opt_p; |
344 | 376 |
345 if (is_gimple_call (stmt) | 377 stmt = dyn_cast <gcall *> (gsi_stmt (gsi)); |
378 if (stmt | |
346 && gimple_call_lhs (stmt) | 379 && gimple_call_lhs (stmt) |
347 && !gimple_call_return_slot_opt_p (stmt) | 380 && !gimple_call_return_slot_opt_p (stmt) |
381 /* Ignore internal functions without direct optabs, | |
382 those are expanded specially and aggregate_value_p | |
383 on their result might result in undesirable warnings | |
384 with some backends. */ | |
385 && (!gimple_call_internal_p (stmt) | |
386 || direct_internal_fn_p (gimple_call_internal_fn (stmt))) | |
348 && aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)), | 387 && aggregate_value_p (TREE_TYPE (gimple_call_lhs (stmt)), |
349 gimple_call_fndecl (stmt))) | 388 gimple_call_fndecl (stmt))) |
350 { | 389 { |
351 /* Check if the location being assigned to is | 390 /* Check if the location being assigned to is |
352 clobbered by the call. */ | 391 clobbered by the call. */ |
353 slot_opt_p = dest_safe_for_nrv_p (stmt); | 392 slot_opt_p = dest_safe_for_nrv_p (stmt); |
354 gimple_call_set_return_slot_opt (stmt, slot_opt_p); | 393 gimple_call_set_return_slot_opt (stmt, slot_opt_p); |
355 } | 394 } |
356 } | 395 } |
357 } | 396 } |
358 return 0; | 397 return 0; |
359 } | 398 } |
360 | 399 |
361 struct gimple_opt_pass pass_return_slot = | 400 } // anon namespace |
362 { | 401 |
363 { | 402 gimple_opt_pass * |
364 GIMPLE_PASS, | 403 make_pass_return_slot (gcc::context *ctxt) |
365 "retslot", /* name */ | 404 { |
366 NULL, /* gate */ | 405 return new pass_return_slot (ctxt); |
367 execute_return_slot_opt, /* execute */ | 406 } |
368 NULL, /* sub */ | |
369 NULL, /* next */ | |
370 0, /* static_pass_number */ | |
371 TV_NONE, /* tv_id */ | |
372 PROP_ssa, /* properties_required */ | |
373 0, /* properties_provided */ | |
374 0, /* properties_destroyed */ | |
375 0, /* todo_flags_start */ | |
376 0 /* todo_flags_finish */ | |
377 } | |
378 }; |