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