1 /* Pass computing data for optimizing stdarg functions.
2    Copyright (C) 2004-2022 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
reachable_at_most_once(basic_block va_arg_bb,basic_block va_start_bb)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
va_list_counter_bump(struct stdarg_info * si,tree counter,tree rhs,bool gpr_p)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
find_va_list_reference(tree * tp,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)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
va_list_counter_op(struct stdarg_info * si,tree ap,tree var,bool gpr_p,bool write_p)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
va_list_counter_struct_op(struct stdarg_info * si,tree ap,tree var,bool write_p)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
va_list_ptr_read(struct stdarg_info * si,tree ap,tree tem)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
va_list_ptr_write(struct stdarg_info * si,tree ap,tree tem2)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
check_va_list_escapes(struct stdarg_info * si,tree lhs,tree rhs)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
check_all_va_list_escapes(struct stdarg_info * si)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
optimize_va_list_gpr_fpr_size(function * fun)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
expand_ifn_va_arg_1(function * fun)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
expand_ifn_va_arg(function * fun)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:
pass_stdarg(gcc::context * ctxt)1124   pass_stdarg (gcc::context *ctxt)
1125     : gimple_opt_pass (pass_data_stdarg, ctxt)
1126   {}
1127 
1128   /* opt_pass methods: */
gate(function *)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
execute(function * fun)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 *
make_pass_stdarg(gcc::context * ctxt)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:
pass_lower_vaarg(gcc::context * ctxt)1183   pass_lower_vaarg (gcc::context *ctxt)
1184     : gimple_opt_pass (pass_data_lower_vaarg, ctxt)
1185   {}
1186 
1187   /* opt_pass methods: */
gate(function *)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
execute(function * fun)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 *
make_pass_lower_vaarg(gcc::context * ctxt)1207 make_pass_lower_vaarg (gcc::context *ctxt)
1208 {
1209   return new pass_lower_vaarg (ctxt);
1210 }
1211