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)
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/>. */
23 #include "coretypes.h"
28 #include "double-int.h"
35 #include "fold-const.h"
36 #include "hard-reg-set.h"
39 #include "langhooks.h"
40 #include "gimple-pretty-print.h"
44 #include "dominance.h"
46 #include "basic-block.h"
47 #include "tree-ssa-alias.h"
48 #include "internal-fn.h"
49 #include "gimple-expr.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"
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. */
76 reachable_at_most_once (basic_block va_arg_bb
, basic_block va_start_bb
)
78 vec
<edge
> stack
= vNULL
;
84 if (va_arg_bb
== va_start_bb
)
87 if (! dominated_by_p (CDI_DOMINATORS
, va_arg_bb
, va_start_bb
))
90 visited
= sbitmap_alloc (last_basic_block_for_fn (cfun
));
91 bitmap_clear (visited
);
94 FOR_EACH_EDGE (e
, ei
, va_arg_bb
->preds
)
97 while (! stack
.is_empty ())
104 if (e
->flags
& EDGE_COMPLEX
)
110 if (src
== va_start_bb
)
113 /* va_arg_bb can be executed more times than va_start_bb. */
114 if (src
== va_arg_bb
)
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
)
131 sbitmap_free (visited
);
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
,
146 unsigned HOST_WIDE_INT ret
= 0, val
, counter_val
;
147 unsigned int max_size
;
149 if (si
->offsets
== NULL
)
153 si
->offsets
= XNEWVEC (int, num_ssa_names
);
154 for (i
= 0; i
< num_ssa_names
; ++i
)
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
;
163 enum tree_code rhs_code
;
166 if (si
->offsets
[SSA_NAME_VERSION (lhs
)] != -1)
168 if (counter_val
>= max_size
)
174 ret
-= counter_val
- si
->offsets
[SSA_NAME_VERSION (lhs
)];
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
)
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
));
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);
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
;
234 val
= ret
+ counter_val
;
237 enum tree_code rhs_code
;
240 if (si
->offsets
[SSA_NAME_VERSION (lhs
)] != -1)
244 si
->offsets
[SSA_NAME_VERSION (lhs
)] = max_size
;
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
)
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
));
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);
287 /* Called by walk_tree to look for references to va_list variables. */
290 find_va_list_reference (tree
*tp
, int *walk_subtrees ATTRIBUTE_UNUSED
,
293 bitmap va_list_vars
= (bitmap
) ((struct walk_stmt_info
*) data
)->info
;
296 if (TREE_CODE (var
) == SSA_NAME
)
298 if (bitmap_bit_p (va_list_vars
, SSA_NAME_VERSION (var
)))
301 else if (TREE_CODE (var
) == VAR_DECL
)
303 if (bitmap_bit_p (va_list_vars
, DECL_UID (var
) + num_ssa_names
))
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
318 va_list_counter_op (struct stdarg_info
*si
, tree ap
, tree var
, bool gpr_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
))
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
);
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
;
347 if (!gpr_p
&& cfun
->va_list_fpr_size
+ increment
< VA_LIST_MAX_FPR_SIZE
)
349 cfun
->va_list_fpr_size
+= increment
;
354 if (write_p
|| !si
->compute_sizes
)
357 cfun
->va_list_gpr_size
= VA_LIST_MAX_GPR_SIZE
;
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
372 va_list_counter_struct_op (struct stdarg_info
*si
, tree ap
, tree var
,
377 if (TREE_CODE (ap
) != COMPONENT_REF
378 || TREE_CODE (TREE_OPERAND (ap
, 1)) != FIELD_DECL
)
381 if (TREE_CODE (var
) != SSA_NAME
382 || bitmap_bit_p (si
->va_list_vars
, SSA_NAME_VERSION (var
)))
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
))
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
);
399 /* Check for TEM = AP. Return true if found and the caller shouldn't
400 search for va_list references in the statement. */
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
))
409 if (TREE_CODE (tem
) != SSA_NAME
410 || bitmap_bit_p (si
->va_list_vars
, SSA_NAME_VERSION (tem
)))
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
))
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
430 if (! si
->compute_sizes
)
433 if (va_list_counter_bump (si
, ap
, tem
, true) == HOST_WIDE_INT_M1U
)
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
));
448 sequence and update cfun->va_list_gpr_size. Return true if found. */
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
))
459 if (TREE_CODE (tem2
) != SSA_NAME
460 || bitmap_bit_p (si
->va_list_vars
, SSA_NAME_VERSION (tem2
)))
463 if (si
->compute_sizes
<= 0)
466 increment
= va_list_counter_bump (si
, ap
, tem2
, true);
467 if (increment
+ 1 <= 1)
470 if (cfun
->va_list_gpr_size
+ increment
< VA_LIST_MAX_GPR_SIZE
)
471 cfun
->va_list_gpr_size
+= increment
;
473 cfun
->va_list_gpr_size
= VA_LIST_MAX_GPR_SIZE
;
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. */
485 check_va_list_escapes (struct stdarg_info
*si
, tree lhs
, tree rhs
)
487 if (! POINTER_TYPE_P (TREE_TYPE (rhs
)))
490 if (TREE_CODE (rhs
) == SSA_NAME
)
492 if (! bitmap_bit_p (si
->va_list_escape_vars
, SSA_NAME_VERSION (rhs
)))
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
)))
506 if (TREE_CODE (lhs
) != SSA_NAME
)
508 si
->va_list_escapes
= true;
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
))
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
529 if (! si
->compute_sizes
)
531 si
->va_list_escapes
= true;
535 if (va_list_counter_bump (si
, si
->va_start_ap
, lhs
, true)
536 == HOST_WIDE_INT_M1U
)
538 si
->va_list_escapes
= true;
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. */
550 check_all_va_list_escapes (struct stdarg_info
*si
)
554 FOR_EACH_BB_FN (bb
, cfun
)
556 for (gphi_iterator i
= gsi_start_phis (bb
); !gsi_end_p (i
);
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
)))
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
);
588 for (gimple_stmt_iterator i
= gsi_start_bb (bb
); !gsi_end_p (i
);
591 gimple stmt
= gsi_stmt (i
);
595 if (is_gimple_debug (stmt
))
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
)))
604 if (is_gimple_assign (stmt
))
606 tree rhs
= gimple_assign_rhs1 (stmt
);
607 enum tree_code rhs_code
= gimple_assign_rhs_code (stmt
);
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
;
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;
636 && ((rhs_code
== POINTER_PLUS_EXPR
637 && (TREE_CODE (gimple_assign_rhs2 (stmt
))
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
)))
650 if (TREE_CODE (lhs
) == VAR_DECL
651 && bitmap_bit_p (si
->va_list_vars
,
652 DECL_UID (lhs
) + num_ssa_names
))
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
)))
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
);
684 const pass_data pass_data_stdarg
=
686 GIMPLE_PASS
, /* type */
688 OPTGROUP_NONE
, /* optinfo_flags */
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
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 /* This optimization is only for stdarg functions. */
708 return fun
->stdarg
!= 0;
711 virtual unsigned int execute (function
*);
713 }; // class pass_stdarg
716 pass_stdarg::execute (function
*fun
)
719 bool va_list_escapes
= false;
720 bool va_list_simple_ptr
;
721 struct stdarg_info si
;
722 struct walk_stmt_info wi
;
723 const char *funcname
= NULL
;
726 fun
->va_list_gpr_size
= 0;
727 fun
->va_list_fpr_size
= 0;
728 memset (&si
, 0, sizeof (si
));
729 si
.va_list_vars
= BITMAP_ALLOC (NULL
);
730 si
.va_list_escape_vars
= BITMAP_ALLOC (NULL
);
733 funcname
= lang_hooks
.decl_printable_name (current_function_decl
, 2);
735 cfun_va_list
= targetm
.fn_abi_va_list (fun
->decl
);
736 va_list_simple_ptr
= POINTER_TYPE_P (cfun_va_list
)
737 && (TREE_TYPE (cfun_va_list
) == void_type_node
738 || TREE_TYPE (cfun_va_list
) == char_type_node
);
739 gcc_assert (is_gimple_reg_type (cfun_va_list
) == va_list_simple_ptr
);
741 FOR_EACH_BB_FN (bb
, fun
)
743 gimple_stmt_iterator i
;
745 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
747 gimple stmt
= gsi_stmt (i
);
750 if (!is_gimple_call (stmt
))
753 callee
= gimple_call_fndecl (stmt
);
755 || DECL_BUILT_IN_CLASS (callee
) != BUILT_IN_NORMAL
)
758 switch (DECL_FUNCTION_CODE (callee
))
760 case BUILT_IN_VA_START
:
762 /* If old style builtins are used, don't optimize anything. */
763 case BUILT_IN_SAVEREGS
:
764 case BUILT_IN_NEXT_ARG
:
765 va_list_escapes
= true;
772 ap
= gimple_call_arg (stmt
, 0);
774 if (TREE_CODE (ap
) != ADDR_EXPR
)
776 va_list_escapes
= true;
779 ap
= TREE_OPERAND (ap
, 0);
780 if (TREE_CODE (ap
) == ARRAY_REF
)
782 if (! integer_zerop (TREE_OPERAND (ap
, 1)))
784 va_list_escapes
= true;
787 ap
= TREE_OPERAND (ap
, 0);
789 if (TYPE_MAIN_VARIANT (TREE_TYPE (ap
))
790 != TYPE_MAIN_VARIANT (targetm
.fn_abi_va_list (fun
->decl
))
791 || TREE_CODE (ap
) != VAR_DECL
)
793 va_list_escapes
= true;
797 if (is_global_var (ap
))
799 va_list_escapes
= true;
803 bitmap_set_bit (si
.va_list_vars
, DECL_UID (ap
) + num_ssa_names
);
805 /* VA_START_BB and VA_START_AP will be only used if there is just
806 one va_start in the function. */
815 /* If there were no va_start uses in the function, there is no need to
817 if (si
.va_start_count
== 0)
820 /* If some va_list arguments weren't local, we can't optimize. */
824 /* For void * or char * va_list, something useful can be done only
825 if there is just one va_start. */
826 if (va_list_simple_ptr
&& si
.va_start_count
> 1)
828 va_list_escapes
= true;
832 /* For struct * va_list, if the backend didn't tell us what the counter fields
833 are, there is nothing more we can do. */
834 if (!va_list_simple_ptr
835 && va_list_gpr_counter_field
== NULL_TREE
836 && va_list_fpr_counter_field
== NULL_TREE
)
838 va_list_escapes
= true;
842 /* For void * or char * va_list there is just one counter
843 (va_list itself). Use VA_LIST_GPR_SIZE for it. */
844 if (va_list_simple_ptr
)
845 fun
->va_list_fpr_size
= VA_LIST_MAX_FPR_SIZE
;
847 calculate_dominance_info (CDI_DOMINATORS
);
848 memset (&wi
, 0, sizeof (wi
));
849 wi
.info
= si
.va_list_vars
;
851 FOR_EACH_BB_FN (bb
, fun
)
853 si
.compute_sizes
= -1;
856 /* For va_list_simple_ptr, we have to check PHI nodes too. We treat
857 them as assignments for the purpose of escape analysis. This is
858 not needed for non-simple va_list because virtual phis don't perform
859 any real data movement. Also, check PHI nodes for taking address of
865 for (gphi_iterator i
= gsi_start_phis (bb
); !gsi_end_p (i
);
868 gphi
*phi
= i
.phi ();
869 lhs
= PHI_RESULT (phi
);
871 if (virtual_operand_p (lhs
))
874 if (va_list_simple_ptr
)
876 FOR_EACH_PHI_ARG (uop
, phi
, soi
, SSA_OP_USE
)
878 rhs
= USE_FROM_PTR (uop
);
879 if (va_list_ptr_read (&si
, rhs
, lhs
))
881 else if (va_list_ptr_write (&si
, lhs
, rhs
))
884 check_va_list_escapes (&si
, lhs
, rhs
);
886 if (si
.va_list_escapes
)
888 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
890 fputs ("va_list escapes in ", dump_file
);
891 print_gimple_stmt (dump_file
, phi
, 0, dump_flags
);
892 fputc ('\n', dump_file
);
894 va_list_escapes
= true;
899 for (unsigned j
= 0; !va_list_escapes
900 && j
< gimple_phi_num_args (phi
); ++j
)
901 if ((!va_list_simple_ptr
902 || TREE_CODE (gimple_phi_arg_def (phi
, j
)) != SSA_NAME
)
903 && walk_tree (gimple_phi_arg_def_ptr (phi
, j
),
904 find_va_list_reference
, &wi
, NULL
))
906 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
908 fputs ("va_list escapes in ", dump_file
);
909 print_gimple_stmt (dump_file
, phi
, 0, dump_flags
);
910 fputc ('\n', dump_file
);
912 va_list_escapes
= true;
916 for (gimple_stmt_iterator i
= gsi_start_bb (bb
);
917 !gsi_end_p (i
) && !va_list_escapes
;
920 gimple stmt
= gsi_stmt (i
);
922 /* Don't look at __builtin_va_{start,end}, they are ok. */
923 if (is_gimple_call (stmt
))
925 tree callee
= gimple_call_fndecl (stmt
);
928 && DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
929 && (DECL_FUNCTION_CODE (callee
) == BUILT_IN_VA_START
930 || DECL_FUNCTION_CODE (callee
) == BUILT_IN_VA_END
))
934 if (is_gimple_assign (stmt
))
936 lhs
= gimple_assign_lhs (stmt
);
937 rhs
= gimple_assign_rhs1 (stmt
);
939 if (va_list_simple_ptr
)
941 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt
))
942 == GIMPLE_SINGLE_RHS
)
944 /* Check for ap ={v} {}. */
945 if (TREE_CLOBBER_P (rhs
))
948 /* Check for tem = ap. */
949 else if (va_list_ptr_read (&si
, rhs
, lhs
))
952 /* Check for the last insn in:
957 else if (va_list_ptr_write (&si
, lhs
, rhs
))
961 if ((gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
962 && TREE_CODE (gimple_assign_rhs2 (stmt
)) == INTEGER_CST
)
963 || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt
))
964 || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt
))
965 == GIMPLE_SINGLE_RHS
))
966 check_va_list_escapes (&si
, lhs
, rhs
);
970 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt
))
971 == GIMPLE_SINGLE_RHS
)
973 /* Check for ap ={v} {}. */
974 if (TREE_CLOBBER_P (rhs
))
977 /* Check for ap[0].field = temp. */
978 else if (va_list_counter_struct_op (&si
, lhs
, rhs
, true))
981 /* Check for temp = ap[0].field. */
982 else if (va_list_counter_struct_op (&si
, rhs
, lhs
,
987 /* Do any architecture specific checking. */
988 if (targetm
.stdarg_optimize_hook
989 && targetm
.stdarg_optimize_hook (&si
, stmt
))
993 else if (is_gimple_debug (stmt
))
996 /* All other uses of va_list are either va_copy (that is not handled
997 in this optimization), taking address of va_list variable or
998 passing va_list to other functions (in that case va_list might
999 escape the function and therefore va_start needs to set it up
1000 fully), or some unexpected use of va_list. None of these should
1001 happen in a gimplified VA_ARG_EXPR. */
1002 if (si
.va_list_escapes
1003 || walk_gimple_op (stmt
, find_va_list_reference
, &wi
))
1005 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1007 fputs ("va_list escapes in ", dump_file
);
1008 print_gimple_stmt (dump_file
, stmt
, 0, dump_flags
);
1009 fputc ('\n', dump_file
);
1011 va_list_escapes
= true;
1015 if (va_list_escapes
)
1019 if (! va_list_escapes
1020 && va_list_simple_ptr
1021 && ! bitmap_empty_p (si
.va_list_escape_vars
)
1022 && check_all_va_list_escapes (&si
))
1023 va_list_escapes
= true;
1026 if (va_list_escapes
)
1028 fun
->va_list_gpr_size
= VA_LIST_MAX_GPR_SIZE
;
1029 fun
->va_list_fpr_size
= VA_LIST_MAX_FPR_SIZE
;
1031 BITMAP_FREE (si
.va_list_vars
);
1032 BITMAP_FREE (si
.va_list_escape_vars
);
1036 fprintf (dump_file
, "%s: va_list escapes %d, needs to save ",
1037 funcname
, (int) va_list_escapes
);
1038 if (fun
->va_list_gpr_size
>= VA_LIST_MAX_GPR_SIZE
)
1039 fputs ("all", dump_file
);
1041 fprintf (dump_file
, "%d", cfun
->va_list_gpr_size
);
1042 fputs (" GPR units and ", dump_file
);
1043 if (fun
->va_list_fpr_size
>= VA_LIST_MAX_FPR_SIZE
)
1044 fputs ("all", dump_file
);
1046 fprintf (dump_file
, "%d", cfun
->va_list_fpr_size
);
1047 fputs (" FPR units.\n", dump_file
);
1055 make_pass_stdarg (gcc::context
*ctxt
)
1057 return new pass_stdarg (ctxt
);