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 };