]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/tree-stdarg.c
* gimple-ssa-isolate-paths.c (pass_isolate_erroneous_paths): Comment fix.
[thirdparty/gcc.git] / gcc / tree-stdarg.c
CommitLineData
a6c787e5 1/* Pass computing data for optimizing stdarg functions.
711789cc 2 Copyright (C) 2004-2013 Free Software Foundation, Inc.
a6c787e5 3 Contributed by Jakub Jelinek <jakub@redhat.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
8c4c00c1 9the Free Software Foundation; either version 3, or (at your option)
a6c787e5 10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
8c4c00c1 18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
a6c787e5 20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "tree.h"
26#include "function.h"
27#include "langhooks.h"
ce084dfc 28#include "gimple-pretty-print.h"
a6c787e5 29#include "target.h"
073c1fd5 30#include "bitmap.h"
31#include "gimple.h"
32#include "gimple-ssa.h"
33#include "tree-phinodes.h"
34#include "ssa-iterators.h"
35#include "tree-ssanames.h"
424a4a92 36#include "sbitmap.h"
a6c787e5 37#include "tree-pass.h"
38#include "tree-stdarg.h"
39
40/* A simple pass that attempts to optimize stdarg functions on architectures
41 that need to save register arguments to stack on entry to stdarg functions.
42 If the function doesn't use any va_start macros, no registers need to
43 be saved. If va_start macros are used, the va_list variables don't escape
44 the function, it is only necessary to save registers that will be used
45 in va_arg macros. E.g. if va_arg is only used with integral types
46 in the function, floating point registers don't need to be saved, etc. */
47
48
49/* Return true if basic block VA_ARG_BB is dominated by VA_START_BB and
50 is executed at most as many times as VA_START_BB. */
51
52static bool
53reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb)
54{
1e094109 55 vec<edge> stack = vNULL;
4b53147e 56 edge e;
a6c787e5 57 edge_iterator ei;
a6c787e5 58 sbitmap visited;
59 bool ret;
60
61 if (va_arg_bb == va_start_bb)
62 return true;
63
64 if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb))
65 return false;
66
a6c787e5 67 visited = sbitmap_alloc (last_basic_block);
53c5d9d4 68 bitmap_clear (visited);
a6c787e5 69 ret = true;
70
71 FOR_EACH_EDGE (e, ei, va_arg_bb->preds)
f1f41a6c 72 stack.safe_push (e);
a6c787e5 73
f1f41a6c 74 while (! stack.is_empty ())
a6c787e5 75 {
76 basic_block src;
77
f1f41a6c 78 e = stack.pop ();
a6c787e5 79 src = e->src;
80
81 if (e->flags & EDGE_COMPLEX)
82 {
83 ret = false;
84 break;
85 }
86
87 if (src == va_start_bb)
88 continue;
89
90 /* va_arg_bb can be executed more times than va_start_bb. */
91 if (src == va_arg_bb)
92 {
93 ret = false;
94 break;
95 }
96
97 gcc_assert (src != ENTRY_BLOCK_PTR);
98
08b7917c 99 if (! bitmap_bit_p (visited, src->index))
a6c787e5 100 {
08b7917c 101 bitmap_set_bit (visited, src->index);
a6c787e5 102 FOR_EACH_EDGE (e, ei, src->preds)
f1f41a6c 103 stack.safe_push (e);
a6c787e5 104 }
105 }
106
f1f41a6c 107 stack.release ();
a6c787e5 108 sbitmap_free (visited);
109 return ret;
110}
111
112
113/* For statement COUNTER = RHS, if RHS is COUNTER + constant,
561f0ec8 114 return constant, otherwise return HOST_WIDE_INT_M1U.
a6c787e5 115 GPR_P is true if this is GPR counter. */
116
117static unsigned HOST_WIDE_INT
118va_list_counter_bump (struct stdarg_info *si, tree counter, tree rhs,
119 bool gpr_p)
120{
75a70cf9 121 tree lhs, orig_lhs;
122 gimple stmt;
a6c787e5 123 unsigned HOST_WIDE_INT ret = 0, val, counter_val;
124 unsigned int max_size;
125
126 if (si->offsets == NULL)
127 {
128 unsigned int i;
129
4c36ffe6 130 si->offsets = XNEWVEC (int, num_ssa_names);
a6c787e5 131 for (i = 0; i < num_ssa_names; ++i)
132 si->offsets[i] = -1;
133 }
134
135 counter_val = gpr_p ? cfun->va_list_gpr_size : cfun->va_list_fpr_size;
136 max_size = gpr_p ? VA_LIST_MAX_GPR_SIZE : VA_LIST_MAX_FPR_SIZE;
137 orig_lhs = lhs = rhs;
138 while (lhs)
139 {
75a70cf9 140 enum tree_code rhs_code;
de508de3 141 tree rhs1;
75a70cf9 142
a6c787e5 143 if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
144 {
145 if (counter_val >= max_size)
146 {
147 ret = max_size;
148 break;
149 }
150
151 ret -= counter_val - si->offsets[SSA_NAME_VERSION (lhs)];
152 break;
153 }
154
155 stmt = SSA_NAME_DEF_STMT (lhs);
156
75a70cf9 157 if (!is_gimple_assign (stmt) || gimple_assign_lhs (stmt) != lhs)
561f0ec8 158 return HOST_WIDE_INT_M1U;
a6c787e5 159
75a70cf9 160 rhs_code = gimple_assign_rhs_code (stmt);
de508de3 161 rhs1 = gimple_assign_rhs1 (stmt);
75a70cf9 162 if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
163 || gimple_assign_cast_p (stmt))
de508de3 164 && TREE_CODE (rhs1) == SSA_NAME)
a6c787e5 165 {
de508de3 166 lhs = rhs1;
a6c787e5 167 continue;
168 }
169
75a70cf9 170 if ((rhs_code == POINTER_PLUS_EXPR
171 || rhs_code == PLUS_EXPR)
de508de3 172 && TREE_CODE (rhs1) == SSA_NAME
75a70cf9 173 && host_integerp (gimple_assign_rhs2 (stmt), 1))
a6c787e5 174 {
75a70cf9 175 ret += tree_low_cst (gimple_assign_rhs2 (stmt), 1);
de508de3 176 lhs = rhs1;
177 continue;
178 }
179
180 if (rhs_code == ADDR_EXPR
181 && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
182 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
183 && host_integerp (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1))
184 {
185 ret += tree_low_cst (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1);
186 lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
a6c787e5 187 continue;
188 }
189
75a70cf9 190 if (get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS)
561f0ec8 191 return HOST_WIDE_INT_M1U;
a6c787e5 192
75a70cf9 193 rhs = gimple_assign_rhs1 (stmt);
a6c787e5 194 if (TREE_CODE (counter) != TREE_CODE (rhs))
561f0ec8 195 return HOST_WIDE_INT_M1U;
a6c787e5 196
197 if (TREE_CODE (counter) == COMPONENT_REF)
198 {
199 if (get_base_address (counter) != get_base_address (rhs)
200 || TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL
201 || TREE_OPERAND (counter, 1) != TREE_OPERAND (rhs, 1))
561f0ec8 202 return HOST_WIDE_INT_M1U;
a6c787e5 203 }
204 else if (counter != rhs)
561f0ec8 205 return HOST_WIDE_INT_M1U;
a6c787e5 206
207 lhs = NULL;
208 }
209
210 lhs = orig_lhs;
211 val = ret + counter_val;
212 while (lhs)
213 {
75a70cf9 214 enum tree_code rhs_code;
de508de3 215 tree rhs1;
75a70cf9 216
a6c787e5 217 if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
218 break;
219
220 if (val >= max_size)
221 si->offsets[SSA_NAME_VERSION (lhs)] = max_size;
222 else
223 si->offsets[SSA_NAME_VERSION (lhs)] = val;
224
225 stmt = SSA_NAME_DEF_STMT (lhs);
226
75a70cf9 227 rhs_code = gimple_assign_rhs_code (stmt);
de508de3 228 rhs1 = gimple_assign_rhs1 (stmt);
75a70cf9 229 if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
230 || gimple_assign_cast_p (stmt))
de508de3 231 && TREE_CODE (rhs1) == SSA_NAME)
a6c787e5 232 {
de508de3 233 lhs = rhs1;
a6c787e5 234 continue;
235 }
236
75a70cf9 237 if ((rhs_code == POINTER_PLUS_EXPR
238 || rhs_code == PLUS_EXPR)
de508de3 239 && TREE_CODE (rhs1) == SSA_NAME
75a70cf9 240 && host_integerp (gimple_assign_rhs2 (stmt), 1))
a6c787e5 241 {
75a70cf9 242 val -= tree_low_cst (gimple_assign_rhs2 (stmt), 1);
de508de3 243 lhs = rhs1;
244 continue;
245 }
246
247 if (rhs_code == ADDR_EXPR
248 && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
249 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
250 && host_integerp (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1))
251 {
252 val -= tree_low_cst (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1), 1);
253 lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
a6c787e5 254 continue;
255 }
256
257 lhs = NULL;
258 }
259
260 return ret;
261}
262
263
264/* Called by walk_tree to look for references to va_list variables. */
265
266static tree
267find_va_list_reference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
268 void *data)
269{
75a70cf9 270 bitmap va_list_vars = (bitmap) ((struct walk_stmt_info *) data)->info;
a6c787e5 271 tree var = *tp;
272
273 if (TREE_CODE (var) == SSA_NAME)
7ecda5e8 274 {
275 if (bitmap_bit_p (va_list_vars, SSA_NAME_VERSION (var)))
276 return var;
277 }
278 else if (TREE_CODE (var) == VAR_DECL)
279 {
280 if (bitmap_bit_p (va_list_vars, DECL_UID (var) + num_ssa_names))
281 return var;
282 }
a6c787e5 283
284 return NULL_TREE;
285}
286
287
288/* Helper function of va_list_counter_struct_op. Compute
289 cfun->va_list_{g,f}pr_size. AP is a va_list GPR/FPR counter,
290 if WRITE_P is true, seen in AP = VAR, otherwise seen in VAR = AP
291 statement. GPR_P is true if AP is a GPR counter, false if it is
292 a FPR counter. */
293
294static void
295va_list_counter_op (struct stdarg_info *si, tree ap, tree var, bool gpr_p,
296 bool write_p)
297{
298 unsigned HOST_WIDE_INT increment;
299
300 if (si->compute_sizes < 0)
301 {
302 si->compute_sizes = 0;
303 if (si->va_start_count == 1
304 && reachable_at_most_once (si->bb, si->va_start_bb))
305 si->compute_sizes = 1;
306
307 if (dump_file && (dump_flags & TDF_DETAILS))
308 fprintf (dump_file,
309 "bb%d will %sbe executed at most once for each va_start "
310 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
311 si->va_start_bb->index);
312 }
313
314 if (write_p
315 && si->compute_sizes
316 && (increment = va_list_counter_bump (si, ap, var, gpr_p)) + 1 > 1)
317 {
318 if (gpr_p && cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
319 {
320 cfun->va_list_gpr_size += increment;
321 return;
322 }
323
324 if (!gpr_p && cfun->va_list_fpr_size + increment < VA_LIST_MAX_FPR_SIZE)
325 {
326 cfun->va_list_fpr_size += increment;
327 return;
328 }
329 }
330
331 if (write_p || !si->compute_sizes)
332 {
333 if (gpr_p)
334 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
335 else
336 cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
337 }
338}
339
340
341/* If AP is a va_list GPR/FPR counter, compute cfun->va_list_{g,f}pr_size.
342 If WRITE_P is true, AP has been seen in AP = VAR assignment, if WRITE_P
343 is false, AP has been seen in VAR = AP assignment.
344 Return true if the AP = VAR (resp. VAR = AP) statement is a recognized
345 va_arg operation that doesn't cause the va_list variable to escape
346 current function. */
347
348static bool
349va_list_counter_struct_op (struct stdarg_info *si, tree ap, tree var,
350 bool write_p)
351{
352 tree base;
353
354 if (TREE_CODE (ap) != COMPONENT_REF
355 || TREE_CODE (TREE_OPERAND (ap, 1)) != FIELD_DECL)
356 return false;
357
358 if (TREE_CODE (var) != SSA_NAME
7ecda5e8 359 || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (var)))
a6c787e5 360 return false;
361
362 base = get_base_address (ap);
363 if (TREE_CODE (base) != VAR_DECL
7ecda5e8 364 || !bitmap_bit_p (si->va_list_vars, DECL_UID (base) + num_ssa_names))
a6c787e5 365 return false;
366
367 if (TREE_OPERAND (ap, 1) == va_list_gpr_counter_field)
368 va_list_counter_op (si, ap, var, true, write_p);
369 else if (TREE_OPERAND (ap, 1) == va_list_fpr_counter_field)
370 va_list_counter_op (si, ap, var, false, write_p);
371
372 return true;
373}
374
375
376/* Check for TEM = AP. Return true if found and the caller shouldn't
377 search for va_list references in the statement. */
378
379static bool
380va_list_ptr_read (struct stdarg_info *si, tree ap, tree tem)
381{
382 if (TREE_CODE (ap) != VAR_DECL
7ecda5e8 383 || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
a6c787e5 384 return false;
385
386 if (TREE_CODE (tem) != SSA_NAME
7ecda5e8 387 || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem)))
a6c787e5 388 return false;
389
390 if (si->compute_sizes < 0)
391 {
392 si->compute_sizes = 0;
393 if (si->va_start_count == 1
394 && reachable_at_most_once (si->bb, si->va_start_bb))
395 si->compute_sizes = 1;
396
397 if (dump_file && (dump_flags & TDF_DETAILS))
398 fprintf (dump_file,
399 "bb%d will %sbe executed at most once for each va_start "
400 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
401 si->va_start_bb->index);
402 }
403
404 /* For void * or char * va_list types, there is just one counter.
405 If va_arg is used in a loop, we don't know how many registers need
406 saving. */
407 if (! si->compute_sizes)
408 return false;
409
561f0ec8 410 if (va_list_counter_bump (si, ap, tem, true) == HOST_WIDE_INT_M1U)
a6c787e5 411 return false;
412
413 /* Note the temporary, as we need to track whether it doesn't escape
414 the current function. */
7ecda5e8 415 bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (tem));
416
a6c787e5 417 return true;
418}
419
420
421/* Check for:
422 tem1 = AP;
423 TEM2 = tem1 + CST;
424 AP = TEM2;
425 sequence and update cfun->va_list_gpr_size. Return true if found. */
426
427static bool
428va_list_ptr_write (struct stdarg_info *si, tree ap, tree tem2)
429{
430 unsigned HOST_WIDE_INT increment;
431
432 if (TREE_CODE (ap) != VAR_DECL
7ecda5e8 433 || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
a6c787e5 434 return false;
435
436 if (TREE_CODE (tem2) != SSA_NAME
7ecda5e8 437 || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem2)))
a6c787e5 438 return false;
439
440 if (si->compute_sizes <= 0)
441 return false;
442
443 increment = va_list_counter_bump (si, ap, tem2, true);
444 if (increment + 1 <= 1)
445 return false;
446
447 if (cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
448 cfun->va_list_gpr_size += increment;
449 else
450 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
451
452 return true;
453}
454
455
456/* If RHS is X, (some type *) X or X + CST for X a temporary variable
457 containing value of some va_list variable plus optionally some constant,
458 either set si->va_list_escapes or add LHS to si->va_list_escape_vars,
459 depending whether LHS is a function local temporary. */
460
461static void
462check_va_list_escapes (struct stdarg_info *si, tree lhs, tree rhs)
463{
464 if (! POINTER_TYPE_P (TREE_TYPE (rhs)))
465 return;
466
de508de3 467 if (TREE_CODE (rhs) == SSA_NAME)
468 {
7ecda5e8 469 if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (rhs)))
de508de3 470 return;
471 }
472 else if (TREE_CODE (rhs) == ADDR_EXPR
473 && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
474 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)) == SSA_NAME)
475 {
7ecda5e8 476 tree ptr = TREE_OPERAND (TREE_OPERAND (rhs, 0), 0);
477 if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (ptr)))
de508de3 478 return;
479 }
480 else
a6c787e5 481 return;
482
7ecda5e8 483 if (TREE_CODE (lhs) != SSA_NAME)
a6c787e5 484 {
485 si->va_list_escapes = true;
486 return;
487 }
488
489 if (si->compute_sizes < 0)
490 {
491 si->compute_sizes = 0;
492 if (si->va_start_count == 1
493 && reachable_at_most_once (si->bb, si->va_start_bb))
494 si->compute_sizes = 1;
495
496 if (dump_file && (dump_flags & TDF_DETAILS))
497 fprintf (dump_file,
498 "bb%d will %sbe executed at most once for each va_start "
499 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
500 si->va_start_bb->index);
501 }
502
503 /* For void * or char * va_list types, there is just one counter.
504 If va_arg is used in a loop, we don't know how many registers need
505 saving. */
506 if (! si->compute_sizes)
507 {
508 si->va_list_escapes = true;
509 return;
510 }
511
512 if (va_list_counter_bump (si, si->va_start_ap, lhs, true)
561f0ec8 513 == HOST_WIDE_INT_M1U)
a6c787e5 514 {
515 si->va_list_escapes = true;
516 return;
517 }
518
7ecda5e8 519 bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (lhs));
a6c787e5 520}
521
522
523/* Check all uses of temporaries from si->va_list_escape_vars bitmap.
524 Return true if va_list might be escaping. */
525
526static bool
527check_all_va_list_escapes (struct stdarg_info *si)
528{
529 basic_block bb;
530
531 FOR_EACH_BB (bb)
532 {
75a70cf9 533 gimple_stmt_iterator i;
a6c787e5 534
2a111350 535 for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i))
536 {
537 tree lhs;
538 use_operand_p uop;
539 ssa_op_iter soi;
540 gimple phi = gsi_stmt (i);
541
542 lhs = PHI_RESULT (phi);
543 if (virtual_operand_p (lhs)
544 || bitmap_bit_p (si->va_list_escape_vars,
545 SSA_NAME_VERSION (lhs)))
546 continue;
547
548 FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
549 {
550 tree rhs = USE_FROM_PTR (uop);
551 if (TREE_CODE (rhs) == SSA_NAME
552 && bitmap_bit_p (si->va_list_escape_vars,
553 SSA_NAME_VERSION (rhs)))
554 {
555 if (dump_file && (dump_flags & TDF_DETAILS))
556 {
557 fputs ("va_list escapes in ", dump_file);
558 print_gimple_stmt (dump_file, phi, 0, dump_flags);
559 fputc ('\n', dump_file);
560 }
561 return true;
562 }
563 }
564 }
565
75a70cf9 566 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
a6c787e5 567 {
75a70cf9 568 gimple stmt = gsi_stmt (i);
569 tree use;
a6c787e5 570 ssa_op_iter iter;
571
9845d120 572 if (is_gimple_debug (stmt))
573 continue;
574
a6c787e5 575 FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_USES)
576 {
577 if (! bitmap_bit_p (si->va_list_escape_vars,
7ecda5e8 578 SSA_NAME_VERSION (use)))
a6c787e5 579 continue;
580
75a70cf9 581 if (is_gimple_assign (stmt))
a6c787e5 582 {
75a70cf9 583 tree rhs = gimple_assign_rhs1 (stmt);
584 enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
a6c787e5 585
586 /* x = *ap_temp; */
de508de3 587 if (rhs_code == MEM_REF
a6c787e5 588 && TREE_OPERAND (rhs, 0) == use
589 && TYPE_SIZE_UNIT (TREE_TYPE (rhs))
590 && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (rhs)), 1)
591 && si->offsets[SSA_NAME_VERSION (use)] != -1)
592 {
593 unsigned HOST_WIDE_INT gpr_size;
594 tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (rhs));
595
596 gpr_size = si->offsets[SSA_NAME_VERSION (use)]
182cf5a9 597 + tree_low_cst (TREE_OPERAND (rhs, 1), 0)
a6c787e5 598 + tree_low_cst (access_size, 1);
599 if (gpr_size >= VA_LIST_MAX_GPR_SIZE)
600 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
601 else if (gpr_size > cfun->va_list_gpr_size)
602 cfun->va_list_gpr_size = gpr_size;
603 continue;
604 }
605
606 /* va_arg sequences may contain
607 other_ap_temp = ap_temp;
608 other_ap_temp = ap_temp + constant;
609 other_ap_temp = (some_type *) ap_temp;
610 ap = ap_temp;
611 statements. */
75a70cf9 612 if (rhs == use
613 && ((rhs_code == POINTER_PLUS_EXPR
614 && (TREE_CODE (gimple_assign_rhs2 (stmt))
615 == INTEGER_CST))
616 || gimple_assign_cast_p (stmt)
617 || (get_gimple_rhs_class (rhs_code)
618 == GIMPLE_SINGLE_RHS)))
a6c787e5 619 {
75a70cf9 620 tree lhs = gimple_assign_lhs (stmt);
621
a6c787e5 622 if (TREE_CODE (lhs) == SSA_NAME
623 && bitmap_bit_p (si->va_list_escape_vars,
7ecda5e8 624 SSA_NAME_VERSION (lhs)))
a6c787e5 625 continue;
626
627 if (TREE_CODE (lhs) == VAR_DECL
628 && bitmap_bit_p (si->va_list_vars,
7ecda5e8 629 DECL_UID (lhs) + num_ssa_names))
a6c787e5 630 continue;
631 }
de508de3 632 else if (rhs_code == ADDR_EXPR
633 && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
634 && TREE_OPERAND (TREE_OPERAND (rhs, 0), 0) == use)
635 {
636 tree lhs = gimple_assign_lhs (stmt);
637
638 if (bitmap_bit_p (si->va_list_escape_vars,
7ecda5e8 639 SSA_NAME_VERSION (lhs)))
de508de3 640 continue;
641 }
a6c787e5 642 }
643
644 if (dump_file && (dump_flags & TDF_DETAILS))
645 {
646 fputs ("va_list escapes in ", dump_file);
75a70cf9 647 print_gimple_stmt (dump_file, stmt, 0, dump_flags);
a6c787e5 648 fputc ('\n', dump_file);
649 }
650 return true;
651 }
652 }
653 }
654
655 return false;
656}
657
658
659/* Return true if this optimization pass should be done.
660 It makes only sense for stdarg functions. */
661
662static bool
663gate_optimize_stdarg (void)
664{
de2ca00d 665 /* This optimization is only for stdarg functions. */
666 return cfun->stdarg != 0;
a6c787e5 667}
668
669
670/* Entry point to the stdarg optimization pass. */
671
2a1990e9 672static unsigned int
a6c787e5 673execute_optimize_stdarg (void)
674{
675 basic_block bb;
676 bool va_list_escapes = false;
677 bool va_list_simple_ptr;
678 struct stdarg_info si;
75a70cf9 679 struct walk_stmt_info wi;
a6c787e5 680 const char *funcname = NULL;
5f57a8b1 681 tree cfun_va_list;
a6c787e5 682
683 cfun->va_list_gpr_size = 0;
684 cfun->va_list_fpr_size = 0;
685 memset (&si, 0, sizeof (si));
686 si.va_list_vars = BITMAP_ALLOC (NULL);
687 si.va_list_escape_vars = BITMAP_ALLOC (NULL);
688
689 if (dump_file)
690 funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
691
5f57a8b1 692 cfun_va_list = targetm.fn_abi_va_list (cfun->decl);
693 va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
694 && (TREE_TYPE (cfun_va_list) == void_type_node
695 || TREE_TYPE (cfun_va_list) == char_type_node);
696 gcc_assert (is_gimple_reg_type (cfun_va_list) == va_list_simple_ptr);
a6c787e5 697
698 FOR_EACH_BB (bb)
699 {
75a70cf9 700 gimple_stmt_iterator i;
a6c787e5 701
75a70cf9 702 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
a6c787e5 703 {
75a70cf9 704 gimple stmt = gsi_stmt (i);
705 tree callee, ap;
a6c787e5 706
75a70cf9 707 if (!is_gimple_call (stmt))
a6c787e5 708 continue;
709
75a70cf9 710 callee = gimple_call_fndecl (stmt);
a6c787e5 711 if (!callee
712 || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
713 continue;
714
715 switch (DECL_FUNCTION_CODE (callee))
716 {
717 case BUILT_IN_VA_START:
718 break;
719 /* If old style builtins are used, don't optimize anything. */
720 case BUILT_IN_SAVEREGS:
a6c787e5 721 case BUILT_IN_NEXT_ARG:
722 va_list_escapes = true;
723 continue;
724 default:
725 continue;
726 }
727
728 si.va_start_count++;
75a70cf9 729 ap = gimple_call_arg (stmt, 0);
8b151587 730
731 if (TREE_CODE (ap) != ADDR_EXPR)
a6c787e5 732 {
733 va_list_escapes = true;
734 break;
735 }
a6c787e5 736 ap = TREE_OPERAND (ap, 0);
8b151587 737 if (TREE_CODE (ap) == ARRAY_REF)
738 {
739 if (! integer_zerop (TREE_OPERAND (ap, 1)))
740 {
741 va_list_escapes = true;
742 break;
743 }
744 ap = TREE_OPERAND (ap, 0);
745 }
746 if (TYPE_MAIN_VARIANT (TREE_TYPE (ap))
5f57a8b1 747 != TYPE_MAIN_VARIANT (targetm.fn_abi_va_list (cfun->decl))
8b151587 748 || TREE_CODE (ap) != VAR_DECL)
749 {
750 va_list_escapes = true;
751 break;
752 }
753
a6c787e5 754 if (is_global_var (ap))
755 {
756 va_list_escapes = true;
757 break;
758 }
759
7ecda5e8 760 bitmap_set_bit (si.va_list_vars, DECL_UID (ap) + num_ssa_names);
a6c787e5 761
762 /* VA_START_BB and VA_START_AP will be only used if there is just
763 one va_start in the function. */
764 si.va_start_bb = bb;
765 si.va_start_ap = ap;
766 }
767
768 if (va_list_escapes)
769 break;
770 }
771
772 /* If there were no va_start uses in the function, there is no need to
773 save anything. */
774 if (si.va_start_count == 0)
775 goto finish;
776
777 /* If some va_list arguments weren't local, we can't optimize. */
778 if (va_list_escapes)
779 goto finish;
780
781 /* For void * or char * va_list, something useful can be done only
782 if there is just one va_start. */
783 if (va_list_simple_ptr && si.va_start_count > 1)
784 {
785 va_list_escapes = true;
786 goto finish;
787 }
788
789 /* For struct * va_list, if the backend didn't tell us what the counter fields
790 are, there is nothing more we can do. */
791 if (!va_list_simple_ptr
792 && va_list_gpr_counter_field == NULL_TREE
793 && va_list_fpr_counter_field == NULL_TREE)
794 {
795 va_list_escapes = true;
796 goto finish;
797 }
798
799 /* For void * or char * va_list there is just one counter
800 (va_list itself). Use VA_LIST_GPR_SIZE for it. */
801 if (va_list_simple_ptr)
802 cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
803
ccc5d6f1 804 calculate_dominance_info (CDI_DOMINATORS);
75a70cf9 805 memset (&wi, 0, sizeof (wi));
806 wi.info = si.va_list_vars;
ccc5d6f1 807
a6c787e5 808 FOR_EACH_BB (bb)
809 {
75a70cf9 810 gimple_stmt_iterator i;
a6c787e5 811
812 si.compute_sizes = -1;
813 si.bb = bb;
35bf4ce8 814
815 /* For va_list_simple_ptr, we have to check PHI nodes too. We treat
816 them as assignments for the purpose of escape analysis. This is
817 not needed for non-simple va_list because virtual phis don't perform
818 any real data movement. */
819 if (va_list_simple_ptr)
820 {
75a70cf9 821 tree lhs, rhs;
35bf4ce8 822 use_operand_p uop;
823 ssa_op_iter soi;
824
75a70cf9 825 for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i))
35bf4ce8 826 {
75a70cf9 827 gimple phi = gsi_stmt (i);
35bf4ce8 828 lhs = PHI_RESULT (phi);
829
7c782c9b 830 if (virtual_operand_p (lhs))
35bf4ce8 831 continue;
832
833 FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
834 {
835 rhs = USE_FROM_PTR (uop);
836 if (va_list_ptr_read (&si, rhs, lhs))
837 continue;
838 else if (va_list_ptr_write (&si, lhs, rhs))
839 continue;
840 else
841 check_va_list_escapes (&si, lhs, rhs);
842
75a70cf9 843 if (si.va_list_escapes)
35bf4ce8 844 {
845 if (dump_file && (dump_flags & TDF_DETAILS))
846 {
847 fputs ("va_list escapes in ", dump_file);
75a70cf9 848 print_gimple_stmt (dump_file, phi, 0, dump_flags);
35bf4ce8 849 fputc ('\n', dump_file);
850 }
851 va_list_escapes = true;
852 }
853 }
854 }
855 }
856
75a70cf9 857 for (i = gsi_start_bb (bb);
858 !gsi_end_p (i) && !va_list_escapes;
859 gsi_next (&i))
a6c787e5 860 {
75a70cf9 861 gimple stmt = gsi_stmt (i);
a6c787e5 862
863 /* Don't look at __builtin_va_{start,end}, they are ok. */
75a70cf9 864 if (is_gimple_call (stmt))
a6c787e5 865 {
75a70cf9 866 tree callee = gimple_call_fndecl (stmt);
a6c787e5 867
868 if (callee
869 && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
870 && (DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_START
871 || DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END))
872 continue;
873 }
874
75a70cf9 875 if (is_gimple_assign (stmt))
a6c787e5 876 {
75a70cf9 877 tree lhs = gimple_assign_lhs (stmt);
878 tree rhs = gimple_assign_rhs1 (stmt);
a6c787e5 879
880 if (va_list_simple_ptr)
881 {
75a70cf9 882 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
883 == GIMPLE_SINGLE_RHS)
884 {
4b4d1c3b 885 /* Check for ap ={v} {}. */
886 if (TREE_CLOBBER_P (rhs))
887 continue;
888
75a70cf9 889 /* Check for tem = ap. */
4b4d1c3b 890 else if (va_list_ptr_read (&si, rhs, lhs))
75a70cf9 891 continue;
a6c787e5 892
75a70cf9 893 /* Check for the last insn in:
894 tem1 = ap;
895 tem2 = tem1 + CST;
896 ap = tem2;
897 sequence. */
898 else if (va_list_ptr_write (&si, lhs, rhs))
899 continue;
900 }
a6c787e5 901
75a70cf9 902 if ((gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
903 && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST)
d9659041 904 || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
75a70cf9 905 || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
906 == GIMPLE_SINGLE_RHS))
a6c787e5 907 check_va_list_escapes (&si, lhs, rhs);
908 }
909 else
910 {
75a70cf9 911 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
912 == GIMPLE_SINGLE_RHS)
913 {
3c25489e 914 /* Check for ap ={v} {}. */
915 if (TREE_CLOBBER_P (rhs))
916 continue;
4b4d1c3b 917
75a70cf9 918 /* Check for ap[0].field = temp. */
3c25489e 919 else if (va_list_counter_struct_op (&si, lhs, rhs, true))
75a70cf9 920 continue;
a6c787e5 921
75a70cf9 922 /* Check for temp = ap[0].field. */
923 else if (va_list_counter_struct_op (&si, rhs, lhs,
924 false))
925 continue;
926 }
a6c787e5 927
928 /* Do any architecture specific checking. */
75a70cf9 929 if (targetm.stdarg_optimize_hook
930 && targetm.stdarg_optimize_hook (&si, stmt))
a6c787e5 931 continue;
932 }
933 }
9845d120 934 else if (is_gimple_debug (stmt))
935 continue;
a6c787e5 936
937 /* All other uses of va_list are either va_copy (that is not handled
938 in this optimization), taking address of va_list variable or
939 passing va_list to other functions (in that case va_list might
940 escape the function and therefore va_start needs to set it up
941 fully), or some unexpected use of va_list. None of these should
942 happen in a gimplified VA_ARG_EXPR. */
943 if (si.va_list_escapes
75a70cf9 944 || walk_gimple_op (stmt, find_va_list_reference, &wi))
a6c787e5 945 {
946 if (dump_file && (dump_flags & TDF_DETAILS))
947 {
948 fputs ("va_list escapes in ", dump_file);
75a70cf9 949 print_gimple_stmt (dump_file, stmt, 0, dump_flags);
a6c787e5 950 fputc ('\n', dump_file);
951 }
952 va_list_escapes = true;
953 }
954 }
955
956 if (va_list_escapes)
957 break;
958 }
959
960 if (! va_list_escapes
961 && va_list_simple_ptr
962 && ! bitmap_empty_p (si.va_list_escape_vars)
963 && check_all_va_list_escapes (&si))
964 va_list_escapes = true;
965
966finish:
967 if (va_list_escapes)
968 {
969 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
970 cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
971 }
972 BITMAP_FREE (si.va_list_vars);
973 BITMAP_FREE (si.va_list_escape_vars);
974 free (si.offsets);
975 if (dump_file)
976 {
977 fprintf (dump_file, "%s: va_list escapes %d, needs to save ",
978 funcname, (int) va_list_escapes);
979 if (cfun->va_list_gpr_size >= VA_LIST_MAX_GPR_SIZE)
980 fputs ("all", dump_file);
981 else
982 fprintf (dump_file, "%d", cfun->va_list_gpr_size);
983 fputs (" GPR units and ", dump_file);
984 if (cfun->va_list_fpr_size >= VA_LIST_MAX_FPR_SIZE)
985 fputs ("all", dump_file);
986 else
987 fprintf (dump_file, "%d", cfun->va_list_fpr_size);
988 fputs (" FPR units.\n", dump_file);
989 }
2a1990e9 990 return 0;
a6c787e5 991}
992
993
cbe8bda8 994namespace {
995
996const pass_data pass_data_stdarg =
a6c787e5 997{
cbe8bda8 998 GIMPLE_PASS, /* type */
999 "stdarg", /* name */
1000 OPTGROUP_NONE, /* optinfo_flags */
1001 true, /* has_gate */
1002 true, /* has_execute */
1003 TV_NONE, /* tv_id */
1004 ( PROP_cfg | PROP_ssa ), /* properties_required */
1005 0, /* properties_provided */
1006 0, /* properties_destroyed */
1007 0, /* todo_flags_start */
1008 0, /* todo_flags_finish */
a6c787e5 1009};
cbe8bda8 1010
1011class pass_stdarg : public gimple_opt_pass
1012{
1013public:
9af5ce0c 1014 pass_stdarg (gcc::context *ctxt)
1015 : gimple_opt_pass (pass_data_stdarg, ctxt)
cbe8bda8 1016 {}
1017
1018 /* opt_pass methods: */
1019 bool gate () { return gate_optimize_stdarg (); }
1020 unsigned int execute () { return execute_optimize_stdarg (); }
1021
1022}; // class pass_stdarg
1023
1024} // anon namespace
1025
1026gimple_opt_pass *
1027make_pass_stdarg (gcc::context *ctxt)
1028{
1029 return new pass_stdarg (ctxt);
1030}