1 /* String length optimization 2 Copyright (C) 2011-2017 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 "rtl.h" 26 #include "tree.h" 27 #include "gimple.h" 28 #include "alloc-pool.h" 29 #include "tree-pass.h" 30 #include "ssa.h" 31 #include "cgraph.h" 32 #include "gimple-pretty-print.h" 33 #include "fold-const.h" 34 #include "stor-layout.h" 35 #include "gimple-fold.h" 36 #include "tree-eh.h" 37 #include "gimplify.h" 38 #include "gimple-iterator.h" 39 #include "gimplify-me.h" 40 #include "expr.h" 41 #include "tree-dfa.h" 42 #include "domwalk.h" 43 #include "tree-ssa-propagate.h" 44 #include "params.h" 45 #include "ipa-chkp.h" 46 #include "tree-hash-traits.h" 47 #include "builtins.h" 48 49 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value 50 is an index into strinfo vector, negative value stands for 51 string length of a string literal (~strlen). */ 52 static vec<int> ssa_ver_to_stridx; 53 54 /* Number of currently active string indexes plus one. */ 55 static int max_stridx; 56 57 /* String information record. */ 58 struct strinfo 59 { 60 /* String length of this string. */ 61 tree length; 62 /* Any of the corresponding pointers for querying alias oracle. */ 63 tree ptr; 64 /* This is used for two things: 65 66 - To record the statement that should be used for delayed length 67 computations. We maintain the invariant that all related strinfos 68 have delayed lengths or none do. 69 70 - To record the malloc or calloc call that produced this result. */ 71 gimple *stmt; 72 /* Pointer to '\0' if known, if NULL, it can be computed as 73 ptr + length. */ 74 tree endptr; 75 /* Reference count. Any changes to strinfo entry possibly shared 76 with dominating basic blocks need unshare_strinfo first, except 77 for dont_invalidate which affects only the immediately next 78 maybe_invalidate. */ 79 int refcount; 80 /* Copy of index. get_strinfo (si->idx) should return si; */ 81 int idx; 82 /* These 3 fields are for chaining related string pointers together. 83 E.g. for 84 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl; 85 strcpy (c, d); e = c + dl; 86 strinfo(a) -> strinfo(c) -> strinfo(e) 87 All have ->first field equal to strinfo(a)->idx and are doubly 88 chained through prev/next fields. The later strinfos are required 89 to point into the same string with zero or more bytes after 90 the previous pointer and all bytes in between the two pointers 91 must be non-zero. Functions like strcpy or memcpy are supposed 92 to adjust all previous strinfo lengths, but not following strinfo 93 lengths (those are uncertain, usually invalidated during 94 maybe_invalidate, except when the alias oracle knows better). 95 Functions like strcat on the other side adjust the whole 96 related strinfo chain. 97 They are updated lazily, so to use the chain the same first fields 98 and si->prev->next == si->idx needs to be verified. */ 99 int first; 100 int next; 101 int prev; 102 /* A flag whether the string is known to be written in the current 103 function. */ 104 bool writable; 105 /* A flag for the next maybe_invalidate that this strinfo shouldn't 106 be invalidated. Always cleared by maybe_invalidate. */ 107 bool dont_invalidate; 108 }; 109 110 /* Pool for allocating strinfo_struct entries. */ 111 static object_allocator<strinfo> strinfo_pool ("strinfo pool"); 112 113 /* Vector mapping positive string indexes to strinfo, for the 114 current basic block. The first pointer in the vector is special, 115 it is either NULL, meaning the vector isn't shared, or it is 116 a basic block pointer to the owner basic_block if shared. 117 If some other bb wants to modify the vector, the vector needs 118 to be unshared first, and only the owner bb is supposed to free it. */ 119 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo; 120 121 /* One OFFSET->IDX mapping. */ 122 struct stridxlist 123 { 124 struct stridxlist *next; 125 HOST_WIDE_INT offset; 126 int idx; 127 }; 128 129 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */ 130 struct decl_stridxlist_map 131 { 132 struct tree_map_base base; 133 struct stridxlist list; 134 }; 135 136 /* Hash table for mapping decls to a chained list of offset -> idx 137 mappings. */ 138 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab; 139 140 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */ 141 static struct obstack stridx_obstack; 142 143 /* Last memcpy statement if it could be adjusted if the trailing 144 '\0' written is immediately overwritten, or 145 *x = '\0' store that could be removed if it is immediately overwritten. */ 146 struct laststmt_struct 147 { 148 gimple *stmt; 149 tree len; 150 int stridx; 151 } laststmt; 152 153 static int get_stridx_plus_constant (strinfo *, HOST_WIDE_INT, tree); 154 155 /* Return strinfo vector entry IDX. */ 156 157 static inline strinfo * 158 get_strinfo (int idx) 159 { 160 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx) 161 return NULL; 162 return (*stridx_to_strinfo)[idx]; 163 } 164 165 /* Get the next strinfo in the chain after SI, or null if none. */ 166 167 static inline strinfo * 168 get_next_strinfo (strinfo *si) 169 { 170 if (si->next == 0) 171 return NULL; 172 strinfo *nextsi = get_strinfo (si->next); 173 if (nextsi == NULL || nextsi->first != si->first || nextsi->prev != si->idx) 174 return NULL; 175 return nextsi; 176 } 177 178 /* Helper function for get_stridx. */ 179 180 static int 181 get_addr_stridx (tree exp, tree ptr) 182 { 183 HOST_WIDE_INT off; 184 struct stridxlist *list, *last = NULL; 185 tree base; 186 187 if (!decl_to_stridxlist_htab) 188 return 0; 189 190 base = get_addr_base_and_unit_offset (exp, &off); 191 if (base == NULL || !DECL_P (base)) 192 return 0; 193 194 list = decl_to_stridxlist_htab->get (base); 195 if (list == NULL) 196 return 0; 197 198 do 199 { 200 if (list->offset == off) 201 return list->idx; 202 if (list->offset > off) 203 return 0; 204 last = list; 205 list = list->next; 206 } 207 while (list); 208 209 if (ptr && last && last->idx > 0) 210 { 211 strinfo *si = get_strinfo (last->idx); 212 if (si 213 && si->length 214 && TREE_CODE (si->length) == INTEGER_CST 215 && compare_tree_int (si->length, off - last->offset) != -1) 216 return get_stridx_plus_constant (si, off - last->offset, ptr); 217 } 218 return 0; 219 } 220 221 /* Return string index for EXP. */ 222 223 static int 224 get_stridx (tree exp) 225 { 226 tree s, o; 227 228 if (TREE_CODE (exp) == SSA_NAME) 229 { 230 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)]) 231 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)]; 232 int i; 233 tree e = exp; 234 HOST_WIDE_INT off = 0; 235 for (i = 0; i < 5; i++) 236 { 237 gimple *def_stmt = SSA_NAME_DEF_STMT (e); 238 if (!is_gimple_assign (def_stmt) 239 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR) 240 return 0; 241 tree rhs1 = gimple_assign_rhs1 (def_stmt); 242 tree rhs2 = gimple_assign_rhs2 (def_stmt); 243 if (TREE_CODE (rhs1) != SSA_NAME 244 || !tree_fits_shwi_p (rhs2)) 245 return 0; 246 HOST_WIDE_INT this_off = tree_to_shwi (rhs2); 247 if (this_off < 0) 248 return 0; 249 off = (unsigned HOST_WIDE_INT) off + this_off; 250 if (off < 0) 251 return 0; 252 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]) 253 { 254 strinfo *si 255 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]); 256 if (si 257 && si->length 258 && TREE_CODE (si->length) == INTEGER_CST 259 && compare_tree_int (si->length, off) != -1) 260 return get_stridx_plus_constant (si, off, exp); 261 } 262 e = rhs1; 263 } 264 return 0; 265 } 266 267 if (TREE_CODE (exp) == ADDR_EXPR) 268 { 269 int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp); 270 if (idx != 0) 271 return idx; 272 } 273 274 s = string_constant (exp, &o); 275 if (s != NULL_TREE 276 && (o == NULL_TREE || tree_fits_shwi_p (o)) 277 && TREE_STRING_LENGTH (s) > 0) 278 { 279 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0; 280 const char *p = TREE_STRING_POINTER (s); 281 int max = TREE_STRING_LENGTH (s) - 1; 282 283 if (p[max] == '\0' && offset >= 0 && offset <= max) 284 return ~(int) strlen (p + offset); 285 } 286 return 0; 287 } 288 289 /* Return true if strinfo vector is shared with the immediate dominator. */ 290 291 static inline bool 292 strinfo_shared (void) 293 { 294 return vec_safe_length (stridx_to_strinfo) 295 && (*stridx_to_strinfo)[0] != NULL; 296 } 297 298 /* Unshare strinfo vector that is shared with the immediate dominator. */ 299 300 static void 301 unshare_strinfo_vec (void) 302 { 303 strinfo *si; 304 unsigned int i = 0; 305 306 gcc_assert (strinfo_shared ()); 307 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo); 308 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i) 309 if (si != NULL) 310 si->refcount++; 311 (*stridx_to_strinfo)[0] = NULL; 312 } 313 314 /* Attempt to create a string index for exp, ADDR_EXPR's operand. 315 Return a pointer to the location where the string index can 316 be stored (if 0) or is stored, or NULL if this can't be tracked. */ 317 318 static int * 319 addr_stridxptr (tree exp) 320 { 321 HOST_WIDE_INT off; 322 323 tree base = get_addr_base_and_unit_offset (exp, &off); 324 if (base == NULL_TREE || !DECL_P (base)) 325 return NULL; 326 327 if (!decl_to_stridxlist_htab) 328 { 329 decl_to_stridxlist_htab 330 = new hash_map<tree_decl_hash, stridxlist> (64); 331 gcc_obstack_init (&stridx_obstack); 332 } 333 334 bool existed; 335 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed); 336 if (existed) 337 { 338 int i; 339 stridxlist *before = NULL; 340 for (i = 0; i < 32; i++) 341 { 342 if (list->offset == off) 343 return &list->idx; 344 if (list->offset > off && before == NULL) 345 before = list; 346 if (list->next == NULL) 347 break; 348 list = list->next; 349 } 350 if (i == 32) 351 return NULL; 352 if (before) 353 { 354 list = before; 355 before = XOBNEW (&stridx_obstack, struct stridxlist); 356 *before = *list; 357 list->next = before; 358 list->offset = off; 359 list->idx = 0; 360 return &list->idx; 361 } 362 list->next = XOBNEW (&stridx_obstack, struct stridxlist); 363 list = list->next; 364 } 365 366 list->next = NULL; 367 list->offset = off; 368 list->idx = 0; 369 return &list->idx; 370 } 371 372 /* Create a new string index, or return 0 if reached limit. */ 373 374 static int 375 new_stridx (tree exp) 376 { 377 int idx; 378 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS)) 379 return 0; 380 if (TREE_CODE (exp) == SSA_NAME) 381 { 382 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp)) 383 return 0; 384 idx = max_stridx++; 385 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx; 386 return idx; 387 } 388 if (TREE_CODE (exp) == ADDR_EXPR) 389 { 390 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0)); 391 if (pidx != NULL) 392 { 393 gcc_assert (*pidx == 0); 394 *pidx = max_stridx++; 395 return *pidx; 396 } 397 } 398 return 0; 399 } 400 401 /* Like new_stridx, but for ADDR_EXPR's operand instead. */ 402 403 static int 404 new_addr_stridx (tree exp) 405 { 406 int *pidx; 407 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS)) 408 return 0; 409 pidx = addr_stridxptr (exp); 410 if (pidx != NULL) 411 { 412 gcc_assert (*pidx == 0); 413 *pidx = max_stridx++; 414 return *pidx; 415 } 416 return 0; 417 } 418 419 /* Create a new strinfo. */ 420 421 static strinfo * 422 new_strinfo (tree ptr, int idx, tree length) 423 { 424 strinfo *si = strinfo_pool.allocate (); 425 si->length = length; 426 si->ptr = ptr; 427 si->stmt = NULL; 428 si->endptr = NULL_TREE; 429 si->refcount = 1; 430 si->idx = idx; 431 si->first = 0; 432 si->prev = 0; 433 si->next = 0; 434 si->writable = false; 435 si->dont_invalidate = false; 436 return si; 437 } 438 439 /* Decrease strinfo refcount and free it if not referenced anymore. */ 440 441 static inline void 442 free_strinfo (strinfo *si) 443 { 444 if (si && --si->refcount == 0) 445 strinfo_pool.remove (si); 446 } 447 448 /* Set strinfo in the vector entry IDX to SI. */ 449 450 static inline void 451 set_strinfo (int idx, strinfo *si) 452 { 453 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0]) 454 unshare_strinfo_vec (); 455 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx) 456 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1); 457 (*stridx_to_strinfo)[idx] = si; 458 } 459 460 /* Return the first strinfo in the related strinfo chain 461 if all strinfos in between belong to the chain, otherwise NULL. */ 462 463 static strinfo * 464 verify_related_strinfos (strinfo *origsi) 465 { 466 strinfo *si = origsi, *psi; 467 468 if (origsi->first == 0) 469 return NULL; 470 for (; si->prev; si = psi) 471 { 472 if (si->first != origsi->first) 473 return NULL; 474 psi = get_strinfo (si->prev); 475 if (psi == NULL) 476 return NULL; 477 if (psi->next != si->idx) 478 return NULL; 479 } 480 if (si->idx != si->first) 481 return NULL; 482 return si; 483 } 484 485 /* Set SI's endptr to ENDPTR and compute its length based on SI->ptr. 486 Use LOC for folding. */ 487 488 static void 489 set_endptr_and_length (location_t loc, strinfo *si, tree endptr) 490 { 491 si->endptr = endptr; 492 si->stmt = NULL; 493 tree start_as_size = fold_convert_loc (loc, size_type_node, si->ptr); 494 tree end_as_size = fold_convert_loc (loc, size_type_node, endptr); 495 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node, 496 end_as_size, start_as_size); 497 } 498 499 /* Return string length, or NULL if it can't be computed. */ 500 501 static tree 502 get_string_length (strinfo *si) 503 { 504 if (si->length) 505 return si->length; 506 507 if (si->stmt) 508 { 509 gimple *stmt = si->stmt, *lenstmt; 510 bool with_bounds = gimple_call_with_bounds_p (stmt); 511 tree callee, lhs, fn, tem; 512 location_t loc; 513 gimple_stmt_iterator gsi; 514 515 gcc_assert (is_gimple_call (stmt)); 516 callee = gimple_call_fndecl (stmt); 517 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL); 518 lhs = gimple_call_lhs (stmt); 519 /* unshare_strinfo is intentionally not called here. The (delayed) 520 transformation of strcpy or strcat into stpcpy is done at the place 521 of the former strcpy/strcat call and so can affect all the strinfos 522 with the same stmt. If they were unshared before and transformation 523 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should 524 just compute the right length. */ 525 switch (DECL_FUNCTION_CODE (callee)) 526 { 527 case BUILT_IN_STRCAT: 528 case BUILT_IN_STRCAT_CHK: 529 case BUILT_IN_STRCAT_CHKP: 530 case BUILT_IN_STRCAT_CHK_CHKP: 531 gsi = gsi_for_stmt (stmt); 532 fn = builtin_decl_implicit (BUILT_IN_STRLEN); 533 gcc_assert (lhs == NULL_TREE); 534 tem = unshare_expr (gimple_call_arg (stmt, 0)); 535 if (with_bounds) 536 { 537 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl, 538 2, tem, gimple_call_arg (stmt, 1)); 539 gimple_call_set_with_bounds (lenstmt, true); 540 } 541 else 542 lenstmt = gimple_build_call (fn, 1, tem); 543 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt); 544 gimple_call_set_lhs (lenstmt, lhs); 545 gimple_set_vuse (lenstmt, gimple_vuse (stmt)); 546 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT); 547 tem = gimple_call_arg (stmt, 0); 548 if (!ptrofftype_p (TREE_TYPE (lhs))) 549 { 550 lhs = convert_to_ptrofftype (lhs); 551 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE, 552 true, GSI_SAME_STMT); 553 } 554 lenstmt = gimple_build_assign 555 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))), 556 POINTER_PLUS_EXPR,tem, lhs); 557 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT); 558 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt)); 559 lhs = NULL_TREE; 560 /* FALLTHRU */ 561 case BUILT_IN_STRCPY: 562 case BUILT_IN_STRCPY_CHK: 563 case BUILT_IN_STRCPY_CHKP: 564 case BUILT_IN_STRCPY_CHK_CHKP: 565 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY)); 566 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2)) 567 fn = builtin_decl_implicit (BUILT_IN_STPCPY); 568 else 569 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK); 570 if (with_bounds) 571 fn = chkp_maybe_create_clone (fn)->decl; 572 gcc_assert (lhs == NULL_TREE); 573 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 574 { 575 fprintf (dump_file, "Optimizing: "); 576 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 577 } 578 gimple_call_set_fndecl (stmt, fn); 579 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt); 580 gimple_call_set_lhs (stmt, lhs); 581 update_stmt (stmt); 582 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 583 { 584 fprintf (dump_file, "into: "); 585 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 586 } 587 /* FALLTHRU */ 588 case BUILT_IN_STPCPY: 589 case BUILT_IN_STPCPY_CHK: 590 case BUILT_IN_STPCPY_CHKP: 591 case BUILT_IN_STPCPY_CHK_CHKP: 592 gcc_assert (lhs != NULL_TREE); 593 loc = gimple_location (stmt); 594 set_endptr_and_length (loc, si, lhs); 595 for (strinfo *chainsi = verify_related_strinfos (si); 596 chainsi != NULL; 597 chainsi = get_next_strinfo (chainsi)) 598 if (chainsi->length == NULL) 599 set_endptr_and_length (loc, chainsi, lhs); 600 break; 601 case BUILT_IN_MALLOC: 602 break; 603 /* BUILT_IN_CALLOC always has si->length set. */ 604 default: 605 gcc_unreachable (); 606 break; 607 } 608 } 609 610 return si->length; 611 } 612 613 /* Invalidate string length information for strings whose length 614 might change due to stores in stmt. */ 615 616 static bool 617 maybe_invalidate (gimple *stmt) 618 { 619 strinfo *si; 620 unsigned int i; 621 bool nonempty = false; 622 623 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i) 624 if (si != NULL) 625 { 626 if (!si->dont_invalidate) 627 { 628 ao_ref r; 629 /* Do not use si->length. */ 630 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE); 631 if (stmt_may_clobber_ref_p_1 (stmt, &r)) 632 { 633 set_strinfo (i, NULL); 634 free_strinfo (si); 635 continue; 636 } 637 } 638 si->dont_invalidate = false; 639 nonempty = true; 640 } 641 return nonempty; 642 } 643 644 /* Unshare strinfo record SI, if it has refcount > 1 or 645 if stridx_to_strinfo vector is shared with some other 646 bbs. */ 647 648 static strinfo * 649 unshare_strinfo (strinfo *si) 650 { 651 strinfo *nsi; 652 653 if (si->refcount == 1 && !strinfo_shared ()) 654 return si; 655 656 nsi = new_strinfo (si->ptr, si->idx, si->length); 657 nsi->stmt = si->stmt; 658 nsi->endptr = si->endptr; 659 nsi->first = si->first; 660 nsi->prev = si->prev; 661 nsi->next = si->next; 662 nsi->writable = si->writable; 663 set_strinfo (si->idx, nsi); 664 free_strinfo (si); 665 return nsi; 666 } 667 668 /* Attempt to create a new strinfo for BASESI + OFF, or find existing 669 strinfo if there is any. Return it's idx, or 0 if no strinfo has 670 been created. */ 671 672 static int 673 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr) 674 { 675 if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr)) 676 return 0; 677 678 if (basesi->length == NULL_TREE 679 || TREE_CODE (basesi->length) != INTEGER_CST 680 || compare_tree_int (basesi->length, off) == -1 681 || !tree_fits_shwi_p (basesi->length)) 682 return 0; 683 684 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off; 685 strinfo *si = basesi, *chainsi; 686 if (si->first || si->prev || si->next) 687 si = verify_related_strinfos (basesi); 688 if (si == NULL 689 || si->length == NULL_TREE 690 || TREE_CODE (si->length) != INTEGER_CST) 691 return 0; 692 693 if (TREE_CODE (ptr) == SSA_NAME 694 && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr)) 695 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names); 696 697 gcc_checking_assert (compare_tree_int (si->length, off) != -1); 698 for (chainsi = si; chainsi->next; chainsi = si) 699 { 700 si = get_strinfo (chainsi->next); 701 if (si == NULL 702 || si->first != chainsi->first 703 || si->prev != chainsi->idx 704 || si->length == NULL_TREE 705 || TREE_CODE (si->length) != INTEGER_CST) 706 break; 707 int r = compare_tree_int (si->length, len); 708 if (r != 1) 709 { 710 if (r == 0) 711 { 712 if (TREE_CODE (ptr) == SSA_NAME) 713 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx; 714 else 715 { 716 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0)); 717 if (pidx != NULL && *pidx == 0) 718 *pidx = si->idx; 719 } 720 return si->idx; 721 } 722 break; 723 } 724 } 725 726 int idx = new_stridx (ptr); 727 if (idx == 0) 728 return 0; 729 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len)); 730 set_strinfo (idx, si); 731 if (chainsi->next) 732 { 733 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next)); 734 si->next = nextsi->idx; 735 nextsi->prev = idx; 736 } 737 chainsi = unshare_strinfo (chainsi); 738 if (chainsi->first == 0) 739 chainsi->first = chainsi->idx; 740 chainsi->next = idx; 741 if (chainsi->endptr == NULL_TREE && len == 0) 742 chainsi->endptr = ptr; 743 si->endptr = chainsi->endptr; 744 si->prev = chainsi->idx; 745 si->first = chainsi->first; 746 si->writable = chainsi->writable; 747 return si->idx; 748 } 749 750 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points 751 to a zero-length string and if possible chain it to a related strinfo 752 chain whose part is or might be CHAINSI. */ 753 754 static strinfo * 755 zero_length_string (tree ptr, strinfo *chainsi) 756 { 757 strinfo *si; 758 int idx; 759 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr)) 760 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names); 761 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME 762 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0); 763 764 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr)) 765 return NULL; 766 if (chainsi != NULL) 767 { 768 si = verify_related_strinfos (chainsi); 769 if (si) 770 { 771 chainsi = si; 772 for (; chainsi->next; chainsi = si) 773 { 774 if (chainsi->endptr == NULL_TREE) 775 { 776 chainsi = unshare_strinfo (chainsi); 777 chainsi->endptr = ptr; 778 } 779 si = get_strinfo (chainsi->next); 780 if (si == NULL 781 || si->first != chainsi->first 782 || si->prev != chainsi->idx) 783 break; 784 } 785 gcc_assert (chainsi->length || chainsi->stmt); 786 if (chainsi->endptr == NULL_TREE) 787 { 788 chainsi = unshare_strinfo (chainsi); 789 chainsi->endptr = ptr; 790 } 791 if (chainsi->length && integer_zerop (chainsi->length)) 792 { 793 if (chainsi->next) 794 { 795 chainsi = unshare_strinfo (chainsi); 796 chainsi->next = 0; 797 } 798 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx; 799 return chainsi; 800 } 801 } 802 else if (chainsi->first || chainsi->prev || chainsi->next) 803 { 804 chainsi = unshare_strinfo (chainsi); 805 chainsi->first = 0; 806 chainsi->prev = 0; 807 chainsi->next = 0; 808 } 809 } 810 idx = new_stridx (ptr); 811 if (idx == 0) 812 return NULL; 813 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0)); 814 set_strinfo (idx, si); 815 si->endptr = ptr; 816 if (chainsi != NULL) 817 { 818 chainsi = unshare_strinfo (chainsi); 819 if (chainsi->first == 0) 820 chainsi->first = chainsi->idx; 821 chainsi->next = idx; 822 if (chainsi->endptr == NULL_TREE) 823 chainsi->endptr = ptr; 824 si->prev = chainsi->idx; 825 si->first = chainsi->first; 826 si->writable = chainsi->writable; 827 } 828 return si; 829 } 830 831 /* For strinfo ORIGSI whose length has been just updated 832 update also related strinfo lengths (add ADJ to each, 833 but don't adjust ORIGSI). */ 834 835 static void 836 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj) 837 { 838 strinfo *si = verify_related_strinfos (origsi); 839 840 if (si == NULL) 841 return; 842 843 while (1) 844 { 845 strinfo *nsi; 846 847 if (si != origsi) 848 { 849 tree tem; 850 851 si = unshare_strinfo (si); 852 if (si->length) 853 { 854 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj); 855 si->length = fold_build2_loc (loc, PLUS_EXPR, 856 TREE_TYPE (si->length), si->length, 857 tem); 858 } 859 else if (si->stmt != NULL) 860 /* Delayed length computation is unaffected. */ 861 ; 862 else 863 gcc_unreachable (); 864 865 si->endptr = NULL_TREE; 866 si->dont_invalidate = true; 867 } 868 if (si->next == 0) 869 return; 870 nsi = get_strinfo (si->next); 871 if (nsi == NULL 872 || nsi->first != si->first 873 || nsi->prev != si->idx) 874 return; 875 si = nsi; 876 } 877 } 878 879 /* Find if there are other SSA_NAME pointers equal to PTR 880 for which we don't track their string lengths yet. If so, use 881 IDX for them. */ 882 883 static void 884 find_equal_ptrs (tree ptr, int idx) 885 { 886 if (TREE_CODE (ptr) != SSA_NAME) 887 return; 888 while (1) 889 { 890 gimple *stmt = SSA_NAME_DEF_STMT (ptr); 891 if (!is_gimple_assign (stmt)) 892 return; 893 ptr = gimple_assign_rhs1 (stmt); 894 switch (gimple_assign_rhs_code (stmt)) 895 { 896 case SSA_NAME: 897 break; 898 CASE_CONVERT: 899 if (!POINTER_TYPE_P (TREE_TYPE (ptr))) 900 return; 901 if (TREE_CODE (ptr) == SSA_NAME) 902 break; 903 if (TREE_CODE (ptr) != ADDR_EXPR) 904 return; 905 /* FALLTHRU */ 906 case ADDR_EXPR: 907 { 908 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0)); 909 if (pidx != NULL && *pidx == 0) 910 *pidx = idx; 911 return; 912 } 913 default: 914 return; 915 } 916 917 /* We might find an endptr created in this pass. Grow the 918 vector in that case. */ 919 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr)) 920 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names); 921 922 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0) 923 return; 924 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx; 925 } 926 } 927 928 /* Return true if STMT is a call to a builtin function with the right 929 arguments and attributes that should be considered for optimization 930 by this pass. */ 931 932 static bool 933 valid_builtin_call (gimple *stmt) 934 { 935 if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) 936 return false; 937 938 tree callee = gimple_call_fndecl (stmt); 939 tree decl = builtin_decl_explicit (DECL_FUNCTION_CODE (callee)); 940 if (decl 941 && decl != callee 942 && !gimple_builtin_call_types_compatible_p (stmt, decl)) 943 return false; 944 945 switch (DECL_FUNCTION_CODE (callee)) 946 { 947 case BUILT_IN_MEMCMP: 948 case BUILT_IN_MEMCMP_EQ: 949 case BUILT_IN_STRCMP: 950 case BUILT_IN_STRNCMP: 951 case BUILT_IN_STRCHR: 952 case BUILT_IN_STRCHR_CHKP: 953 case BUILT_IN_STRLEN: 954 case BUILT_IN_STRLEN_CHKP: 955 /* The above functions should be pure. Punt if they aren't. */ 956 if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE) 957 return false; 958 break; 959 960 case BUILT_IN_CALLOC: 961 case BUILT_IN_MALLOC: 962 case BUILT_IN_MEMCPY: 963 case BUILT_IN_MEMCPY_CHK: 964 case BUILT_IN_MEMCPY_CHKP: 965 case BUILT_IN_MEMCPY_CHK_CHKP: 966 case BUILT_IN_MEMPCPY: 967 case BUILT_IN_MEMPCPY_CHK: 968 case BUILT_IN_MEMPCPY_CHKP: 969 case BUILT_IN_MEMPCPY_CHK_CHKP: 970 case BUILT_IN_MEMSET: 971 case BUILT_IN_STPCPY: 972 case BUILT_IN_STPCPY_CHK: 973 case BUILT_IN_STPCPY_CHKP: 974 case BUILT_IN_STPCPY_CHK_CHKP: 975 case BUILT_IN_STPNCPY: 976 case BUILT_IN_STPNCPY_CHK: 977 case BUILT_IN_STRCAT: 978 case BUILT_IN_STRCAT_CHK: 979 case BUILT_IN_STRCAT_CHKP: 980 case BUILT_IN_STRCAT_CHK_CHKP: 981 case BUILT_IN_STRCPY: 982 case BUILT_IN_STRCPY_CHK: 983 case BUILT_IN_STRCPY_CHKP: 984 case BUILT_IN_STRCPY_CHK_CHKP: 985 case BUILT_IN_STRNCAT: 986 case BUILT_IN_STRNCAT_CHK: 987 case BUILT_IN_STRNCPY: 988 case BUILT_IN_STRNCPY_CHK: 989 /* The above functions should be neither const nor pure. Punt if they 990 aren't. */ 991 if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE) 992 return false; 993 break; 994 995 default: 996 break; 997 } 998 999 return true; 1000 } 1001 1002 /* If the last .MEM setter statement before STMT is 1003 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT 1004 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to 1005 just memcpy (x, y, strlen (y)). SI must be the zero length 1006 strinfo. */ 1007 1008 static void 1009 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat) 1010 { 1011 tree vuse, callee, len; 1012 struct laststmt_struct last = laststmt; 1013 strinfo *lastsi, *firstsi; 1014 unsigned len_arg_no = 2; 1015 1016 laststmt.stmt = NULL; 1017 laststmt.len = NULL_TREE; 1018 laststmt.stridx = 0; 1019 1020 if (last.stmt == NULL) 1021 return; 1022 1023 vuse = gimple_vuse (stmt); 1024 if (vuse == NULL_TREE 1025 || SSA_NAME_DEF_STMT (vuse) != last.stmt 1026 || !has_single_use (vuse)) 1027 return; 1028 1029 gcc_assert (last.stridx > 0); 1030 lastsi = get_strinfo (last.stridx); 1031 if (lastsi == NULL) 1032 return; 1033 1034 if (lastsi != si) 1035 { 1036 if (lastsi->first == 0 || lastsi->first != si->first) 1037 return; 1038 1039 firstsi = verify_related_strinfos (si); 1040 if (firstsi == NULL) 1041 return; 1042 while (firstsi != lastsi) 1043 { 1044 strinfo *nextsi; 1045 if (firstsi->next == 0) 1046 return; 1047 nextsi = get_strinfo (firstsi->next); 1048 if (nextsi == NULL 1049 || nextsi->prev != firstsi->idx 1050 || nextsi->first != si->first) 1051 return; 1052 firstsi = nextsi; 1053 } 1054 } 1055 1056 if (!is_strcat) 1057 { 1058 if (si->length == NULL_TREE || !integer_zerop (si->length)) 1059 return; 1060 } 1061 1062 if (is_gimple_assign (last.stmt)) 1063 { 1064 gimple_stmt_iterator gsi; 1065 1066 if (!integer_zerop (gimple_assign_rhs1 (last.stmt))) 1067 return; 1068 if (stmt_could_throw_p (last.stmt)) 1069 return; 1070 gsi = gsi_for_stmt (last.stmt); 1071 unlink_stmt_vdef (last.stmt); 1072 release_defs (last.stmt); 1073 gsi_remove (&gsi, true); 1074 return; 1075 } 1076 1077 if (!valid_builtin_call (last.stmt)) 1078 return; 1079 1080 callee = gimple_call_fndecl (last.stmt); 1081 switch (DECL_FUNCTION_CODE (callee)) 1082 { 1083 case BUILT_IN_MEMCPY: 1084 case BUILT_IN_MEMCPY_CHK: 1085 break; 1086 case BUILT_IN_MEMCPY_CHKP: 1087 case BUILT_IN_MEMCPY_CHK_CHKP: 1088 len_arg_no = 4; 1089 break; 1090 default: 1091 return; 1092 } 1093 1094 len = gimple_call_arg (last.stmt, len_arg_no); 1095 if (tree_fits_uhwi_p (len)) 1096 { 1097 if (!tree_fits_uhwi_p (last.len) 1098 || integer_zerop (len) 1099 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1) 1100 return; 1101 /* Don't adjust the length if it is divisible by 4, it is more efficient 1102 to store the extra '\0' in that case. */ 1103 if ((tree_to_uhwi (len) & 3) == 0) 1104 return; 1105 } 1106 else if (TREE_CODE (len) == SSA_NAME) 1107 { 1108 gimple *def_stmt = SSA_NAME_DEF_STMT (len); 1109 if (!is_gimple_assign (def_stmt) 1110 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR 1111 || gimple_assign_rhs1 (def_stmt) != last.len 1112 || !integer_onep (gimple_assign_rhs2 (def_stmt))) 1113 return; 1114 } 1115 else 1116 return; 1117 1118 gimple_call_set_arg (last.stmt, len_arg_no, last.len); 1119 update_stmt (last.stmt); 1120 } 1121 1122 /* Handle a strlen call. If strlen of the argument is known, replace 1123 the strlen call with the known value, otherwise remember that strlen 1124 of the argument is stored in the lhs SSA_NAME. */ 1125 1126 static void 1127 handle_builtin_strlen (gimple_stmt_iterator *gsi) 1128 { 1129 int idx; 1130 tree src; 1131 gimple *stmt = gsi_stmt (*gsi); 1132 tree lhs = gimple_call_lhs (stmt); 1133 1134 if (lhs == NULL_TREE) 1135 return; 1136 1137 src = gimple_call_arg (stmt, 0); 1138 idx = get_stridx (src); 1139 if (idx) 1140 { 1141 strinfo *si = NULL; 1142 tree rhs; 1143 1144 if (idx < 0) 1145 rhs = build_int_cst (TREE_TYPE (lhs), ~idx); 1146 else 1147 { 1148 rhs = NULL_TREE; 1149 si = get_strinfo (idx); 1150 if (si != NULL) 1151 rhs = get_string_length (si); 1152 } 1153 if (rhs != NULL_TREE) 1154 { 1155 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1156 { 1157 fprintf (dump_file, "Optimizing: "); 1158 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1159 } 1160 rhs = unshare_expr (rhs); 1161 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) 1162 rhs = fold_convert_loc (gimple_location (stmt), 1163 TREE_TYPE (lhs), rhs); 1164 if (!update_call_from_tree (gsi, rhs)) 1165 gimplify_and_update_call_from_tree (gsi, rhs); 1166 stmt = gsi_stmt (*gsi); 1167 update_stmt (stmt); 1168 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1169 { 1170 fprintf (dump_file, "into: "); 1171 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1172 } 1173 if (si != NULL 1174 && TREE_CODE (si->length) != SSA_NAME 1175 && TREE_CODE (si->length) != INTEGER_CST 1176 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)) 1177 { 1178 si = unshare_strinfo (si); 1179 si->length = lhs; 1180 } 1181 return; 1182 } 1183 } 1184 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)) 1185 return; 1186 if (idx == 0) 1187 idx = new_stridx (src); 1188 else if (get_strinfo (idx) != NULL) 1189 return; 1190 if (idx) 1191 { 1192 strinfo *si = new_strinfo (src, idx, lhs); 1193 set_strinfo (idx, si); 1194 find_equal_ptrs (src, idx); 1195 } 1196 } 1197 1198 /* Handle a strchr call. If strlen of the first argument is known, replace 1199 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember 1200 that lhs of the call is endptr and strlen of the argument is endptr - x. */ 1201 1202 static void 1203 handle_builtin_strchr (gimple_stmt_iterator *gsi) 1204 { 1205 int idx; 1206 tree src; 1207 gimple *stmt = gsi_stmt (*gsi); 1208 tree lhs = gimple_call_lhs (stmt); 1209 bool with_bounds = gimple_call_with_bounds_p (stmt); 1210 1211 if (lhs == NULL_TREE) 1212 return; 1213 1214 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1))) 1215 return; 1216 1217 src = gimple_call_arg (stmt, 0); 1218 idx = get_stridx (src); 1219 if (idx) 1220 { 1221 strinfo *si = NULL; 1222 tree rhs; 1223 1224 if (idx < 0) 1225 rhs = build_int_cst (size_type_node, ~idx); 1226 else 1227 { 1228 rhs = NULL_TREE; 1229 si = get_strinfo (idx); 1230 if (si != NULL) 1231 rhs = get_string_length (si); 1232 } 1233 if (rhs != NULL_TREE) 1234 { 1235 location_t loc = gimple_location (stmt); 1236 1237 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1238 { 1239 fprintf (dump_file, "Optimizing: "); 1240 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1241 } 1242 if (si != NULL && si->endptr != NULL_TREE) 1243 { 1244 rhs = unshare_expr (si->endptr); 1245 if (!useless_type_conversion_p (TREE_TYPE (lhs), 1246 TREE_TYPE (rhs))) 1247 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs); 1248 } 1249 else 1250 { 1251 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs)); 1252 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR, 1253 TREE_TYPE (src), src, rhs); 1254 if (!useless_type_conversion_p (TREE_TYPE (lhs), 1255 TREE_TYPE (rhs))) 1256 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs); 1257 } 1258 if (!update_call_from_tree (gsi, rhs)) 1259 gimplify_and_update_call_from_tree (gsi, rhs); 1260 stmt = gsi_stmt (*gsi); 1261 update_stmt (stmt); 1262 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1263 { 1264 fprintf (dump_file, "into: "); 1265 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1266 } 1267 if (si != NULL 1268 && si->endptr == NULL_TREE 1269 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)) 1270 { 1271 si = unshare_strinfo (si); 1272 si->endptr = lhs; 1273 } 1274 zero_length_string (lhs, si); 1275 return; 1276 } 1277 } 1278 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)) 1279 return; 1280 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src)) 1281 { 1282 if (idx == 0) 1283 idx = new_stridx (src); 1284 else if (get_strinfo (idx) != NULL) 1285 { 1286 zero_length_string (lhs, NULL); 1287 return; 1288 } 1289 if (idx) 1290 { 1291 location_t loc = gimple_location (stmt); 1292 tree lhsu = fold_convert_loc (loc, size_type_node, lhs); 1293 tree srcu = fold_convert_loc (loc, size_type_node, src); 1294 tree length = fold_build2_loc (loc, MINUS_EXPR, 1295 size_type_node, lhsu, srcu); 1296 strinfo *si = new_strinfo (src, idx, length); 1297 si->endptr = lhs; 1298 set_strinfo (idx, si); 1299 find_equal_ptrs (src, idx); 1300 zero_length_string (lhs, si); 1301 } 1302 } 1303 else 1304 zero_length_string (lhs, NULL); 1305 } 1306 1307 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call. 1308 If strlen of the second argument is known, strlen of the first argument 1309 is the same after this call. Furthermore, attempt to convert it to 1310 memcpy. */ 1311 1312 static void 1313 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi) 1314 { 1315 int idx, didx; 1316 tree src, dst, srclen, len, lhs, args, type, fn, oldlen; 1317 bool success; 1318 gimple *stmt = gsi_stmt (*gsi); 1319 strinfo *si, *dsi, *olddsi, *zsi; 1320 location_t loc; 1321 bool with_bounds = gimple_call_with_bounds_p (stmt); 1322 1323 src = gimple_call_arg (stmt, with_bounds ? 2 : 1); 1324 dst = gimple_call_arg (stmt, 0); 1325 lhs = gimple_call_lhs (stmt); 1326 idx = get_stridx (src); 1327 si = NULL; 1328 if (idx > 0) 1329 si = get_strinfo (idx); 1330 1331 didx = get_stridx (dst); 1332 olddsi = NULL; 1333 oldlen = NULL_TREE; 1334 if (didx > 0) 1335 olddsi = get_strinfo (didx); 1336 else if (didx < 0) 1337 return; 1338 1339 if (olddsi != NULL) 1340 adjust_last_stmt (olddsi, stmt, false); 1341 1342 srclen = NULL_TREE; 1343 if (si != NULL) 1344 srclen = get_string_length (si); 1345 else if (idx < 0) 1346 srclen = build_int_cst (size_type_node, ~idx); 1347 1348 loc = gimple_location (stmt); 1349 if (srclen == NULL_TREE) 1350 switch (bcode) 1351 { 1352 case BUILT_IN_STRCPY: 1353 case BUILT_IN_STRCPY_CHK: 1354 case BUILT_IN_STRCPY_CHKP: 1355 case BUILT_IN_STRCPY_CHK_CHKP: 1356 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY)) 1357 return; 1358 break; 1359 case BUILT_IN_STPCPY: 1360 case BUILT_IN_STPCPY_CHK: 1361 case BUILT_IN_STPCPY_CHKP: 1362 case BUILT_IN_STPCPY_CHK_CHKP: 1363 if (lhs == NULL_TREE) 1364 return; 1365 else 1366 { 1367 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs); 1368 srclen = fold_convert_loc (loc, size_type_node, dst); 1369 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node, 1370 lhsuint, srclen); 1371 } 1372 break; 1373 default: 1374 gcc_unreachable (); 1375 } 1376 1377 if (didx == 0) 1378 { 1379 didx = new_stridx (dst); 1380 if (didx == 0) 1381 return; 1382 } 1383 if (olddsi != NULL) 1384 { 1385 oldlen = olddsi->length; 1386 dsi = unshare_strinfo (olddsi); 1387 dsi->length = srclen; 1388 /* Break the chain, so adjust_related_strinfo on later pointers in 1389 the chain won't adjust this one anymore. */ 1390 dsi->next = 0; 1391 dsi->stmt = NULL; 1392 dsi->endptr = NULL_TREE; 1393 } 1394 else 1395 { 1396 dsi = new_strinfo (dst, didx, srclen); 1397 set_strinfo (didx, dsi); 1398 find_equal_ptrs (dst, didx); 1399 } 1400 dsi->writable = true; 1401 dsi->dont_invalidate = true; 1402 1403 if (dsi->length == NULL_TREE) 1404 { 1405 strinfo *chainsi; 1406 1407 /* If string length of src is unknown, use delayed length 1408 computation. If string lenth of dst will be needed, it 1409 can be computed by transforming this strcpy call into 1410 stpcpy and subtracting dst from the return value. */ 1411 1412 /* Look for earlier strings whose length could be determined if 1413 this strcpy is turned into an stpcpy. */ 1414 1415 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL) 1416 { 1417 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next)) 1418 { 1419 /* When setting a stmt for delayed length computation 1420 prevent all strinfos through dsi from being 1421 invalidated. */ 1422 chainsi = unshare_strinfo (chainsi); 1423 chainsi->stmt = stmt; 1424 chainsi->length = NULL_TREE; 1425 chainsi->endptr = NULL_TREE; 1426 chainsi->dont_invalidate = true; 1427 } 1428 } 1429 dsi->stmt = stmt; 1430 return; 1431 } 1432 1433 if (olddsi != NULL) 1434 { 1435 tree adj = NULL_TREE; 1436 if (oldlen == NULL_TREE) 1437 ; 1438 else if (integer_zerop (oldlen)) 1439 adj = srclen; 1440 else if (TREE_CODE (oldlen) == INTEGER_CST 1441 || TREE_CODE (srclen) == INTEGER_CST) 1442 adj = fold_build2_loc (loc, MINUS_EXPR, 1443 TREE_TYPE (srclen), srclen, 1444 fold_convert_loc (loc, TREE_TYPE (srclen), 1445 oldlen)); 1446 if (adj != NULL_TREE) 1447 adjust_related_strinfos (loc, dsi, adj); 1448 else 1449 dsi->prev = 0; 1450 } 1451 /* strcpy src may not overlap dst, so src doesn't need to be 1452 invalidated either. */ 1453 if (si != NULL) 1454 si->dont_invalidate = true; 1455 1456 fn = NULL_TREE; 1457 zsi = NULL; 1458 switch (bcode) 1459 { 1460 case BUILT_IN_STRCPY: 1461 case BUILT_IN_STRCPY_CHKP: 1462 fn = builtin_decl_implicit (BUILT_IN_MEMCPY); 1463 if (lhs) 1464 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx; 1465 break; 1466 case BUILT_IN_STRCPY_CHK: 1467 case BUILT_IN_STRCPY_CHK_CHKP: 1468 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK); 1469 if (lhs) 1470 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx; 1471 break; 1472 case BUILT_IN_STPCPY: 1473 case BUILT_IN_STPCPY_CHKP: 1474 /* This would need adjustment of the lhs (subtract one), 1475 or detection that the trailing '\0' doesn't need to be 1476 written, if it will be immediately overwritten. 1477 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */ 1478 if (lhs) 1479 { 1480 dsi->endptr = lhs; 1481 zsi = zero_length_string (lhs, dsi); 1482 } 1483 break; 1484 case BUILT_IN_STPCPY_CHK: 1485 case BUILT_IN_STPCPY_CHK_CHKP: 1486 /* This would need adjustment of the lhs (subtract one), 1487 or detection that the trailing '\0' doesn't need to be 1488 written, if it will be immediately overwritten. 1489 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */ 1490 if (lhs) 1491 { 1492 dsi->endptr = lhs; 1493 zsi = zero_length_string (lhs, dsi); 1494 } 1495 break; 1496 default: 1497 gcc_unreachable (); 1498 } 1499 if (zsi != NULL) 1500 zsi->dont_invalidate = true; 1501 1502 if (fn == NULL_TREE) 1503 return; 1504 1505 args = TYPE_ARG_TYPES (TREE_TYPE (fn)); 1506 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); 1507 1508 len = fold_convert_loc (loc, type, unshare_expr (srclen)); 1509 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1)); 1510 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true, 1511 GSI_SAME_STMT); 1512 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1513 { 1514 fprintf (dump_file, "Optimizing: "); 1515 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1516 } 1517 if (with_bounds) 1518 { 1519 fn = chkp_maybe_create_clone (fn)->decl; 1520 if (gimple_call_num_args (stmt) == 4) 1521 success = update_gimple_call (gsi, fn, 5, dst, 1522 gimple_call_arg (stmt, 1), 1523 src, 1524 gimple_call_arg (stmt, 3), 1525 len); 1526 else 1527 success = update_gimple_call (gsi, fn, 6, dst, 1528 gimple_call_arg (stmt, 1), 1529 src, 1530 gimple_call_arg (stmt, 3), 1531 len, 1532 gimple_call_arg (stmt, 4)); 1533 } 1534 else 1535 if (gimple_call_num_args (stmt) == 2) 1536 success = update_gimple_call (gsi, fn, 3, dst, src, len); 1537 else 1538 success = update_gimple_call (gsi, fn, 4, dst, src, len, 1539 gimple_call_arg (stmt, 2)); 1540 if (success) 1541 { 1542 stmt = gsi_stmt (*gsi); 1543 gimple_call_set_with_bounds (stmt, with_bounds); 1544 update_stmt (stmt); 1545 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1546 { 1547 fprintf (dump_file, "into: "); 1548 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1549 } 1550 /* Allow adjust_last_stmt to decrease this memcpy's size. */ 1551 laststmt.stmt = stmt; 1552 laststmt.len = srclen; 1553 laststmt.stridx = dsi->idx; 1554 } 1555 else if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1556 fprintf (dump_file, "not possible.\n"); 1557 } 1558 1559 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call. 1560 If strlen of the second argument is known and length of the third argument 1561 is that plus one, strlen of the first argument is the same after this 1562 call. */ 1563 1564 static void 1565 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi) 1566 { 1567 int idx, didx; 1568 tree src, dst, len, lhs, oldlen, newlen; 1569 gimple *stmt = gsi_stmt (*gsi); 1570 strinfo *si, *dsi, *olddsi; 1571 bool with_bounds = gimple_call_with_bounds_p (stmt); 1572 1573 len = gimple_call_arg (stmt, with_bounds ? 4 : 2); 1574 src = gimple_call_arg (stmt, with_bounds ? 2 : 1); 1575 dst = gimple_call_arg (stmt, 0); 1576 idx = get_stridx (src); 1577 if (idx == 0) 1578 return; 1579 1580 didx = get_stridx (dst); 1581 olddsi = NULL; 1582 if (didx > 0) 1583 olddsi = get_strinfo (didx); 1584 else if (didx < 0) 1585 return; 1586 1587 if (olddsi != NULL 1588 && tree_fits_uhwi_p (len) 1589 && !integer_zerop (len)) 1590 adjust_last_stmt (olddsi, stmt, false); 1591 1592 if (idx > 0) 1593 { 1594 gimple *def_stmt; 1595 1596 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */ 1597 si = get_strinfo (idx); 1598 if (si == NULL || si->length == NULL_TREE) 1599 return; 1600 if (TREE_CODE (len) != SSA_NAME) 1601 return; 1602 def_stmt = SSA_NAME_DEF_STMT (len); 1603 if (!is_gimple_assign (def_stmt) 1604 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR 1605 || gimple_assign_rhs1 (def_stmt) != si->length 1606 || !integer_onep (gimple_assign_rhs2 (def_stmt))) 1607 return; 1608 } 1609 else 1610 { 1611 si = NULL; 1612 /* Handle memcpy (x, "abcd", 5) or 1613 memcpy (x, "abc\0uvw", 7). */ 1614 if (!tree_fits_uhwi_p (len) 1615 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx) 1616 return; 1617 } 1618 1619 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME) 1620 adjust_last_stmt (olddsi, stmt, false); 1621 1622 if (didx == 0) 1623 { 1624 didx = new_stridx (dst); 1625 if (didx == 0) 1626 return; 1627 } 1628 if (si != NULL) 1629 newlen = si->length; 1630 else 1631 newlen = build_int_cst (size_type_node, ~idx); 1632 oldlen = NULL_TREE; 1633 if (olddsi != NULL) 1634 { 1635 dsi = unshare_strinfo (olddsi); 1636 oldlen = olddsi->length; 1637 dsi->length = newlen; 1638 /* Break the chain, so adjust_related_strinfo on later pointers in 1639 the chain won't adjust this one anymore. */ 1640 dsi->next = 0; 1641 dsi->stmt = NULL; 1642 dsi->endptr = NULL_TREE; 1643 } 1644 else 1645 { 1646 dsi = new_strinfo (dst, didx, newlen); 1647 set_strinfo (didx, dsi); 1648 find_equal_ptrs (dst, didx); 1649 } 1650 dsi->writable = true; 1651 dsi->dont_invalidate = true; 1652 if (olddsi != NULL) 1653 { 1654 tree adj = NULL_TREE; 1655 location_t loc = gimple_location (stmt); 1656 if (oldlen == NULL_TREE) 1657 ; 1658 else if (integer_zerop (oldlen)) 1659 adj = dsi->length; 1660 else if (TREE_CODE (oldlen) == INTEGER_CST 1661 || TREE_CODE (dsi->length) == INTEGER_CST) 1662 adj = fold_build2_loc (loc, MINUS_EXPR, 1663 TREE_TYPE (dsi->length), dsi->length, 1664 fold_convert_loc (loc, TREE_TYPE (dsi->length), 1665 oldlen)); 1666 if (adj != NULL_TREE) 1667 adjust_related_strinfos (loc, dsi, adj); 1668 else 1669 dsi->prev = 0; 1670 } 1671 /* memcpy src may not overlap dst, so src doesn't need to be 1672 invalidated either. */ 1673 if (si != NULL) 1674 si->dont_invalidate = true; 1675 1676 lhs = gimple_call_lhs (stmt); 1677 switch (bcode) 1678 { 1679 case BUILT_IN_MEMCPY: 1680 case BUILT_IN_MEMCPY_CHK: 1681 case BUILT_IN_MEMCPY_CHKP: 1682 case BUILT_IN_MEMCPY_CHK_CHKP: 1683 /* Allow adjust_last_stmt to decrease this memcpy's size. */ 1684 laststmt.stmt = stmt; 1685 laststmt.len = dsi->length; 1686 laststmt.stridx = dsi->idx; 1687 if (lhs) 1688 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx; 1689 break; 1690 case BUILT_IN_MEMPCPY: 1691 case BUILT_IN_MEMPCPY_CHK: 1692 case BUILT_IN_MEMPCPY_CHKP: 1693 case BUILT_IN_MEMPCPY_CHK_CHKP: 1694 break; 1695 default: 1696 gcc_unreachable (); 1697 } 1698 } 1699 1700 /* Handle a strcat-like ({strcat,__strcat_chk}) call. 1701 If strlen of the second argument is known, strlen of the first argument 1702 is increased by the length of the second argument. Furthermore, attempt 1703 to convert it to memcpy/strcpy if the length of the first argument 1704 is known. */ 1705 1706 static void 1707 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi) 1708 { 1709 int idx, didx; 1710 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr; 1711 bool success; 1712 gimple *stmt = gsi_stmt (*gsi); 1713 strinfo *si, *dsi; 1714 location_t loc; 1715 bool with_bounds = gimple_call_with_bounds_p (stmt); 1716 1717 src = gimple_call_arg (stmt, with_bounds ? 2 : 1); 1718 dst = gimple_call_arg (stmt, 0); 1719 lhs = gimple_call_lhs (stmt); 1720 1721 didx = get_stridx (dst); 1722 if (didx < 0) 1723 return; 1724 1725 dsi = NULL; 1726 if (didx > 0) 1727 dsi = get_strinfo (didx); 1728 if (dsi == NULL || get_string_length (dsi) == NULL_TREE) 1729 { 1730 /* strcat (p, q) can be transformed into 1731 tmp = p + strlen (p); endptr = strpcpy (tmp, q); 1732 with length endptr - p if we need to compute the length 1733 later on. Don't do this transformation if we don't need 1734 it. */ 1735 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE) 1736 { 1737 if (didx == 0) 1738 { 1739 didx = new_stridx (dst); 1740 if (didx == 0) 1741 return; 1742 } 1743 if (dsi == NULL) 1744 { 1745 dsi = new_strinfo (dst, didx, NULL_TREE); 1746 set_strinfo (didx, dsi); 1747 find_equal_ptrs (dst, didx); 1748 } 1749 else 1750 { 1751 dsi = unshare_strinfo (dsi); 1752 dsi->length = NULL_TREE; 1753 dsi->next = 0; 1754 dsi->endptr = NULL_TREE; 1755 } 1756 dsi->writable = true; 1757 dsi->stmt = stmt; 1758 dsi->dont_invalidate = true; 1759 } 1760 return; 1761 } 1762 1763 srclen = NULL_TREE; 1764 si = NULL; 1765 idx = get_stridx (src); 1766 if (idx < 0) 1767 srclen = build_int_cst (size_type_node, ~idx); 1768 else if (idx > 0) 1769 { 1770 si = get_strinfo (idx); 1771 if (si != NULL) 1772 srclen = get_string_length (si); 1773 } 1774 1775 loc = gimple_location (stmt); 1776 dstlen = dsi->length; 1777 endptr = dsi->endptr; 1778 1779 dsi = unshare_strinfo (dsi); 1780 dsi->endptr = NULL_TREE; 1781 dsi->stmt = NULL; 1782 dsi->writable = true; 1783 1784 if (srclen != NULL_TREE) 1785 { 1786 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length), 1787 dsi->length, srclen); 1788 adjust_related_strinfos (loc, dsi, srclen); 1789 dsi->dont_invalidate = true; 1790 } 1791 else 1792 { 1793 dsi->length = NULL; 1794 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY)) 1795 dsi->dont_invalidate = true; 1796 } 1797 1798 if (si != NULL) 1799 /* strcat src may not overlap dst, so src doesn't need to be 1800 invalidated either. */ 1801 si->dont_invalidate = true; 1802 1803 /* For now. Could remove the lhs from the call and add 1804 lhs = dst; afterwards. */ 1805 if (lhs) 1806 return; 1807 1808 fn = NULL_TREE; 1809 objsz = NULL_TREE; 1810 switch (bcode) 1811 { 1812 case BUILT_IN_STRCAT: 1813 case BUILT_IN_STRCAT_CHKP: 1814 if (srclen != NULL_TREE) 1815 fn = builtin_decl_implicit (BUILT_IN_MEMCPY); 1816 else 1817 fn = builtin_decl_implicit (BUILT_IN_STRCPY); 1818 break; 1819 case BUILT_IN_STRCAT_CHK: 1820 case BUILT_IN_STRCAT_CHK_CHKP: 1821 if (srclen != NULL_TREE) 1822 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK); 1823 else 1824 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK); 1825 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2); 1826 break; 1827 default: 1828 gcc_unreachable (); 1829 } 1830 1831 if (fn == NULL_TREE) 1832 return; 1833 1834 len = NULL_TREE; 1835 if (srclen != NULL_TREE) 1836 { 1837 args = TYPE_ARG_TYPES (TREE_TYPE (fn)); 1838 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); 1839 1840 len = fold_convert_loc (loc, type, unshare_expr (srclen)); 1841 len = fold_build2_loc (loc, PLUS_EXPR, type, len, 1842 build_int_cst (type, 1)); 1843 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true, 1844 GSI_SAME_STMT); 1845 } 1846 if (endptr) 1847 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr)); 1848 else 1849 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR, 1850 TREE_TYPE (dst), unshare_expr (dst), 1851 fold_convert_loc (loc, sizetype, 1852 unshare_expr (dstlen))); 1853 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true, 1854 GSI_SAME_STMT); 1855 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1856 { 1857 fprintf (dump_file, "Optimizing: "); 1858 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1859 } 1860 if (with_bounds) 1861 { 1862 fn = chkp_maybe_create_clone (fn)->decl; 1863 if (srclen != NULL_TREE) 1864 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE), 1865 dst, 1866 gimple_call_arg (stmt, 1), 1867 src, 1868 gimple_call_arg (stmt, 3), 1869 len, objsz); 1870 else 1871 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE), 1872 dst, 1873 gimple_call_arg (stmt, 1), 1874 src, 1875 gimple_call_arg (stmt, 3), 1876 objsz); 1877 } 1878 else 1879 if (srclen != NULL_TREE) 1880 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE), 1881 dst, src, len, objsz); 1882 else 1883 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE), 1884 dst, src, objsz); 1885 if (success) 1886 { 1887 stmt = gsi_stmt (*gsi); 1888 gimple_call_set_with_bounds (stmt, with_bounds); 1889 update_stmt (stmt); 1890 if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1891 { 1892 fprintf (dump_file, "into: "); 1893 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); 1894 } 1895 /* If srclen == NULL, note that current string length can be 1896 computed by transforming this strcpy into stpcpy. */ 1897 if (srclen == NULL_TREE && dsi->dont_invalidate) 1898 dsi->stmt = stmt; 1899 adjust_last_stmt (dsi, stmt, true); 1900 if (srclen != NULL_TREE) 1901 { 1902 laststmt.stmt = stmt; 1903 laststmt.len = srclen; 1904 laststmt.stridx = dsi->idx; 1905 } 1906 } 1907 else if (dump_file && (dump_flags & TDF_DETAILS) != 0) 1908 fprintf (dump_file, "not possible.\n"); 1909 } 1910 1911 /* Handle a call to malloc or calloc. */ 1912 1913 static void 1914 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi) 1915 { 1916 gimple *stmt = gsi_stmt (*gsi); 1917 tree lhs = gimple_call_lhs (stmt); 1918 if (lhs == NULL_TREE) 1919 return; 1920 1921 gcc_assert (get_stridx (lhs) == 0); 1922 int idx = new_stridx (lhs); 1923 tree length = NULL_TREE; 1924 if (bcode == BUILT_IN_CALLOC) 1925 length = build_int_cst (size_type_node, 0); 1926 strinfo *si = new_strinfo (lhs, idx, length); 1927 if (bcode == BUILT_IN_CALLOC) 1928 si->endptr = lhs; 1929 set_strinfo (idx, si); 1930 si->writable = true; 1931 si->stmt = stmt; 1932 si->dont_invalidate = true; 1933 } 1934 1935 /* Handle a call to memset. 1936 After a call to calloc, memset(,0,) is unnecessary. 1937 memset(malloc(n),0,n) is calloc(n,1). */ 1938 1939 static bool 1940 handle_builtin_memset (gimple_stmt_iterator *gsi) 1941 { 1942 gimple *stmt2 = gsi_stmt (*gsi); 1943 if (!integer_zerop (gimple_call_arg (stmt2, 1))) 1944 return true; 1945 tree ptr = gimple_call_arg (stmt2, 0); 1946 int idx1 = get_stridx (ptr); 1947 if (idx1 <= 0) 1948 return true; 1949 strinfo *si1 = get_strinfo (idx1); 1950 if (!si1) 1951 return true; 1952 gimple *stmt1 = si1->stmt; 1953 if (!stmt1 || !is_gimple_call (stmt1)) 1954 return true; 1955 tree callee1 = gimple_call_fndecl (stmt1); 1956 if (!valid_builtin_call (stmt1)) 1957 return true; 1958 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1); 1959 tree size = gimple_call_arg (stmt2, 2); 1960 if (code1 == BUILT_IN_CALLOC) 1961 /* Not touching stmt1 */ ; 1962 else if (code1 == BUILT_IN_MALLOC 1963 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0)) 1964 { 1965 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1); 1966 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2, 1967 size, build_one_cst (size_type_node)); 1968 si1->length = build_int_cst (size_type_node, 0); 1969 si1->stmt = gsi_stmt (gsi1); 1970 } 1971 else 1972 return true; 1973 tree lhs = gimple_call_lhs (stmt2); 1974 unlink_stmt_vdef (stmt2); 1975 if (lhs) 1976 { 1977 gimple *assign = gimple_build_assign (lhs, ptr); 1978 gsi_replace (gsi, assign, false); 1979 } 1980 else 1981 { 1982 gsi_remove (gsi, true); 1983 release_defs (stmt2); 1984 } 1985 1986 return false; 1987 } 1988 1989 /* Handle a call to memcmp. We try to handle small comparisons by 1990 converting them to load and compare, and replacing the call to memcmp 1991 with a __builtin_memcmp_eq call where possible. */ 1992 1993 static bool 1994 handle_builtin_memcmp (gimple_stmt_iterator *gsi) 1995 { 1996 gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi)); 1997 tree res = gimple_call_lhs (stmt2); 1998 tree arg1 = gimple_call_arg (stmt2, 0); 1999 tree arg2 = gimple_call_arg (stmt2, 1); 2000 tree len = gimple_call_arg (stmt2, 2); 2001 unsigned HOST_WIDE_INT leni; 2002 use_operand_p use_p; 2003 imm_use_iterator iter; 2004 2005 if (!res) 2006 return true; 2007 2008 FOR_EACH_IMM_USE_FAST (use_p, iter, res) 2009 { 2010 gimple *ustmt = USE_STMT (use_p); 2011 2012 if (is_gimple_debug (ustmt)) 2013 continue; 2014 if (gimple_code (ustmt) == GIMPLE_ASSIGN) 2015 { 2016 gassign *asgn = as_a <gassign *> (ustmt); 2017 tree_code code = gimple_assign_rhs_code (asgn); 2018 if ((code != EQ_EXPR && code != NE_EXPR) 2019 || !integer_zerop (gimple_assign_rhs2 (asgn))) 2020 return true; 2021 } 2022 else if (gimple_code (ustmt) == GIMPLE_COND) 2023 { 2024 tree_code code = gimple_cond_code (ustmt); 2025 if ((code != EQ_EXPR && code != NE_EXPR) 2026 || !integer_zerop (gimple_cond_rhs (ustmt))) 2027 return true; 2028 } 2029 else 2030 return true; 2031 } 2032 2033 if (tree_fits_uhwi_p (len) 2034 && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode) 2035 && pow2p_hwi (leni)) 2036 { 2037 leni *= CHAR_TYPE_SIZE; 2038 unsigned align1 = get_pointer_alignment (arg1); 2039 unsigned align2 = get_pointer_alignment (arg2); 2040 unsigned align = MIN (align1, align2); 2041 machine_mode mode = mode_for_size (leni, MODE_INT, 1); 2042 if (mode != BLKmode 2043 && (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align))) 2044 { 2045 location_t loc = gimple_location (stmt2); 2046 tree type, off; 2047 type = build_nonstandard_integer_type (leni, 1); 2048 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni); 2049 tree ptrtype = build_pointer_type_for_mode (char_type_node, 2050 ptr_mode, true); 2051 off = build_int_cst (ptrtype, 0); 2052 arg1 = build2_loc (loc, MEM_REF, type, arg1, off); 2053 arg2 = build2_loc (loc, MEM_REF, type, arg2, off); 2054 tree tem1 = fold_const_aggregate_ref (arg1); 2055 if (tem1) 2056 arg1 = tem1; 2057 tree tem2 = fold_const_aggregate_ref (arg2); 2058 if (tem2) 2059 arg2 = tem2; 2060 res = fold_convert_loc (loc, TREE_TYPE (res), 2061 fold_build2_loc (loc, NE_EXPR, 2062 boolean_type_node, 2063 arg1, arg2)); 2064 gimplify_and_update_call_from_tree (gsi, res); 2065 return false; 2066 } 2067 } 2068 2069 gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ)); 2070 return false; 2071 } 2072 2073 /* Handle a POINTER_PLUS_EXPR statement. 2074 For p = "abcd" + 2; compute associated length, or if 2075 p = q + off is pointing to a '\0' character of a string, call 2076 zero_length_string on it. */ 2077 2078 static void 2079 handle_pointer_plus (gimple_stmt_iterator *gsi) 2080 { 2081 gimple *stmt = gsi_stmt (*gsi); 2082 tree lhs = gimple_assign_lhs (stmt), off; 2083 int idx = get_stridx (gimple_assign_rhs1 (stmt)); 2084 strinfo *si, *zsi; 2085 2086 if (idx == 0) 2087 return; 2088 2089 if (idx < 0) 2090 { 2091 tree off = gimple_assign_rhs2 (stmt); 2092 if (tree_fits_uhwi_p (off) 2093 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx) 2094 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] 2095 = ~(~idx - (int) tree_to_uhwi (off)); 2096 return; 2097 } 2098 2099 si = get_strinfo (idx); 2100 if (si == NULL || si->length == NULL_TREE) 2101 return; 2102 2103 off = gimple_assign_rhs2 (stmt); 2104 zsi = NULL; 2105 if (operand_equal_p (si->length, off, 0)) 2106 zsi = zero_length_string (lhs, si); 2107 else if (TREE_CODE (off) == SSA_NAME) 2108 { 2109 gimple *def_stmt = SSA_NAME_DEF_STMT (off); 2110 if (gimple_assign_single_p (def_stmt) 2111 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0)) 2112 zsi = zero_length_string (lhs, si); 2113 } 2114 if (zsi != NULL 2115 && si->endptr != NULL_TREE 2116 && si->endptr != lhs 2117 && TREE_CODE (si->endptr) == SSA_NAME) 2118 { 2119 enum tree_code rhs_code 2120 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr)) 2121 ? SSA_NAME : NOP_EXPR; 2122 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr); 2123 gcc_assert (gsi_stmt (*gsi) == stmt); 2124 update_stmt (stmt); 2125 } 2126 } 2127 2128 /* Handle a single character store. */ 2129 2130 static bool 2131 handle_char_store (gimple_stmt_iterator *gsi) 2132 { 2133 int idx = -1; 2134 strinfo *si = NULL; 2135 gimple *stmt = gsi_stmt (*gsi); 2136 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt); 2137 2138 if (TREE_CODE (lhs) == MEM_REF 2139 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME) 2140 { 2141 if (integer_zerop (TREE_OPERAND (lhs, 1))) 2142 { 2143 ssaname = TREE_OPERAND (lhs, 0); 2144 idx = get_stridx (ssaname); 2145 } 2146 } 2147 else 2148 idx = get_addr_stridx (lhs, NULL_TREE); 2149 2150 if (idx > 0) 2151 { 2152 si = get_strinfo (idx); 2153 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length)) 2154 { 2155 if (initializer_zerop (gimple_assign_rhs1 (stmt))) 2156 { 2157 /* When storing '\0', the store can be removed 2158 if we know it has been stored in the current function. */ 2159 if (!stmt_could_throw_p (stmt) && si->writable) 2160 { 2161 unlink_stmt_vdef (stmt); 2162 release_defs (stmt); 2163 gsi_remove (gsi, true); 2164 return false; 2165 } 2166 else 2167 { 2168 si->writable = true; 2169 gsi_next (gsi); 2170 return false; 2171 } 2172 } 2173 else 2174 /* Otherwise this statement overwrites the '\0' with 2175 something, if the previous stmt was a memcpy, 2176 its length may be decreased. */ 2177 adjust_last_stmt (si, stmt, false); 2178 } 2179 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt))) 2180 { 2181 si = unshare_strinfo (si); 2182 si->length = build_int_cst (size_type_node, 0); 2183 si->endptr = NULL; 2184 si->prev = 0; 2185 si->next = 0; 2186 si->stmt = NULL; 2187 si->first = 0; 2188 si->writable = true; 2189 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname)) 2190 si->endptr = ssaname; 2191 si->dont_invalidate = true; 2192 } 2193 /* If si->length is non-zero constant, we aren't overwriting '\0', 2194 and if we aren't storing '\0', we know that the length of the 2195 string and any other zero terminated string in memory remains 2196 the same. In that case we move to the next gimple statement and 2197 return to signal the caller that it shouldn't invalidate anything. 2198 2199 This is benefical for cases like: 2200 2201 char p[20]; 2202 void foo (char *q) 2203 { 2204 strcpy (p, "foobar"); 2205 size_t len = strlen (p); // This can be optimized into 6 2206 size_t len2 = strlen (q); // This has to be computed 2207 p[0] = 'X'; 2208 size_t len3 = strlen (p); // This can be optimized into 6 2209 size_t len4 = strlen (q); // This can be optimized into len2 2210 bar (len, len2, len3, len4); 2211 } 2212 */ 2213 else if (si != NULL && si->length != NULL_TREE 2214 && TREE_CODE (si->length) == INTEGER_CST 2215 && integer_nonzerop (gimple_assign_rhs1 (stmt))) 2216 { 2217 gsi_next (gsi); 2218 return false; 2219 } 2220 } 2221 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt))) 2222 { 2223 if (ssaname) 2224 { 2225 si = zero_length_string (ssaname, NULL); 2226 if (si != NULL) 2227 si->dont_invalidate = true; 2228 } 2229 else 2230 { 2231 int idx = new_addr_stridx (lhs); 2232 if (idx != 0) 2233 { 2234 si = new_strinfo (build_fold_addr_expr (lhs), idx, 2235 build_int_cst (size_type_node, 0)); 2236 set_strinfo (idx, si); 2237 si->dont_invalidate = true; 2238 } 2239 } 2240 if (si != NULL) 2241 si->writable = true; 2242 } 2243 else if (idx == 0 2244 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST 2245 && ssaname == NULL_TREE 2246 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE) 2247 { 2248 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt))); 2249 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs)); 2250 if (a > 0 && (unsigned HOST_WIDE_INT) a > l) 2251 { 2252 int idx = new_addr_stridx (lhs); 2253 if (idx != 0) 2254 { 2255 si = new_strinfo (build_fold_addr_expr (lhs), idx, 2256 build_int_cst (size_type_node, l)); 2257 set_strinfo (idx, si); 2258 si->dont_invalidate = true; 2259 } 2260 } 2261 } 2262 2263 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt))) 2264 { 2265 /* Allow adjust_last_stmt to remove it if the stored '\0' 2266 is immediately overwritten. */ 2267 laststmt.stmt = stmt; 2268 laststmt.len = build_int_cst (size_type_node, 1); 2269 laststmt.stridx = si->idx; 2270 } 2271 return true; 2272 } 2273 2274 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0. */ 2275 2276 static void 2277 fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt) 2278 { 2279 if (TREE_CODE (rhs1) != SSA_NAME 2280 || TREE_CODE (rhs2) != SSA_NAME) 2281 return; 2282 2283 gimple *call_stmt = NULL; 2284 for (int pass = 0; pass < 2; pass++) 2285 { 2286 gimple *g = SSA_NAME_DEF_STMT (rhs1); 2287 if (gimple_call_builtin_p (g, BUILT_IN_STRSTR) 2288 && has_single_use (rhs1) 2289 && gimple_call_arg (g, 0) == rhs2) 2290 { 2291 call_stmt = g; 2292 break; 2293 } 2294 std::swap (rhs1, rhs2); 2295 } 2296 2297 if (call_stmt) 2298 { 2299 tree arg0 = gimple_call_arg (call_stmt, 0); 2300 2301 if (arg0 == rhs2) 2302 { 2303 tree arg1 = gimple_call_arg (call_stmt, 1); 2304 tree arg1_len = NULL_TREE; 2305 int idx = get_stridx (arg1); 2306 2307 if (idx) 2308 { 2309 if (idx < 0) 2310 arg1_len = build_int_cst (size_type_node, ~idx); 2311 else 2312 { 2313 strinfo *si = get_strinfo (idx); 2314 if (si) 2315 arg1_len = get_string_length (si); 2316 } 2317 } 2318 2319 if (arg1_len != NULL_TREE) 2320 { 2321 gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt); 2322 tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP); 2323 2324 if (!is_gimple_val (arg1_len)) 2325 { 2326 tree arg1_len_tmp = make_ssa_name (TREE_TYPE (arg1_len)); 2327 gassign *arg1_stmt = gimple_build_assign (arg1_len_tmp, 2328 arg1_len); 2329 gsi_insert_before (&gsi, arg1_stmt, GSI_SAME_STMT); 2330 arg1_len = arg1_len_tmp; 2331 } 2332 2333 gcall *strncmp_call = gimple_build_call (strncmp_decl, 3, 2334 arg0, arg1, arg1_len); 2335 tree strncmp_lhs = make_ssa_name (integer_type_node); 2336 gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt)); 2337 gimple_call_set_lhs (strncmp_call, strncmp_lhs); 2338 gsi_remove (&gsi, true); 2339 gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT); 2340 tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs)); 2341 2342 if (is_gimple_assign (stmt)) 2343 { 2344 if (gimple_assign_rhs_code (stmt) == COND_EXPR) 2345 { 2346 tree cond = gimple_assign_rhs1 (stmt); 2347 TREE_OPERAND (cond, 0) = strncmp_lhs; 2348 TREE_OPERAND (cond, 1) = zero; 2349 } 2350 else 2351 { 2352 gimple_assign_set_rhs1 (stmt, strncmp_lhs); 2353 gimple_assign_set_rhs2 (stmt, zero); 2354 } 2355 } 2356 else 2357 { 2358 gcond *cond = as_a<gcond *> (stmt); 2359 gimple_cond_set_lhs (cond, strncmp_lhs); 2360 gimple_cond_set_rhs (cond, zero); 2361 } 2362 update_stmt (stmt); 2363 } 2364 } 2365 } 2366 } 2367 2368 /* Attempt to optimize a single statement at *GSI using string length 2369 knowledge. */ 2370 2371 static bool 2372 strlen_optimize_stmt (gimple_stmt_iterator *gsi) 2373 { 2374 gimple *stmt = gsi_stmt (*gsi); 2375 2376 if (is_gimple_call (stmt)) 2377 { 2378 tree callee = gimple_call_fndecl (stmt); 2379 if (valid_builtin_call (stmt)) 2380 switch (DECL_FUNCTION_CODE (callee)) 2381 { 2382 case BUILT_IN_STRLEN: 2383 case BUILT_IN_STRLEN_CHKP: 2384 handle_builtin_strlen (gsi); 2385 break; 2386 case BUILT_IN_STRCHR: 2387 case BUILT_IN_STRCHR_CHKP: 2388 handle_builtin_strchr (gsi); 2389 break; 2390 case BUILT_IN_STRCPY: 2391 case BUILT_IN_STRCPY_CHK: 2392 case BUILT_IN_STPCPY: 2393 case BUILT_IN_STPCPY_CHK: 2394 case BUILT_IN_STRCPY_CHKP: 2395 case BUILT_IN_STRCPY_CHK_CHKP: 2396 case BUILT_IN_STPCPY_CHKP: 2397 case BUILT_IN_STPCPY_CHK_CHKP: 2398 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi); 2399 break; 2400 case BUILT_IN_MEMCPY: 2401 case BUILT_IN_MEMCPY_CHK: 2402 case BUILT_IN_MEMPCPY: 2403 case BUILT_IN_MEMPCPY_CHK: 2404 case BUILT_IN_MEMCPY_CHKP: 2405 case BUILT_IN_MEMCPY_CHK_CHKP: 2406 case BUILT_IN_MEMPCPY_CHKP: 2407 case BUILT_IN_MEMPCPY_CHK_CHKP: 2408 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi); 2409 break; 2410 case BUILT_IN_STRCAT: 2411 case BUILT_IN_STRCAT_CHK: 2412 case BUILT_IN_STRCAT_CHKP: 2413 case BUILT_IN_STRCAT_CHK_CHKP: 2414 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi); 2415 break; 2416 case BUILT_IN_MALLOC: 2417 case BUILT_IN_CALLOC: 2418 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi); 2419 break; 2420 case BUILT_IN_MEMSET: 2421 if (!handle_builtin_memset (gsi)) 2422 return false; 2423 break; 2424 case BUILT_IN_MEMCMP: 2425 if (!handle_builtin_memcmp (gsi)) 2426 return false; 2427 break; 2428 default: 2429 break; 2430 } 2431 } 2432 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt)) 2433 { 2434 tree lhs = gimple_assign_lhs (stmt); 2435 2436 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs))) 2437 { 2438 if (gimple_assign_single_p (stmt) 2439 || (gimple_assign_cast_p (stmt) 2440 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))) 2441 { 2442 int idx = get_stridx (gimple_assign_rhs1 (stmt)); 2443 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx; 2444 } 2445 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) 2446 handle_pointer_plus (gsi); 2447 } 2448 else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs))) 2449 { 2450 enum tree_code code = gimple_assign_rhs_code (stmt); 2451 if (code == COND_EXPR) 2452 { 2453 tree cond = gimple_assign_rhs1 (stmt); 2454 enum tree_code cond_code = TREE_CODE (cond); 2455 2456 if (cond_code == EQ_EXPR || cond_code == NE_EXPR) 2457 fold_strstr_to_strncmp (TREE_OPERAND (cond, 0), 2458 TREE_OPERAND (cond, 1), stmt); 2459 } 2460 else if (code == EQ_EXPR || code == NE_EXPR) 2461 fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt), 2462 gimple_assign_rhs2 (stmt), stmt); 2463 } 2464 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs)) 2465 { 2466 tree type = TREE_TYPE (lhs); 2467 if (TREE_CODE (type) == ARRAY_TYPE) 2468 type = TREE_TYPE (type); 2469 if (TREE_CODE (type) == INTEGER_TYPE 2470 && TYPE_MODE (type) == TYPE_MODE (char_type_node) 2471 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node)) 2472 { 2473 if (! handle_char_store (gsi)) 2474 return false; 2475 } 2476 } 2477 } 2478 else if (gcond *cond = dyn_cast<gcond *> (stmt)) 2479 { 2480 enum tree_code code = gimple_cond_code (cond); 2481 if (code == EQ_EXPR || code == NE_EXPR) 2482 fold_strstr_to_strncmp (gimple_cond_lhs (stmt), 2483 gimple_cond_rhs (stmt), stmt); 2484 } 2485 2486 if (gimple_vdef (stmt)) 2487 maybe_invalidate (stmt); 2488 return true; 2489 } 2490 2491 /* Recursively call maybe_invalidate on stmts that might be executed 2492 in between dombb and current bb and that contain a vdef. Stop when 2493 *count stmts are inspected, or if the whole strinfo vector has 2494 been invalidated. */ 2495 2496 static void 2497 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count) 2498 { 2499 unsigned int i, n = gimple_phi_num_args (phi); 2500 2501 for (i = 0; i < n; i++) 2502 { 2503 tree vuse = gimple_phi_arg_def (phi, i); 2504 gimple *stmt = SSA_NAME_DEF_STMT (vuse); 2505 basic_block bb = gimple_bb (stmt); 2506 if (bb == NULL 2507 || bb == dombb 2508 || !bitmap_set_bit (visited, bb->index) 2509 || !dominated_by_p (CDI_DOMINATORS, bb, dombb)) 2510 continue; 2511 while (1) 2512 { 2513 if (gimple_code (stmt) == GIMPLE_PHI) 2514 { 2515 do_invalidate (dombb, stmt, visited, count); 2516 if (*count == 0) 2517 return; 2518 break; 2519 } 2520 if (--*count == 0) 2521 return; 2522 if (!maybe_invalidate (stmt)) 2523 { 2524 *count = 0; 2525 return; 2526 } 2527 vuse = gimple_vuse (stmt); 2528 stmt = SSA_NAME_DEF_STMT (vuse); 2529 if (gimple_bb (stmt) != bb) 2530 { 2531 bb = gimple_bb (stmt); 2532 if (bb == NULL 2533 || bb == dombb 2534 || !bitmap_set_bit (visited, bb->index) 2535 || !dominated_by_p (CDI_DOMINATORS, bb, dombb)) 2536 break; 2537 } 2538 } 2539 } 2540 } 2541 2542 class strlen_dom_walker : public dom_walker 2543 { 2544 public: 2545 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {} 2546 2547 virtual edge before_dom_children (basic_block); 2548 virtual void after_dom_children (basic_block); 2549 }; 2550 2551 /* Callback for walk_dominator_tree. Attempt to optimize various 2552 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */ 2553 2554 edge 2555 strlen_dom_walker::before_dom_children (basic_block bb) 2556 { 2557 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb); 2558 2559 if (dombb == NULL) 2560 stridx_to_strinfo = NULL; 2561 else 2562 { 2563 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux); 2564 if (stridx_to_strinfo) 2565 { 2566 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); 2567 gsi_next (&gsi)) 2568 { 2569 gphi *phi = gsi.phi (); 2570 if (virtual_operand_p (gimple_phi_result (phi))) 2571 { 2572 bitmap visited = BITMAP_ALLOC (NULL); 2573 int count_vdef = 100; 2574 do_invalidate (dombb, phi, visited, &count_vdef); 2575 BITMAP_FREE (visited); 2576 if (count_vdef == 0) 2577 { 2578 /* If there were too many vdefs in between immediate 2579 dominator and current bb, invalidate everything. 2580 If stridx_to_strinfo has been unshared, we need 2581 to free it, otherwise just set it to NULL. */ 2582 if (!strinfo_shared ()) 2583 { 2584 unsigned int i; 2585 strinfo *si; 2586 2587 for (i = 1; 2588 vec_safe_iterate (stridx_to_strinfo, i, &si); 2589 ++i) 2590 { 2591 free_strinfo (si); 2592 (*stridx_to_strinfo)[i] = NULL; 2593 } 2594 } 2595 else 2596 stridx_to_strinfo = NULL; 2597 } 2598 break; 2599 } 2600 } 2601 } 2602 } 2603 2604 /* If all PHI arguments have the same string index, the PHI result 2605 has it as well. */ 2606 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); 2607 gsi_next (&gsi)) 2608 { 2609 gphi *phi = gsi.phi (); 2610 tree result = gimple_phi_result (phi); 2611 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result))) 2612 { 2613 int idx = get_stridx (gimple_phi_arg_def (phi, 0)); 2614 if (idx != 0) 2615 { 2616 unsigned int i, n = gimple_phi_num_args (phi); 2617 for (i = 1; i < n; i++) 2618 if (idx != get_stridx (gimple_phi_arg_def (phi, i))) 2619 break; 2620 if (i == n) 2621 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx; 2622 } 2623 } 2624 } 2625 2626 /* Attempt to optimize individual statements. */ 2627 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) 2628 if (strlen_optimize_stmt (&gsi)) 2629 gsi_next (&gsi); 2630 2631 bb->aux = stridx_to_strinfo; 2632 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ()) 2633 (*stridx_to_strinfo)[0] = (strinfo *) bb; 2634 return NULL; 2635 } 2636 2637 /* Callback for walk_dominator_tree. Free strinfo vector if it is 2638 owned by the current bb, clear bb->aux. */ 2639 2640 void 2641 strlen_dom_walker::after_dom_children (basic_block bb) 2642 { 2643 if (bb->aux) 2644 { 2645 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux); 2646 if (vec_safe_length (stridx_to_strinfo) 2647 && (*stridx_to_strinfo)[0] == (strinfo *) bb) 2648 { 2649 unsigned int i; 2650 strinfo *si; 2651 2652 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i) 2653 free_strinfo (si); 2654 vec_free (stridx_to_strinfo); 2655 } 2656 bb->aux = NULL; 2657 } 2658 } 2659 2660 /* Main entry point. */ 2661 2662 namespace { 2663 2664 const pass_data pass_data_strlen = 2665 { 2666 GIMPLE_PASS, /* type */ 2667 "strlen", /* name */ 2668 OPTGROUP_NONE, /* optinfo_flags */ 2669 TV_TREE_STRLEN, /* tv_id */ 2670 ( PROP_cfg | PROP_ssa ), /* properties_required */ 2671 0, /* properties_provided */ 2672 0, /* properties_destroyed */ 2673 0, /* todo_flags_start */ 2674 0, /* todo_flags_finish */ 2675 }; 2676 2677 class pass_strlen : public gimple_opt_pass 2678 { 2679 public: 2680 pass_strlen (gcc::context *ctxt) 2681 : gimple_opt_pass (pass_data_strlen, ctxt) 2682 {} 2683 2684 /* opt_pass methods: */ 2685 virtual bool gate (function *) { return flag_optimize_strlen != 0; } 2686 virtual unsigned int execute (function *); 2687 2688 }; // class pass_strlen 2689 2690 unsigned int 2691 pass_strlen::execute (function *fun) 2692 { 2693 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names); 2694 max_stridx = 1; 2695 2696 calculate_dominance_info (CDI_DOMINATORS); 2697 2698 /* String length optimization is implemented as a walk of the dominator 2699 tree and a forward walk of statements within each block. */ 2700 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr); 2701 2702 ssa_ver_to_stridx.release (); 2703 strinfo_pool.release (); 2704 if (decl_to_stridxlist_htab) 2705 { 2706 obstack_free (&stridx_obstack, NULL); 2707 delete decl_to_stridxlist_htab; 2708 decl_to_stridxlist_htab = NULL; 2709 } 2710 laststmt.stmt = NULL; 2711 laststmt.len = NULL_TREE; 2712 laststmt.stridx = 0; 2713 2714 return 0; 2715 } 2716 2717 } // anon namespace 2718 2719 gimple_opt_pass * 2720 make_pass_strlen (gcc::context *ctxt) 2721 { 2722 return new pass_strlen (ctxt); 2723 } 2724