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