00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023 #include "system.h"
00024 #include "coretypes.h"
00025 #include "tm.h"
00026 #include "tree.h"
00027 #include "function.h"
00028 #include "langhooks.h"
00029 #include "diagnostic.h"
00030 #include "target.h"
00031 #include "tree-flow.h"
00032 #include "tree-pass.h"
00033 #include "tree-stdarg.h"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 static bool
00048 reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb)
00049 {
00050 edge *stack, e;
00051 edge_iterator ei;
00052 int sp;
00053 sbitmap visited;
00054 bool ret;
00055
00056 if (va_arg_bb == va_start_bb)
00057 return true;
00058
00059 if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb))
00060 return false;
00061
00062 stack = XNEWVEC (edge, n_basic_blocks + 1);
00063 sp = 0;
00064
00065 visited = sbitmap_alloc (last_basic_block);
00066 sbitmap_zero (visited);
00067 ret = true;
00068
00069 FOR_EACH_EDGE (e, ei, va_arg_bb->preds)
00070 stack[sp++] = e;
00071
00072 while (sp)
00073 {
00074 basic_block src;
00075
00076 --sp;
00077 e = stack[sp];
00078 src = e->src;
00079
00080 if (e->flags & EDGE_COMPLEX)
00081 {
00082 ret = false;
00083 break;
00084 }
00085
00086 if (src == va_start_bb)
00087 continue;
00088
00089
00090 if (src == va_arg_bb)
00091 {
00092 ret = false;
00093 break;
00094 }
00095
00096 gcc_assert (src != ENTRY_BLOCK_PTR);
00097
00098 if (! TEST_BIT (visited, src->index))
00099 {
00100 SET_BIT (visited, src->index);
00101 FOR_EACH_EDGE (e, ei, src->preds)
00102 stack[sp++] = e;
00103 }
00104 }
00105
00106 free (stack);
00107 sbitmap_free (visited);
00108 return ret;
00109 }
00110
00111
00112
00113
00114
00115
00116 static unsigned HOST_WIDE_INT
00117 va_list_counter_bump (struct stdarg_info *si, tree counter, tree rhs,
00118 bool gpr_p)
00119 {
00120 tree stmt, lhs, orig_lhs;
00121 unsigned HOST_WIDE_INT ret = 0, val, counter_val;
00122 unsigned int max_size;
00123
00124 if (si->offsets == NULL)
00125 {
00126 unsigned int i;
00127
00128 si->offsets = XNEWVEC (int, num_ssa_names);
00129 for (i = 0; i < num_ssa_names; ++i)
00130 si->offsets[i] = -1;
00131 }
00132
00133 counter_val = gpr_p ? cfun->va_list_gpr_size : cfun->va_list_fpr_size;
00134 max_size = gpr_p ? VA_LIST_MAX_GPR_SIZE : VA_LIST_MAX_FPR_SIZE;
00135 orig_lhs = lhs = rhs;
00136 while (lhs)
00137 {
00138 if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
00139 {
00140 if (counter_val >= max_size)
00141 {
00142 ret = max_size;
00143 break;
00144 }
00145
00146 ret -= counter_val - si->offsets[SSA_NAME_VERSION (lhs)];
00147 break;
00148 }
00149
00150 stmt = SSA_NAME_DEF_STMT (lhs);
00151
00152 if (TREE_CODE (stmt) != MODIFY_EXPR
00153 || TREE_OPERAND (stmt, 0) != lhs)
00154 return (unsigned HOST_WIDE_INT) -1;
00155
00156 rhs = TREE_OPERAND (stmt, 1);
00157 if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
00158 rhs = TREE_OPERAND (rhs, 0);
00159
00160 if (TREE_CODE (rhs) == SSA_NAME)
00161 {
00162 lhs = rhs;
00163 continue;
00164 }
00165
00166 if ((TREE_CODE (rhs) == NOP_EXPR
00167 || TREE_CODE (rhs) == CONVERT_EXPR)
00168 && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
00169 {
00170 lhs = TREE_OPERAND (rhs, 0);
00171 continue;
00172 }
00173
00174 if (TREE_CODE (rhs) == PLUS_EXPR
00175 && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
00176 && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST
00177 && host_integerp (TREE_OPERAND (rhs, 1), 1))
00178 {
00179 ret += tree_low_cst (TREE_OPERAND (rhs, 1), 1);
00180 lhs = TREE_OPERAND (rhs, 0);
00181 continue;
00182 }
00183
00184 if (TREE_CODE (counter) != TREE_CODE (rhs))
00185 return (unsigned HOST_WIDE_INT) -1;
00186
00187 if (TREE_CODE (counter) == COMPONENT_REF)
00188 {
00189 if (get_base_address (counter) != get_base_address (rhs)
00190 || TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL
00191 || TREE_OPERAND (counter, 1) != TREE_OPERAND (rhs, 1))
00192 return (unsigned HOST_WIDE_INT) -1;
00193 }
00194 else if (counter != rhs)
00195 return (unsigned HOST_WIDE_INT) -1;
00196
00197 lhs = NULL;
00198 }
00199
00200 lhs = orig_lhs;
00201 val = ret + counter_val;
00202 while (lhs)
00203 {
00204 if (si->offsets[SSA_NAME_VERSION (lhs)] != -1)
00205 break;
00206
00207 if (val >= max_size)
00208 si->offsets[SSA_NAME_VERSION (lhs)] = max_size;
00209 else
00210 si->offsets[SSA_NAME_VERSION (lhs)] = val;
00211
00212 stmt = SSA_NAME_DEF_STMT (lhs);
00213
00214 rhs = TREE_OPERAND (stmt, 1);
00215 if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
00216 rhs = TREE_OPERAND (rhs, 0);
00217
00218 if (TREE_CODE (rhs) == SSA_NAME)
00219 {
00220 lhs = rhs;
00221 continue;
00222 }
00223
00224 if ((TREE_CODE (rhs) == NOP_EXPR
00225 || TREE_CODE (rhs) == CONVERT_EXPR)
00226 && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
00227 {
00228 lhs = TREE_OPERAND (rhs, 0);
00229 continue;
00230 }
00231
00232 if (TREE_CODE (rhs) == PLUS_EXPR
00233 && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
00234 && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST
00235 && host_integerp (TREE_OPERAND (rhs, 1), 1))
00236 {
00237 val -= tree_low_cst (TREE_OPERAND (rhs, 1), 1);
00238 lhs = TREE_OPERAND (rhs, 0);
00239 continue;
00240 }
00241
00242 lhs = NULL;
00243 }
00244
00245 return ret;
00246 }
00247
00248
00249
00250
00251 static tree
00252 find_va_list_reference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
00253 void *data)
00254 {
00255 bitmap va_list_vars = (bitmap) data;
00256 tree var = *tp;
00257
00258 if (TREE_CODE (var) == SSA_NAME)
00259 var = SSA_NAME_VAR (var);
00260
00261 if (TREE_CODE (var) == VAR_DECL
00262 && bitmap_bit_p (va_list_vars, DECL_UID (var)))
00263 return var;
00264
00265 return NULL_TREE;
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275 static void
00276 va_list_counter_op (struct stdarg_info *si, tree ap, tree var, bool gpr_p,
00277 bool write_p)
00278 {
00279 unsigned HOST_WIDE_INT increment;
00280
00281 if (si->compute_sizes < 0)
00282 {
00283 si->compute_sizes = 0;
00284 if (si->va_start_count == 1
00285 && reachable_at_most_once (si->bb, si->va_start_bb))
00286 si->compute_sizes = 1;
00287
00288 if (dump_file && (dump_flags & TDF_DETAILS))
00289 fprintf (dump_file,
00290 "bb%d will %sbe executed at most once for each va_start "
00291 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
00292 si->va_start_bb->index);
00293 }
00294
00295 if (write_p
00296 && si->compute_sizes
00297 && (increment = va_list_counter_bump (si, ap, var, gpr_p)) + 1 > 1)
00298 {
00299 if (gpr_p && cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
00300 {
00301 cfun->va_list_gpr_size += increment;
00302 return;
00303 }
00304
00305 if (!gpr_p && cfun->va_list_fpr_size + increment < VA_LIST_MAX_FPR_SIZE)
00306 {
00307 cfun->va_list_fpr_size += increment;
00308 return;
00309 }
00310 }
00311
00312 if (write_p || !si->compute_sizes)
00313 {
00314 if (gpr_p)
00315 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
00316 else
00317 cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
00318 }
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 static bool
00330 va_list_counter_struct_op (struct stdarg_info *si, tree ap, tree var,
00331 bool write_p)
00332 {
00333 tree base;
00334
00335 if (TREE_CODE (ap) != COMPONENT_REF
00336 || TREE_CODE (TREE_OPERAND (ap, 1)) != FIELD_DECL)
00337 return false;
00338
00339 if (TREE_CODE (var) != SSA_NAME
00340 || bitmap_bit_p (si->va_list_vars, DECL_UID (SSA_NAME_VAR (var))))
00341 return false;
00342
00343 base = get_base_address (ap);
00344 if (TREE_CODE (base) != VAR_DECL
00345 || !bitmap_bit_p (si->va_list_vars, DECL_UID (base)))
00346 return false;
00347
00348 if (TREE_OPERAND (ap, 1) == va_list_gpr_counter_field)
00349 va_list_counter_op (si, ap, var, true, write_p);
00350 else if (TREE_OPERAND (ap, 1) == va_list_fpr_counter_field)
00351 va_list_counter_op (si, ap, var, false, write_p);
00352
00353 return true;
00354 }
00355
00356
00357
00358
00359
00360 static bool
00361 va_list_ptr_read (struct stdarg_info *si, tree ap, tree tem)
00362 {
00363 if (TREE_CODE (ap) != VAR_DECL
00364 || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap)))
00365 return false;
00366
00367 if (TREE_CODE (tem) != SSA_NAME
00368 || bitmap_bit_p (si->va_list_vars,
00369 DECL_UID (SSA_NAME_VAR (tem)))
00370 || is_global_var (SSA_NAME_VAR (tem)))
00371 return false;
00372
00373 if (si->compute_sizes < 0)
00374 {
00375 si->compute_sizes = 0;
00376 if (si->va_start_count == 1
00377 && reachable_at_most_once (si->bb, si->va_start_bb))
00378 si->compute_sizes = 1;
00379
00380 if (dump_file && (dump_flags & TDF_DETAILS))
00381 fprintf (dump_file,
00382 "bb%d will %sbe executed at most once for each va_start "
00383 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
00384 si->va_start_bb->index);
00385 }
00386
00387
00388
00389
00390 if (! si->compute_sizes)
00391 return false;
00392
00393 if (va_list_counter_bump (si, ap, tem, true) == (unsigned HOST_WIDE_INT) -1)
00394 return false;
00395
00396
00397
00398 bitmap_set_bit (si->va_list_escape_vars,
00399 DECL_UID (SSA_NAME_VAR (tem)));
00400 return true;
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410 static bool
00411 va_list_ptr_write (struct stdarg_info *si, tree ap, tree tem2)
00412 {
00413 unsigned HOST_WIDE_INT increment;
00414
00415 if (TREE_CODE (ap) != VAR_DECL
00416 || !bitmap_bit_p (si->va_list_vars, DECL_UID (ap)))
00417 return false;
00418
00419 if (TREE_CODE (tem2) != SSA_NAME
00420 || bitmap_bit_p (si->va_list_vars, DECL_UID (SSA_NAME_VAR (tem2))))
00421 return false;
00422
00423 if (si->compute_sizes <= 0)
00424 return false;
00425
00426 increment = va_list_counter_bump (si, ap, tem2, true);
00427 if (increment + 1 <= 1)
00428 return false;
00429
00430 if (cfun->va_list_gpr_size + increment < VA_LIST_MAX_GPR_SIZE)
00431 cfun->va_list_gpr_size += increment;
00432 else
00433 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
00434
00435 return true;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444 static void
00445 check_va_list_escapes (struct stdarg_info *si, tree lhs, tree rhs)
00446 {
00447 if (! POINTER_TYPE_P (TREE_TYPE (rhs)))
00448 return;
00449
00450 if ((TREE_CODE (rhs) == PLUS_EXPR
00451 && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST)
00452 || TREE_CODE (rhs) == NOP_EXPR
00453 || TREE_CODE (rhs) == CONVERT_EXPR)
00454 rhs = TREE_OPERAND (rhs, 0);
00455
00456 if (TREE_CODE (rhs) != SSA_NAME
00457 || ! bitmap_bit_p (si->va_list_escape_vars,
00458 DECL_UID (SSA_NAME_VAR (rhs))))
00459 return;
00460
00461 if (TREE_CODE (lhs) != SSA_NAME || is_global_var (SSA_NAME_VAR (lhs)))
00462 {
00463 si->va_list_escapes = true;
00464 return;
00465 }
00466
00467 if (si->compute_sizes < 0)
00468 {
00469 si->compute_sizes = 0;
00470 if (si->va_start_count == 1
00471 && reachable_at_most_once (si->bb, si->va_start_bb))
00472 si->compute_sizes = 1;
00473
00474 if (dump_file && (dump_flags & TDF_DETAILS))
00475 fprintf (dump_file,
00476 "bb%d will %sbe executed at most once for each va_start "
00477 "in bb%d\n", si->bb->index, si->compute_sizes ? "" : "not ",
00478 si->va_start_bb->index);
00479 }
00480
00481
00482
00483
00484 if (! si->compute_sizes)
00485 {
00486 si->va_list_escapes = true;
00487 return;
00488 }
00489
00490 if (va_list_counter_bump (si, si->va_start_ap, lhs, true)
00491 == (unsigned HOST_WIDE_INT) -1)
00492 {
00493 si->va_list_escapes = true;
00494 return;
00495 }
00496
00497 bitmap_set_bit (si->va_list_escape_vars,
00498 DECL_UID (SSA_NAME_VAR (lhs)));
00499 }
00500
00501
00502
00503
00504
00505 static bool
00506 check_all_va_list_escapes (struct stdarg_info *si)
00507 {
00508 basic_block bb;
00509
00510 FOR_EACH_BB (bb)
00511 {
00512 block_stmt_iterator i;
00513
00514 for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
00515 {
00516 tree stmt = bsi_stmt (i), use;
00517 ssa_op_iter iter;
00518
00519 FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_ALL_USES)
00520 {
00521 if (! bitmap_bit_p (si->va_list_escape_vars,
00522 DECL_UID (SSA_NAME_VAR (use))))
00523 continue;
00524
00525 if (TREE_CODE (stmt) == MODIFY_EXPR)
00526 {
00527 tree lhs = TREE_OPERAND (stmt, 0);
00528 tree rhs = TREE_OPERAND (stmt, 1);
00529
00530 if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
00531 rhs = TREE_OPERAND (rhs, 0);
00532
00533
00534 if (TREE_CODE (rhs) == INDIRECT_REF
00535 && TREE_OPERAND (rhs, 0) == use
00536 && TYPE_SIZE_UNIT (TREE_TYPE (rhs))
00537 && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (rhs)), 1)
00538 && si->offsets[SSA_NAME_VERSION (use)] != -1)
00539 {
00540 unsigned HOST_WIDE_INT gpr_size;
00541 tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (rhs));
00542
00543 gpr_size = si->offsets[SSA_NAME_VERSION (use)]
00544 + tree_low_cst (access_size, 1);
00545 if (gpr_size >= VA_LIST_MAX_GPR_SIZE)
00546 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
00547 else if (gpr_size > cfun->va_list_gpr_size)
00548 cfun->va_list_gpr_size = gpr_size;
00549 continue;
00550 }
00551
00552
00553
00554
00555
00556
00557
00558 if ((TREE_CODE (rhs) == PLUS_EXPR
00559 && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST)
00560 || TREE_CODE (rhs) == NOP_EXPR
00561 || TREE_CODE (rhs) == CONVERT_EXPR)
00562 rhs = TREE_OPERAND (rhs, 0);
00563
00564 if (rhs == use)
00565 {
00566 if (TREE_CODE (lhs) == SSA_NAME
00567 && bitmap_bit_p (si->va_list_escape_vars,
00568 DECL_UID (SSA_NAME_VAR (lhs))))
00569 continue;
00570
00571 if (TREE_CODE (lhs) == VAR_DECL
00572 && bitmap_bit_p (si->va_list_vars,
00573 DECL_UID (lhs)))
00574 continue;
00575 }
00576 }
00577
00578 if (dump_file && (dump_flags & TDF_DETAILS))
00579 {
00580 fputs ("va_list escapes in ", dump_file);
00581 print_generic_expr (dump_file, stmt, dump_flags);
00582 fputc ('\n', dump_file);
00583 }
00584 return true;
00585 }
00586 }
00587 }
00588
00589 return false;
00590 }
00591
00592
00593
00594
00595
00596 static bool
00597 gate_optimize_stdarg (void)
00598 {
00599
00600 return current_function_stdarg != 0;
00601 }
00602
00603
00604
00605
00606 static unsigned int
00607 execute_optimize_stdarg (void)
00608 {
00609 basic_block bb;
00610 bool va_list_escapes = false;
00611 bool va_list_simple_ptr;
00612 struct stdarg_info si;
00613 const char *funcname = NULL;
00614
00615 cfun->va_list_gpr_size = 0;
00616 cfun->va_list_fpr_size = 0;
00617 memset (&si, 0, sizeof (si));
00618 si.va_list_vars = BITMAP_ALLOC (NULL);
00619 si.va_list_escape_vars = BITMAP_ALLOC (NULL);
00620
00621 if (dump_file)
00622 funcname = lang_hooks.decl_printable_name (current_function_decl, 2);
00623
00624 va_list_simple_ptr = POINTER_TYPE_P (va_list_type_node)
00625 && (TREE_TYPE (va_list_type_node) == void_type_node
00626 || TREE_TYPE (va_list_type_node) == char_type_node);
00627 gcc_assert (is_gimple_reg_type (va_list_type_node) == va_list_simple_ptr);
00628
00629 FOR_EACH_BB (bb)
00630 {
00631 block_stmt_iterator i;
00632
00633 for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
00634 {
00635 tree stmt = bsi_stmt (i);
00636 tree call = get_call_expr_in (stmt), callee;
00637 tree ap;
00638
00639 if (!call)
00640 continue;
00641
00642 callee = get_callee_fndecl (call);
00643 if (!callee
00644 || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
00645 continue;
00646
00647 switch (DECL_FUNCTION_CODE (callee))
00648 {
00649 case BUILT_IN_VA_START:
00650 break;
00651
00652 case BUILT_IN_SAVEREGS:
00653 case BUILT_IN_STDARG_START:
00654 case BUILT_IN_ARGS_INFO:
00655 case BUILT_IN_NEXT_ARG:
00656 va_list_escapes = true;
00657 continue;
00658 default:
00659 continue;
00660 }
00661
00662 si.va_start_count++;
00663 ap = TREE_VALUE (TREE_OPERAND (call, 1));
00664
00665 if (TREE_CODE (ap) != ADDR_EXPR)
00666 {
00667 va_list_escapes = true;
00668 break;
00669 }
00670 ap = TREE_OPERAND (ap, 0);
00671 if (TREE_CODE (ap) == ARRAY_REF)
00672 {
00673 if (! integer_zerop (TREE_OPERAND (ap, 1)))
00674 {
00675 va_list_escapes = true;
00676 break;
00677 }
00678 ap = TREE_OPERAND (ap, 0);
00679 }
00680 if (TYPE_MAIN_VARIANT (TREE_TYPE (ap))
00681 != TYPE_MAIN_VARIANT (va_list_type_node)
00682 || TREE_CODE (ap) != VAR_DECL)
00683 {
00684 va_list_escapes = true;
00685 break;
00686 }
00687
00688 if (is_global_var (ap))
00689 {
00690 va_list_escapes = true;
00691 break;
00692 }
00693
00694 bitmap_set_bit (si.va_list_vars, DECL_UID (ap));
00695
00696
00697
00698 si.va_start_bb = bb;
00699 si.va_start_ap = ap;
00700 }
00701
00702 if (va_list_escapes)
00703 break;
00704 }
00705
00706
00707
00708 if (si.va_start_count == 0)
00709 goto finish;
00710
00711
00712 if (va_list_escapes)
00713 goto finish;
00714
00715
00716
00717 if (va_list_simple_ptr && si.va_start_count > 1)
00718 {
00719 va_list_escapes = true;
00720 goto finish;
00721 }
00722
00723
00724
00725 if (!va_list_simple_ptr
00726 && va_list_gpr_counter_field == NULL_TREE
00727 && va_list_fpr_counter_field == NULL_TREE)
00728 {
00729 va_list_escapes = true;
00730 goto finish;
00731 }
00732
00733
00734
00735 if (va_list_simple_ptr)
00736 cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
00737
00738 calculate_dominance_info (CDI_DOMINATORS);
00739
00740 FOR_EACH_BB (bb)
00741 {
00742 block_stmt_iterator i;
00743
00744 si.compute_sizes = -1;
00745 si.bb = bb;
00746
00747
00748
00749
00750
00751 if (va_list_simple_ptr)
00752 {
00753 tree phi, lhs, rhs;
00754 use_operand_p uop;
00755 ssa_op_iter soi;
00756
00757 for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
00758 {
00759 lhs = PHI_RESULT (phi);
00760
00761 if (!is_gimple_reg (lhs))
00762 continue;
00763
00764 FOR_EACH_PHI_ARG (uop, phi, soi, SSA_OP_USE)
00765 {
00766 rhs = USE_FROM_PTR (uop);
00767 if (va_list_ptr_read (&si, rhs, lhs))
00768 continue;
00769 else if (va_list_ptr_write (&si, lhs, rhs))
00770 continue;
00771 else
00772 check_va_list_escapes (&si, lhs, rhs);
00773
00774 if (si.va_list_escapes
00775 || walk_tree (&phi, find_va_list_reference,
00776 si.va_list_vars, NULL))
00777 {
00778 if (dump_file && (dump_flags & TDF_DETAILS))
00779 {
00780 fputs ("va_list escapes in ", dump_file);
00781 print_generic_expr (dump_file, phi, dump_flags);
00782 fputc ('\n', dump_file);
00783 }
00784 va_list_escapes = true;
00785 }
00786 }
00787 }
00788 }
00789
00790 for (i = bsi_start (bb);
00791 !bsi_end_p (i) && !va_list_escapes;
00792 bsi_next (&i))
00793 {
00794 tree stmt = bsi_stmt (i);
00795 tree call;
00796
00797
00798 call = get_call_expr_in (stmt);
00799 if (call)
00800 {
00801 tree callee = get_callee_fndecl (call);
00802
00803 if (callee
00804 && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
00805 && (DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_START
00806 || DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END))
00807 continue;
00808 }
00809
00810 if (TREE_CODE (stmt) == MODIFY_EXPR)
00811 {
00812 tree lhs = TREE_OPERAND (stmt, 0);
00813 tree rhs = TREE_OPERAND (stmt, 1);
00814
00815 if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
00816 rhs = TREE_OPERAND (rhs, 0);
00817
00818 if (va_list_simple_ptr)
00819 {
00820
00821 if (va_list_ptr_read (&si, rhs, lhs))
00822 continue;
00823
00824
00825
00826
00827
00828
00829 else if (va_list_ptr_write (&si, lhs, rhs))
00830 continue;
00831
00832 else
00833 check_va_list_escapes (&si, lhs, rhs);
00834 }
00835 else
00836 {
00837
00838 if (va_list_counter_struct_op (&si, lhs, rhs, true))
00839 continue;
00840
00841
00842 else if (va_list_counter_struct_op (&si, rhs, lhs, false))
00843 continue;
00844
00845
00846 else if (targetm.stdarg_optimize_hook
00847 && targetm.stdarg_optimize_hook (&si, lhs, rhs))
00848 continue;
00849 }
00850 }
00851
00852
00853
00854
00855
00856
00857
00858 if (si.va_list_escapes
00859 || walk_tree (&stmt, find_va_list_reference,
00860 si.va_list_vars, NULL))
00861 {
00862 if (dump_file && (dump_flags & TDF_DETAILS))
00863 {
00864 fputs ("va_list escapes in ", dump_file);
00865 print_generic_expr (dump_file, stmt, dump_flags);
00866 fputc ('\n', dump_file);
00867 }
00868 va_list_escapes = true;
00869 }
00870 }
00871
00872 if (va_list_escapes)
00873 break;
00874 }
00875
00876 if (! va_list_escapes
00877 && va_list_simple_ptr
00878 && ! bitmap_empty_p (si.va_list_escape_vars)
00879 && check_all_va_list_escapes (&si))
00880 va_list_escapes = true;
00881
00882 finish:
00883 if (va_list_escapes)
00884 {
00885 cfun->va_list_gpr_size = VA_LIST_MAX_GPR_SIZE;
00886 cfun->va_list_fpr_size = VA_LIST_MAX_FPR_SIZE;
00887 }
00888 BITMAP_FREE (si.va_list_vars);
00889 BITMAP_FREE (si.va_list_escape_vars);
00890 free (si.offsets);
00891 if (dump_file)
00892 {
00893 fprintf (dump_file, "%s: va_list escapes %d, needs to save ",
00894 funcname, (int) va_list_escapes);
00895 if (cfun->va_list_gpr_size >= VA_LIST_MAX_GPR_SIZE)
00896 fputs ("all", dump_file);
00897 else
00898 fprintf (dump_file, "%d", cfun->va_list_gpr_size);
00899 fputs (" GPR units and ", dump_file);
00900 if (cfun->va_list_fpr_size >= VA_LIST_MAX_FPR_SIZE)
00901 fputs ("all", dump_file);
00902 else
00903 fprintf (dump_file, "%d", cfun->va_list_fpr_size);
00904 fputs (" FPR units.\n", dump_file);
00905 }
00906 return 0;
00907 }
00908
00909
00910 struct tree_opt_pass pass_stdarg =
00911 {
00912 "stdarg",
00913 gate_optimize_stdarg,
00914 execute_optimize_stdarg,
00915 NULL,
00916 NULL,
00917 0,
00918 0,
00919 PROP_cfg | PROP_ssa | PROP_alias,
00920 0,
00921 0,
00922 0,
00923 TODO_dump_func,
00924 0
00925 };