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