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