1/* Pass computing data for optimizing stdarg functions.
2   Copyright (C) 2004-2015 Free Software Foundation, Inc.
3   Contributed by Jakub Jelinek <jakub@redhat.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "hash-set.h"
26#include "machmode.h"
27#include "vec.h"
28#include "double-int.h"
29#include "input.h"
30#include "alias.h"
31#include "symtab.h"
32#include "wide-int.h"
33#include "inchash.h"
34#include "tree.h"
35#include "fold-const.h"
36#include "hard-reg-set.h"
37#include "input.h"
38#include "function.h"
39#include "langhooks.h"
40#include "gimple-pretty-print.h"
41#include "target.h"
42#include "bitmap.h"
43#include "predict.h"
44#include "dominance.h"
45#include "cfg.h"
46#include "basic-block.h"
47#include "tree-ssa-alias.h"
48#include "internal-fn.h"
49#include "gimple-expr.h"
50#include "is-a.h"
51#include "gimple.h"
52#include "gimple-iterator.h"
53#include "gimple-walk.h"
54#include "gimple-ssa.h"
55#include "tree-phinodes.h"
56#include "ssa-iterators.h"
57#include "stringpool.h"
58#include "tree-ssanames.h"
59#include "sbitmap.h"
60#include "tree-pass.h"
61#include "tree-stdarg.h"
62
63/* A simple pass that attempts to optimize stdarg functions on architectures
64   that need to save register arguments to stack on entry to stdarg functions.
65   If the function doesn't use any va_start macros, no registers need to
66   be saved.  If va_start macros are used, the va_list variables don't escape
67   the function, it is only necessary to save registers that will be used
68   in va_arg macros.  E.g. if va_arg is only used with integral types
69   in the function, floating point registers don't need to be saved, etc.  */
70
71
72/* Return true if basic block VA_ARG_BB is dominated by VA_START_BB and
73   is executed at most as many times as VA_START_BB.  */
74
75static bool
76reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb)
77{
78  vec<edge> stack = vNULL;
79  edge e;
80  edge_iterator ei;
81  sbitmap visited;
82  bool ret;
83
84  if (va_arg_bb == va_start_bb)
85    return true;
86
87  if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb))
88    return false;
89
90  visited = sbitmap_alloc (last_basic_block_for_fn (cfun));
91  bitmap_clear (visited);
92  ret = true;
93
94  FOR_EACH_EDGE (e, ei, va_arg_bb->preds)
95    stack.safe_push (e);
96
97  while (! stack.is_empty ())
98    {
99      basic_block src;
100
101      e = stack.pop ();
102      src = e->src;
103
104      if (e->flags & EDGE_COMPLEX)
105	{
106	  ret = false;
107	  break;
108	}
109
110      if (src == va_start_bb)
111	continue;
112
113      /* va_arg_bb can be executed more times than va_start_bb.  */
114      if (src == va_arg_bb)
115	{
116	  ret = false;
117	  break;
118	}
119
120      gcc_assert (src != ENTRY_BLOCK_PTR_FOR_FN (cfun));
121
122      if (! bitmap_bit_p (visited, src->index))
123	{
124	  bitmap_set_bit (visited, src->index);
125	  FOR_EACH_EDGE (e, ei, src->preds)
126	    stack.safe_push (e);
127	}
128    }
129
130  stack.release ();
131  sbitmap_free (visited);
132  return ret;
133}
134
135
136/* For statement COUNTER = RHS, if RHS is COUNTER + constant,
137   return constant, otherwise return HOST_WIDE_INT_M1U.
138   GPR_P is true if this is GPR counter.  */
139
140static unsigned HOST_WIDE_INT
141va_list_counter_bump (struct stdarg_info *si, tree counter, tree rhs,
142		      bool gpr_p)
143{
144  tree lhs, orig_lhs;
145  gimple stmt;
146  unsigned HOST_WIDE_INT ret = 0, val, counter_val;
147  unsigned int max_size;
148
149  if (si->offsets == NULL)
150    {
151      unsigned int i;
152
153      si->offsets = XNEWVEC (int, num_ssa_names);
154      for (i = 0; i < num_ssa_names; ++i)
155	si->offsets[i] = -1;
156    }
157
158  counter_val = gpr_p ? cfun->va_list_gpr_size : cfun->va_list_fpr_size;
159  max_size = gpr_p ? VA_LIST_MAX_GPR_SIZE : VA_LIST_MAX_FPR_SIZE;
160  orig_lhs = lhs = rhs;
161  while (lhs)
162    {
163      enum tree_code rhs_code;
164      tree rhs1;
165
166      if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
167	{
168	  if (counter_val >= max_size)
169	    {
170	      ret = max_size;
171	      break;
172	    }
173
174	  ret -= counter_val - si->offsets[SSA_NAME_VERSION (lhs)];
175	  break;
176	}
177
178      stmt = SSA_NAME_DEF_STMT (lhs);
179
180      if (!is_gimple_assign (stmt) || gimple_assign_lhs (stmt) != lhs)
181	return HOST_WIDE_INT_M1U;
182
183      rhs_code = gimple_assign_rhs_code (stmt);
184      rhs1 = gimple_assign_rhs1 (stmt);
185      if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
186	   || gimple_assign_cast_p (stmt))
187	  && TREE_CODE (rhs1) == SSA_NAME)
188	{
189	  lhs = rhs1;
190	  continue;
191	}
192
193      if ((rhs_code == POINTER_PLUS_EXPR
194	   || rhs_code == PLUS_EXPR)
195	  && TREE_CODE (rhs1) == SSA_NAME
196	  && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))
197	{
198	  ret += tree_to_uhwi (gimple_assign_rhs2 (stmt));
199	  lhs = rhs1;
200	  continue;
201	}
202
203      if (rhs_code == ADDR_EXPR
204	  && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
205	  && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
206	  && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1)))
207	{
208	  ret += tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1));
209	  lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
210	  continue;
211	}
212
213      if (get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS)
214	return HOST_WIDE_INT_M1U;
215
216      rhs = gimple_assign_rhs1 (stmt);
217      if (TREE_CODE (counter) != TREE_CODE (rhs))
218	return HOST_WIDE_INT_M1U;
219
220      if (TREE_CODE (counter) == COMPONENT_REF)
221	{
222	  if (get_base_address (counter) != get_base_address (rhs)
223	      || TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL
224	      || TREE_OPERAND (counter, 1) != TREE_OPERAND (rhs, 1))
225	    return HOST_WIDE_INT_M1U;
226	}
227      else if (counter != rhs)
228	return HOST_WIDE_INT_M1U;
229
230      lhs = NULL;
231    }
232
233  lhs = orig_lhs;
234  val = ret + counter_val;
235  while (lhs)
236    {
237      enum tree_code rhs_code;
238      tree rhs1;
239
240      if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
241	break;
242
243      if (val >= max_size)
244	si->offsets[SSA_NAME_VERSION (lhs)] = max_size;
245      else
246	si->offsets[SSA_NAME_VERSION (lhs)] = val;
247
248      stmt = SSA_NAME_DEF_STMT (lhs);
249
250      rhs_code = gimple_assign_rhs_code (stmt);
251      rhs1 = gimple_assign_rhs1 (stmt);
252      if ((get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS
253	   || gimple_assign_cast_p (stmt))
254	  && TREE_CODE (rhs1) == SSA_NAME)
255	{
256	  lhs = rhs1;
257	  continue;
258	}
259
260      if ((rhs_code == POINTER_PLUS_EXPR
261	   || rhs_code == PLUS_EXPR)
262	  && TREE_CODE (rhs1) == SSA_NAME
263	  && tree_fits_uhwi_p (gimple_assign_rhs2 (stmt)))
264	{
265	  val -= tree_to_uhwi (gimple_assign_rhs2 (stmt));
266	  lhs = rhs1;
267	  continue;
268	}
269
270      if (rhs_code == ADDR_EXPR
271	  && TREE_CODE (TREE_OPERAND (rhs1, 0)) == MEM_REF
272	  && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0)) == SSA_NAME
273	  && tree_fits_uhwi_p (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1)))
274	{
275	  val -= tree_to_uhwi (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1));
276	  lhs = TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0);
277	  continue;
278	}
279
280      lhs = NULL;
281    }
282
283  return ret;
284}
285
286
287/* Called by walk_tree to look for references to va_list variables.  */
288
289static tree
290find_va_list_reference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
291			void *data)
292{
293  bitmap va_list_vars = (bitmap) ((struct walk_stmt_info *) data)->info;
294  tree var = *tp;
295
296  if (TREE_CODE (var) == SSA_NAME)
297    {
298      if (bitmap_bit_p (va_list_vars, SSA_NAME_VERSION (var)))
299	return var;
300    }
301  else if (TREE_CODE (var) == VAR_DECL)
302    {
303      if (bitmap_bit_p (va_list_vars, DECL_UID (var) + num_ssa_names))
304	return var;
305    }
306
307  return NULL_TREE;
308}
309
310
311/* Helper function of va_list_counter_struct_op.  Compute
312   cfun->va_list_{g,f}pr_size.  AP is a va_list GPR/FPR counter,
313   if WRITE_P is true, seen in AP = VAR, otherwise seen in VAR = AP
314   statement.  GPR_P is true if AP is a GPR counter, false if it is
315   a FPR counter.  */
316
317static void
318va_list_counter_op (struct stdarg_info *si, tree ap, tree var, bool gpr_p,
319		    bool write_p)
320{
321  unsigned HOST_WIDE_INT increment;
322
323  if (si->compute_sizes < 0)
324    {
325      si->compute_sizes = 0;
326      if (si->va_start_count == 1
327	  && reachable_at_most_once (si->bb, si->va_start_bb))
328	si->compute_sizes = 1;
329
330      if (dump_file && (dump_flags & TDF_DETAILS))
331	fprintf (dump_file,
332		 "bb%d will %sbe executed at most once for each va_start "
333		 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
334		 si->va_start_bb->index);
335    }
336
337  if (write_p
338      && si->compute_sizes
339      && (increment = va_list_counter_bump (si, ap, var, gpr_p)) + 1 > 1)
340    {
341      if (gpr_p && cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
342	{
343	  cfun->va_list_gpr_size += increment;
344	  return;
345	}
346
347      if (!gpr_p && cfun->va_list_fpr_size + increment < VA_LIST_MAX_FPR_SIZE)
348	{
349	  cfun->va_list_fpr_size += increment;
350	  return;
351	}
352    }
353
354  if (write_p || !si->compute_sizes)
355    {
356      if (gpr_p)
357	cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
358      else
359	cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
360    }
361}
362
363
364/* If AP is a va_list GPR/FPR counter, compute cfun->va_list_{g,f}pr_size.
365   If WRITE_P is true, AP has been seen in AP = VAR assignment, if WRITE_P
366   is false, AP has been seen in VAR = AP assignment.
367   Return true if the AP = VAR (resp. VAR = AP) statement is a recognized
368   va_arg operation that doesn't cause the va_list variable to escape
369   current function.  */
370
371static bool
372va_list_counter_struct_op (struct stdarg_info *si, tree ap, tree var,
373			   bool write_p)
374{
375  tree base;
376
377  if (TREE_CODE (ap) != COMPONENT_REF
378      || TREE_CODE (TREE_OPERAND (ap, 1)) != FIELD_DECL)
379    return false;
380
381  if (TREE_CODE (var) != SSA_NAME
382      || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (var)))
383    return false;
384
385  base = get_base_address (ap);
386  if (TREE_CODE (base) != VAR_DECL
387      || !bitmap_bit_p (si->va_list_vars, DECL_UID (base) + num_ssa_names))
388    return false;
389
390  if (TREE_OPERAND (ap, 1) == va_list_gpr_counter_field)
391    va_list_counter_op (si, ap, var, true, write_p);
392  else if (TREE_OPERAND (ap, 1) == va_list_fpr_counter_field)
393    va_list_counter_op (si, ap, var, false, write_p);
394
395  return true;
396}
397
398
399/* Check for TEM = AP.  Return true if found and the caller shouldn't
400   search for va_list references in the statement.  */
401
402static bool
403va_list_ptr_read (struct stdarg_info *si, tree ap, tree tem)
404{
405  if (TREE_CODE (ap) != VAR_DECL
406      || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
407    return false;
408
409  if (TREE_CODE (tem) != SSA_NAME
410      || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem)))
411    return false;
412
413  if (si->compute_sizes < 0)
414    {
415      si->compute_sizes = 0;
416      if (si->va_start_count == 1
417	  && reachable_at_most_once (si->bb, si->va_start_bb))
418	si->compute_sizes = 1;
419
420      if (dump_file && (dump_flags & TDF_DETAILS))
421	fprintf (dump_file,
422		 "bb%d will %sbe executed at most once for each va_start "
423		 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
424		 si->va_start_bb->index);
425    }
426
427  /* For void * or char * va_list types, there is just one counter.
428     If va_arg is used in a loop, we don't know how many registers need
429     saving.  */
430  if (! si->compute_sizes)
431    return false;
432
433  if (va_list_counter_bump (si, ap, tem, true) == HOST_WIDE_INT_M1U)
434    return false;
435
436  /* Note the temporary, as we need to track whether it doesn't escape
437     the current function.  */
438  bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (tem));
439
440  return true;
441}
442
443
444/* Check for:
445     tem1 = AP;
446     TEM2 = tem1 + CST;
447     AP = TEM2;
448   sequence and update cfun->va_list_gpr_size.  Return true if found.  */
449
450static bool
451va_list_ptr_write (struct stdarg_info *si, tree ap, tree tem2)
452{
453  unsigned HOST_WIDE_INT increment;
454
455  if (TREE_CODE (ap) != VAR_DECL
456      || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap) + num_ssa_names))
457    return false;
458
459  if (TREE_CODE (tem2) != SSA_NAME
460      || bitmap_bit_p (si->va_list_vars, SSA_NAME_VERSION (tem2)))
461    return false;
462
463  if (si->compute_sizes <= 0)
464    return false;
465
466  increment = va_list_counter_bump (si, ap, tem2, true);
467  if (increment + 1 <= 1)
468    return false;
469
470  if (cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
471    cfun->va_list_gpr_size += increment;
472  else
473    cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
474
475  return true;
476}
477
478
479/* If RHS is X, (some type *) X or X + CST for X a temporary variable
480   containing value of some va_list variable plus optionally some constant,
481   either set si->va_list_escapes or add LHS to si->va_list_escape_vars,
482   depending whether LHS is a function local temporary.  */
483
484static void
485check_va_list_escapes (struct stdarg_info *si, tree lhs, tree rhs)
486{
487  if (! POINTER_TYPE_P (TREE_TYPE (rhs)))
488    return;
489
490  if (TREE_CODE (rhs) == SSA_NAME)
491    {
492      if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (rhs)))
493	return;
494    }
495  else if (TREE_CODE (rhs) == ADDR_EXPR
496	   && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
497	   && TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)) == SSA_NAME)
498    {
499      tree ptr = TREE_OPERAND (TREE_OPERAND (rhs, 0), 0);
500      if (! bitmap_bit_p (si->va_list_escape_vars, SSA_NAME_VERSION (ptr)))
501	return;
502    }
503  else
504    return;
505
506  if (TREE_CODE (lhs) != SSA_NAME)
507    {
508      si->va_list_escapes = true;
509      return;
510    }
511
512  if (si->compute_sizes < 0)
513    {
514      si->compute_sizes = 0;
515      if (si->va_start_count == 1
516	  && reachable_at_most_once (si->bb, si->va_start_bb))
517	si->compute_sizes = 1;
518
519      if (dump_file && (dump_flags & TDF_DETAILS))
520	fprintf (dump_file,
521		 "bb%d will %sbe executed at most once for each va_start "
522		 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
523		 si->va_start_bb->index);
524    }
525
526  /* For void * or char * va_list types, there is just one counter.
527     If va_arg is used in a loop, we don't know how many registers need
528     saving.  */
529  if (! si->compute_sizes)
530    {
531      si->va_list_escapes = true;
532      return;
533    }
534
535  if (va_list_counter_bump (si, si->va_start_ap, lhs, true)
536      == HOST_WIDE_INT_M1U)
537    {
538      si->va_list_escapes = true;
539      return;
540    }
541
542  bitmap_set_bit (si->va_list_escape_vars, SSA_NAME_VERSION (lhs));
543}
544
545
546/* Check all uses of temporaries from si->va_list_escape_vars bitmap.
547   Return true if va_list might be escaping.  */
548
549static bool
550check_all_va_list_escapes (struct stdarg_info *si)
551{
552  basic_block bb;
553
554  FOR_EACH_BB_FN (bb, cfun)
555    {
556      for (gphi_iterator i = gsi_start_phis (bb); !gsi_end_p (i);
557	   gsi_next (&i))
558	{
559	  tree lhs;
560	  use_operand_p uop;
561	  ssa_op_iter soi;
562	  gphi *phi = i.phi ();
563
564	  lhs = PHI_RESULT (phi);
565	  if (virtual_operand_p (lhs)
566	      || bitmap_bit_p (si->va_list_escape_vars,
567			       SSA_NAME_VERSION (lhs)))
568	    continue;
569
570	  FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
571	    {
572	      tree rhs = USE_FROM_PTR (uop);
573	      if (TREE_CODE (rhs) == SSA_NAME
574		  && bitmap_bit_p (si->va_list_escape_vars,
575				SSA_NAME_VERSION (rhs)))
576		{
577		  if (dump_file && (dump_flags & TDF_DETAILS))
578		    {
579		      fputs ("va_list escapes in ", dump_file);
580		      print_gimple_stmt (dump_file, phi, 0, dump_flags);
581		      fputc ('\n', dump_file);
582		    }
583		  return true;
584		}
585	    }
586	}
587
588      for (gimple_stmt_iterator i = gsi_start_bb (bb); !gsi_end_p (i);
589	   gsi_next (&i))
590	{
591	  gimple stmt = gsi_stmt (i);
592	  tree use;
593	  ssa_op_iter iter;
594
595	  if (is_gimple_debug (stmt))
596	    continue;
597
598	  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_USES)
599	    {
600	      if (! bitmap_bit_p (si->va_list_escape_vars,
601				  SSA_NAME_VERSION (use)))
602		continue;
603
604	      if (is_gimple_assign (stmt))
605		{
606		  tree rhs = gimple_assign_rhs1 (stmt);
607		  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
608
609		  /* x = *ap_temp;  */
610		  if (rhs_code == MEM_REF
611		      && TREE_OPERAND (rhs, 0) == use
612		      && TYPE_SIZE_UNIT (TREE_TYPE (rhs))
613		      && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (rhs)))
614		      && si->offsets[SSA_NAME_VERSION (use)] != -1)
615		    {
616		      unsigned HOST_WIDE_INT gpr_size;
617		      tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (rhs));
618
619		      gpr_size = si->offsets[SSA_NAME_VERSION (use)]
620			  	 + tree_to_shwi (TREE_OPERAND (rhs, 1))
621				 + tree_to_uhwi (access_size);
622		      if (gpr_size >= VA_LIST_MAX_GPR_SIZE)
623			cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
624		      else if (gpr_size > cfun->va_list_gpr_size)
625			cfun->va_list_gpr_size = gpr_size;
626		      continue;
627		    }
628
629		  /* va_arg sequences may contain
630		     other_ap_temp = ap_temp;
631		     other_ap_temp = ap_temp + constant;
632		     other_ap_temp = (some_type *) ap_temp;
633		     ap = ap_temp;
634		     statements.  */
635		  if (rhs == use
636		      && ((rhs_code == POINTER_PLUS_EXPR
637			   && (TREE_CODE (gimple_assign_rhs2 (stmt))
638			       == INTEGER_CST))
639			  || gimple_assign_cast_p (stmt)
640			  || (get_gimple_rhs_class (rhs_code)
641			      == GIMPLE_SINGLE_RHS)))
642		    {
643		      tree lhs = gimple_assign_lhs (stmt);
644
645		      if (TREE_CODE (lhs) == SSA_NAME
646			  && bitmap_bit_p (si->va_list_escape_vars,
647					   SSA_NAME_VERSION (lhs)))
648			continue;
649
650		      if (TREE_CODE (lhs) == VAR_DECL
651			  && bitmap_bit_p (si->va_list_vars,
652					   DECL_UID (lhs) + num_ssa_names))
653			continue;
654		    }
655		  else if (rhs_code == ADDR_EXPR
656			   && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF
657			   && TREE_OPERAND (TREE_OPERAND (rhs, 0), 0) == use)
658		    {
659		      tree lhs = gimple_assign_lhs (stmt);
660
661		      if (bitmap_bit_p (si->va_list_escape_vars,
662					SSA_NAME_VERSION (lhs)))
663			continue;
664		    }
665		}
666
667	      if (dump_file && (dump_flags & TDF_DETAILS))
668		{
669		  fputs ("va_list escapes in ", dump_file);
670		  print_gimple_stmt (dump_file, stmt, 0, dump_flags);
671		  fputc ('\n', dump_file);
672		}
673	      return true;
674	    }
675	}
676    }
677
678  return false;
679}
680
681
682namespace {
683
684const pass_data pass_data_stdarg =
685{
686  GIMPLE_PASS, /* type */
687  "stdarg", /* name */
688  OPTGROUP_NONE, /* optinfo_flags */
689  TV_NONE, /* tv_id */
690  ( PROP_cfg | PROP_ssa ), /* properties_required */
691  0, /* properties_provided */
692  0, /* properties_destroyed */
693  0, /* todo_flags_start */
694  0, /* todo_flags_finish */
695};
696
697class pass_stdarg : public gimple_opt_pass
698{
699public:
700  pass_stdarg (gcc::context *ctxt)
701    : gimple_opt_pass (pass_data_stdarg, ctxt)
702  {}
703
704  /* opt_pass methods: */
705  virtual bool gate (function *fun)
706    {
707      return (flag_stdarg_opt
708#ifdef ACCEL_COMPILER
709	      /* Disable for GCC5 in the offloading compilers, as
710		 va_list and gpr/fpr counter fields are not merged.
711		 In GCC6 when stdarg is lowered late this shouldn't be
712		 an issue.  */
713	      && !in_lto_p
714#endif
715	      /* This optimization is only for stdarg functions.  */
716	      && fun->stdarg != 0);
717    }
718
719  virtual unsigned int execute (function *);
720
721}; // class pass_stdarg
722
723unsigned int
724pass_stdarg::execute (function *fun)
725{
726  basic_block bb;
727  bool va_list_escapes = false;
728  bool va_list_simple_ptr;
729  struct stdarg_info si;
730  struct walk_stmt_info wi;
731  const char *funcname = NULL;
732  tree cfun_va_list;
733
734  fun->va_list_gpr_size = 0;
735  fun->va_list_fpr_size = 0;
736  memset (&si, 0, sizeof (si));
737  si.va_list_vars = BITMAP_ALLOC (NULL);
738  si.va_list_escape_vars = BITMAP_ALLOC (NULL);
739
740  if (dump_file)
741    funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
742
743  cfun_va_list = targetm.fn_abi_va_list (fun->decl);
744  va_list_simple_ptr = POINTER_TYPE_P (cfun_va_list)
745		       && (TREE_TYPE (cfun_va_list) == void_type_node
746			   || TREE_TYPE (cfun_va_list) == char_type_node);
747  gcc_assert (is_gimple_reg_type (cfun_va_list) == va_list_simple_ptr);
748
749  FOR_EACH_BB_FN (bb, fun)
750    {
751      gimple_stmt_iterator i;
752
753      for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
754	{
755	  gimple stmt = gsi_stmt (i);
756	  tree callee, ap;
757
758	  if (!is_gimple_call (stmt))
759	    continue;
760
761	  callee = gimple_call_fndecl (stmt);
762	  if (!callee
763	      || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
764	    continue;
765
766	  switch (DECL_FUNCTION_CODE (callee))
767	    {
768	    case BUILT_IN_VA_START:
769	      break;
770	      /* If old style builtins are used, don't optimize anything.  */
771	    case BUILT_IN_SAVEREGS:
772	    case BUILT_IN_NEXT_ARG:
773	      va_list_escapes = true;
774	      continue;
775	    default:
776	      continue;
777	    }
778
779	  si.va_start_count++;
780	  ap = gimple_call_arg (stmt, 0);
781
782	  if (TREE_CODE (ap) != ADDR_EXPR)
783	    {
784	      va_list_escapes = true;
785	      break;
786	    }
787	  ap = TREE_OPERAND (ap, 0);
788	  if (TREE_CODE (ap) == ARRAY_REF)
789	    {
790	      if (! integer_zerop (TREE_OPERAND (ap, 1)))
791	        {
792	          va_list_escapes = true;
793	          break;
794		}
795	      ap = TREE_OPERAND (ap, 0);
796	    }
797	  if (TYPE_MAIN_VARIANT (TREE_TYPE (ap))
798	      != TYPE_MAIN_VARIANT (targetm.fn_abi_va_list (fun->decl))
799	      || TREE_CODE (ap) != VAR_DECL)
800	    {
801	      va_list_escapes = true;
802	      break;
803	    }
804
805	  if (is_global_var (ap))
806	    {
807	      va_list_escapes = true;
808	      break;
809	    }
810
811	  bitmap_set_bit (si.va_list_vars, DECL_UID (ap) + num_ssa_names);
812
813	  /* VA_START_BB and VA_START_AP will be only used if there is just
814	     one va_start in the function.  */
815	  si.va_start_bb = bb;
816	  si.va_start_ap = ap;
817	}
818
819      if (va_list_escapes)
820	break;
821    }
822
823  /* If there were no va_start uses in the function, there is no need to
824     save anything.  */
825  if (si.va_start_count == 0)
826    goto finish;
827
828  /* If some va_list arguments weren't local, we can't optimize.  */
829  if (va_list_escapes)
830    goto finish;
831
832  /* For void * or char * va_list, something useful can be done only
833     if there is just one va_start.  */
834  if (va_list_simple_ptr && si.va_start_count > 1)
835    {
836      va_list_escapes = true;
837      goto finish;
838    }
839
840  /* For struct * va_list, if the backend didn't tell us what the counter fields
841     are, there is nothing more we can do.  */
842  if (!va_list_simple_ptr
843      && va_list_gpr_counter_field == NULL_TREE
844      && va_list_fpr_counter_field == NULL_TREE)
845    {
846      va_list_escapes = true;
847      goto finish;
848    }
849
850  /* For void * or char * va_list there is just one counter
851     (va_list itself).  Use VA_LIST_GPR_SIZE for it.  */
852  if (va_list_simple_ptr)
853    fun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
854
855  calculate_dominance_info (CDI_DOMINATORS);
856  memset (&wi, 0, sizeof (wi));
857  wi.info = si.va_list_vars;
858
859  FOR_EACH_BB_FN (bb, fun)
860    {
861      si.compute_sizes = -1;
862      si.bb = bb;
863
864      /* For va_list_simple_ptr, we have to check PHI nodes too.  We treat
865	 them as assignments for the purpose of escape analysis.  This is
866	 not needed for non-simple va_list because virtual phis don't perform
867	 any real data movement.  Also, check PHI nodes for taking address of
868	 the va_list vars.  */
869      tree lhs, rhs;
870      use_operand_p uop;
871      ssa_op_iter soi;
872
873      for (gphi_iterator i = gsi_start_phis (bb); !gsi_end_p (i);
874	   gsi_next (&i))
875	{
876	  gphi *phi = i.phi ();
877	  lhs = PHI_RESULT (phi);
878
879	  if (virtual_operand_p (lhs))
880	    continue;
881
882	  if (va_list_simple_ptr)
883	    {
884	      FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
885		{
886		  rhs = USE_FROM_PTR (uop);
887		  if (va_list_ptr_read (&si, rhs, lhs))
888		    continue;
889		  else if (va_list_ptr_write (&si, lhs, rhs))
890		    continue;
891		  else
892		    check_va_list_escapes (&si, lhs, rhs);
893
894		  if (si.va_list_escapes)
895		    {
896		      if (dump_file && (dump_flags & TDF_DETAILS))
897			{
898			  fputs ("va_list escapes in ", dump_file);
899			  print_gimple_stmt (dump_file, phi, 0, dump_flags);
900			  fputc ('\n', dump_file);
901			}
902		      va_list_escapes = true;
903		    }
904		}
905	    }
906
907	  for (unsigned j = 0; !va_list_escapes
908			       && j < gimple_phi_num_args (phi); ++j)
909	    if ((!va_list_simple_ptr
910		 || TREE_CODE (gimple_phi_arg_def (phi, j)) != SSA_NAME)
911		&& walk_tree (gimple_phi_arg_def_ptr (phi, j),
912			      find_va_list_reference, &wi, NULL))
913	      {
914		if (dump_file && (dump_flags & TDF_DETAILS))
915		  {
916		    fputs ("va_list escapes in ", dump_file);
917		    print_gimple_stmt (dump_file, phi, 0, dump_flags);
918		    fputc ('\n', dump_file);
919		  }
920		va_list_escapes = true;
921	      }
922	}
923
924      for (gimple_stmt_iterator i = gsi_start_bb (bb);
925	   !gsi_end_p (i) && !va_list_escapes;
926	   gsi_next (&i))
927	{
928	  gimple stmt = gsi_stmt (i);
929
930	  /* Don't look at __builtin_va_{start,end}, they are ok.  */
931	  if (is_gimple_call (stmt))
932	    {
933	      tree callee = gimple_call_fndecl (stmt);
934
935	      if (callee
936		  && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
937		  && (DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_START
938		      || DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END))
939		continue;
940	    }
941
942	  if (is_gimple_assign (stmt))
943	    {
944	      lhs = gimple_assign_lhs (stmt);
945	      rhs = gimple_assign_rhs1 (stmt);
946
947	      if (va_list_simple_ptr)
948		{
949		  if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
950		      == GIMPLE_SINGLE_RHS)
951		    {
952		      /* Check for ap ={v} {}.  */
953		      if (TREE_CLOBBER_P (rhs))
954			continue;
955
956		      /* Check for tem = ap.  */
957		      else if (va_list_ptr_read (&si, rhs, lhs))
958			continue;
959
960		      /* Check for the last insn in:
961			 tem1 = ap;
962			 tem2 = tem1 + CST;
963			 ap = tem2;
964			 sequence.  */
965		      else if (va_list_ptr_write (&si, lhs, rhs))
966			continue;
967		    }
968
969		  if ((gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
970		       && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST)
971		      || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
972		      || (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
973			  == GIMPLE_SINGLE_RHS))
974		    check_va_list_escapes (&si, lhs, rhs);
975		}
976	      else
977		{
978		  if (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
979		      == GIMPLE_SINGLE_RHS)
980		    {
981		      /* Check for ap ={v} {}.  */
982		      if (TREE_CLOBBER_P (rhs))
983			continue;
984
985		      /* Check for ap[0].field = temp.  */
986		      else if (va_list_counter_struct_op (&si, lhs, rhs, true))
987			continue;
988
989		      /* Check for temp = ap[0].field.  */
990		      else if (va_list_counter_struct_op (&si, rhs, lhs,
991							  false))
992			continue;
993		    }
994
995		  /* Do any architecture specific checking.  */
996		  if (targetm.stdarg_optimize_hook
997		      && targetm.stdarg_optimize_hook (&si, stmt))
998		    continue;
999		}
1000	    }
1001	  else if (is_gimple_debug (stmt))
1002	    continue;
1003
1004	  /* All other uses of va_list are either va_copy (that is not handled
1005	     in this optimization), taking address of va_list variable or
1006	     passing va_list to other functions (in that case va_list might
1007	     escape the function and therefore va_start needs to set it up
1008	     fully), or some unexpected use of va_list.  None of these should
1009	     happen in a gimplified VA_ARG_EXPR.  */
1010	  if (si.va_list_escapes
1011	      || walk_gimple_op (stmt, find_va_list_reference, &wi))
1012	    {
1013	      if (dump_file && (dump_flags & TDF_DETAILS))
1014		{
1015		  fputs ("va_list escapes in ", dump_file);
1016		  print_gimple_stmt (dump_file, stmt, 0, dump_flags);
1017		  fputc ('\n', dump_file);
1018		}
1019	      va_list_escapes = true;
1020	    }
1021	}
1022
1023      if (va_list_escapes)
1024	break;
1025    }
1026
1027  if (! va_list_escapes
1028      && va_list_simple_ptr
1029      && ! bitmap_empty_p (si.va_list_escape_vars)
1030      && check_all_va_list_escapes (&si))
1031    va_list_escapes = true;
1032
1033finish:
1034  if (va_list_escapes)
1035    {
1036      fun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
1037      fun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
1038    }
1039  BITMAP_FREE (si.va_list_vars);
1040  BITMAP_FREE (si.va_list_escape_vars);
1041  free (si.offsets);
1042  if (dump_file)
1043    {
1044      fprintf (dump_file, "%s: va_list escapes %d, needs to save ",
1045	       funcname, (int) va_list_escapes);
1046      if (fun->va_list_gpr_size >= VA_LIST_MAX_GPR_SIZE)
1047	fputs ("all", dump_file);
1048      else
1049	fprintf (dump_file, "%d", cfun->va_list_gpr_size);
1050      fputs (" GPR units and ", dump_file);
1051      if (fun->va_list_fpr_size >= VA_LIST_MAX_FPR_SIZE)
1052	fputs ("all", dump_file);
1053      else
1054	fprintf (dump_file, "%d", cfun->va_list_fpr_size);
1055      fputs (" FPR units.\n", dump_file);
1056    }
1057  return 0;
1058}
1059
1060} // anon namespace
1061
1062gimple_opt_pass *
1063make_pass_stdarg (gcc::context *ctxt)
1064{
1065  return new pass_stdarg (ctxt);
1066}
1067