Daily bump.
[platform/upstream/gcc.git] / gcc / tree-stdarg.c
1 /* Pass computing data for optimizing stdarg functions.
2    Copyright (C) 2004-2021 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 "backend.h"
25 #include "target.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "tree-pass.h"
29 #include "ssa.h"
30 #include "gimple-pretty-print.h"
31 #include "fold-const.h"
32 #include "langhooks.h"
33 #include "gimple-iterator.h"
34 #include "gimple-walk.h"
35 #include "gimplify.h"
36 #include "tree-into-ssa.h"
37 #include "tree-cfg.h"
38 #include "tree-stdarg.h"
39
40 /* A simple pass that attempts to optimize stdarg functions on architectures
41    that need to save register arguments to stack on entry to stdarg functions.
42    If the function doesn't use any va_start macros, no registers need to
43    be saved.  If va_start macros are used, the va_list variables don't escape
44    the function, it is only necessary to save registers that will be used
45    in va_arg macros.  E.g. if va_arg is only used with integral types
46    in the function, floating point registers don't need to be saved, etc.  */
47
48
49 /* Return true if basic block VA_ARG_BB is dominated by VA_START_BB and
50    is executed at most as many times as VA_START_BB.  */
51
52 static bool
53 reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb)
54 {
55   auto_vec<edge, 10> stack;
56   edge e;
57   edge_iterator ei;
58   bool ret;
59
60   if (va_arg_bb == va_start_bb)
61     return true;
62
63   if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb))
64     return false;
65
66   auto_sbitmap visited (last_basic_block_for_fn (cfun));
67   bitmap_clear (visited);
68   ret = true;
69
70   FOR_EACH_EDGE (e, ei, va_arg_bb->preds)
71     stack.safe_push (e);
72
73   while (! stack.is_empty ())
74     {
75       basic_block src;
76
77       e = stack.pop ();
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_FOR_FN (cfun));
97
98       if (! bitmap_bit_p (visited, src->index))
99         {
100           bitmap_set_bit (visited, src->index);
101           FOR_EACH_EDGE (e, ei, src->preds)
102             stack.safe_push (e);
103         }
104     }
105
106   return ret;
107 }
108
109
110 /* For statement COUNTER = RHS, if RHS is COUNTER + constant,
111    return constant, otherwise return HOST_WIDE_INT_M1U.
112    GPR_P is true if this is GPR counter.  */
113
114 static unsigned HOST_WIDE_INT
115 va_list_counter_bump (struct stdarg_info *si, tree counter, tree rhs,
116                       bool gpr_p)
117 {
118   tree lhs, orig_lhs;
119   gimple *stmt;
120   unsigned HOST_WIDE_INT ret = 0, val, counter_val;
121   unsigned int max_size;
122
123   if (si->offsets == NULL)
124     {
125       unsigned int i;
126
127       si->offsets = XNEWVEC (int, num_ssa_names);
128       for (i = 0; i < num_ssa_names; ++i)
129         si->offsets[i] = -1;
130     }
131
132   counter_val = gpr_p ? cfun->va_list_gpr_size : cfun->va_list_fpr_size;
133   max_size = gpr_p ? VA_LIST_MAX_GPR_SIZE : VA_LIST_MAX_FPR_SIZE;
134   orig_lhs = lhs = rhs;
135   while (lhs)
136     {
137       enum tree_code rhs_code;
138       tree rhs1;
139
140       if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
141         {
142           if (counter_val >= max_size)
143             {
144               ret = max_size;
145               break;
146             }
147
148           ret -= counter_val - si->offsets[SSA_NAME_VERSION (lhs)];
149           break;
150         }
151
152       stmt = SSA_NAME_DEF_STMT (lhs);
153
154       if (!is_gimple_assign (stmt) || gimple_assign_lhs (stmt) != lhs)
155         return HOST_WIDE_INT_M1U;
156
157       rhs_code = gimple_assign_rhs_code (stmt);
158       rhs1 = gimple_assign_rhs1 (stmt);
159       if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
160            || gimple_assign_cast_p (stmt))
161           && TREE_CODE (rhs1) == SSA_NAME)
162         {
163           lhs = rhs1;
164           continue;
165         }
166
167       if ((rhs_code == POINTER_PLUS_EXPR
168            || rhs_code == PLUS_EXPR)
169           && TREE_CODE (rhs1) == SSA_NAME
170           && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))
171         {
172           ret += tree_to_uhwi (gimple_assign_rhs2 (stmt));
173           lhs = rhs1;
174           continue;
175         }
176
177       if (rhs_code == ADDR_EXPR 
178           && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
179           && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
180           && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1)))
181         {
182           ret += tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1));
183           lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
184           continue;
185         }
186
187       if (get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS)
188         return HOST_WIDE_INT_M1U;
189
190       rhs = gimple_assign_rhs1 (stmt);
191       if (TREE_CODE (counter) != TREE_CODE (rhs))
192         return HOST_WIDE_INT_M1U;
193
194       if (TREE_CODE (counter) == COMPONENT_REF)
195         {
196           if (get_base_address (counter) != get_base_address (rhs)
197               || TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL
198               || TREE_OPERAND (counter, 1) != TREE_OPERAND (rhs, 1))
199             return HOST_WIDE_INT_M1U;
200         }
201       else if (counter != rhs)
202         return HOST_WIDE_INT_M1U;
203
204       lhs = NULL;
205     }
206
207   lhs = orig_lhs;
208   val = ret + counter_val;
209   while (lhs)
210     {
211       enum tree_code rhs_code;
212       tree rhs1;
213
214       if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
215         break;
216
217       if (val >= max_size)
218         si->offsets[SSA_NAME_VERSION (lhs)] = max_size;
219       else
220         si->offsets[SSA_NAME_VERSION (lhs)] = val;
221
222       stmt = SSA_NAME_DEF_STMT (lhs);
223
224       rhs_code = gimple_assign_rhs_code (stmt);
225       rhs1 = gimple_assign_rhs1 (stmt);
226       if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
227            || gimple_assign_cast_p (stmt))
228           && TREE_CODE (rhs1) == SSA_NAME)
229         {
230           lhs = rhs1;
231           continue;
232         }
233
234       if ((rhs_code == POINTER_PLUS_EXPR
235            || rhs_code == PLUS_EXPR)
236           && TREE_CODE (rhs1) == SSA_NAME
237           && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))
238         {
239           val -= tree_to_uhwi (gimple_assign_rhs2 (stmt));
240           lhs = rhs1;
241           continue;
242         }
243
244       if (rhs_code == ADDR_EXPR 
245           && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
246           && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
247           && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1)))
248         {
249           val -= tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1));
250           lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
251           continue;
252         }
253
254       lhs = NULL;
255     }
256
257   return ret;
258 }
259
260
261 /* Called by walk_tree to look for references to va_list variables.  */
262
263 static tree
264 find_va_list_reference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
265                         void *data)
266 {
267   bitmap va_list_vars = (bitmap) ((struct walk_stmt_info *) data)->info;
268   tree var = *tp;
269
270   if (TREE_CODE (var) == SSA_NAME)
271     {
272       if (bitmap_bit_p (va_list_vars, SSA_NAME_VERSION (var)))
273         return var;
274     }
275   else if (VAR_P (var))
276     {
277       if (bitmap_bit_p (va_list_vars, DECL_UID (var) + num_ssa_names))
278         return var;
279     }
280
281   return NULL_TREE;
282 }
283
284
285 /* Helper function of va_list_counter_struct_op.  Compute
286    cfun->va_list_{g,f}pr_size.  AP is a va_list GPR/FPR counter,
287    if WRITE_P is true, seen in AP = VAR, otherwise seen in VAR = AP
288    statement.  GPR_P is true if AP is a GPR counter, false if it is
289    a FPR counter.  */
290
291 static void
292 va_list_counter_op (struct stdarg_info *si, tree ap, tree var, bool gpr_p,
293                     bool write_p)
294 {
295   unsigned HOST_WIDE_INT increment;
296
297   if (si->compute_sizes < 0)
298     {
299       si->compute_sizes = 0;
300       if (si->va_start_count == 1
301           && reachable_at_most_once (si->bb, si->va_start_bb))
302         si->compute_sizes = 1;
303
304       if (dump_file && (dump_flags & TDF_DETAILS))
305         fprintf (dump_file,
306                  "bb%d will %sbe executed at most once for each va_start "
307                  "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
308                  si->va_start_bb->index);
309     }
310
311   if (write_p
312       && si->compute_sizes
313       && (increment = va_list_counter_bump (si, ap, var, gpr_p)) + 1 > 1)
314     {
315       if (gpr_p && cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
316         {
317           cfun->va_list_gpr_size += increment;
318           return;
319         }
320
321       if (!gpr_p && cfun->va_list_fpr_size + increment < VA_LIST_MAX_FPR_SIZE)
322         {
323           cfun->va_list_fpr_size += increment;
324           return;
325         }
326     }
327
328   if (write_p || !si->compute_sizes)
329     {
330       if (gpr_p)
331         cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
332       else
333         cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
334     }
335 }
336
337
338 /* If AP is a va_list GPR/FPR counter, compute cfun->va_list_{g,f}pr_size.
339    If WRITE_P is true, AP has been seen in AP = VAR assignment, if WRITE_P
340    is false, AP has been seen in VAR = AP assignment.
341    Return true if the AP = VAR (resp. VAR = AP) statement is a recognized
342    va_arg operation that doesn't cause the va_list variable to escape
343    current function.  */
344
345 static bool
346 va_list_counter_struct_op (struct stdarg_info *si, tree ap, tree var,
347                            bool write_p)
348 {
349   tree base;
350
351   if (TREE_CODE (ap) != COMPONENT_REF
352       || TREE_CODE (TREE_OPERAND (ap, 1)) != FIELD_DECL)
353     return false;
354
355   if (TREE_CODE (var) != SSA_NAME
356       || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (var)))
357     return false;
358
359   base = get_base_address (ap);
360   if (!VAR_P (base)
361       || !bitmap_bit_p (si->va_list_vars, DECL_UID (base) + num_ssa_names))
362     return false;
363
364   if (TREE_OPERAND (ap, 1) == va_list_gpr_counter_field)
365     va_list_counter_op (si, ap, var, true, write_p);
366   else if (TREE_OPERAND (ap, 1) == va_list_fpr_counter_field)
367     va_list_counter_op (si, ap, var, false, write_p);
368
369   return true;
370 }
371
372
373 /* Check for TEM = AP.  Return true if found and the caller shouldn't
374    search for va_list references in the statement.  */
375
376 static bool
377 va_list_ptr_read (struct stdarg_info *si, tree ap, tree tem)
378 {
379   if (!VAR_P (ap)
380       || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
381     return false;
382
383   if (TREE_CODE (tem) != SSA_NAME
384       || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem)))
385     return false;
386
387   if (si->compute_sizes < 0)
388     {
389       si->compute_sizes = 0;
390       if (si->va_start_count == 1
391           && reachable_at_most_once (si->bb, si->va_start_bb))
392         si->compute_sizes = 1;
393
394       if (dump_file && (dump_flags & TDF_DETAILS))
395         fprintf (dump_file,
396                  "bb%d will %sbe executed at most once for each va_start "
397                  "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
398                  si->va_start_bb->index);
399     }
400
401   /* For void * or char * va_list types, there is just one counter.
402      If va_arg is used in a loop, we don't know how many registers need
403      saving.  */
404   if (! si->compute_sizes)
405     return false;
406
407   if (va_list_counter_bump (si, ap, tem, true) == HOST_WIDE_INT_M1U)
408     return false;
409
410   /* Note the temporary, as we need to track whether it doesn't escape
411      the current function.  */
412   bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (tem));
413
414   return true;
415 }
416
417
418 /* Check for:
419      tem1 = AP;
420      TEM2 = tem1 + CST;
421      AP = TEM2;
422    sequence and update cfun->va_list_gpr_size.  Return true if found.  */
423
424 static bool
425 va_list_ptr_write (struct stdarg_info *si, tree ap, tree tem2)
426 {
427   unsigned HOST_WIDE_INT increment;
428
429   if (!VAR_P (ap)
430       || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
431     return false;
432
433   if (TREE_CODE (tem2) != SSA_NAME
434       || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem2)))
435     return false;
436
437   if (si->compute_sizes <= 0)
438     return false;
439
440   increment = va_list_counter_bump (si, ap, tem2, true);
441   if (increment + 1 <= 1)
442     return false;
443
444   if (cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
445     cfun->va_list_gpr_size += increment;
446   else
447     cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
448
449   return true;
450 }
451
452
453 /* If RHS is X, (some type *) X or X + CST for X a temporary variable
454    containing value of some va_list variable plus optionally some constant,
455    either set si->va_list_escapes or add LHS to si->va_list_escape_vars,
456    depending whether LHS is a function local temporary.  */
457
458 static void
459 check_va_list_escapes (struct stdarg_info *si, tree lhs, tree rhs)
460 {
461   if (! POINTER_TYPE_P (TREE_TYPE (rhs)))
462     return;
463
464   if (TREE_CODE (rhs) == SSA_NAME)
465     {
466       if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (rhs)))
467         return;
468     }
469   else if (TREE_CODE (rhs) == ADDR_EXPR
470            && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
471            && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)) == SSA_NAME)
472     {
473       tree ptr = TREE_OPERAND (TREE_OPERAND (rhs, 0), 0);
474       if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (ptr)))
475         return;
476     }
477   else
478     return;
479
480   if (TREE_CODE (lhs) != SSA_NAME)
481     {
482       si->va_list_escapes = true;
483       return;
484     }
485
486   if (si->compute_sizes < 0)
487     {
488       si->compute_sizes = 0;
489       if (si->va_start_count == 1
490           && reachable_at_most_once (si->bb, si->va_start_bb))
491         si->compute_sizes = 1;
492
493       if (dump_file && (dump_flags & TDF_DETAILS))
494         fprintf (dump_file,
495                  "bb%d will %sbe executed at most once for each va_start "
496                  "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
497                  si->va_start_bb->index);
498     }
499
500   /* For void * or char * va_list types, there is just one counter.
501      If va_arg is used in a loop, we don't know how many registers need
502      saving.  */
503   if (! si->compute_sizes)
504     {
505       si->va_list_escapes = true;
506       return;
507     }
508
509   if (va_list_counter_bump (si, si->va_start_ap, lhs, true)
510       == HOST_WIDE_INT_M1U)
511     {
512       si->va_list_escapes = true;
513       return;
514     }
515
516   bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (lhs));
517 }
518
519
520 /* Check all uses of temporaries from si->va_list_escape_vars bitmap.
521    Return true if va_list might be escaping.  */
522
523 static bool
524 check_all_va_list_escapes (struct stdarg_info *si)
525 {
526   basic_block bb;
527
528   FOR_EACH_BB_FN (bb, cfun)
529     {
530       for (gphi_iterator i = gsi_start_phis (bb); !gsi_end_p (i);
531            gsi_next (&i))
532         {
533           tree lhs;
534           use_operand_p uop;
535           ssa_op_iter soi;
536           gphi *phi = i.phi ();
537
538           lhs = PHI_RESULT (phi);
539           if (virtual_operand_p (lhs)
540               || bitmap_bit_p (si->va_list_escape_vars,
541                                SSA_NAME_VERSION (lhs)))
542             continue;
543
544           FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
545             {
546               tree rhs = USE_FROM_PTR (uop);
547               if (TREE_CODE (rhs) == SSA_NAME
548                   && bitmap_bit_p (si->va_list_escape_vars,
549                                 SSA_NAME_VERSION (rhs)))
550                 {
551                   if (dump_file && (dump_flags & TDF_DETAILS))
552                     {
553                       fputs ("va_list escapes in ", dump_file);
554                       print_gimple_stmt (dump_file, phi, 0, dump_flags);
555                       fputc ('\n', dump_file);
556                     }
557                   return true;
558                 }
559             }
560         }
561
562       for (gimple_stmt_iterator i = gsi_start_bb (bb); !gsi_end_p (i);
563            gsi_next (&i))
564         {
565           gimple *stmt = gsi_stmt (i);
566           tree use;
567           ssa_op_iter iter;
568
569           if (is_gimple_debug (stmt))
570             continue;
571
572           FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_USES)
573             {
574               if (! bitmap_bit_p (si->va_list_escape_vars,
575                                   SSA_NAME_VERSION (use)))
576                 continue;
577
578               if (is_gimple_assign (stmt))
579                 {
580                   tree rhs = gimple_assign_rhs1 (stmt);
581                   enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
582
583                   /* x = *ap_temp;  */
584                   if (rhs_code == MEM_REF
585                       && TREE_OPERAND (rhs, 0) == use
586                       && TYPE_SIZE_UNIT (TREE_TYPE (rhs))
587                       && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (rhs)))
588                       && si->offsets[SSA_NAME_VERSION (use)] != -1)
589                     {
590                       unsigned HOST_WIDE_INT gpr_size;
591                       tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (rhs));
592
593                       gpr_size = si->offsets[SSA_NAME_VERSION (use)]
594                                  + tree_to_shwi (TREE_OPERAND (rhs, 1))
595                                  + tree_to_uhwi (access_size);
596                       if (gpr_size >= VA_LIST_MAX_GPR_SIZE)
597                         cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
598                       else if (gpr_size > cfun->va_list_gpr_size)
599                         cfun->va_list_gpr_size = gpr_size;
600                       continue;
601                     }
602
603                   /* va_arg sequences may contain
604                      other_ap_temp = ap_temp;
605                      other_ap_temp = ap_temp + constant;
606                      other_ap_temp = (some_type *) ap_temp;
607                      ap = ap_temp;
608                      statements.  */
609                   if (rhs == use
610                       && ((rhs_code == POINTER_PLUS_EXPR
611                            && (TREE_CODE (gimple_assign_rhs2 (stmt))
612                                == INTEGER_CST))
613                           || gimple_assign_cast_p (stmt)
614                           || (get_gimple_rhs_class (rhs_code)
615                               == GIMPLE_SINGLE_RHS)))
616                     {
617                       tree lhs = gimple_assign_lhs (stmt);
618
619                       if (TREE_CODE (lhs) == SSA_NAME
620                           && bitmap_bit_p (si->va_list_escape_vars,
621                                            SSA_NAME_VERSION (lhs)))
622                         continue;
623
624                       if (VAR_P (lhs)
625                           && bitmap_bit_p (si->va_list_vars,
626                                            DECL_UID (lhs) + num_ssa_names))
627                         continue;
628                     }
629                   else if (rhs_code == ADDR_EXPR
630                            && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
631                            && TREE_OPERAND (TREE_OPERAND (rhs, 0), 0) == use)
632                     {
633                       tree lhs = gimple_assign_lhs (stmt);
634
635                       if (bitmap_bit_p (si->va_list_escape_vars,
636                                         SSA_NAME_VERSION (lhs)))
637                         continue;
638                     }
639                 }
640
641               if (dump_file && (dump_flags & TDF_DETAILS))
642                 {
643                   fputs ("va_list escapes in ", dump_file);
644                   print_gimple_stmt (dump_file, stmt, 0, dump_flags);
645                   fputc ('\n', dump_file);
646                 }
647               return true;
648             }
649         }
650     }
651
652   return false;
653 }
654
655 /* Optimize FUN->va_list_gpr_size and FUN->va_list_fpr_size.  */
656
657 static void
658 optimize_va_list_gpr_fpr_size (function *fun)
659 {
660   basic_block bb;
661   bool va_list_escapes = false;
662   bool va_list_simple_ptr;
663   struct stdarg_info si;
664   struct walk_stmt_info wi;
665   const char *funcname = NULL;
666   tree cfun_va_list;
667
668   fun->va_list_gpr_size = 0;
669   fun->va_list_fpr_size = 0;
670   memset (&si, 0, sizeof (si));
671   si.va_list_vars = BITMAP_ALLOC (NULL);
672   si.va_list_escape_vars = BITMAP_ALLOC (NULL);
673
674   if (dump_file)
675     funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
676
677   cfun_va_list = targetm.fn_abi_va_list (fun->decl);
678   va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
679                        && (TREE_TYPE (cfun_va_list) == void_type_node
680                            || TREE_TYPE (cfun_va_list) == char_type_node);
681   gcc_assert (is_gimple_reg_type (cfun_va_list) == va_list_simple_ptr);
682
683   FOR_EACH_BB_FN (bb, fun)
684     {
685       gimple_stmt_iterator i;
686
687       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
688         {
689           gimple *stmt = gsi_stmt (i);
690           tree callee, ap;
691
692           if (!is_gimple_call (stmt))
693             continue;
694
695           callee = gimple_call_fndecl (stmt);
696           if (!callee
697               || !fndecl_built_in_p (callee, BUILT_IN_NORMAL))
698             continue;
699
700           switch (DECL_FUNCTION_CODE (callee))
701             {
702             case BUILT_IN_VA_START:
703               break;
704               /* If old style builtins are used, don't optimize anything.  */
705             case BUILT_IN_SAVEREGS:
706             case BUILT_IN_NEXT_ARG:
707               va_list_escapes = true;
708               continue;
709             default:
710               continue;
711             }
712
713           si.va_start_count++;
714           ap = gimple_call_arg (stmt, 0);
715
716           if (TREE_CODE (ap) != ADDR_EXPR)
717             {
718               va_list_escapes = true;
719               break;
720             }
721           ap = TREE_OPERAND (ap, 0);
722           if (TREE_CODE (ap) == ARRAY_REF)
723             {
724               if (! integer_zerop (TREE_OPERAND (ap, 1)))
725                 {
726                   va_list_escapes = true;
727                   break;
728                 }
729               ap = TREE_OPERAND (ap, 0);
730             }
731           if (TYPE_MAIN_VARIANT (TREE_TYPE (ap))
732               != TYPE_MAIN_VARIANT (targetm.fn_abi_va_list (fun->decl))
733               || !VAR_P (ap))
734             {
735               va_list_escapes = true;
736               break;
737             }
738
739           if (is_global_var (ap))
740             {
741               va_list_escapes = true;
742               break;
743             }
744
745           bitmap_set_bit (si.va_list_vars, DECL_UID (ap) + num_ssa_names);
746
747           /* VA_START_BB and VA_START_AP will be only used if there is just
748              one va_start in the function.  */
749           si.va_start_bb = bb;
750           si.va_start_ap = ap;
751         }
752
753       if (va_list_escapes)
754         break;
755     }
756
757   /* If there were no va_start uses in the function, there is no need to
758      save anything.  */
759   if (si.va_start_count == 0)
760     goto finish;
761
762   /* If some va_list arguments weren't local, we can't optimize.  */
763   if (va_list_escapes)
764     goto finish;
765
766   /* For void * or char * va_list, something useful can be done only
767      if there is just one va_start.  */
768   if (va_list_simple_ptr && si.va_start_count > 1)
769     {
770       va_list_escapes = true;
771       goto finish;
772     }
773
774   /* For struct * va_list, if the backend didn't tell us what the counter fields
775      are, there is nothing more we can do.  */
776   if (!va_list_simple_ptr
777       && va_list_gpr_counter_field == NULL_TREE
778       && va_list_fpr_counter_field == NULL_TREE)
779     {
780       va_list_escapes = true;
781       goto finish;
782     }
783
784   /* For void * or char * va_list there is just one counter
785      (va_list itself).  Use VA_LIST_GPR_SIZE for it.  */
786   if (va_list_simple_ptr)
787     fun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
788
789   calculate_dominance_info (CDI_DOMINATORS);
790   memset (&wi, 0, sizeof (wi));
791   wi.info = si.va_list_vars;
792
793   FOR_EACH_BB_FN (bb, fun)
794     {
795       si.compute_sizes = -1;
796       si.bb = bb;
797
798       /* For va_list_simple_ptr, we have to check PHI nodes too.  We treat
799          them as assignments for the purpose of escape analysis.  This is
800          not needed for non-simple va_list because virtual phis don't perform
801          any real data movement.  Also, check PHI nodes for taking address of
802          the va_list vars.  */
803       tree lhs, rhs;
804       use_operand_p uop;
805       ssa_op_iter soi;
806
807       for (gphi_iterator i = gsi_start_phis (bb); !gsi_end_p (i);
808            gsi_next (&i))
809         {
810           gphi *phi = i.phi ();
811           lhs = PHI_RESULT (phi);
812
813           if (virtual_operand_p (lhs))
814             continue;
815
816           if (va_list_simple_ptr)
817             {
818               FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
819                 {
820                   rhs = USE_FROM_PTR (uop);
821                   if (va_list_ptr_read (&si, rhs, lhs))
822                     continue;
823                   else if (va_list_ptr_write (&si, lhs, rhs))
824                     continue;
825                   else
826                     check_va_list_escapes (&si, lhs, rhs);
827
828                   if (si.va_list_escapes)
829                     {
830                       if (dump_file && (dump_flags & TDF_DETAILS))
831                         {
832                           fputs ("va_list escapes in ", dump_file);
833                           print_gimple_stmt (dump_file, phi, 0, dump_flags);
834                           fputc ('\n', dump_file);
835                         }
836                       va_list_escapes = true;
837                     }
838                 }
839             }
840
841           for (unsigned j = 0; !va_list_escapes
842                                && j < gimple_phi_num_args (phi); ++j)
843             if ((!va_list_simple_ptr
844                  || TREE_CODE (gimple_phi_arg_def (phi, j)) != SSA_NAME)
845                 && walk_tree (gimple_phi_arg_def_ptr (phi, j),
846                               find_va_list_reference, &wi, NULL))
847               {
848                 if (dump_file && (dump_flags & TDF_DETAILS))
849                   {
850                     fputs ("va_list escapes in ", dump_file);
851                     print_gimple_stmt (dump_file, phi, 0, dump_flags);
852                     fputc ('\n', dump_file);
853                   }
854                 va_list_escapes = true;
855               }
856         }
857
858       for (gimple_stmt_iterator i = gsi_start_bb (bb);
859            !gsi_end_p (i) && !va_list_escapes;
860            gsi_next (&i))
861         {
862           gimple *stmt = gsi_stmt (i);
863
864           /* Don't look at __builtin_va_{start,end}, they are ok.  */
865           if (is_gimple_call (stmt))
866             {
867               tree callee = gimple_call_fndecl (stmt);
868
869               if (callee
870                   && (fndecl_built_in_p (callee, BUILT_IN_VA_START)
871                       || fndecl_built_in_p (callee, BUILT_IN_VA_END)))
872                 continue;
873             }
874
875           if (is_gimple_assign (stmt))
876             {
877               lhs = gimple_assign_lhs (stmt);
878               rhs = gimple_assign_rhs1 (stmt);
879
880               if (va_list_simple_ptr)
881                 {
882                   if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
883                       == GIMPLE_SINGLE_RHS)
884                     {
885                       /* Check for ap ={v} {}.  */
886                       if (TREE_CLOBBER_P (rhs))
887                         continue;
888
889                       /* Check for tem = ap.  */
890                       else if (va_list_ptr_read (&si, rhs, lhs))
891                         continue;
892
893                       /* Check for the last insn in:
894                          tem1 = ap;
895                          tem2 = tem1 + CST;
896                          ap = tem2;
897                          sequence.  */
898                       else if (va_list_ptr_write (&si, lhs, rhs))
899                         continue;
900                     }
901
902                   if ((gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
903                        && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST)
904                       || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
905                       || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
906                           == GIMPLE_SINGLE_RHS))
907                     check_va_list_escapes (&si, lhs, rhs);
908                 }
909               else
910                 {
911                   if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
912                       == GIMPLE_SINGLE_RHS)
913                     {
914                       /* Check for ap ={v} {}.  */
915                       if (TREE_CLOBBER_P (rhs))
916                         continue;
917
918                       /* Check for ap[0].field = temp.  */
919                       else if (va_list_counter_struct_op (&si, lhs, rhs, true))
920                         continue;
921
922                       /* Check for temp = ap[0].field.  */
923                       else if (va_list_counter_struct_op (&si, rhs, lhs,
924                                                           false))
925                         continue;
926                     }
927
928                   /* Do any architecture specific checking.  */
929                   if (targetm.stdarg_optimize_hook
930                       && targetm.stdarg_optimize_hook (&si, stmt))
931                     continue;
932                 }
933             }
934           else if (is_gimple_debug (stmt))
935             continue;
936
937           /* All other uses of va_list are either va_copy (that is not handled
938              in this optimization), taking address of va_list variable or
939              passing va_list to other functions (in that case va_list might
940              escape the function and therefore va_start needs to set it up
941              fully), or some unexpected use of va_list.  None of these should
942              happen in a gimplified VA_ARG_EXPR.  */
943           if (si.va_list_escapes
944               || walk_gimple_op (stmt, find_va_list_reference, &wi))
945             {
946               if (dump_file && (dump_flags & TDF_DETAILS))
947                 {
948                   fputs ("va_list escapes in ", dump_file);
949                   print_gimple_stmt (dump_file, stmt, 0, dump_flags);
950                   fputc ('\n', dump_file);
951                 }
952               va_list_escapes = true;
953             }
954         }
955
956       if (va_list_escapes)
957         break;
958     }
959
960   if (! va_list_escapes
961       && va_list_simple_ptr
962       && ! bitmap_empty_p (si.va_list_escape_vars)
963       && check_all_va_list_escapes (&si))
964     va_list_escapes = true;
965
966 finish:
967   if (va_list_escapes)
968     {
969       fun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
970       fun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
971     }
972   BITMAP_FREE (si.va_list_vars);
973   BITMAP_FREE (si.va_list_escape_vars);
974   free (si.offsets);
975   if (dump_file)
976     {
977       fprintf (dump_file, "%s: va_list escapes %d, needs to save ",
978                funcname, (int) va_list_escapes);
979       if (fun->va_list_gpr_size >= VA_LIST_MAX_GPR_SIZE)
980         fputs ("all", dump_file);
981       else
982         fprintf (dump_file, "%d", cfun->va_list_gpr_size);
983       fputs (" GPR units and ", dump_file);
984       if (fun->va_list_fpr_size >= VA_LIST_MAX_FPR_SIZE)
985         fputs ("all", dump_file);
986       else
987         fprintf (dump_file, "%d", cfun->va_list_fpr_size);
988       fputs (" FPR units.\n", dump_file);
989     }
990 }
991
992 /* Expand IFN_VA_ARGs in FUN.  */
993
994 static void
995 expand_ifn_va_arg_1 (function *fun)
996 {
997   bool modified = false;
998   basic_block bb;
999   gimple_stmt_iterator i;
1000   location_t saved_location;
1001
1002   FOR_EACH_BB_FN (bb, fun)
1003     for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
1004       {
1005         gimple *stmt = gsi_stmt (i);
1006         tree ap, aptype, expr, lhs, type;
1007         gimple_seq pre = NULL, post = NULL;
1008
1009         if (!gimple_call_internal_p (stmt, IFN_VA_ARG))
1010           continue;
1011
1012         modified = true;
1013
1014         type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 1)));
1015         ap = gimple_call_arg (stmt, 0);
1016         aptype = TREE_TYPE (gimple_call_arg (stmt, 2));
1017         gcc_assert (POINTER_TYPE_P (aptype));
1018
1019         /* Balanced out the &ap, usually added by build_va_arg.  */
1020         ap = build2 (MEM_REF, TREE_TYPE (aptype), ap,
1021                      build_int_cst (aptype, 0));
1022
1023         push_gimplify_context (false);
1024         saved_location = input_location;
1025         input_location = gimple_location (stmt);
1026
1027         /* Make it easier for the backends by protecting the valist argument
1028            from multiple evaluations.  */
1029         gimplify_expr (&ap, &pre, &post, is_gimple_min_lval, fb_lvalue);
1030
1031         expr = targetm.gimplify_va_arg_expr (ap, type, &pre, &post);
1032
1033         lhs = gimple_call_lhs (stmt);
1034         if (lhs != NULL_TREE)
1035           {
1036             unsigned int nargs = gimple_call_num_args (stmt);
1037             gcc_assert (useless_type_conversion_p (TREE_TYPE (lhs), type));
1038
1039             if (nargs == 4)
1040               {
1041                 /* We've transported the size of with WITH_SIZE_EXPR here as
1042                    the last argument of the internal fn call.  Now reinstate
1043                    it.  */
1044                 tree size = gimple_call_arg (stmt, nargs - 1);
1045                 expr = build2 (WITH_SIZE_EXPR, TREE_TYPE (expr), expr, size);
1046               }
1047
1048             /* We use gimplify_assign here, rather than gimple_build_assign,
1049                because gimple_assign knows how to deal with variable-sized
1050                types.  */
1051             gimplify_assign (lhs, expr, &pre);
1052           }
1053         else
1054           gimplify_and_add (expr, &pre);
1055
1056         input_location = saved_location;
1057         pop_gimplify_context (NULL);
1058
1059         gimple_seq_add_seq (&pre, post);
1060         update_modified_stmts (pre);
1061
1062         /* Add the sequence after IFN_VA_ARG.  This splits the bb right
1063            after IFN_VA_ARG, and adds the sequence in one or more new bbs
1064            inbetween.  */
1065         gimple_find_sub_bbs (pre, &i);
1066
1067         /* Remove the IFN_VA_ARG gimple_call.  It's the last stmt in the
1068            bb.  */
1069         unlink_stmt_vdef (stmt);
1070         release_ssa_name_fn (fun, gimple_vdef (stmt));
1071         gsi_remove (&i, true);
1072         gcc_assert (gsi_end_p (i));
1073
1074         /* We're walking here into the bbs which contain the expansion of
1075            IFN_VA_ARG, and will not contain another IFN_VA_ARG that needs
1076            expanding.  We could try to skip walking these bbs, perhaps by
1077            walking backwards over gimples and bbs.  */
1078         break;
1079       }
1080
1081   if (!modified)
1082     return;
1083
1084   free_dominance_info (CDI_DOMINATORS);
1085   update_ssa (TODO_update_ssa);
1086 }
1087
1088 /* Expand IFN_VA_ARGs in FUN, if necessary.  */
1089
1090 static void
1091 expand_ifn_va_arg (function *fun)
1092 {
1093   if ((fun->curr_properties & PROP_gimple_lva) == 0)
1094     expand_ifn_va_arg_1 (fun);
1095
1096   if (flag_checking)
1097     {
1098       basic_block bb;
1099       gimple_stmt_iterator i;
1100       FOR_EACH_BB_FN (bb, fun)
1101         for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
1102           gcc_assert (!gimple_call_internal_p (gsi_stmt (i), IFN_VA_ARG));
1103     }
1104 }
1105
1106 namespace {
1107
1108 const pass_data pass_data_stdarg =
1109 {
1110   GIMPLE_PASS, /* type */
1111   "stdarg", /* name */
1112   OPTGROUP_NONE, /* optinfo_flags */
1113   TV_NONE, /* tv_id */
1114   ( PROP_cfg | PROP_ssa ), /* properties_required */
1115   PROP_gimple_lva, /* properties_provided */
1116   0, /* properties_destroyed */
1117   TODO_remove_unused_locals, /* todo_flags_start */
1118   0, /* todo_flags_finish */
1119 };
1120
1121 class pass_stdarg : public gimple_opt_pass
1122 {
1123 public:
1124   pass_stdarg (gcc::context *ctxt)
1125     : gimple_opt_pass (pass_data_stdarg, ctxt)
1126   {}
1127
1128   /* opt_pass methods: */
1129   virtual bool gate (function *)
1130     {
1131       /* Always run this pass, in order to expand va_arg internal_fns.  We
1132          also need to do that if fun->stdarg == 0, because a va_arg may also
1133          occur in a function without varargs, f.i. if when passing a va_list to
1134          another function.  */
1135       return true;
1136     }
1137
1138   virtual unsigned int execute (function *);
1139
1140 }; // class pass_stdarg
1141
1142 unsigned int
1143 pass_stdarg::execute (function *fun)
1144 {
1145   /* TODO: Postpone expand_ifn_va_arg till after
1146      optimize_va_list_gpr_fpr_size.  */
1147   expand_ifn_va_arg (fun);
1148
1149   if (flag_stdarg_opt
1150       /* This optimization is only for stdarg functions.  */
1151       && fun->stdarg != 0)
1152     optimize_va_list_gpr_fpr_size (fun);
1153
1154   return 0;
1155 }
1156
1157 } // anon namespace
1158
1159 gimple_opt_pass *
1160 make_pass_stdarg (gcc::context *ctxt)
1161 {
1162   return new pass_stdarg (ctxt);
1163 }
1164
1165 namespace {
1166
1167 const pass_data pass_data_lower_vaarg =
1168 {
1169   GIMPLE_PASS, /* type */
1170   "lower_vaarg", /* name */
1171   OPTGROUP_NONE, /* optinfo_flags */
1172   TV_NONE, /* tv_id */
1173   ( PROP_cfg | PROP_ssa ), /* properties_required */
1174   PROP_gimple_lva, /* properties_provided */
1175   0, /* properties_destroyed */
1176   0, /* todo_flags_start */
1177   0, /* todo_flags_finish */
1178 };
1179
1180 class pass_lower_vaarg : public gimple_opt_pass
1181 {
1182 public:
1183   pass_lower_vaarg (gcc::context *ctxt)
1184     : gimple_opt_pass (pass_data_lower_vaarg, ctxt)
1185   {}
1186
1187   /* opt_pass methods: */
1188   virtual bool gate (function *)
1189     {
1190       return (cfun->curr_properties & PROP_gimple_lva) == 0;
1191     }
1192
1193   virtual unsigned int execute (function *);
1194
1195 }; // class pass_lower_vaarg
1196
1197 unsigned int
1198 pass_lower_vaarg::execute (function *fun)
1199 {
1200   expand_ifn_va_arg (fun);
1201   return 0;
1202 }
1203
1204 } // anon namespace
1205
1206 gimple_opt_pass *
1207 make_pass_lower_vaarg (gcc::context *ctxt)
1208 {
1209   return new pass_lower_vaarg (ctxt);
1210 }