OSDN Git Service

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