Clean up some minor white space issues in trans-decl.c and trans-expr.c
[official-gcc.git] / gcc / tree-ssa-strlen.c
blobd27b60754d31362867b4a64de385e65f42a86737
1 /* String length optimization
2 Copyright (C) 2011-2016 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
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.
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.
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/>. */
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"
48 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
49 is an index into strinfo vector, negative value stands for
50 string length of a string literal (~strlen). */
51 static vec<int> ssa_ver_to_stridx;
53 /* Number of currently active string indexes plus one. */
54 static int max_stridx;
56 /* String information record. */
57 struct strinfo
59 /* String length of this string. */
60 tree length;
61 /* Any of the corresponding pointers for querying alias oracle. */
62 tree ptr;
63 /* Statement for delayed length computation. */
64 gimple *stmt;
65 /* Pointer to '\0' if known, if NULL, it can be computed as
66 ptr + length. */
67 tree endptr;
68 /* Reference count. Any changes to strinfo entry possibly shared
69 with dominating basic blocks need unshare_strinfo first, except
70 for dont_invalidate which affects only the immediately next
71 maybe_invalidate. */
72 int refcount;
73 /* Copy of index. get_strinfo (si->idx) should return si; */
74 int idx;
75 /* These 3 fields are for chaining related string pointers together.
76 E.g. for
77 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
78 strcpy (c, d); e = c + dl;
79 strinfo(a) -> strinfo(c) -> strinfo(e)
80 All have ->first field equal to strinfo(a)->idx and are doubly
81 chained through prev/next fields. The later strinfos are required
82 to point into the same string with zero or more bytes after
83 the previous pointer and all bytes in between the two pointers
84 must be non-zero. Functions like strcpy or memcpy are supposed
85 to adjust all previous strinfo lengths, but not following strinfo
86 lengths (those are uncertain, usually invalidated during
87 maybe_invalidate, except when the alias oracle knows better).
88 Functions like strcat on the other side adjust the whole
89 related strinfo chain.
90 They are updated lazily, so to use the chain the same first fields
91 and si->prev->next == si->idx needs to be verified. */
92 int first;
93 int next;
94 int prev;
95 /* A flag whether the string is known to be written in the current
96 function. */
97 bool writable;
98 /* A flag for the next maybe_invalidate that this strinfo shouldn't
99 be invalidated. Always cleared by maybe_invalidate. */
100 bool dont_invalidate;
103 /* Pool for allocating strinfo_struct entries. */
104 static object_allocator<strinfo> strinfo_pool ("strinfo pool");
106 /* Vector mapping positive string indexes to strinfo, for the
107 current basic block. The first pointer in the vector is special,
108 it is either NULL, meaning the vector isn't shared, or it is
109 a basic block pointer to the owner basic_block if shared.
110 If some other bb wants to modify the vector, the vector needs
111 to be unshared first, and only the owner bb is supposed to free it. */
112 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
114 /* One OFFSET->IDX mapping. */
115 struct stridxlist
117 struct stridxlist *next;
118 HOST_WIDE_INT offset;
119 int idx;
122 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
123 struct decl_stridxlist_map
125 struct tree_map_base base;
126 struct stridxlist list;
129 /* Hash table for mapping decls to a chained list of offset -> idx
130 mappings. */
131 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
133 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
134 static struct obstack stridx_obstack;
136 /* Last memcpy statement if it could be adjusted if the trailing
137 '\0' written is immediately overwritten, or
138 *x = '\0' store that could be removed if it is immediately overwritten. */
139 struct laststmt_struct
141 gimple *stmt;
142 tree len;
143 int stridx;
144 } laststmt;
146 static int get_stridx_plus_constant (strinfo *, HOST_WIDE_INT, tree);
148 /* Return strinfo vector entry IDX. */
150 static inline strinfo *
151 get_strinfo (int idx)
153 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
154 return NULL;
155 return (*stridx_to_strinfo)[idx];
158 /* Helper function for get_stridx. */
160 static int
161 get_addr_stridx (tree exp)
163 HOST_WIDE_INT off;
164 struct stridxlist *list;
165 tree base;
167 if (!decl_to_stridxlist_htab)
168 return 0;
170 base = get_addr_base_and_unit_offset (exp, &off);
171 if (base == NULL || !DECL_P (base))
172 return 0;
174 list = decl_to_stridxlist_htab->get (base);
175 if (list == NULL)
176 return 0;
180 if (list->offset == off)
181 return list->idx;
182 list = list->next;
184 while (list);
185 return 0;
188 /* Return string index for EXP. */
190 static int
191 get_stridx (tree exp)
193 tree s, o;
195 if (TREE_CODE (exp) == SSA_NAME)
197 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
198 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
199 int i;
200 tree e = exp;
201 HOST_WIDE_INT off = 0;
202 for (i = 0; i < 5; i++)
204 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
205 if (!is_gimple_assign (def_stmt)
206 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
207 return 0;
208 tree rhs1 = gimple_assign_rhs1 (def_stmt);
209 tree rhs2 = gimple_assign_rhs2 (def_stmt);
210 if (TREE_CODE (rhs1) != SSA_NAME
211 || !tree_fits_shwi_p (rhs2))
212 return 0;
213 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
214 if (this_off < 0)
215 return 0;
216 off = (unsigned HOST_WIDE_INT) off + this_off;
217 if (off < 0)
218 return 0;
219 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
221 strinfo *si
222 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
223 if (si
224 && si->length
225 && TREE_CODE (si->length) == INTEGER_CST
226 && compare_tree_int (si->length, off) != -1)
227 return get_stridx_plus_constant (si, off, exp);
229 e = rhs1;
231 return 0;
234 if (TREE_CODE (exp) == ADDR_EXPR)
236 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
237 if (idx != 0)
238 return idx;
241 s = string_constant (exp, &o);
242 if (s != NULL_TREE
243 && (o == NULL_TREE || tree_fits_shwi_p (o))
244 && TREE_STRING_LENGTH (s) > 0)
246 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
247 const char *p = TREE_STRING_POINTER (s);
248 int max = TREE_STRING_LENGTH (s) - 1;
250 if (p[max] == '\0' && offset >= 0 && offset <= max)
251 return ~(int) strlen (p + offset);
253 return 0;
256 /* Return true if strinfo vector is shared with the immediate dominator. */
258 static inline bool
259 strinfo_shared (void)
261 return vec_safe_length (stridx_to_strinfo)
262 && (*stridx_to_strinfo)[0] != NULL;
265 /* Unshare strinfo vector that is shared with the immediate dominator. */
267 static void
268 unshare_strinfo_vec (void)
270 strinfo *si;
271 unsigned int i = 0;
273 gcc_assert (strinfo_shared ());
274 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
275 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
276 if (si != NULL)
277 si->refcount++;
278 (*stridx_to_strinfo)[0] = NULL;
281 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
282 Return a pointer to the location where the string index can
283 be stored (if 0) or is stored, or NULL if this can't be tracked. */
285 static int *
286 addr_stridxptr (tree exp)
288 HOST_WIDE_INT off;
290 tree base = get_addr_base_and_unit_offset (exp, &off);
291 if (base == NULL_TREE || !DECL_P (base))
292 return NULL;
294 if (!decl_to_stridxlist_htab)
296 decl_to_stridxlist_htab
297 = new hash_map<tree_decl_hash, stridxlist> (64);
298 gcc_obstack_init (&stridx_obstack);
301 bool existed;
302 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
303 if (existed)
305 int i;
306 for (i = 0; i < 16; i++)
308 if (list->offset == off)
309 return &list->idx;
310 if (list->next == NULL)
311 break;
313 if (i == 16)
314 return NULL;
315 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
316 list = list->next;
319 list->next = NULL;
320 list->offset = off;
321 list->idx = 0;
322 return &list->idx;
325 /* Create a new string index, or return 0 if reached limit. */
327 static int
328 new_stridx (tree exp)
330 int idx;
331 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
332 return 0;
333 if (TREE_CODE (exp) == SSA_NAME)
335 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
336 return 0;
337 idx = max_stridx++;
338 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
339 return idx;
341 if (TREE_CODE (exp) == ADDR_EXPR)
343 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
344 if (pidx != NULL)
346 gcc_assert (*pidx == 0);
347 *pidx = max_stridx++;
348 return *pidx;
351 return 0;
354 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
356 static int
357 new_addr_stridx (tree exp)
359 int *pidx;
360 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
361 return 0;
362 pidx = addr_stridxptr (exp);
363 if (pidx != NULL)
365 gcc_assert (*pidx == 0);
366 *pidx = max_stridx++;
367 return *pidx;
369 return 0;
372 /* Create a new strinfo. */
374 static strinfo *
375 new_strinfo (tree ptr, int idx, tree length)
377 strinfo *si = strinfo_pool.allocate ();
378 si->length = length;
379 si->ptr = ptr;
380 si->stmt = NULL;
381 si->endptr = NULL_TREE;
382 si->refcount = 1;
383 si->idx = idx;
384 si->first = 0;
385 si->prev = 0;
386 si->next = 0;
387 si->writable = false;
388 si->dont_invalidate = false;
389 return si;
392 /* Decrease strinfo refcount and free it if not referenced anymore. */
394 static inline void
395 free_strinfo (strinfo *si)
397 if (si && --si->refcount == 0)
398 strinfo_pool.remove (si);
401 /* Set strinfo in the vector entry IDX to SI. */
403 static inline void
404 set_strinfo (int idx, strinfo *si)
406 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
407 unshare_strinfo_vec ();
408 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
409 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
410 (*stridx_to_strinfo)[idx] = si;
413 /* Return string length, or NULL if it can't be computed. */
415 static tree
416 get_string_length (strinfo *si)
418 if (si->length)
419 return si->length;
421 if (si->stmt)
423 gimple *stmt = si->stmt, *lenstmt;
424 bool with_bounds = gimple_call_with_bounds_p (stmt);
425 tree callee, lhs, fn, tem;
426 location_t loc;
427 gimple_stmt_iterator gsi;
429 gcc_assert (is_gimple_call (stmt));
430 callee = gimple_call_fndecl (stmt);
431 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
432 lhs = gimple_call_lhs (stmt);
433 /* unshare_strinfo is intentionally not called here. The (delayed)
434 transformation of strcpy or strcat into stpcpy is done at the place
435 of the former strcpy/strcat call and so can affect all the strinfos
436 with the same stmt. If they were unshared before and transformation
437 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
438 just compute the right length. */
439 switch (DECL_FUNCTION_CODE (callee))
441 case BUILT_IN_STRCAT:
442 case BUILT_IN_STRCAT_CHK:
443 case BUILT_IN_STRCAT_CHKP:
444 case BUILT_IN_STRCAT_CHK_CHKP:
445 gsi = gsi_for_stmt (stmt);
446 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
447 gcc_assert (lhs == NULL_TREE);
448 tem = unshare_expr (gimple_call_arg (stmt, 0));
449 if (with_bounds)
451 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
452 2, tem, gimple_call_arg (stmt, 1));
453 gimple_call_set_with_bounds (lenstmt, true);
455 else
456 lenstmt = gimple_build_call (fn, 1, tem);
457 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
458 gimple_call_set_lhs (lenstmt, lhs);
459 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
460 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
461 tem = gimple_call_arg (stmt, 0);
462 if (!ptrofftype_p (TREE_TYPE (lhs)))
464 lhs = convert_to_ptrofftype (lhs);
465 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
466 true, GSI_SAME_STMT);
468 lenstmt = gimple_build_assign
469 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
470 POINTER_PLUS_EXPR,tem, lhs);
471 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
472 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
473 lhs = NULL_TREE;
474 /* FALLTHRU */
475 case BUILT_IN_STRCPY:
476 case BUILT_IN_STRCPY_CHK:
477 case BUILT_IN_STRCPY_CHKP:
478 case BUILT_IN_STRCPY_CHK_CHKP:
479 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
480 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
481 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
482 else
483 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
484 if (with_bounds)
485 fn = chkp_maybe_create_clone (fn)->decl;
486 gcc_assert (lhs == NULL_TREE);
487 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
489 fprintf (dump_file, "Optimizing: ");
490 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
492 gimple_call_set_fndecl (stmt, fn);
493 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
494 gimple_call_set_lhs (stmt, lhs);
495 update_stmt (stmt);
496 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
498 fprintf (dump_file, "into: ");
499 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
501 /* FALLTHRU */
502 case BUILT_IN_STPCPY:
503 case BUILT_IN_STPCPY_CHK:
504 case BUILT_IN_STPCPY_CHKP:
505 case BUILT_IN_STPCPY_CHK_CHKP:
506 gcc_assert (lhs != NULL_TREE);
507 loc = gimple_location (stmt);
508 si->endptr = lhs;
509 si->stmt = NULL;
510 lhs = fold_convert_loc (loc, size_type_node, lhs);
511 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
512 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
513 lhs, si->length);
514 break;
515 case BUILT_IN_MALLOC:
516 break;
517 /* BUILT_IN_CALLOC always has si->length set. */
518 default:
519 gcc_unreachable ();
520 break;
524 return si->length;
527 /* Invalidate string length information for strings whose length
528 might change due to stores in stmt. */
530 static bool
531 maybe_invalidate (gimple *stmt)
533 strinfo *si;
534 unsigned int i;
535 bool nonempty = false;
537 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
538 if (si != NULL)
540 if (!si->dont_invalidate)
542 ao_ref r;
543 /* Do not use si->length. */
544 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
545 if (stmt_may_clobber_ref_p_1 (stmt, &r))
547 set_strinfo (i, NULL);
548 free_strinfo (si);
549 continue;
552 si->dont_invalidate = false;
553 nonempty = true;
555 return nonempty;
558 /* Unshare strinfo record SI, if it has refcount > 1 or
559 if stridx_to_strinfo vector is shared with some other
560 bbs. */
562 static strinfo *
563 unshare_strinfo (strinfo *si)
565 strinfo *nsi;
567 if (si->refcount == 1 && !strinfo_shared ())
568 return si;
570 nsi = new_strinfo (si->ptr, si->idx, si->length);
571 nsi->stmt = si->stmt;
572 nsi->endptr = si->endptr;
573 nsi->first = si->first;
574 nsi->prev = si->prev;
575 nsi->next = si->next;
576 nsi->writable = si->writable;
577 set_strinfo (si->idx, nsi);
578 free_strinfo (si);
579 return nsi;
582 /* Return first strinfo in the related strinfo chain
583 if all strinfos in between belong to the chain, otherwise
584 NULL. */
586 static strinfo *
587 verify_related_strinfos (strinfo *origsi)
589 strinfo *si = origsi, *psi;
591 if (origsi->first == 0)
592 return NULL;
593 for (; si->prev; si = psi)
595 if (si->first != origsi->first)
596 return NULL;
597 psi = get_strinfo (si->prev);
598 if (psi == NULL)
599 return NULL;
600 if (psi->next != si->idx)
601 return NULL;
603 if (si->idx != si->first)
604 return NULL;
605 return si;
608 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
609 strinfo if there is any. Return it's idx, or 0 if no strinfo has
610 been created. */
612 static int
613 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
615 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
617 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
618 return 0;
620 if (basesi->length == NULL_TREE
621 || TREE_CODE (basesi->length) != INTEGER_CST
622 || compare_tree_int (basesi->length, off) == -1
623 || !tree_fits_shwi_p (basesi->length))
624 return 0;
626 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
627 strinfo *si = basesi, *chainsi;
628 if (si->first || si->prev || si->next)
629 si = verify_related_strinfos (basesi);
630 if (si == NULL
631 || si->length == NULL_TREE
632 || TREE_CODE (si->length) != INTEGER_CST)
633 return 0;
635 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
636 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
638 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
639 for (chainsi = si; chainsi->next; chainsi = si)
641 si = get_strinfo (chainsi->next);
642 if (si == NULL
643 || si->first != chainsi->first
644 || si->prev != chainsi->idx
645 || si->length == NULL_TREE
646 || TREE_CODE (si->length) != INTEGER_CST)
647 break;
648 int r = compare_tree_int (si->length, len);
649 if (r != 1)
651 if (r == 0)
653 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
654 return si->idx;
656 break;
660 int idx = new_stridx (ptr);
661 if (idx == 0)
662 return 0;
663 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
664 set_strinfo (idx, si);
665 if (chainsi->next)
667 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
668 si->next = nextsi->idx;
669 nextsi->prev = idx;
671 chainsi = unshare_strinfo (chainsi);
672 if (chainsi->first == 0)
673 chainsi->first = chainsi->idx;
674 chainsi->next = idx;
675 if (chainsi->endptr == NULL_TREE && len == 0)
676 chainsi->endptr = ptr;
677 si->endptr = chainsi->endptr;
678 si->prev = chainsi->idx;
679 si->first = chainsi->first;
680 si->writable = chainsi->writable;
681 return si->idx;
684 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
685 to a zero-length string and if possible chain it to a related strinfo
686 chain whose part is or might be CHAINSI. */
688 static strinfo *
689 zero_length_string (tree ptr, strinfo *chainsi)
691 strinfo *si;
692 int idx;
693 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
694 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
695 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
696 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
698 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
699 return NULL;
700 if (chainsi != NULL)
702 si = verify_related_strinfos (chainsi);
703 if (si)
705 chainsi = si;
706 for (; chainsi->next; chainsi = si)
708 if (chainsi->endptr == NULL_TREE)
710 chainsi = unshare_strinfo (chainsi);
711 chainsi->endptr = ptr;
713 si = get_strinfo (chainsi->next);
714 if (si == NULL
715 || si->first != chainsi->first
716 || si->prev != chainsi->idx)
717 break;
719 gcc_assert (chainsi->length || chainsi->stmt);
720 if (chainsi->endptr == NULL_TREE)
722 chainsi = unshare_strinfo (chainsi);
723 chainsi->endptr = ptr;
725 if (chainsi->length && integer_zerop (chainsi->length))
727 if (chainsi->next)
729 chainsi = unshare_strinfo (chainsi);
730 chainsi->next = 0;
732 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
733 return chainsi;
736 else if (chainsi->first || chainsi->prev || chainsi->next)
738 chainsi = unshare_strinfo (chainsi);
739 chainsi->first = 0;
740 chainsi->prev = 0;
741 chainsi->next = 0;
744 idx = new_stridx (ptr);
745 if (idx == 0)
746 return NULL;
747 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
748 set_strinfo (idx, si);
749 si->endptr = ptr;
750 if (chainsi != NULL)
752 chainsi = unshare_strinfo (chainsi);
753 if (chainsi->first == 0)
754 chainsi->first = chainsi->idx;
755 chainsi->next = idx;
756 if (chainsi->endptr == NULL_TREE)
757 chainsi->endptr = ptr;
758 si->prev = chainsi->idx;
759 si->first = chainsi->first;
760 si->writable = chainsi->writable;
762 return si;
765 /* For strinfo ORIGSI whose length has been just updated
766 update also related strinfo lengths (add ADJ to each,
767 but don't adjust ORIGSI). */
769 static void
770 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
772 strinfo *si = verify_related_strinfos (origsi);
774 if (si == NULL)
775 return;
777 while (1)
779 strinfo *nsi;
781 if (si != origsi)
783 tree tem;
785 si = unshare_strinfo (si);
786 if (si->length)
788 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
789 si->length = fold_build2_loc (loc, PLUS_EXPR,
790 TREE_TYPE (si->length), si->length,
791 tem);
793 else if (si->stmt != NULL)
794 /* Delayed length computation is unaffected. */
796 else
797 gcc_unreachable ();
799 si->endptr = NULL_TREE;
800 si->dont_invalidate = true;
802 if (si->next == 0)
803 return;
804 nsi = get_strinfo (si->next);
805 if (nsi == NULL
806 || nsi->first != si->first
807 || nsi->prev != si->idx)
808 return;
809 si = nsi;
813 /* Find if there are other SSA_NAME pointers equal to PTR
814 for which we don't track their string lengths yet. If so, use
815 IDX for them. */
817 static void
818 find_equal_ptrs (tree ptr, int idx)
820 if (TREE_CODE (ptr) != SSA_NAME)
821 return;
822 while (1)
824 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
825 if (!is_gimple_assign (stmt))
826 return;
827 ptr = gimple_assign_rhs1 (stmt);
828 switch (gimple_assign_rhs_code (stmt))
830 case SSA_NAME:
831 break;
832 CASE_CONVERT:
833 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
834 return;
835 if (TREE_CODE (ptr) == SSA_NAME)
836 break;
837 if (TREE_CODE (ptr) != ADDR_EXPR)
838 return;
839 /* FALLTHRU */
840 case ADDR_EXPR:
842 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
843 if (pidx != NULL && *pidx == 0)
844 *pidx = idx;
845 return;
847 default:
848 return;
851 /* We might find an endptr created in this pass. Grow the
852 vector in that case. */
853 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
854 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
856 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
857 return;
858 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
862 /* If the last .MEM setter statement before STMT is
863 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
864 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
865 just memcpy (x, y, strlen (y)). SI must be the zero length
866 strinfo. */
868 static void
869 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
871 tree vuse, callee, len;
872 struct laststmt_struct last = laststmt;
873 strinfo *lastsi, *firstsi;
874 unsigned len_arg_no = 2;
876 laststmt.stmt = NULL;
877 laststmt.len = NULL_TREE;
878 laststmt.stridx = 0;
880 if (last.stmt == NULL)
881 return;
883 vuse = gimple_vuse (stmt);
884 if (vuse == NULL_TREE
885 || SSA_NAME_DEF_STMT (vuse) != last.stmt
886 || !has_single_use (vuse))
887 return;
889 gcc_assert (last.stridx > 0);
890 lastsi = get_strinfo (last.stridx);
891 if (lastsi == NULL)
892 return;
894 if (lastsi != si)
896 if (lastsi->first == 0 || lastsi->first != si->first)
897 return;
899 firstsi = verify_related_strinfos (si);
900 if (firstsi == NULL)
901 return;
902 while (firstsi != lastsi)
904 strinfo *nextsi;
905 if (firstsi->next == 0)
906 return;
907 nextsi = get_strinfo (firstsi->next);
908 if (nextsi == NULL
909 || nextsi->prev != firstsi->idx
910 || nextsi->first != si->first)
911 return;
912 firstsi = nextsi;
916 if (!is_strcat)
918 if (si->length == NULL_TREE || !integer_zerop (si->length))
919 return;
922 if (is_gimple_assign (last.stmt))
924 gimple_stmt_iterator gsi;
926 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
927 return;
928 if (stmt_could_throw_p (last.stmt))
929 return;
930 gsi = gsi_for_stmt (last.stmt);
931 unlink_stmt_vdef (last.stmt);
932 release_defs (last.stmt);
933 gsi_remove (&gsi, true);
934 return;
937 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
938 return;
940 callee = gimple_call_fndecl (last.stmt);
941 switch (DECL_FUNCTION_CODE (callee))
943 case BUILT_IN_MEMCPY:
944 case BUILT_IN_MEMCPY_CHK:
945 break;
946 case BUILT_IN_MEMCPY_CHKP:
947 case BUILT_IN_MEMCPY_CHK_CHKP:
948 len_arg_no = 4;
949 break;
950 default:
951 return;
954 len = gimple_call_arg (last.stmt, len_arg_no);
955 if (tree_fits_uhwi_p (len))
957 if (!tree_fits_uhwi_p (last.len)
958 || integer_zerop (len)
959 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
960 return;
961 /* Don't adjust the length if it is divisible by 4, it is more efficient
962 to store the extra '\0' in that case. */
963 if ((tree_to_uhwi (len) & 3) == 0)
964 return;
966 else if (TREE_CODE (len) == SSA_NAME)
968 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
969 if (!is_gimple_assign (def_stmt)
970 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
971 || gimple_assign_rhs1 (def_stmt) != last.len
972 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
973 return;
975 else
976 return;
978 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
979 update_stmt (last.stmt);
982 /* Handle a strlen call. If strlen of the argument is known, replace
983 the strlen call with the known value, otherwise remember that strlen
984 of the argument is stored in the lhs SSA_NAME. */
986 static void
987 handle_builtin_strlen (gimple_stmt_iterator *gsi)
989 int idx;
990 tree src;
991 gimple *stmt = gsi_stmt (*gsi);
992 tree lhs = gimple_call_lhs (stmt);
994 if (lhs == NULL_TREE)
995 return;
997 src = gimple_call_arg (stmt, 0);
998 idx = get_stridx (src);
999 if (idx)
1001 strinfo *si = NULL;
1002 tree rhs;
1004 if (idx < 0)
1005 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1006 else
1008 rhs = NULL_TREE;
1009 si = get_strinfo (idx);
1010 if (si != NULL)
1011 rhs = get_string_length (si);
1013 if (rhs != NULL_TREE)
1015 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1017 fprintf (dump_file, "Optimizing: ");
1018 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1020 rhs = unshare_expr (rhs);
1021 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1022 rhs = fold_convert_loc (gimple_location (stmt),
1023 TREE_TYPE (lhs), rhs);
1024 if (!update_call_from_tree (gsi, rhs))
1025 gimplify_and_update_call_from_tree (gsi, rhs);
1026 stmt = gsi_stmt (*gsi);
1027 update_stmt (stmt);
1028 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1030 fprintf (dump_file, "into: ");
1031 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1033 if (si != NULL
1034 && TREE_CODE (si->length) != SSA_NAME
1035 && TREE_CODE (si->length) != INTEGER_CST
1036 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1038 si = unshare_strinfo (si);
1039 si->length = lhs;
1041 return;
1044 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1045 return;
1046 if (idx == 0)
1047 idx = new_stridx (src);
1048 else if (get_strinfo (idx) != NULL)
1049 return;
1050 if (idx)
1052 strinfo *si = new_strinfo (src, idx, lhs);
1053 set_strinfo (idx, si);
1054 find_equal_ptrs (src, idx);
1058 /* Handle a strchr call. If strlen of the first argument is known, replace
1059 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1060 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1062 static void
1063 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1065 int idx;
1066 tree src;
1067 gimple *stmt = gsi_stmt (*gsi);
1068 tree lhs = gimple_call_lhs (stmt);
1069 bool with_bounds = gimple_call_with_bounds_p (stmt);
1071 if (lhs == NULL_TREE)
1072 return;
1074 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1075 return;
1077 src = gimple_call_arg (stmt, 0);
1078 idx = get_stridx (src);
1079 if (idx)
1081 strinfo *si = NULL;
1082 tree rhs;
1084 if (idx < 0)
1085 rhs = build_int_cst (size_type_node, ~idx);
1086 else
1088 rhs = NULL_TREE;
1089 si = get_strinfo (idx);
1090 if (si != NULL)
1091 rhs = get_string_length (si);
1093 if (rhs != NULL_TREE)
1095 location_t loc = gimple_location (stmt);
1097 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1099 fprintf (dump_file, "Optimizing: ");
1100 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1102 if (si != NULL && si->endptr != NULL_TREE)
1104 rhs = unshare_expr (si->endptr);
1105 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1106 TREE_TYPE (rhs)))
1107 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1109 else
1111 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1112 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1113 TREE_TYPE (src), src, rhs);
1114 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1115 TREE_TYPE (rhs)))
1116 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1118 if (!update_call_from_tree (gsi, rhs))
1119 gimplify_and_update_call_from_tree (gsi, rhs);
1120 stmt = gsi_stmt (*gsi);
1121 update_stmt (stmt);
1122 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1124 fprintf (dump_file, "into: ");
1125 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1127 if (si != NULL
1128 && si->endptr == NULL_TREE
1129 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1131 si = unshare_strinfo (si);
1132 si->endptr = lhs;
1134 zero_length_string (lhs, si);
1135 return;
1138 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1139 return;
1140 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1142 if (idx == 0)
1143 idx = new_stridx (src);
1144 else if (get_strinfo (idx) != NULL)
1146 zero_length_string (lhs, NULL);
1147 return;
1149 if (idx)
1151 location_t loc = gimple_location (stmt);
1152 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1153 tree srcu = fold_convert_loc (loc, size_type_node, src);
1154 tree length = fold_build2_loc (loc, MINUS_EXPR,
1155 size_type_node, lhsu, srcu);
1156 strinfo *si = new_strinfo (src, idx, length);
1157 si->endptr = lhs;
1158 set_strinfo (idx, si);
1159 find_equal_ptrs (src, idx);
1160 zero_length_string (lhs, si);
1163 else
1164 zero_length_string (lhs, NULL);
1167 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1168 If strlen of the second argument is known, strlen of the first argument
1169 is the same after this call. Furthermore, attempt to convert it to
1170 memcpy. */
1172 static void
1173 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1175 int idx, didx;
1176 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1177 bool success;
1178 gimple *stmt = gsi_stmt (*gsi);
1179 strinfo *si, *dsi, *olddsi, *zsi;
1180 location_t loc;
1181 bool with_bounds = gimple_call_with_bounds_p (stmt);
1183 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1184 dst = gimple_call_arg (stmt, 0);
1185 lhs = gimple_call_lhs (stmt);
1186 idx = get_stridx (src);
1187 si = NULL;
1188 if (idx > 0)
1189 si = get_strinfo (idx);
1191 didx = get_stridx (dst);
1192 olddsi = NULL;
1193 oldlen = NULL_TREE;
1194 if (didx > 0)
1195 olddsi = get_strinfo (didx);
1196 else if (didx < 0)
1197 return;
1199 if (olddsi != NULL)
1200 adjust_last_stmt (olddsi, stmt, false);
1202 srclen = NULL_TREE;
1203 if (si != NULL)
1204 srclen = get_string_length (si);
1205 else if (idx < 0)
1206 srclen = build_int_cst (size_type_node, ~idx);
1208 loc = gimple_location (stmt);
1209 if (srclen == NULL_TREE)
1210 switch (bcode)
1212 case BUILT_IN_STRCPY:
1213 case BUILT_IN_STRCPY_CHK:
1214 case BUILT_IN_STRCPY_CHKP:
1215 case BUILT_IN_STRCPY_CHK_CHKP:
1216 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1217 return;
1218 break;
1219 case BUILT_IN_STPCPY:
1220 case BUILT_IN_STPCPY_CHK:
1221 case BUILT_IN_STPCPY_CHKP:
1222 case BUILT_IN_STPCPY_CHK_CHKP:
1223 if (lhs == NULL_TREE)
1224 return;
1225 else
1227 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1228 srclen = fold_convert_loc (loc, size_type_node, dst);
1229 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1230 lhsuint, srclen);
1232 break;
1233 default:
1234 gcc_unreachable ();
1237 if (didx == 0)
1239 didx = new_stridx (dst);
1240 if (didx == 0)
1241 return;
1243 if (olddsi != NULL)
1245 oldlen = olddsi->length;
1246 dsi = unshare_strinfo (olddsi);
1247 dsi->length = srclen;
1248 /* Break the chain, so adjust_related_strinfo on later pointers in
1249 the chain won't adjust this one anymore. */
1250 dsi->next = 0;
1251 dsi->stmt = NULL;
1252 dsi->endptr = NULL_TREE;
1254 else
1256 dsi = new_strinfo (dst, didx, srclen);
1257 set_strinfo (didx, dsi);
1258 find_equal_ptrs (dst, didx);
1260 dsi->writable = true;
1261 dsi->dont_invalidate = true;
1263 if (dsi->length == NULL_TREE)
1265 strinfo *chainsi;
1267 /* If string length of src is unknown, use delayed length
1268 computation. If string lenth of dst will be needed, it
1269 can be computed by transforming this strcpy call into
1270 stpcpy and subtracting dst from the return value. */
1272 /* Look for earlier strings whose length could be determined if
1273 this strcpy is turned into an stpcpy. */
1275 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1277 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1279 /* When setting a stmt for delayed length computation
1280 prevent all strinfos through dsi from being
1281 invalidated. */
1282 chainsi = unshare_strinfo (chainsi);
1283 chainsi->stmt = stmt;
1284 chainsi->length = NULL_TREE;
1285 chainsi->endptr = NULL_TREE;
1286 chainsi->dont_invalidate = true;
1289 dsi->stmt = stmt;
1290 return;
1293 if (olddsi != NULL)
1295 tree adj = NULL_TREE;
1296 if (oldlen == NULL_TREE)
1298 else if (integer_zerop (oldlen))
1299 adj = srclen;
1300 else if (TREE_CODE (oldlen) == INTEGER_CST
1301 || TREE_CODE (srclen) == INTEGER_CST)
1302 adj = fold_build2_loc (loc, MINUS_EXPR,
1303 TREE_TYPE (srclen), srclen,
1304 fold_convert_loc (loc, TREE_TYPE (srclen),
1305 oldlen));
1306 if (adj != NULL_TREE)
1307 adjust_related_strinfos (loc, dsi, adj);
1308 else
1309 dsi->prev = 0;
1311 /* strcpy src may not overlap dst, so src doesn't need to be
1312 invalidated either. */
1313 if (si != NULL)
1314 si->dont_invalidate = true;
1316 fn = NULL_TREE;
1317 zsi = NULL;
1318 switch (bcode)
1320 case BUILT_IN_STRCPY:
1321 case BUILT_IN_STRCPY_CHKP:
1322 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1323 if (lhs)
1324 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1325 break;
1326 case BUILT_IN_STRCPY_CHK:
1327 case BUILT_IN_STRCPY_CHK_CHKP:
1328 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1329 if (lhs)
1330 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1331 break;
1332 case BUILT_IN_STPCPY:
1333 case BUILT_IN_STPCPY_CHKP:
1334 /* This would need adjustment of the lhs (subtract one),
1335 or detection that the trailing '\0' doesn't need to be
1336 written, if it will be immediately overwritten.
1337 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1338 if (lhs)
1340 dsi->endptr = lhs;
1341 zsi = zero_length_string (lhs, dsi);
1343 break;
1344 case BUILT_IN_STPCPY_CHK:
1345 case BUILT_IN_STPCPY_CHK_CHKP:
1346 /* This would need adjustment of the lhs (subtract one),
1347 or detection that the trailing '\0' doesn't need to be
1348 written, if it will be immediately overwritten.
1349 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1350 if (lhs)
1352 dsi->endptr = lhs;
1353 zsi = zero_length_string (lhs, dsi);
1355 break;
1356 default:
1357 gcc_unreachable ();
1359 if (zsi != NULL)
1360 zsi->dont_invalidate = true;
1362 if (fn == NULL_TREE)
1363 return;
1365 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1366 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1368 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1369 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1370 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1371 GSI_SAME_STMT);
1372 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1374 fprintf (dump_file, "Optimizing: ");
1375 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1377 if (with_bounds)
1379 fn = chkp_maybe_create_clone (fn)->decl;
1380 if (gimple_call_num_args (stmt) == 4)
1381 success = update_gimple_call (gsi, fn, 5, dst,
1382 gimple_call_arg (stmt, 1),
1383 src,
1384 gimple_call_arg (stmt, 3),
1385 len);
1386 else
1387 success = update_gimple_call (gsi, fn, 6, dst,
1388 gimple_call_arg (stmt, 1),
1389 src,
1390 gimple_call_arg (stmt, 3),
1391 len,
1392 gimple_call_arg (stmt, 4));
1394 else
1395 if (gimple_call_num_args (stmt) == 2)
1396 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1397 else
1398 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1399 gimple_call_arg (stmt, 2));
1400 if (success)
1402 stmt = gsi_stmt (*gsi);
1403 gimple_call_set_with_bounds (stmt, with_bounds);
1404 update_stmt (stmt);
1405 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1407 fprintf (dump_file, "into: ");
1408 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1410 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1411 laststmt.stmt = stmt;
1412 laststmt.len = srclen;
1413 laststmt.stridx = dsi->idx;
1415 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1416 fprintf (dump_file, "not possible.\n");
1419 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1420 If strlen of the second argument is known and length of the third argument
1421 is that plus one, strlen of the first argument is the same after this
1422 call. */
1424 static void
1425 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1427 int idx, didx;
1428 tree src, dst, len, lhs, oldlen, newlen;
1429 gimple *stmt = gsi_stmt (*gsi);
1430 strinfo *si, *dsi, *olddsi;
1431 bool with_bounds = gimple_call_with_bounds_p (stmt);
1433 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1434 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1435 dst = gimple_call_arg (stmt, 0);
1436 idx = get_stridx (src);
1437 if (idx == 0)
1438 return;
1440 didx = get_stridx (dst);
1441 olddsi = NULL;
1442 if (didx > 0)
1443 olddsi = get_strinfo (didx);
1444 else if (didx < 0)
1445 return;
1447 if (olddsi != NULL
1448 && tree_fits_uhwi_p (len)
1449 && !integer_zerop (len))
1450 adjust_last_stmt (olddsi, stmt, false);
1452 if (idx > 0)
1454 gimple *def_stmt;
1456 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1457 si = get_strinfo (idx);
1458 if (si == NULL || si->length == NULL_TREE)
1459 return;
1460 if (TREE_CODE (len) != SSA_NAME)
1461 return;
1462 def_stmt = SSA_NAME_DEF_STMT (len);
1463 if (!is_gimple_assign (def_stmt)
1464 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1465 || gimple_assign_rhs1 (def_stmt) != si->length
1466 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1467 return;
1469 else
1471 si = NULL;
1472 /* Handle memcpy (x, "abcd", 5) or
1473 memcpy (x, "abc\0uvw", 7). */
1474 if (!tree_fits_uhwi_p (len)
1475 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1476 return;
1479 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1480 adjust_last_stmt (olddsi, stmt, false);
1482 if (didx == 0)
1484 didx = new_stridx (dst);
1485 if (didx == 0)
1486 return;
1488 if (si != NULL)
1489 newlen = si->length;
1490 else
1491 newlen = build_int_cst (size_type_node, ~idx);
1492 oldlen = NULL_TREE;
1493 if (olddsi != NULL)
1495 dsi = unshare_strinfo (olddsi);
1496 oldlen = olddsi->length;
1497 dsi->length = newlen;
1498 /* Break the chain, so adjust_related_strinfo on later pointers in
1499 the chain won't adjust this one anymore. */
1500 dsi->next = 0;
1501 dsi->stmt = NULL;
1502 dsi->endptr = NULL_TREE;
1504 else
1506 dsi = new_strinfo (dst, didx, newlen);
1507 set_strinfo (didx, dsi);
1508 find_equal_ptrs (dst, didx);
1510 dsi->writable = true;
1511 dsi->dont_invalidate = true;
1512 if (olddsi != NULL)
1514 tree adj = NULL_TREE;
1515 location_t loc = gimple_location (stmt);
1516 if (oldlen == NULL_TREE)
1518 else if (integer_zerop (oldlen))
1519 adj = dsi->length;
1520 else if (TREE_CODE (oldlen) == INTEGER_CST
1521 || TREE_CODE (dsi->length) == INTEGER_CST)
1522 adj = fold_build2_loc (loc, MINUS_EXPR,
1523 TREE_TYPE (dsi->length), dsi->length,
1524 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1525 oldlen));
1526 if (adj != NULL_TREE)
1527 adjust_related_strinfos (loc, dsi, adj);
1528 else
1529 dsi->prev = 0;
1531 /* memcpy src may not overlap dst, so src doesn't need to be
1532 invalidated either. */
1533 if (si != NULL)
1534 si->dont_invalidate = true;
1536 lhs = gimple_call_lhs (stmt);
1537 switch (bcode)
1539 case BUILT_IN_MEMCPY:
1540 case BUILT_IN_MEMCPY_CHK:
1541 case BUILT_IN_MEMCPY_CHKP:
1542 case BUILT_IN_MEMCPY_CHK_CHKP:
1543 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1544 laststmt.stmt = stmt;
1545 laststmt.len = dsi->length;
1546 laststmt.stridx = dsi->idx;
1547 if (lhs)
1548 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1549 break;
1550 case BUILT_IN_MEMPCPY:
1551 case BUILT_IN_MEMPCPY_CHK:
1552 case BUILT_IN_MEMPCPY_CHKP:
1553 case BUILT_IN_MEMPCPY_CHK_CHKP:
1554 break;
1555 default:
1556 gcc_unreachable ();
1560 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1561 If strlen of the second argument is known, strlen of the first argument
1562 is increased by the length of the second argument. Furthermore, attempt
1563 to convert it to memcpy/strcpy if the length of the first argument
1564 is known. */
1566 static void
1567 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1569 int idx, didx;
1570 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1571 bool success;
1572 gimple *stmt = gsi_stmt (*gsi);
1573 strinfo *si, *dsi;
1574 location_t loc;
1575 bool with_bounds = gimple_call_with_bounds_p (stmt);
1577 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1578 dst = gimple_call_arg (stmt, 0);
1579 lhs = gimple_call_lhs (stmt);
1581 didx = get_stridx (dst);
1582 if (didx < 0)
1583 return;
1585 dsi = NULL;
1586 if (didx > 0)
1587 dsi = get_strinfo (didx);
1588 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1590 /* strcat (p, q) can be transformed into
1591 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1592 with length endptr - p if we need to compute the length
1593 later on. Don't do this transformation if we don't need
1594 it. */
1595 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1597 if (didx == 0)
1599 didx = new_stridx (dst);
1600 if (didx == 0)
1601 return;
1603 if (dsi == NULL)
1605 dsi = new_strinfo (dst, didx, NULL_TREE);
1606 set_strinfo (didx, dsi);
1607 find_equal_ptrs (dst, didx);
1609 else
1611 dsi = unshare_strinfo (dsi);
1612 dsi->length = NULL_TREE;
1613 dsi->next = 0;
1614 dsi->endptr = NULL_TREE;
1616 dsi->writable = true;
1617 dsi->stmt = stmt;
1618 dsi->dont_invalidate = true;
1620 return;
1623 srclen = NULL_TREE;
1624 si = NULL;
1625 idx = get_stridx (src);
1626 if (idx < 0)
1627 srclen = build_int_cst (size_type_node, ~idx);
1628 else if (idx > 0)
1630 si = get_strinfo (idx);
1631 if (si != NULL)
1632 srclen = get_string_length (si);
1635 loc = gimple_location (stmt);
1636 dstlen = dsi->length;
1637 endptr = dsi->endptr;
1639 dsi = unshare_strinfo (dsi);
1640 dsi->endptr = NULL_TREE;
1641 dsi->stmt = NULL;
1642 dsi->writable = true;
1644 if (srclen != NULL_TREE)
1646 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1647 dsi->length, srclen);
1648 adjust_related_strinfos (loc, dsi, srclen);
1649 dsi->dont_invalidate = true;
1651 else
1653 dsi->length = NULL;
1654 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1655 dsi->dont_invalidate = true;
1658 if (si != NULL)
1659 /* strcat src may not overlap dst, so src doesn't need to be
1660 invalidated either. */
1661 si->dont_invalidate = true;
1663 /* For now. Could remove the lhs from the call and add
1664 lhs = dst; afterwards. */
1665 if (lhs)
1666 return;
1668 fn = NULL_TREE;
1669 objsz = NULL_TREE;
1670 switch (bcode)
1672 case BUILT_IN_STRCAT:
1673 case BUILT_IN_STRCAT_CHKP:
1674 if (srclen != NULL_TREE)
1675 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1676 else
1677 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1678 break;
1679 case BUILT_IN_STRCAT_CHK:
1680 case BUILT_IN_STRCAT_CHK_CHKP:
1681 if (srclen != NULL_TREE)
1682 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1683 else
1684 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1685 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1686 break;
1687 default:
1688 gcc_unreachable ();
1691 if (fn == NULL_TREE)
1692 return;
1694 len = NULL_TREE;
1695 if (srclen != NULL_TREE)
1697 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1698 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1700 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1701 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1702 build_int_cst (type, 1));
1703 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1704 GSI_SAME_STMT);
1706 if (endptr)
1707 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1708 else
1709 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1710 TREE_TYPE (dst), unshare_expr (dst),
1711 fold_convert_loc (loc, sizetype,
1712 unshare_expr (dstlen)));
1713 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1714 GSI_SAME_STMT);
1715 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1717 fprintf (dump_file, "Optimizing: ");
1718 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1720 if (with_bounds)
1722 fn = chkp_maybe_create_clone (fn)->decl;
1723 if (srclen != NULL_TREE)
1724 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1725 dst,
1726 gimple_call_arg (stmt, 1),
1727 src,
1728 gimple_call_arg (stmt, 3),
1729 len, objsz);
1730 else
1731 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1732 dst,
1733 gimple_call_arg (stmt, 1),
1734 src,
1735 gimple_call_arg (stmt, 3),
1736 objsz);
1738 else
1739 if (srclen != NULL_TREE)
1740 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1741 dst, src, len, objsz);
1742 else
1743 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1744 dst, src, objsz);
1745 if (success)
1747 stmt = gsi_stmt (*gsi);
1748 gimple_call_set_with_bounds (stmt, with_bounds);
1749 update_stmt (stmt);
1750 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1752 fprintf (dump_file, "into: ");
1753 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1755 /* If srclen == NULL, note that current string length can be
1756 computed by transforming this strcpy into stpcpy. */
1757 if (srclen == NULL_TREE && dsi->dont_invalidate)
1758 dsi->stmt = stmt;
1759 adjust_last_stmt (dsi, stmt, true);
1760 if (srclen != NULL_TREE)
1762 laststmt.stmt = stmt;
1763 laststmt.len = srclen;
1764 laststmt.stridx = dsi->idx;
1767 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1768 fprintf (dump_file, "not possible.\n");
1771 /* Handle a call to malloc or calloc. */
1773 static void
1774 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1776 gimple *stmt = gsi_stmt (*gsi);
1777 tree lhs = gimple_call_lhs (stmt);
1778 gcc_assert (get_stridx (lhs) == 0);
1779 int idx = new_stridx (lhs);
1780 tree length = NULL_TREE;
1781 if (bcode == BUILT_IN_CALLOC)
1782 length = build_int_cst (size_type_node, 0);
1783 strinfo *si = new_strinfo (lhs, idx, length);
1784 if (bcode == BUILT_IN_CALLOC)
1785 si->endptr = lhs;
1786 set_strinfo (idx, si);
1787 si->writable = true;
1788 si->stmt = stmt;
1789 si->dont_invalidate = true;
1792 /* Handle a call to memset.
1793 After a call to calloc, memset(,0,) is unnecessary.
1794 memset(malloc(n),0,n) is calloc(n,1). */
1796 static bool
1797 handle_builtin_memset (gimple_stmt_iterator *gsi)
1799 gimple *stmt2 = gsi_stmt (*gsi);
1800 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1801 return true;
1802 tree ptr = gimple_call_arg (stmt2, 0);
1803 int idx1 = get_stridx (ptr);
1804 if (idx1 <= 0)
1805 return true;
1806 strinfo *si1 = get_strinfo (idx1);
1807 if (!si1)
1808 return true;
1809 gimple *stmt1 = si1->stmt;
1810 if (!stmt1 || !is_gimple_call (stmt1))
1811 return true;
1812 tree callee1 = gimple_call_fndecl (stmt1);
1813 if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL))
1814 return true;
1815 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1816 tree size = gimple_call_arg (stmt2, 2);
1817 if (code1 == BUILT_IN_CALLOC)
1818 /* Not touching stmt1 */ ;
1819 else if (code1 == BUILT_IN_MALLOC
1820 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1822 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1823 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1824 size, build_one_cst (size_type_node));
1825 si1->length = build_int_cst (size_type_node, 0);
1826 si1->stmt = gsi_stmt (gsi1);
1828 else
1829 return true;
1830 tree lhs = gimple_call_lhs (stmt2);
1831 unlink_stmt_vdef (stmt2);
1832 if (lhs)
1834 gimple *assign = gimple_build_assign (lhs, ptr);
1835 gsi_replace (gsi, assign, false);
1837 else
1839 gsi_remove (gsi, true);
1840 release_defs (stmt2);
1843 return false;
1846 /* Handle a POINTER_PLUS_EXPR statement.
1847 For p = "abcd" + 2; compute associated length, or if
1848 p = q + off is pointing to a '\0' character of a string, call
1849 zero_length_string on it. */
1851 static void
1852 handle_pointer_plus (gimple_stmt_iterator *gsi)
1854 gimple *stmt = gsi_stmt (*gsi);
1855 tree lhs = gimple_assign_lhs (stmt), off;
1856 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1857 strinfo *si, *zsi;
1859 if (idx == 0)
1860 return;
1862 if (idx < 0)
1864 tree off = gimple_assign_rhs2 (stmt);
1865 if (tree_fits_uhwi_p (off)
1866 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1867 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1868 = ~(~idx - (int) tree_to_uhwi (off));
1869 return;
1872 si = get_strinfo (idx);
1873 if (si == NULL || si->length == NULL_TREE)
1874 return;
1876 off = gimple_assign_rhs2 (stmt);
1877 zsi = NULL;
1878 if (operand_equal_p (si->length, off, 0))
1879 zsi = zero_length_string (lhs, si);
1880 else if (TREE_CODE (off) == SSA_NAME)
1882 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
1883 if (gimple_assign_single_p (def_stmt)
1884 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1885 zsi = zero_length_string (lhs, si);
1887 if (zsi != NULL
1888 && si->endptr != NULL_TREE
1889 && si->endptr != lhs
1890 && TREE_CODE (si->endptr) == SSA_NAME)
1892 enum tree_code rhs_code
1893 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1894 ? SSA_NAME : NOP_EXPR;
1895 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
1896 gcc_assert (gsi_stmt (*gsi) == stmt);
1897 update_stmt (stmt);
1901 /* Handle a single character store. */
1903 static bool
1904 handle_char_store (gimple_stmt_iterator *gsi)
1906 int idx = -1;
1907 strinfo *si = NULL;
1908 gimple *stmt = gsi_stmt (*gsi);
1909 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1911 if (TREE_CODE (lhs) == MEM_REF
1912 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1914 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1916 ssaname = TREE_OPERAND (lhs, 0);
1917 idx = get_stridx (ssaname);
1920 else
1921 idx = get_addr_stridx (lhs);
1923 if (idx > 0)
1925 si = get_strinfo (idx);
1926 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1928 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1930 /* When storing '\0', the store can be removed
1931 if we know it has been stored in the current function. */
1932 if (!stmt_could_throw_p (stmt) && si->writable)
1934 unlink_stmt_vdef (stmt);
1935 release_defs (stmt);
1936 gsi_remove (gsi, true);
1937 return false;
1939 else
1941 si->writable = true;
1942 gsi_next (gsi);
1943 return false;
1946 else
1947 /* Otherwise this statement overwrites the '\0' with
1948 something, if the previous stmt was a memcpy,
1949 its length may be decreased. */
1950 adjust_last_stmt (si, stmt, false);
1952 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1954 si = unshare_strinfo (si);
1955 si->length = build_int_cst (size_type_node, 0);
1956 si->endptr = NULL;
1957 si->prev = 0;
1958 si->next = 0;
1959 si->stmt = NULL;
1960 si->first = 0;
1961 si->writable = true;
1962 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1963 si->endptr = ssaname;
1964 si->dont_invalidate = true;
1966 /* If si->length is non-zero constant, we aren't overwriting '\0',
1967 and if we aren't storing '\0', we know that the length of the
1968 string and any other zero terminated string in memory remains
1969 the same. In that case we move to the next gimple statement and
1970 return to signal the caller that it shouldn't invalidate anything.
1972 This is benefical for cases like:
1974 char p[20];
1975 void foo (char *q)
1977 strcpy (p, "foobar");
1978 size_t len = strlen (p); // This can be optimized into 6
1979 size_t len2 = strlen (q); // This has to be computed
1980 p[0] = 'X';
1981 size_t len3 = strlen (p); // This can be optimized into 6
1982 size_t len4 = strlen (q); // This can be optimized into len2
1983 bar (len, len2, len3, len4);
1986 else if (si != NULL && si->length != NULL_TREE
1987 && TREE_CODE (si->length) == INTEGER_CST
1988 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
1990 gsi_next (gsi);
1991 return false;
1994 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1996 if (ssaname)
1998 si = zero_length_string (ssaname, NULL);
1999 if (si != NULL)
2000 si->dont_invalidate = true;
2002 else
2004 int idx = new_addr_stridx (lhs);
2005 if (idx != 0)
2007 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2008 build_int_cst (size_type_node, 0));
2009 set_strinfo (idx, si);
2010 si->dont_invalidate = true;
2013 if (si != NULL)
2014 si->writable = true;
2016 else if (idx == 0
2017 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2018 && ssaname == NULL_TREE
2019 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2021 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2022 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2023 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2025 int idx = new_addr_stridx (lhs);
2026 if (idx != 0)
2028 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2029 build_int_cst (size_type_node, l));
2030 set_strinfo (idx, si);
2031 si->dont_invalidate = true;
2036 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2038 /* Allow adjust_last_stmt to remove it if the stored '\0'
2039 is immediately overwritten. */
2040 laststmt.stmt = stmt;
2041 laststmt.len = build_int_cst (size_type_node, 1);
2042 laststmt.stridx = si->idx;
2044 return true;
2047 /* Attempt to optimize a single statement at *GSI using string length
2048 knowledge. */
2050 static bool
2051 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2053 gimple *stmt = gsi_stmt (*gsi);
2055 if (is_gimple_call (stmt))
2057 tree callee = gimple_call_fndecl (stmt);
2058 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
2059 switch (DECL_FUNCTION_CODE (callee))
2061 case BUILT_IN_STRLEN:
2062 case BUILT_IN_STRLEN_CHKP:
2063 handle_builtin_strlen (gsi);
2064 break;
2065 case BUILT_IN_STRCHR:
2066 case BUILT_IN_STRCHR_CHKP:
2067 handle_builtin_strchr (gsi);
2068 break;
2069 case BUILT_IN_STRCPY:
2070 case BUILT_IN_STRCPY_CHK:
2071 case BUILT_IN_STPCPY:
2072 case BUILT_IN_STPCPY_CHK:
2073 case BUILT_IN_STRCPY_CHKP:
2074 case BUILT_IN_STRCPY_CHK_CHKP:
2075 case BUILT_IN_STPCPY_CHKP:
2076 case BUILT_IN_STPCPY_CHK_CHKP:
2077 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2078 break;
2079 case BUILT_IN_MEMCPY:
2080 case BUILT_IN_MEMCPY_CHK:
2081 case BUILT_IN_MEMPCPY:
2082 case BUILT_IN_MEMPCPY_CHK:
2083 case BUILT_IN_MEMCPY_CHKP:
2084 case BUILT_IN_MEMCPY_CHK_CHKP:
2085 case BUILT_IN_MEMPCPY_CHKP:
2086 case BUILT_IN_MEMPCPY_CHK_CHKP:
2087 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2088 break;
2089 case BUILT_IN_STRCAT:
2090 case BUILT_IN_STRCAT_CHK:
2091 case BUILT_IN_STRCAT_CHKP:
2092 case BUILT_IN_STRCAT_CHK_CHKP:
2093 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2094 break;
2095 case BUILT_IN_MALLOC:
2096 case BUILT_IN_CALLOC:
2097 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2098 break;
2099 case BUILT_IN_MEMSET:
2100 if (!handle_builtin_memset (gsi))
2101 return false;
2102 break;
2103 default:
2104 break;
2107 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2109 tree lhs = gimple_assign_lhs (stmt);
2111 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2113 if (gimple_assign_single_p (stmt)
2114 || (gimple_assign_cast_p (stmt)
2115 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2117 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2118 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2120 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2121 handle_pointer_plus (gsi);
2123 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2125 tree type = TREE_TYPE (lhs);
2126 if (TREE_CODE (type) == ARRAY_TYPE)
2127 type = TREE_TYPE (type);
2128 if (TREE_CODE (type) == INTEGER_TYPE
2129 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2130 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2132 if (! handle_char_store (gsi))
2133 return false;
2138 if (gimple_vdef (stmt))
2139 maybe_invalidate (stmt);
2140 return true;
2143 /* Recursively call maybe_invalidate on stmts that might be executed
2144 in between dombb and current bb and that contain a vdef. Stop when
2145 *count stmts are inspected, or if the whole strinfo vector has
2146 been invalidated. */
2148 static void
2149 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2151 unsigned int i, n = gimple_phi_num_args (phi);
2153 for (i = 0; i < n; i++)
2155 tree vuse = gimple_phi_arg_def (phi, i);
2156 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2157 basic_block bb = gimple_bb (stmt);
2158 if (bb == NULL
2159 || bb == dombb
2160 || !bitmap_set_bit (visited, bb->index)
2161 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2162 continue;
2163 while (1)
2165 if (gimple_code (stmt) == GIMPLE_PHI)
2167 do_invalidate (dombb, stmt, visited, count);
2168 if (*count == 0)
2169 return;
2170 break;
2172 if (--*count == 0)
2173 return;
2174 if (!maybe_invalidate (stmt))
2176 *count = 0;
2177 return;
2179 vuse = gimple_vuse (stmt);
2180 stmt = SSA_NAME_DEF_STMT (vuse);
2181 if (gimple_bb (stmt) != bb)
2183 bb = gimple_bb (stmt);
2184 if (bb == NULL
2185 || bb == dombb
2186 || !bitmap_set_bit (visited, bb->index)
2187 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2188 break;
2194 class strlen_dom_walker : public dom_walker
2196 public:
2197 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2199 virtual edge before_dom_children (basic_block);
2200 virtual void after_dom_children (basic_block);
2203 /* Callback for walk_dominator_tree. Attempt to optimize various
2204 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2206 edge
2207 strlen_dom_walker::before_dom_children (basic_block bb)
2209 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2211 if (dombb == NULL)
2212 stridx_to_strinfo = NULL;
2213 else
2215 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2216 if (stridx_to_strinfo)
2218 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2219 gsi_next (&gsi))
2221 gphi *phi = gsi.phi ();
2222 if (virtual_operand_p (gimple_phi_result (phi)))
2224 bitmap visited = BITMAP_ALLOC (NULL);
2225 int count_vdef = 100;
2226 do_invalidate (dombb, phi, visited, &count_vdef);
2227 BITMAP_FREE (visited);
2228 if (count_vdef == 0)
2230 /* If there were too many vdefs in between immediate
2231 dominator and current bb, invalidate everything.
2232 If stridx_to_strinfo has been unshared, we need
2233 to free it, otherwise just set it to NULL. */
2234 if (!strinfo_shared ())
2236 unsigned int i;
2237 strinfo *si;
2239 for (i = 1;
2240 vec_safe_iterate (stridx_to_strinfo, i, &si);
2241 ++i)
2243 free_strinfo (si);
2244 (*stridx_to_strinfo)[i] = NULL;
2247 else
2248 stridx_to_strinfo = NULL;
2250 break;
2256 /* If all PHI arguments have the same string index, the PHI result
2257 has it as well. */
2258 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2259 gsi_next (&gsi))
2261 gphi *phi = gsi.phi ();
2262 tree result = gimple_phi_result (phi);
2263 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2265 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2266 if (idx != 0)
2268 unsigned int i, n = gimple_phi_num_args (phi);
2269 for (i = 1; i < n; i++)
2270 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2271 break;
2272 if (i == n)
2273 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2278 /* Attempt to optimize individual statements. */
2279 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2280 if (strlen_optimize_stmt (&gsi))
2281 gsi_next (&gsi);
2283 bb->aux = stridx_to_strinfo;
2284 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2285 (*stridx_to_strinfo)[0] = (strinfo *) bb;
2286 return NULL;
2289 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2290 owned by the current bb, clear bb->aux. */
2292 void
2293 strlen_dom_walker::after_dom_children (basic_block bb)
2295 if (bb->aux)
2297 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2298 if (vec_safe_length (stridx_to_strinfo)
2299 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2301 unsigned int i;
2302 strinfo *si;
2304 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2305 free_strinfo (si);
2306 vec_free (stridx_to_strinfo);
2308 bb->aux = NULL;
2312 /* Main entry point. */
2314 namespace {
2316 const pass_data pass_data_strlen =
2318 GIMPLE_PASS, /* type */
2319 "strlen", /* name */
2320 OPTGROUP_NONE, /* optinfo_flags */
2321 TV_TREE_STRLEN, /* tv_id */
2322 ( PROP_cfg | PROP_ssa ), /* properties_required */
2323 0, /* properties_provided */
2324 0, /* properties_destroyed */
2325 0, /* todo_flags_start */
2326 0, /* todo_flags_finish */
2329 class pass_strlen : public gimple_opt_pass
2331 public:
2332 pass_strlen (gcc::context *ctxt)
2333 : gimple_opt_pass (pass_data_strlen, ctxt)
2336 /* opt_pass methods: */
2337 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2338 virtual unsigned int execute (function *);
2340 }; // class pass_strlen
2342 unsigned int
2343 pass_strlen::execute (function *fun)
2345 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2346 max_stridx = 1;
2348 calculate_dominance_info (CDI_DOMINATORS);
2350 /* String length optimization is implemented as a walk of the dominator
2351 tree and a forward walk of statements within each block. */
2352 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2354 ssa_ver_to_stridx.release ();
2355 strinfo_pool.release ();
2356 if (decl_to_stridxlist_htab)
2358 obstack_free (&stridx_obstack, NULL);
2359 delete decl_to_stridxlist_htab;
2360 decl_to_stridxlist_htab = NULL;
2362 laststmt.stmt = NULL;
2363 laststmt.len = NULL_TREE;
2364 laststmt.stridx = 0;
2366 return 0;
2369 } // anon namespace
2371 gimple_opt_pass *
2372 make_pass_strlen (gcc::context *ctxt)
2374 return new pass_strlen (ctxt);