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