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