OSDN Git Service

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