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