PR target/62251
[official-gcc.git] / gcc / tree-stdarg.c
blob0c70790f3eb875609716a37cf1df19e8019001b3
1 /* Pass computing data for optimizing stdarg functions.
2 Copyright (C) 2004-2015 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 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
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "hash-set.h"
26 #include "machmode.h"
27 #include "vec.h"
28 #include "double-int.h"
29 #include "input.h"
30 #include "alias.h"
31 #include "symtab.h"
32 #include "wide-int.h"
33 #include "inchash.h"
34 #include "tree.h"
35 #include "fold-const.h"
36 #include "hard-reg-set.h"
37 #include "input.h"
38 #include "function.h"
39 #include "langhooks.h"
40 #include "gimple-pretty-print.h"
41 #include "target.h"
42 #include "bitmap.h"
43 #include "predict.h"
44 #include "dominance.h"
45 #include "cfg.h"
46 #include "basic-block.h"
47 #include "tree-ssa-alias.h"
48 #include "internal-fn.h"
49 #include "gimple-expr.h"
50 #include "is-a.h"
51 #include "gimple.h"
52 #include "gimple-iterator.h"
53 #include "gimple-walk.h"
54 #include "gimple-ssa.h"
55 #include "tree-phinodes.h"
56 #include "ssa-iterators.h"
57 #include "stringpool.h"
58 #include "tree-ssanames.h"
59 #include "sbitmap.h"
60 #include "tree-pass.h"
61 #include "tree-stdarg.h"
63 /* A simple pass that attempts to optimize stdarg functions on architectures
64 that need to save register arguments to stack on entry to stdarg functions.
65 If the function doesn't use any va_start macros, no registers need to
66 be saved. If va_start macros are used, the va_list variables don't escape
67 the function, it is only necessary to save registers that will be used
68 in va_arg macros. E.g. if va_arg is only used with integral types
69 in the function, floating point registers don't need to be saved, etc. */
72 /* Return true if basic block VA_ARG_BB is dominated by VA_START_BB and
73 is executed at most as many times as VA_START_BB. */
75 static bool
76 reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb)
78 vec<edge> stack = vNULL;
79 edge e;
80 edge_iterator ei;
81 sbitmap visited;
82 bool ret;
84 if (va_arg_bb == va_start_bb)
85 return true;
87 if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb))
88 return false;
90 visited = sbitmap_alloc (last_basic_block_for_fn (cfun));
91 bitmap_clear (visited);
92 ret = true;
94 FOR_EACH_EDGE (e, ei, va_arg_bb->preds)
95 stack.safe_push (e);
97 while (! stack.is_empty ())
99 basic_block src;
101 e = stack.pop ();
102 src = e->src;
104 if (e->flags & EDGE_COMPLEX)
106 ret = false;
107 break;
110 if (src == va_start_bb)
111 continue;
113 /* va_arg_bb can be executed more times than va_start_bb. */
114 if (src == va_arg_bb)
116 ret = false;
117 break;
120 gcc_assert (src != ENTRY_BLOCK_PTR_FOR_FN (cfun));
122 if (! bitmap_bit_p (visited, src->index))
124 bitmap_set_bit (visited, src->index);
125 FOR_EACH_EDGE (e, ei, src->preds)
126 stack.safe_push (e);
130 stack.release ();
131 sbitmap_free (visited);
132 return ret;
136 /* For statement COUNTER = RHS, if RHS is COUNTER + constant,
137 return constant, otherwise return HOST_WIDE_INT_M1U.
138 GPR_P is true if this is GPR counter. */
140 static unsigned HOST_WIDE_INT
141 va_list_counter_bump (struct stdarg_info *si, tree counter, tree rhs,
142 bool gpr_p)
144 tree lhs, orig_lhs;
145 gimple stmt;
146 unsigned HOST_WIDE_INT ret = 0, val, counter_val;
147 unsigned int max_size;
149 if (si->offsets == NULL)
151 unsigned int i;
153 si->offsets = XNEWVEC (int, num_ssa_names);
154 for (i = 0; i < num_ssa_names; ++i)
155 si->offsets[i] = -1;
158 counter_val = gpr_p ? cfun->va_list_gpr_size : cfun->va_list_fpr_size;
159 max_size = gpr_p ? VA_LIST_MAX_GPR_SIZE : VA_LIST_MAX_FPR_SIZE;
160 orig_lhs = lhs = rhs;
161 while (lhs)
163 enum tree_code rhs_code;
164 tree rhs1;
166 if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
168 if (counter_val >= max_size)
170 ret = max_size;
171 break;
174 ret -= counter_val - si->offsets[SSA_NAME_VERSION (lhs)];
175 break;
178 stmt = SSA_NAME_DEF_STMT (lhs);
180 if (!is_gimple_assign (stmt) || gimple_assign_lhs (stmt) != lhs)
181 return HOST_WIDE_INT_M1U;
183 rhs_code = gimple_assign_rhs_code (stmt);
184 rhs1 = gimple_assign_rhs1 (stmt);
185 if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
186 || gimple_assign_cast_p (stmt))
187 && TREE_CODE (rhs1) == SSA_NAME)
189 lhs = rhs1;
190 continue;
193 if ((rhs_code == POINTER_PLUS_EXPR
194 || rhs_code == PLUS_EXPR)
195 && TREE_CODE (rhs1) == SSA_NAME
196 && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))
198 ret += tree_to_uhwi (gimple_assign_rhs2 (stmt));
199 lhs = rhs1;
200 continue;
203 if (rhs_code == ADDR_EXPR
204 && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
205 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
206 && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1)))
208 ret += tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1));
209 lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
210 continue;
213 if (get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS)
214 return HOST_WIDE_INT_M1U;
216 rhs = gimple_assign_rhs1 (stmt);
217 if (TREE_CODE (counter) != TREE_CODE (rhs))
218 return HOST_WIDE_INT_M1U;
220 if (TREE_CODE (counter) == COMPONENT_REF)
222 if (get_base_address (counter) != get_base_address (rhs)
223 || TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL
224 || TREE_OPERAND (counter, 1) != TREE_OPERAND (rhs, 1))
225 return HOST_WIDE_INT_M1U;
227 else if (counter != rhs)
228 return HOST_WIDE_INT_M1U;
230 lhs = NULL;
233 lhs = orig_lhs;
234 val = ret + counter_val;
235 while (lhs)
237 enum tree_code rhs_code;
238 tree rhs1;
240 if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
241 break;
243 if (val >= max_size)
244 si->offsets[SSA_NAME_VERSION (lhs)] = max_size;
245 else
246 si->offsets[SSA_NAME_VERSION (lhs)] = val;
248 stmt = SSA_NAME_DEF_STMT (lhs);
250 rhs_code = gimple_assign_rhs_code (stmt);
251 rhs1 = gimple_assign_rhs1 (stmt);
252 if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
253 || gimple_assign_cast_p (stmt))
254 && TREE_CODE (rhs1) == SSA_NAME)
256 lhs = rhs1;
257 continue;
260 if ((rhs_code == POINTER_PLUS_EXPR
261 || rhs_code == PLUS_EXPR)
262 && TREE_CODE (rhs1) == SSA_NAME
263 && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))
265 val -= tree_to_uhwi (gimple_assign_rhs2 (stmt));
266 lhs = rhs1;
267 continue;
270 if (rhs_code == ADDR_EXPR
271 && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
272 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
273 && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1)))
275 val -= tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1));
276 lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
277 continue;
280 lhs = NULL;
283 return ret;
287 /* Called by walk_tree to look for references to va_list variables. */
289 static tree
290 find_va_list_reference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
291 void *data)
293 bitmap va_list_vars = (bitmap) ((struct walk_stmt_info *) data)->info;
294 tree var = *tp;
296 if (TREE_CODE (var) == SSA_NAME)
298 if (bitmap_bit_p (va_list_vars, SSA_NAME_VERSION (var)))
299 return var;
301 else if (TREE_CODE (var) == VAR_DECL)
303 if (bitmap_bit_p (va_list_vars, DECL_UID (var) + num_ssa_names))
304 return var;
307 return NULL_TREE;
311 /* Helper function of va_list_counter_struct_op. Compute
312 cfun->va_list_{g,f}pr_size. AP is a va_list GPR/FPR counter,
313 if WRITE_P is true, seen in AP = VAR, otherwise seen in VAR = AP
314 statement. GPR_P is true if AP is a GPR counter, false if it is
315 a FPR counter. */
317 static void
318 va_list_counter_op (struct stdarg_info *si, tree ap, tree var, bool gpr_p,
319 bool write_p)
321 unsigned HOST_WIDE_INT increment;
323 if (si->compute_sizes < 0)
325 si->compute_sizes = 0;
326 if (si->va_start_count == 1
327 && reachable_at_most_once (si->bb, si->va_start_bb))
328 si->compute_sizes = 1;
330 if (dump_file && (dump_flags & TDF_DETAILS))
331 fprintf (dump_file,
332 "bb%d will %sbe executed at most once for each va_start "
333 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
334 si->va_start_bb->index);
337 if (write_p
338 && si->compute_sizes
339 && (increment = va_list_counter_bump (si, ap, var, gpr_p)) + 1 > 1)
341 if (gpr_p && cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
343 cfun->va_list_gpr_size += increment;
344 return;
347 if (!gpr_p && cfun->va_list_fpr_size + increment < VA_LIST_MAX_FPR_SIZE)
349 cfun->va_list_fpr_size += increment;
350 return;
354 if (write_p || !si->compute_sizes)
356 if (gpr_p)
357 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
358 else
359 cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
364 /* If AP is a va_list GPR/FPR counter, compute cfun->va_list_{g,f}pr_size.
365 If WRITE_P is true, AP has been seen in AP = VAR assignment, if WRITE_P
366 is false, AP has been seen in VAR = AP assignment.
367 Return true if the AP = VAR (resp. VAR = AP) statement is a recognized
368 va_arg operation that doesn't cause the va_list variable to escape
369 current function. */
371 static bool
372 va_list_counter_struct_op (struct stdarg_info *si, tree ap, tree var,
373 bool write_p)
375 tree base;
377 if (TREE_CODE (ap) != COMPONENT_REF
378 || TREE_CODE (TREE_OPERAND (ap, 1)) != FIELD_DECL)
379 return false;
381 if (TREE_CODE (var) != SSA_NAME
382 || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (var)))
383 return false;
385 base = get_base_address (ap);
386 if (TREE_CODE (base) != VAR_DECL
387 || !bitmap_bit_p (si->va_list_vars, DECL_UID (base) + num_ssa_names))
388 return false;
390 if (TREE_OPERAND (ap, 1) == va_list_gpr_counter_field)
391 va_list_counter_op (si, ap, var, true, write_p);
392 else if (TREE_OPERAND (ap, 1) == va_list_fpr_counter_field)
393 va_list_counter_op (si, ap, var, false, write_p);
395 return true;
399 /* Check for TEM = AP. Return true if found and the caller shouldn't
400 search for va_list references in the statement. */
402 static bool
403 va_list_ptr_read (struct stdarg_info *si, tree ap, tree tem)
405 if (TREE_CODE (ap) != VAR_DECL
406 || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
407 return false;
409 if (TREE_CODE (tem) != SSA_NAME
410 || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem)))
411 return false;
413 if (si->compute_sizes < 0)
415 si->compute_sizes = 0;
416 if (si->va_start_count == 1
417 && reachable_at_most_once (si->bb, si->va_start_bb))
418 si->compute_sizes = 1;
420 if (dump_file && (dump_flags & TDF_DETAILS))
421 fprintf (dump_file,
422 "bb%d will %sbe executed at most once for each va_start "
423 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
424 si->va_start_bb->index);
427 /* For void * or char * va_list types, there is just one counter.
428 If va_arg is used in a loop, we don't know how many registers need
429 saving. */
430 if (! si->compute_sizes)
431 return false;
433 if (va_list_counter_bump (si, ap, tem, true) == HOST_WIDE_INT_M1U)
434 return false;
436 /* Note the temporary, as we need to track whether it doesn't escape
437 the current function. */
438 bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (tem));
440 return true;
444 /* Check for:
445 tem1 = AP;
446 TEM2 = tem1 + CST;
447 AP = TEM2;
448 sequence and update cfun->va_list_gpr_size. Return true if found. */
450 static bool
451 va_list_ptr_write (struct stdarg_info *si, tree ap, tree tem2)
453 unsigned HOST_WIDE_INT increment;
455 if (TREE_CODE (ap) != VAR_DECL
456 || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
457 return false;
459 if (TREE_CODE (tem2) != SSA_NAME
460 || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem2)))
461 return false;
463 if (si->compute_sizes <= 0)
464 return false;
466 increment = va_list_counter_bump (si, ap, tem2, true);
467 if (increment + 1 <= 1)
468 return false;
470 if (cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
471 cfun->va_list_gpr_size += increment;
472 else
473 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
475 return true;
479 /* If RHS is X, (some type *) X or X + CST for X a temporary variable
480 containing value of some va_list variable plus optionally some constant,
481 either set si->va_list_escapes or add LHS to si->va_list_escape_vars,
482 depending whether LHS is a function local temporary. */
484 static void
485 check_va_list_escapes (struct stdarg_info *si, tree lhs, tree rhs)
487 if (! POINTER_TYPE_P (TREE_TYPE (rhs)))
488 return;
490 if (TREE_CODE (rhs) == SSA_NAME)
492 if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (rhs)))
493 return;
495 else if (TREE_CODE (rhs) == ADDR_EXPR
496 && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
497 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)) == SSA_NAME)
499 tree ptr = TREE_OPERAND (TREE_OPERAND (rhs, 0), 0);
500 if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (ptr)))
501 return;
503 else
504 return;
506 if (TREE_CODE (lhs) != SSA_NAME)
508 si->va_list_escapes = true;
509 return;
512 if (si->compute_sizes < 0)
514 si->compute_sizes = 0;
515 if (si->va_start_count == 1
516 && reachable_at_most_once (si->bb, si->va_start_bb))
517 si->compute_sizes = 1;
519 if (dump_file && (dump_flags & TDF_DETAILS))
520 fprintf (dump_file,
521 "bb%d will %sbe executed at most once for each va_start "
522 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
523 si->va_start_bb->index);
526 /* For void * or char * va_list types, there is just one counter.
527 If va_arg is used in a loop, we don't know how many registers need
528 saving. */
529 if (! si->compute_sizes)
531 si->va_list_escapes = true;
532 return;
535 if (va_list_counter_bump (si, si->va_start_ap, lhs, true)
536 == HOST_WIDE_INT_M1U)
538 si->va_list_escapes = true;
539 return;
542 bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (lhs));
546 /* Check all uses of temporaries from si->va_list_escape_vars bitmap.
547 Return true if va_list might be escaping. */
549 static bool
550 check_all_va_list_escapes (struct stdarg_info *si)
552 basic_block bb;
554 FOR_EACH_BB_FN (bb, cfun)
556 for (gphi_iterator i = gsi_start_phis (bb); !gsi_end_p (i);
557 gsi_next (&i))
559 tree lhs;
560 use_operand_p uop;
561 ssa_op_iter soi;
562 gphi *phi = i.phi ();
564 lhs = PHI_RESULT (phi);
565 if (virtual_operand_p (lhs)
566 || bitmap_bit_p (si->va_list_escape_vars,
567 SSA_NAME_VERSION (lhs)))
568 continue;
570 FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
572 tree rhs = USE_FROM_PTR (uop);
573 if (TREE_CODE (rhs) == SSA_NAME
574 && bitmap_bit_p (si->va_list_escape_vars,
575 SSA_NAME_VERSION (rhs)))
577 if (dump_file && (dump_flags & TDF_DETAILS))
579 fputs ("va_list escapes in ", dump_file);
580 print_gimple_stmt (dump_file, phi, 0, dump_flags);
581 fputc ('\n', dump_file);
583 return true;
588 for (gimple_stmt_iterator i = gsi_start_bb (bb); !gsi_end_p (i);
589 gsi_next (&i))
591 gimple stmt = gsi_stmt (i);
592 tree use;
593 ssa_op_iter iter;
595 if (is_gimple_debug (stmt))
596 continue;
598 FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_USES)
600 if (! bitmap_bit_p (si->va_list_escape_vars,
601 SSA_NAME_VERSION (use)))
602 continue;
604 if (is_gimple_assign (stmt))
606 tree rhs = gimple_assign_rhs1 (stmt);
607 enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
609 /* x = *ap_temp; */
610 if (rhs_code == MEM_REF
611 && TREE_OPERAND (rhs, 0) == use
612 && TYPE_SIZE_UNIT (TREE_TYPE (rhs))
613 && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (rhs)))
614 && si->offsets[SSA_NAME_VERSION (use)] != -1)
616 unsigned HOST_WIDE_INT gpr_size;
617 tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (rhs));
619 gpr_size = si->offsets[SSA_NAME_VERSION (use)]
620 + tree_to_shwi (TREE_OPERAND (rhs, 1))
621 + tree_to_uhwi (access_size);
622 if (gpr_size >= VA_LIST_MAX_GPR_SIZE)
623 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
624 else if (gpr_size > cfun->va_list_gpr_size)
625 cfun->va_list_gpr_size = gpr_size;
626 continue;
629 /* va_arg sequences may contain
630 other_ap_temp = ap_temp;
631 other_ap_temp = ap_temp + constant;
632 other_ap_temp = (some_type *) ap_temp;
633 ap = ap_temp;
634 statements. */
635 if (rhs == use
636 && ((rhs_code == POINTER_PLUS_EXPR
637 && (TREE_CODE (gimple_assign_rhs2 (stmt))
638 == INTEGER_CST))
639 || gimple_assign_cast_p (stmt)
640 || (get_gimple_rhs_class (rhs_code)
641 == GIMPLE_SINGLE_RHS)))
643 tree lhs = gimple_assign_lhs (stmt);
645 if (TREE_CODE (lhs) == SSA_NAME
646 && bitmap_bit_p (si->va_list_escape_vars,
647 SSA_NAME_VERSION (lhs)))
648 continue;
650 if (TREE_CODE (lhs) == VAR_DECL
651 && bitmap_bit_p (si->va_list_vars,
652 DECL_UID (lhs) + num_ssa_names))
653 continue;
655 else if (rhs_code == ADDR_EXPR
656 && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
657 && TREE_OPERAND (TREE_OPERAND (rhs, 0), 0) == use)
659 tree lhs = gimple_assign_lhs (stmt);
661 if (bitmap_bit_p (si->va_list_escape_vars,
662 SSA_NAME_VERSION (lhs)))
663 continue;
667 if (dump_file && (dump_flags & TDF_DETAILS))
669 fputs ("va_list escapes in ", dump_file);
670 print_gimple_stmt (dump_file, stmt, 0, dump_flags);
671 fputc ('\n', dump_file);
673 return true;
678 return false;
682 namespace {
684 const pass_data pass_data_stdarg =
686 GIMPLE_PASS, /* type */
687 "stdarg", /* name */
688 OPTGROUP_NONE, /* optinfo_flags */
689 TV_NONE, /* tv_id */
690 ( PROP_cfg | PROP_ssa ), /* properties_required */
691 0, /* properties_provided */
692 0, /* properties_destroyed */
693 0, /* todo_flags_start */
694 0, /* todo_flags_finish */
697 class pass_stdarg : public gimple_opt_pass
699 public:
700 pass_stdarg (gcc::context *ctxt)
701 : gimple_opt_pass (pass_data_stdarg, ctxt)
704 /* opt_pass methods: */
705 virtual bool gate (function *fun)
707 return (flag_stdarg_opt
708 #ifdef ACCEL_COMPILER
709 /* Disable for GCC5 in the offloading compilers, as
710 va_list and gpr/fpr counter fields are not merged.
711 In GCC6 when stdarg is lowered late this shouldn't be
712 an issue. */
713 && !in_lto_p
714 #endif
715 /* This optimization is only for stdarg functions. */
716 && fun->stdarg != 0);
719 virtual unsigned int execute (function *);
721 }; // class pass_stdarg
723 unsigned int
724 pass_stdarg::execute (function *fun)
726 basic_block bb;
727 bool va_list_escapes = false;
728 bool va_list_simple_ptr;
729 struct stdarg_info si;
730 struct walk_stmt_info wi;
731 const char *funcname = NULL;
732 tree cfun_va_list;
734 fun->va_list_gpr_size = 0;
735 fun->va_list_fpr_size = 0;
736 memset (&si, 0, sizeof (si));
737 si.va_list_vars = BITMAP_ALLOC (NULL);
738 si.va_list_escape_vars = BITMAP_ALLOC (NULL);
740 if (dump_file)
741 funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
743 cfun_va_list = targetm.fn_abi_va_list (fun->decl);
744 va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
745 && (TREE_TYPE (cfun_va_list) == void_type_node
746 || TREE_TYPE (cfun_va_list) == char_type_node);
747 gcc_assert (is_gimple_reg_type (cfun_va_list) == va_list_simple_ptr);
749 FOR_EACH_BB_FN (bb, fun)
751 gimple_stmt_iterator i;
753 for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
755 gimple stmt = gsi_stmt (i);
756 tree callee, ap;
758 if (!is_gimple_call (stmt))
759 continue;
761 callee = gimple_call_fndecl (stmt);
762 if (!callee
763 || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
764 continue;
766 switch (DECL_FUNCTION_CODE (callee))
768 case BUILT_IN_VA_START:
769 break;
770 /* If old style builtins are used, don't optimize anything. */
771 case BUILT_IN_SAVEREGS:
772 case BUILT_IN_NEXT_ARG:
773 va_list_escapes = true;
774 continue;
775 default:
776 continue;
779 si.va_start_count++;
780 ap = gimple_call_arg (stmt, 0);
782 if (TREE_CODE (ap) != ADDR_EXPR)
784 va_list_escapes = true;
785 break;
787 ap = TREE_OPERAND (ap, 0);
788 if (TREE_CODE (ap) == ARRAY_REF)
790 if (! integer_zerop (TREE_OPERAND (ap, 1)))
792 va_list_escapes = true;
793 break;
795 ap = TREE_OPERAND (ap, 0);
797 if (TYPE_MAIN_VARIANT (TREE_TYPE (ap))
798 != TYPE_MAIN_VARIANT (targetm.fn_abi_va_list (fun->decl))
799 || TREE_CODE (ap) != VAR_DECL)
801 va_list_escapes = true;
802 break;
805 if (is_global_var (ap))
807 va_list_escapes = true;
808 break;
811 bitmap_set_bit (si.va_list_vars, DECL_UID (ap) + num_ssa_names);
813 /* VA_START_BB and VA_START_AP will be only used if there is just
814 one va_start in the function. */
815 si.va_start_bb = bb;
816 si.va_start_ap = ap;
819 if (va_list_escapes)
820 break;
823 /* If there were no va_start uses in the function, there is no need to
824 save anything. */
825 if (si.va_start_count == 0)
826 goto finish;
828 /* If some va_list arguments weren't local, we can't optimize. */
829 if (va_list_escapes)
830 goto finish;
832 /* For void * or char * va_list, something useful can be done only
833 if there is just one va_start. */
834 if (va_list_simple_ptr && si.va_start_count > 1)
836 va_list_escapes = true;
837 goto finish;
840 /* For struct * va_list, if the backend didn't tell us what the counter fields
841 are, there is nothing more we can do. */
842 if (!va_list_simple_ptr
843 && va_list_gpr_counter_field == NULL_TREE
844 && va_list_fpr_counter_field == NULL_TREE)
846 va_list_escapes = true;
847 goto finish;
850 /* For void * or char * va_list there is just one counter
851 (va_list itself). Use VA_LIST_GPR_SIZE for it. */
852 if (va_list_simple_ptr)
853 fun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
855 calculate_dominance_info (CDI_DOMINATORS);
856 memset (&wi, 0, sizeof (wi));
857 wi.info = si.va_list_vars;
859 FOR_EACH_BB_FN (bb, fun)
861 si.compute_sizes = -1;
862 si.bb = bb;
864 /* For va_list_simple_ptr, we have to check PHI nodes too. We treat
865 them as assignments for the purpose of escape analysis. This is
866 not needed for non-simple va_list because virtual phis don't perform
867 any real data movement. Also, check PHI nodes for taking address of
868 the va_list vars. */
869 tree lhs, rhs;
870 use_operand_p uop;
871 ssa_op_iter soi;
873 for (gphi_iterator i = gsi_start_phis (bb); !gsi_end_p (i);
874 gsi_next (&i))
876 gphi *phi = i.phi ();
877 lhs = PHI_RESULT (phi);
879 if (virtual_operand_p (lhs))
880 continue;
882 if (va_list_simple_ptr)
884 FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
886 rhs = USE_FROM_PTR (uop);
887 if (va_list_ptr_read (&si, rhs, lhs))
888 continue;
889 else if (va_list_ptr_write (&si, lhs, rhs))
890 continue;
891 else
892 check_va_list_escapes (&si, lhs, rhs);
894 if (si.va_list_escapes)
896 if (dump_file && (dump_flags & TDF_DETAILS))
898 fputs ("va_list escapes in ", dump_file);
899 print_gimple_stmt (dump_file, phi, 0, dump_flags);
900 fputc ('\n', dump_file);
902 va_list_escapes = true;
907 for (unsigned j = 0; !va_list_escapes
908 && j < gimple_phi_num_args (phi); ++j)
909 if ((!va_list_simple_ptr
910 || TREE_CODE (gimple_phi_arg_def (phi, j)) != SSA_NAME)
911 && walk_tree (gimple_phi_arg_def_ptr (phi, j),
912 find_va_list_reference, &wi, NULL))
914 if (dump_file && (dump_flags & TDF_DETAILS))
916 fputs ("va_list escapes in ", dump_file);
917 print_gimple_stmt (dump_file, phi, 0, dump_flags);
918 fputc ('\n', dump_file);
920 va_list_escapes = true;
924 for (gimple_stmt_iterator i = gsi_start_bb (bb);
925 !gsi_end_p (i) && !va_list_escapes;
926 gsi_next (&i))
928 gimple stmt = gsi_stmt (i);
930 /* Don't look at __builtin_va_{start,end}, they are ok. */
931 if (is_gimple_call (stmt))
933 tree callee = gimple_call_fndecl (stmt);
935 if (callee
936 && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
937 && (DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_START
938 || DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END))
939 continue;
942 if (is_gimple_assign (stmt))
944 lhs = gimple_assign_lhs (stmt);
945 rhs = gimple_assign_rhs1 (stmt);
947 if (va_list_simple_ptr)
949 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
950 == GIMPLE_SINGLE_RHS)
952 /* Check for ap ={v} {}. */
953 if (TREE_CLOBBER_P (rhs))
954 continue;
956 /* Check for tem = ap. */
957 else if (va_list_ptr_read (&si, rhs, lhs))
958 continue;
960 /* Check for the last insn in:
961 tem1 = ap;
962 tem2 = tem1 + CST;
963 ap = tem2;
964 sequence. */
965 else if (va_list_ptr_write (&si, lhs, rhs))
966 continue;
969 if ((gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
970 && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST)
971 || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
972 || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
973 == GIMPLE_SINGLE_RHS))
974 check_va_list_escapes (&si, lhs, rhs);
976 else
978 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
979 == GIMPLE_SINGLE_RHS)
981 /* Check for ap ={v} {}. */
982 if (TREE_CLOBBER_P (rhs))
983 continue;
985 /* Check for ap[0].field = temp. */
986 else if (va_list_counter_struct_op (&si, lhs, rhs, true))
987 continue;
989 /* Check for temp = ap[0].field. */
990 else if (va_list_counter_struct_op (&si, rhs, lhs,
991 false))
992 continue;
995 /* Do any architecture specific checking. */
996 if (targetm.stdarg_optimize_hook
997 && targetm.stdarg_optimize_hook (&si, stmt))
998 continue;
1001 else if (is_gimple_debug (stmt))
1002 continue;
1004 /* All other uses of va_list are either va_copy (that is not handled
1005 in this optimization), taking address of va_list variable or
1006 passing va_list to other functions (in that case va_list might
1007 escape the function and therefore va_start needs to set it up
1008 fully), or some unexpected use of va_list. None of these should
1009 happen in a gimplified VA_ARG_EXPR. */
1010 if (si.va_list_escapes
1011 || walk_gimple_op (stmt, find_va_list_reference, &wi))
1013 if (dump_file && (dump_flags & TDF_DETAILS))
1015 fputs ("va_list escapes in ", dump_file);
1016 print_gimple_stmt (dump_file, stmt, 0, dump_flags);
1017 fputc ('\n', dump_file);
1019 va_list_escapes = true;
1023 if (va_list_escapes)
1024 break;
1027 if (! va_list_escapes
1028 && va_list_simple_ptr
1029 && ! bitmap_empty_p (si.va_list_escape_vars)
1030 && check_all_va_list_escapes (&si))
1031 va_list_escapes = true;
1033 finish:
1034 if (va_list_escapes)
1036 fun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
1037 fun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
1039 BITMAP_FREE (si.va_list_vars);
1040 BITMAP_FREE (si.va_list_escape_vars);
1041 free (si.offsets);
1042 if (dump_file)
1044 fprintf (dump_file, "%s: va_list escapes %d, needs to save ",
1045 funcname, (int) va_list_escapes);
1046 if (fun->va_list_gpr_size >= VA_LIST_MAX_GPR_SIZE)
1047 fputs ("all", dump_file);
1048 else
1049 fprintf (dump_file, "%d", cfun->va_list_gpr_size);
1050 fputs (" GPR units and ", dump_file);
1051 if (fun->va_list_fpr_size >= VA_LIST_MAX_FPR_SIZE)
1052 fputs ("all", dump_file);
1053 else
1054 fprintf (dump_file, "%d", cfun->va_list_fpr_size);
1055 fputs (" FPR units.\n", dump_file);
1057 return 0;
1060 } // anon namespace
1062 gimple_opt_pass *
1063 make_pass_stdarg (gcc::context *ctxt)
1065 return new pass_stdarg (ctxt);