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"
27 #include "hard-reg-set.h"
30 #include "fold-const.h"
31 #include "langhooks.h"
32 #include "gimple-pretty-print.h"
34 #include "internal-fn.h"
35 #include "gimple-iterator.h"
36 #include "gimple-walk.h"
38 #include "tree-into-ssa.h"
40 #include "tree-pass.h"
41 #include "tree-stdarg.h"
43 /* A simple pass that attempts to optimize stdarg functions on architectures
44 that need to save register arguments to stack on entry to stdarg functions.
45 If the function doesn't use any va_start macros, no registers need to
46 be saved. If va_start macros are used, the va_list variables don't escape
47 the function, it is only necessary to save registers that will be used
48 in va_arg macros. E.g. if va_arg is only used with integral types
49 in the function, floating point registers don't need to be saved, etc. */
52 /* Return true if basic block VA_ARG_BB is dominated by VA_START_BB and
53 is executed at most as many times as VA_START_BB. */
56 reachable_at_most_once (basic_block va_arg_bb
, basic_block va_start_bb
)
58 vec
<edge
> stack
= vNULL
;
64 if (va_arg_bb
== va_start_bb
)
67 if (! dominated_by_p (CDI_DOMINATORS
, va_arg_bb
, va_start_bb
))
70 visited
= sbitmap_alloc (last_basic_block_for_fn (cfun
));
71 bitmap_clear (visited
);
74 FOR_EACH_EDGE (e
, ei
, va_arg_bb
->preds
)
77 while (! stack
.is_empty ())
84 if (e
->flags
& EDGE_COMPLEX
)
90 if (src
== va_start_bb
)
93 /* va_arg_bb can be executed more times than va_start_bb. */
100 gcc_assert (src
!= ENTRY_BLOCK_PTR_FOR_FN (cfun
));
102 if (! bitmap_bit_p (visited
, src
->index
))
104 bitmap_set_bit (visited
, src
->index
);
105 FOR_EACH_EDGE (e
, ei
, src
->preds
)
111 sbitmap_free (visited
);
116 /* For statement COUNTER = RHS, if RHS is COUNTER + constant,
117 return constant, otherwise return HOST_WIDE_INT_M1U.
118 GPR_P is true if this is GPR counter. */
120 static unsigned HOST_WIDE_INT
121 va_list_counter_bump (struct stdarg_info
*si
, tree counter
, tree rhs
,
126 unsigned HOST_WIDE_INT ret
= 0, val
, counter_val
;
127 unsigned int max_size
;
129 if (si
->offsets
== NULL
)
133 si
->offsets
= XNEWVEC (int, num_ssa_names
);
134 for (i
= 0; i
< num_ssa_names
; ++i
)
138 counter_val
= gpr_p
? cfun
->va_list_gpr_size
: cfun
->va_list_fpr_size
;
139 max_size
= gpr_p
? VA_LIST_MAX_GPR_SIZE
: VA_LIST_MAX_FPR_SIZE
;
140 orig_lhs
= lhs
= rhs
;
143 enum tree_code rhs_code
;
146 if (si
->offsets
[SSA_NAME_VERSION (lhs
)] != -1)
148 if (counter_val
>= max_size
)
154 ret
-= counter_val
- si
->offsets
[SSA_NAME_VERSION (lhs
)];
158 stmt
= SSA_NAME_DEF_STMT (lhs
);
160 if (!is_gimple_assign (stmt
) || gimple_assign_lhs (stmt
) != lhs
)
161 return HOST_WIDE_INT_M1U
;
163 rhs_code
= gimple_assign_rhs_code (stmt
);
164 rhs1
= gimple_assign_rhs1 (stmt
);
165 if ((get_gimple_rhs_class (rhs_code
) == GIMPLE_SINGLE_RHS
166 || gimple_assign_cast_p (stmt
))
167 && TREE_CODE (rhs1
) == SSA_NAME
)
173 if ((rhs_code
== POINTER_PLUS_EXPR
174 || rhs_code
== PLUS_EXPR
)
175 && TREE_CODE (rhs1
) == SSA_NAME
176 && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt
)))
178 ret
+= tree_to_uhwi (gimple_assign_rhs2 (stmt
));
183 if (rhs_code
== ADDR_EXPR
184 && TREE_CODE (TREE_OPERAND (rhs1
, 0)) == MEM_REF
185 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 0)) == SSA_NAME
186 && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 1)))
188 ret
+= tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 1));
189 lhs
= TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 0);
193 if (get_gimple_rhs_class (rhs_code
) != GIMPLE_SINGLE_RHS
)
194 return HOST_WIDE_INT_M1U
;
196 rhs
= gimple_assign_rhs1 (stmt
);
197 if (TREE_CODE (counter
) != TREE_CODE (rhs
))
198 return HOST_WIDE_INT_M1U
;
200 if (TREE_CODE (counter
) == COMPONENT_REF
)
202 if (get_base_address (counter
) != get_base_address (rhs
)
203 || TREE_CODE (TREE_OPERAND (rhs
, 1)) != FIELD_DECL
204 || TREE_OPERAND (counter
, 1) != TREE_OPERAND (rhs
, 1))
205 return HOST_WIDE_INT_M1U
;
207 else if (counter
!= rhs
)
208 return HOST_WIDE_INT_M1U
;
214 val
= ret
+ counter_val
;
217 enum tree_code rhs_code
;
220 if (si
->offsets
[SSA_NAME_VERSION (lhs
)] != -1)
224 si
->offsets
[SSA_NAME_VERSION (lhs
)] = max_size
;
226 si
->offsets
[SSA_NAME_VERSION (lhs
)] = val
;
228 stmt
= SSA_NAME_DEF_STMT (lhs
);
230 rhs_code
= gimple_assign_rhs_code (stmt
);
231 rhs1
= gimple_assign_rhs1 (stmt
);
232 if ((get_gimple_rhs_class (rhs_code
) == GIMPLE_SINGLE_RHS
233 || gimple_assign_cast_p (stmt
))
234 && TREE_CODE (rhs1
) == SSA_NAME
)
240 if ((rhs_code
== POINTER_PLUS_EXPR
241 || rhs_code
== PLUS_EXPR
)
242 && TREE_CODE (rhs1
) == SSA_NAME
243 && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt
)))
245 val
-= tree_to_uhwi (gimple_assign_rhs2 (stmt
));
250 if (rhs_code
== ADDR_EXPR
251 && TREE_CODE (TREE_OPERAND (rhs1
, 0)) == MEM_REF
252 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 0)) == SSA_NAME
253 && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 1)))
255 val
-= tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 1));
256 lhs
= TREE_OPERAND (TREE_OPERAND (rhs1
, 0), 0);
267 /* Called by walk_tree to look for references to va_list variables. */
270 find_va_list_reference (tree
*tp
, int *walk_subtrees ATTRIBUTE_UNUSED
,
273 bitmap va_list_vars
= (bitmap
) ((struct walk_stmt_info
*) data
)->info
;
276 if (TREE_CODE (var
) == SSA_NAME
)
278 if (bitmap_bit_p (va_list_vars
, SSA_NAME_VERSION (var
)))
281 else if (TREE_CODE (var
) == VAR_DECL
)
283 if (bitmap_bit_p (va_list_vars
, DECL_UID (var
) + num_ssa_names
))
291 /* Helper function of va_list_counter_struct_op. Compute
292 cfun->va_list_{g,f}pr_size. AP is a va_list GPR/FPR counter,
293 if WRITE_P is true, seen in AP = VAR, otherwise seen in VAR = AP
294 statement. GPR_P is true if AP is a GPR counter, false if it is
298 va_list_counter_op (struct stdarg_info
*si
, tree ap
, tree var
, bool gpr_p
,
301 unsigned HOST_WIDE_INT increment
;
303 if (si
->compute_sizes
< 0)
305 si
->compute_sizes
= 0;
306 if (si
->va_start_count
== 1
307 && reachable_at_most_once (si
->bb
, si
->va_start_bb
))
308 si
->compute_sizes
= 1;
310 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
312 "bb%d will %sbe executed at most once for each va_start "
313 "in bb%d\n", si
->bb
->index
, si
->compute_sizes
? "" : "not ",
314 si
->va_start_bb
->index
);
319 && (increment
= va_list_counter_bump (si
, ap
, var
, gpr_p
)) + 1 > 1)
321 if (gpr_p
&& cfun
->va_list_gpr_size
+ increment
< VA_LIST_MAX_GPR_SIZE
)
323 cfun
->va_list_gpr_size
+= increment
;
327 if (!gpr_p
&& cfun
->va_list_fpr_size
+ increment
< VA_LIST_MAX_FPR_SIZE
)
329 cfun
->va_list_fpr_size
+= increment
;
334 if (write_p
|| !si
->compute_sizes
)
337 cfun
->va_list_gpr_size
= VA_LIST_MAX_GPR_SIZE
;
339 cfun
->va_list_fpr_size
= VA_LIST_MAX_FPR_SIZE
;
344 /* If AP is a va_list GPR/FPR counter, compute cfun->va_list_{g,f}pr_size.
345 If WRITE_P is true, AP has been seen in AP = VAR assignment, if WRITE_P
346 is false, AP has been seen in VAR = AP assignment.
347 Return true if the AP = VAR (resp. VAR = AP) statement is a recognized
348 va_arg operation that doesn't cause the va_list variable to escape
352 va_list_counter_struct_op (struct stdarg_info
*si
, tree ap
, tree var
,
357 if (TREE_CODE (ap
) != COMPONENT_REF
358 || TREE_CODE (TREE_OPERAND (ap
, 1)) != FIELD_DECL
)
361 if (TREE_CODE (var
) != SSA_NAME
362 || bitmap_bit_p (si
->va_list_vars
, SSA_NAME_VERSION (var
)))
365 base
= get_base_address (ap
);
366 if (TREE_CODE (base
) != VAR_DECL
367 || !bitmap_bit_p (si
->va_list_vars
, DECL_UID (base
) + num_ssa_names
))
370 if (TREE_OPERAND (ap
, 1) == va_list_gpr_counter_field
)
371 va_list_counter_op (si
, ap
, var
, true, write_p
);
372 else if (TREE_OPERAND (ap
, 1) == va_list_fpr_counter_field
)
373 va_list_counter_op (si
, ap
, var
, false, write_p
);
379 /* Check for TEM = AP. Return true if found and the caller shouldn't
380 search for va_list references in the statement. */
383 va_list_ptr_read (struct stdarg_info
*si
, tree ap
, tree tem
)
385 if (TREE_CODE (ap
) != VAR_DECL
386 || !bitmap_bit_p (si
->va_list_vars
, DECL_UID (ap
) + num_ssa_names
))
389 if (TREE_CODE (tem
) != SSA_NAME
390 || bitmap_bit_p (si
->va_list_vars
, SSA_NAME_VERSION (tem
)))
393 if (si
->compute_sizes
< 0)
395 si
->compute_sizes
= 0;
396 if (si
->va_start_count
== 1
397 && reachable_at_most_once (si
->bb
, si
->va_start_bb
))
398 si
->compute_sizes
= 1;
400 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
402 "bb%d will %sbe executed at most once for each va_start "
403 "in bb%d\n", si
->bb
->index
, si
->compute_sizes
? "" : "not ",
404 si
->va_start_bb
->index
);
407 /* For void * or char * va_list types, there is just one counter.
408 If va_arg is used in a loop, we don't know how many registers need
410 if (! si
->compute_sizes
)
413 if (va_list_counter_bump (si
, ap
, tem
, true) == HOST_WIDE_INT_M1U
)
416 /* Note the temporary, as we need to track whether it doesn't escape
417 the current function. */
418 bitmap_set_bit (si
->va_list_escape_vars
, SSA_NAME_VERSION (tem
));
428 sequence and update cfun->va_list_gpr_size. Return true if found. */
431 va_list_ptr_write (struct stdarg_info
*si
, tree ap
, tree tem2
)
433 unsigned HOST_WIDE_INT increment
;
435 if (TREE_CODE (ap
) != VAR_DECL
436 || !bitmap_bit_p (si
->va_list_vars
, DECL_UID (ap
) + num_ssa_names
))
439 if (TREE_CODE (tem2
) != SSA_NAME
440 || bitmap_bit_p (si
->va_list_vars
, SSA_NAME_VERSION (tem2
)))
443 if (si
->compute_sizes
<= 0)
446 increment
= va_list_counter_bump (si
, ap
, tem2
, true);
447 if (increment
+ 1 <= 1)
450 if (cfun
->va_list_gpr_size
+ increment
< VA_LIST_MAX_GPR_SIZE
)
451 cfun
->va_list_gpr_size
+= increment
;
453 cfun
->va_list_gpr_size
= VA_LIST_MAX_GPR_SIZE
;
459 /* If RHS is X, (some type *) X or X + CST for X a temporary variable
460 containing value of some va_list variable plus optionally some constant,
461 either set si->va_list_escapes or add LHS to si->va_list_escape_vars,
462 depending whether LHS is a function local temporary. */
465 check_va_list_escapes (struct stdarg_info
*si
, tree lhs
, tree rhs
)
467 if (! POINTER_TYPE_P (TREE_TYPE (rhs
)))
470 if (TREE_CODE (rhs
) == SSA_NAME
)
472 if (! bitmap_bit_p (si
->va_list_escape_vars
, SSA_NAME_VERSION (rhs
)))
475 else if (TREE_CODE (rhs
) == ADDR_EXPR
476 && TREE_CODE (TREE_OPERAND (rhs
, 0)) == MEM_REF
477 && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs
, 0), 0)) == SSA_NAME
)
479 tree ptr
= TREE_OPERAND (TREE_OPERAND (rhs
, 0), 0);
480 if (! bitmap_bit_p (si
->va_list_escape_vars
, SSA_NAME_VERSION (ptr
)))
486 if (TREE_CODE (lhs
) != SSA_NAME
)
488 si
->va_list_escapes
= true;
492 if (si
->compute_sizes
< 0)
494 si
->compute_sizes
= 0;
495 if (si
->va_start_count
== 1
496 && reachable_at_most_once (si
->bb
, si
->va_start_bb
))
497 si
->compute_sizes
= 1;
499 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
501 "bb%d will %sbe executed at most once for each va_start "
502 "in bb%d\n", si
->bb
->index
, si
->compute_sizes
? "" : "not ",
503 si
->va_start_bb
->index
);
506 /* For void * or char * va_list types, there is just one counter.
507 If va_arg is used in a loop, we don't know how many registers need
509 if (! si
->compute_sizes
)
511 si
->va_list_escapes
= true;
515 if (va_list_counter_bump (si
, si
->va_start_ap
, lhs
, true)
516 == HOST_WIDE_INT_M1U
)
518 si
->va_list_escapes
= true;
522 bitmap_set_bit (si
->va_list_escape_vars
, SSA_NAME_VERSION (lhs
));
526 /* Check all uses of temporaries from si->va_list_escape_vars bitmap.
527 Return true if va_list might be escaping. */
530 check_all_va_list_escapes (struct stdarg_info
*si
)
534 FOR_EACH_BB_FN (bb
, cfun
)
536 for (gphi_iterator i
= gsi_start_phis (bb
); !gsi_end_p (i
);
542 gphi
*phi
= i
.phi ();
544 lhs
= PHI_RESULT (phi
);
545 if (virtual_operand_p (lhs
)
546 || bitmap_bit_p (si
->va_list_escape_vars
,
547 SSA_NAME_VERSION (lhs
)))
550 FOR_EACH_PHI_ARG (uop
, phi
, soi
, SSA_OP_USE
)
552 tree rhs
= USE_FROM_PTR (uop
);
553 if (TREE_CODE (rhs
) == SSA_NAME
554 && bitmap_bit_p (si
->va_list_escape_vars
,
555 SSA_NAME_VERSION (rhs
)))
557 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
559 fputs ("va_list escapes in ", dump_file
);
560 print_gimple_stmt (dump_file
, phi
, 0, dump_flags
);
561 fputc ('\n', dump_file
);
568 for (gimple_stmt_iterator i
= gsi_start_bb (bb
); !gsi_end_p (i
);
571 gimple stmt
= gsi_stmt (i
);
575 if (is_gimple_debug (stmt
))
578 FOR_EACH_SSA_TREE_OPERAND (use
, stmt
, iter
, SSA_OP_ALL_USES
)
580 if (! bitmap_bit_p (si
->va_list_escape_vars
,
581 SSA_NAME_VERSION (use
)))
584 if (is_gimple_assign (stmt
))
586 tree rhs
= gimple_assign_rhs1 (stmt
);
587 enum tree_code rhs_code
= gimple_assign_rhs_code (stmt
);
590 if (rhs_code
== MEM_REF
591 && TREE_OPERAND (rhs
, 0) == use
592 && TYPE_SIZE_UNIT (TREE_TYPE (rhs
))
593 && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (rhs
)))
594 && si
->offsets
[SSA_NAME_VERSION (use
)] != -1)
596 unsigned HOST_WIDE_INT gpr_size
;
597 tree access_size
= TYPE_SIZE_UNIT (TREE_TYPE (rhs
));
599 gpr_size
= si
->offsets
[SSA_NAME_VERSION (use
)]
600 + tree_to_shwi (TREE_OPERAND (rhs
, 1))
601 + tree_to_uhwi (access_size
);
602 if (gpr_size
>= VA_LIST_MAX_GPR_SIZE
)
603 cfun
->va_list_gpr_size
= VA_LIST_MAX_GPR_SIZE
;
604 else if (gpr_size
> cfun
->va_list_gpr_size
)
605 cfun
->va_list_gpr_size
= gpr_size
;
609 /* va_arg sequences may contain
610 other_ap_temp = ap_temp;
611 other_ap_temp = ap_temp + constant;
612 other_ap_temp = (some_type *) ap_temp;
616 && ((rhs_code
== POINTER_PLUS_EXPR
617 && (TREE_CODE (gimple_assign_rhs2 (stmt
))
619 || gimple_assign_cast_p (stmt
)
620 || (get_gimple_rhs_class (rhs_code
)
621 == GIMPLE_SINGLE_RHS
)))
623 tree lhs
= gimple_assign_lhs (stmt
);
625 if (TREE_CODE (lhs
) == SSA_NAME
626 && bitmap_bit_p (si
->va_list_escape_vars
,
627 SSA_NAME_VERSION (lhs
)))
630 if (TREE_CODE (lhs
) == VAR_DECL
631 && bitmap_bit_p (si
->va_list_vars
,
632 DECL_UID (lhs
) + num_ssa_names
))
635 else if (rhs_code
== ADDR_EXPR
636 && TREE_CODE (TREE_OPERAND (rhs
, 0)) == MEM_REF
637 && TREE_OPERAND (TREE_OPERAND (rhs
, 0), 0) == use
)
639 tree lhs
= gimple_assign_lhs (stmt
);
641 if (bitmap_bit_p (si
->va_list_escape_vars
,
642 SSA_NAME_VERSION (lhs
)))
647 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
649 fputs ("va_list escapes in ", dump_file
);
650 print_gimple_stmt (dump_file
, stmt
, 0, dump_flags
);
651 fputc ('\n', dump_file
);
661 /* Optimize FUN->va_list_gpr_size and FUN->va_list_fpr_size. */
664 optimize_va_list_gpr_fpr_size (function
*fun
)
667 bool va_list_escapes
= false;
668 bool va_list_simple_ptr
;
669 struct stdarg_info si
;
670 struct walk_stmt_info wi
;
671 const char *funcname
= NULL
;
674 fun
->va_list_gpr_size
= 0;
675 fun
->va_list_fpr_size
= 0;
676 memset (&si
, 0, sizeof (si
));
677 si
.va_list_vars
= BITMAP_ALLOC (NULL
);
678 si
.va_list_escape_vars
= BITMAP_ALLOC (NULL
);
681 funcname
= lang_hooks
.decl_printable_name (current_function_decl
, 2);
683 cfun_va_list
= targetm
.fn_abi_va_list (fun
->decl
);
684 va_list_simple_ptr
= POINTER_TYPE_P (cfun_va_list
)
685 && (TREE_TYPE (cfun_va_list
) == void_type_node
686 || TREE_TYPE (cfun_va_list
) == char_type_node
);
687 gcc_assert (is_gimple_reg_type (cfun_va_list
) == va_list_simple_ptr
);
689 FOR_EACH_BB_FN (bb
, fun
)
691 gimple_stmt_iterator i
;
693 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
695 gimple stmt
= gsi_stmt (i
);
698 if (!is_gimple_call (stmt
))
701 callee
= gimple_call_fndecl (stmt
);
703 || DECL_BUILT_IN_CLASS (callee
) != BUILT_IN_NORMAL
)
706 switch (DECL_FUNCTION_CODE (callee
))
708 case BUILT_IN_VA_START
:
710 /* If old style builtins are used, don't optimize anything. */
711 case BUILT_IN_SAVEREGS
:
712 case BUILT_IN_NEXT_ARG
:
713 va_list_escapes
= true;
720 ap
= gimple_call_arg (stmt
, 0);
722 if (TREE_CODE (ap
) != ADDR_EXPR
)
724 va_list_escapes
= true;
727 ap
= TREE_OPERAND (ap
, 0);
728 if (TREE_CODE (ap
) == ARRAY_REF
)
730 if (! integer_zerop (TREE_OPERAND (ap
, 1)))
732 va_list_escapes
= true;
735 ap
= TREE_OPERAND (ap
, 0);
737 if (TYPE_MAIN_VARIANT (TREE_TYPE (ap
))
738 != TYPE_MAIN_VARIANT (targetm
.fn_abi_va_list (fun
->decl
))
739 || TREE_CODE (ap
) != VAR_DECL
)
741 va_list_escapes
= true;
745 if (is_global_var (ap
))
747 va_list_escapes
= true;
751 bitmap_set_bit (si
.va_list_vars
, DECL_UID (ap
) + num_ssa_names
);
753 /* VA_START_BB and VA_START_AP will be only used if there is just
754 one va_start in the function. */
763 /* If there were no va_start uses in the function, there is no need to
765 if (si
.va_start_count
== 0)
768 /* If some va_list arguments weren't local, we can't optimize. */
772 /* For void * or char * va_list, something useful can be done only
773 if there is just one va_start. */
774 if (va_list_simple_ptr
&& si
.va_start_count
> 1)
776 va_list_escapes
= true;
780 /* For struct * va_list, if the backend didn't tell us what the counter fields
781 are, there is nothing more we can do. */
782 if (!va_list_simple_ptr
783 && va_list_gpr_counter_field
== NULL_TREE
784 && va_list_fpr_counter_field
== NULL_TREE
)
786 va_list_escapes
= true;
790 /* For void * or char * va_list there is just one counter
791 (va_list itself). Use VA_LIST_GPR_SIZE for it. */
792 if (va_list_simple_ptr
)
793 fun
->va_list_fpr_size
= VA_LIST_MAX_FPR_SIZE
;
795 calculate_dominance_info (CDI_DOMINATORS
);
796 memset (&wi
, 0, sizeof (wi
));
797 wi
.info
= si
.va_list_vars
;
799 FOR_EACH_BB_FN (bb
, fun
)
801 si
.compute_sizes
= -1;
804 /* For va_list_simple_ptr, we have to check PHI nodes too. We treat
805 them as assignments for the purpose of escape analysis. This is
806 not needed for non-simple va_list because virtual phis don't perform
807 any real data movement. Also, check PHI nodes for taking address of
813 for (gphi_iterator i
= gsi_start_phis (bb
); !gsi_end_p (i
);
816 gphi
*phi
= i
.phi ();
817 lhs
= PHI_RESULT (phi
);
819 if (virtual_operand_p (lhs
))
822 if (va_list_simple_ptr
)
824 FOR_EACH_PHI_ARG (uop
, phi
, soi
, SSA_OP_USE
)
826 rhs
= USE_FROM_PTR (uop
);
827 if (va_list_ptr_read (&si
, rhs
, lhs
))
829 else if (va_list_ptr_write (&si
, lhs
, rhs
))
832 check_va_list_escapes (&si
, lhs
, rhs
);
834 if (si
.va_list_escapes
)
836 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
838 fputs ("va_list escapes in ", dump_file
);
839 print_gimple_stmt (dump_file
, phi
, 0, dump_flags
);
840 fputc ('\n', dump_file
);
842 va_list_escapes
= true;
847 for (unsigned j
= 0; !va_list_escapes
848 && j
< gimple_phi_num_args (phi
); ++j
)
849 if ((!va_list_simple_ptr
850 || TREE_CODE (gimple_phi_arg_def (phi
, j
)) != SSA_NAME
)
851 && walk_tree (gimple_phi_arg_def_ptr (phi
, j
),
852 find_va_list_reference
, &wi
, NULL
))
854 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
856 fputs ("va_list escapes in ", dump_file
);
857 print_gimple_stmt (dump_file
, phi
, 0, dump_flags
);
858 fputc ('\n', dump_file
);
860 va_list_escapes
= true;
864 for (gimple_stmt_iterator i
= gsi_start_bb (bb
);
865 !gsi_end_p (i
) && !va_list_escapes
;
868 gimple stmt
= gsi_stmt (i
);
870 /* Don't look at __builtin_va_{start,end}, they are ok. */
871 if (is_gimple_call (stmt
))
873 tree callee
= gimple_call_fndecl (stmt
);
876 && DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
877 && (DECL_FUNCTION_CODE (callee
) == BUILT_IN_VA_START
878 || DECL_FUNCTION_CODE (callee
) == BUILT_IN_VA_END
))
882 if (is_gimple_assign (stmt
))
884 lhs
= gimple_assign_lhs (stmt
);
885 rhs
= gimple_assign_rhs1 (stmt
);
887 if (va_list_simple_ptr
)
889 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt
))
890 == GIMPLE_SINGLE_RHS
)
892 /* Check for ap ={v} {}. */
893 if (TREE_CLOBBER_P (rhs
))
896 /* Check for tem = ap. */
897 else if (va_list_ptr_read (&si
, rhs
, lhs
))
900 /* Check for the last insn in:
905 else if (va_list_ptr_write (&si
, lhs
, rhs
))
909 if ((gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
910 && TREE_CODE (gimple_assign_rhs2 (stmt
)) == INTEGER_CST
)
911 || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt
))
912 || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt
))
913 == GIMPLE_SINGLE_RHS
))
914 check_va_list_escapes (&si
, lhs
, rhs
);
918 if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt
))
919 == GIMPLE_SINGLE_RHS
)
921 /* Check for ap ={v} {}. */
922 if (TREE_CLOBBER_P (rhs
))
925 /* Check for ap[0].field = temp. */
926 else if (va_list_counter_struct_op (&si
, lhs
, rhs
, true))
929 /* Check for temp = ap[0].field. */
930 else if (va_list_counter_struct_op (&si
, rhs
, lhs
,
935 /* Do any architecture specific checking. */
936 if (targetm
.stdarg_optimize_hook
937 && targetm
.stdarg_optimize_hook (&si
, stmt
))
941 else if (is_gimple_debug (stmt
))
944 /* All other uses of va_list are either va_copy (that is not handled
945 in this optimization), taking address of va_list variable or
946 passing va_list to other functions (in that case va_list might
947 escape the function and therefore va_start needs to set it up
948 fully), or some unexpected use of va_list. None of these should
949 happen in a gimplified VA_ARG_EXPR. */
950 if (si
.va_list_escapes
951 || walk_gimple_op (stmt
, find_va_list_reference
, &wi
))
953 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
955 fputs ("va_list escapes in ", dump_file
);
956 print_gimple_stmt (dump_file
, stmt
, 0, dump_flags
);
957 fputc ('\n', dump_file
);
959 va_list_escapes
= true;
967 if (! va_list_escapes
968 && va_list_simple_ptr
969 && ! bitmap_empty_p (si
.va_list_escape_vars
)
970 && check_all_va_list_escapes (&si
))
971 va_list_escapes
= true;
976 fun
->va_list_gpr_size
= VA_LIST_MAX_GPR_SIZE
;
977 fun
->va_list_fpr_size
= VA_LIST_MAX_FPR_SIZE
;
979 BITMAP_FREE (si
.va_list_vars
);
980 BITMAP_FREE (si
.va_list_escape_vars
);
984 fprintf (dump_file
, "%s: va_list escapes %d, needs to save ",
985 funcname
, (int) va_list_escapes
);
986 if (fun
->va_list_gpr_size
>= VA_LIST_MAX_GPR_SIZE
)
987 fputs ("all", dump_file
);
989 fprintf (dump_file
, "%d", cfun
->va_list_gpr_size
);
990 fputs (" GPR units and ", dump_file
);
991 if (fun
->va_list_fpr_size
>= VA_LIST_MAX_FPR_SIZE
)
992 fputs ("all", dump_file
);
994 fprintf (dump_file
, "%d", cfun
->va_list_fpr_size
);
995 fputs (" FPR units.\n", dump_file
);
999 /* Return true if STMT is IFN_VA_ARG. */
1002 gimple_call_ifn_va_arg_p (gimple stmt
)
1004 return (is_gimple_call (stmt
)
1005 && gimple_call_internal_p (stmt
)
1006 && gimple_call_internal_fn (stmt
) == IFN_VA_ARG
);
1009 /* Expand IFN_VA_ARGs in FUN. */
1012 expand_ifn_va_arg_1 (function
*fun
)
1014 bool modified
= false;
1016 gimple_stmt_iterator i
;
1017 location_t saved_location
;
1019 FOR_EACH_BB_FN (bb
, fun
)
1020 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
1022 gimple stmt
= gsi_stmt (i
);
1023 tree ap
, expr
, lhs
, type
;
1024 gimple_seq pre
= NULL
, post
= NULL
;
1026 if (!gimple_call_ifn_va_arg_p (stmt
))
1031 type
= TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt
, 1)));
1032 ap
= gimple_call_arg (stmt
, 0);
1034 /* Balanced out the &ap, usually added by build_va_arg. */
1035 ap
= build_fold_indirect_ref (ap
);
1037 push_gimplify_context (false);
1038 saved_location
= input_location
;
1039 input_location
= gimple_location (stmt
);
1041 /* Make it easier for the backends by protecting the valist argument
1042 from multiple evaluations. */
1043 gimplify_expr (&ap
, &pre
, &post
, is_gimple_min_lval
, fb_lvalue
);
1045 expr
= targetm
.gimplify_va_arg_expr (ap
, type
, &pre
, &post
);
1047 lhs
= gimple_call_lhs (stmt
);
1048 if (lhs
!= NULL_TREE
)
1050 unsigned int nargs
= gimple_call_num_args (stmt
);
1051 gcc_assert (useless_type_conversion_p (TREE_TYPE (lhs
), type
));
1055 /* We've transported the size of with WITH_SIZE_EXPR here as
1056 the last argument of the internal fn call. Now reinstate
1058 tree size
= gimple_call_arg (stmt
, nargs
- 1);
1059 expr
= build2 (WITH_SIZE_EXPR
, TREE_TYPE (expr
), expr
, size
);
1062 /* We use gimplify_assign here, rather than gimple_build_assign,
1063 because gimple_assign knows how to deal with variable-sized
1065 gimplify_assign (lhs
, expr
, &pre
);
1068 gimplify_expr (&expr
, &pre
, &post
, is_gimple_lvalue
, fb_lvalue
);
1070 input_location
= saved_location
;
1071 pop_gimplify_context (NULL
);
1073 gimple_seq_add_seq (&pre
, post
);
1074 update_modified_stmts (pre
);
1076 /* Add the sequence after IFN_VA_ARG. This splits the bb right
1077 after IFN_VA_ARG, and adds the sequence in one or more new bbs
1079 gimple_find_sub_bbs (pre
, &i
);
1081 /* Remove the IFN_VA_ARG gimple_call. It's the last stmt in the
1083 gsi_remove (&i
, true);
1084 gcc_assert (gsi_end_p (i
));
1086 /* We're walking here into the bbs which contain the expansion of
1087 IFN_VA_ARG, and will not contain another IFN_VA_ARG that needs
1088 expanding. We could try to skip walking these bbs, perhaps by
1089 walking backwards over gimples and bbs. */
1096 free_dominance_info (CDI_DOMINATORS
);
1097 update_ssa (TODO_update_ssa
);
1100 /* Expand IFN_VA_ARGs in FUN, if necessary. */
1103 expand_ifn_va_arg (function
*fun
)
1105 if ((fun
->curr_properties
& PROP_gimple_lva
) == 0)
1106 expand_ifn_va_arg_1 (fun
);
1110 gimple_stmt_iterator i
;
1111 FOR_EACH_BB_FN (bb
, fun
)
1112 for (i
= gsi_start_bb (bb
); !gsi_end_p (i
); gsi_next (&i
))
1113 gcc_assert (!gimple_call_ifn_va_arg_p (gsi_stmt (i
)));
1119 const pass_data pass_data_stdarg
=
1121 GIMPLE_PASS
, /* type */
1122 "stdarg", /* name */
1123 OPTGROUP_NONE
, /* optinfo_flags */
1124 TV_NONE
, /* tv_id */
1125 ( PROP_cfg
| PROP_ssa
), /* properties_required */
1126 PROP_gimple_lva
, /* properties_provided */
1127 0, /* properties_destroyed */
1128 0, /* todo_flags_start */
1129 0, /* todo_flags_finish */
1132 class pass_stdarg
: public gimple_opt_pass
1135 pass_stdarg (gcc::context
*ctxt
)
1136 : gimple_opt_pass (pass_data_stdarg
, ctxt
)
1139 /* opt_pass methods: */
1140 virtual bool gate (function
*)
1142 /* Always run this pass, in order to expand va_arg internal_fns. We
1143 also need to do that if fun->stdarg == 0, because a va_arg may also
1144 occur in a function without varargs, f.i. if when passing a va_list to
1145 another function. */
1149 virtual unsigned int execute (function
*);
1151 }; // class pass_stdarg
1154 pass_stdarg::execute (function
*fun
)
1156 /* TODO: Postpone expand_ifn_va_arg till after
1157 optimize_va_list_gpr_fpr_size. */
1158 expand_ifn_va_arg (fun
);
1161 /* This optimization is only for stdarg functions. */
1162 && fun
->stdarg
!= 0)
1163 optimize_va_list_gpr_fpr_size (fun
);
1171 make_pass_stdarg (gcc::context
*ctxt
)
1173 return new pass_stdarg (ctxt
);
1178 const pass_data pass_data_lower_vaarg
=
1180 GIMPLE_PASS
, /* type */
1181 "lower_vaarg", /* name */
1182 OPTGROUP_NONE
, /* optinfo_flags */
1183 TV_NONE
, /* tv_id */
1184 ( PROP_cfg
| PROP_ssa
), /* properties_required */
1185 PROP_gimple_lva
, /* properties_provided */
1186 0, /* properties_destroyed */
1187 0, /* todo_flags_start */
1188 0, /* todo_flags_finish */
1191 class pass_lower_vaarg
: public gimple_opt_pass
1194 pass_lower_vaarg (gcc::context
*ctxt
)
1195 : gimple_opt_pass (pass_data_lower_vaarg
, ctxt
)
1198 /* opt_pass methods: */
1199 virtual bool gate (function
*)
1201 return (cfun
->curr_properties
& PROP_gimple_lva
) == 0;
1204 virtual unsigned int execute (function
*);
1206 }; // class pass_lower_vaarg
1209 pass_lower_vaarg::execute (function
*fun
)
1211 expand_ifn_va_arg (fun
);
1218 make_pass_lower_vaarg (gcc::context
*ctxt
)
1220 return new pass_lower_vaarg (ctxt
);