PR c++/83634
[official-gcc.git] / gcc / tree-ssa-strlen.c
blobc8b86b69dbe2bd65261fa7713042e160ce181d84
1 /* String length optimization
2 Copyright (C) 2011-2018 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 "gimple-ssa-warn-restrict.h"
34 #include "fold-const.h"
35 #include "stor-layout.h"
36 #include "gimple-fold.h"
37 #include "tree-eh.h"
38 #include "gimplify.h"
39 #include "gimple-iterator.h"
40 #include "gimplify-me.h"
41 #include "expr.h"
42 #include "tree-dfa.h"
43 #include "domwalk.h"
44 #include "tree-ssa-alias.h"
45 #include "tree-ssa-propagate.h"
46 #include "params.h"
47 #include "ipa-chkp.h"
48 #include "tree-hash-traits.h"
49 #include "builtins.h"
50 #include "target.h"
51 #include "diagnostic-core.h"
52 #include "diagnostic.h"
53 #include "intl.h"
54 #include "attribs.h"
55 #include "calls.h"
57 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
58 is an index into strinfo vector, negative value stands for
59 string length of a string literal (~strlen). */
60 static vec<int> ssa_ver_to_stridx;
62 /* Number of currently active string indexes plus one. */
63 static int max_stridx;
65 /* String information record. */
66 struct strinfo
68 /* Number of leading characters that are known to be nonzero. This is
69 also the length of the string if FULL_STRING_P.
71 The values in a list of related string pointers must be consistent;
72 that is, if strinfo B comes X bytes after strinfo A, it must be
73 the case that A->nonzero_chars == X + B->nonzero_chars. */
74 tree nonzero_chars;
75 /* Any of the corresponding pointers for querying alias oracle. */
76 tree ptr;
77 /* This is used for two things:
79 - To record the statement that should be used for delayed length
80 computations. We maintain the invariant that all related strinfos
81 have delayed lengths or none do.
83 - To record the malloc or calloc call that produced this result. */
84 gimple *stmt;
85 /* Pointer to '\0' if known, if NULL, it can be computed as
86 ptr + length. */
87 tree endptr;
88 /* Reference count. Any changes to strinfo entry possibly shared
89 with dominating basic blocks need unshare_strinfo first, except
90 for dont_invalidate which affects only the immediately next
91 maybe_invalidate. */
92 int refcount;
93 /* Copy of index. get_strinfo (si->idx) should return si; */
94 int idx;
95 /* These 3 fields are for chaining related string pointers together.
96 E.g. for
97 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
98 strcpy (c, d); e = c + dl;
99 strinfo(a) -> strinfo(c) -> strinfo(e)
100 All have ->first field equal to strinfo(a)->idx and are doubly
101 chained through prev/next fields. The later strinfos are required
102 to point into the same string with zero or more bytes after
103 the previous pointer and all bytes in between the two pointers
104 must be non-zero. Functions like strcpy or memcpy are supposed
105 to adjust all previous strinfo lengths, but not following strinfo
106 lengths (those are uncertain, usually invalidated during
107 maybe_invalidate, except when the alias oracle knows better).
108 Functions like strcat on the other side adjust the whole
109 related strinfo chain.
110 They are updated lazily, so to use the chain the same first fields
111 and si->prev->next == si->idx needs to be verified. */
112 int first;
113 int next;
114 int prev;
115 /* A flag whether the string is known to be written in the current
116 function. */
117 bool writable;
118 /* A flag for the next maybe_invalidate that this strinfo shouldn't
119 be invalidated. Always cleared by maybe_invalidate. */
120 bool dont_invalidate;
121 /* True if the string is known to be nul-terminated after NONZERO_CHARS
122 characters. False is useful when detecting strings that are built
123 up via successive memcpys. */
124 bool full_string_p;
127 /* Pool for allocating strinfo_struct entries. */
128 static object_allocator<strinfo> strinfo_pool ("strinfo pool");
130 /* Vector mapping positive string indexes to strinfo, for the
131 current basic block. The first pointer in the vector is special,
132 it is either NULL, meaning the vector isn't shared, or it is
133 a basic block pointer to the owner basic_block if shared.
134 If some other bb wants to modify the vector, the vector needs
135 to be unshared first, and only the owner bb is supposed to free it. */
136 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
138 /* One OFFSET->IDX mapping. */
139 struct stridxlist
141 struct stridxlist *next;
142 HOST_WIDE_INT offset;
143 int idx;
146 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
147 struct decl_stridxlist_map
149 struct tree_map_base base;
150 struct stridxlist list;
153 /* Hash table for mapping decls to a chained list of offset -> idx
154 mappings. */
155 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
157 /* Hash table mapping strlen calls to stridx instances describing
158 the calls' arguments. Non-null only when warn_stringop_truncation
159 is non-zero. */
160 typedef std::pair<int, location_t> stridx_strlenloc;
161 static hash_map<tree, stridx_strlenloc> *strlen_to_stridx;
163 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
164 static struct obstack stridx_obstack;
166 /* Last memcpy statement if it could be adjusted if the trailing
167 '\0' written is immediately overwritten, or
168 *x = '\0' store that could be removed if it is immediately overwritten. */
169 struct laststmt_struct
171 gimple *stmt;
172 tree len;
173 int stridx;
174 } laststmt;
176 static int get_stridx_plus_constant (strinfo *, unsigned HOST_WIDE_INT, tree);
177 static void handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *);
179 /* Return:
181 - 1 if SI is known to start with more than OFF nonzero characters.
183 - 0 if SI is known to start with OFF nonzero characters,
184 but is not known to start with more.
186 - -1 if SI might not start with OFF nonzero characters. */
188 static inline int
189 compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off)
191 if (si->nonzero_chars
192 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
193 return compare_tree_int (si->nonzero_chars, off);
194 else
195 return -1;
198 /* Return true if SI is known to be a zero-length string. */
200 static inline bool
201 zero_length_string_p (strinfo *si)
203 return si->full_string_p && integer_zerop (si->nonzero_chars);
206 /* Return strinfo vector entry IDX. */
208 static inline strinfo *
209 get_strinfo (int idx)
211 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
212 return NULL;
213 return (*stridx_to_strinfo)[idx];
216 /* Get the next strinfo in the chain after SI, or null if none. */
218 static inline strinfo *
219 get_next_strinfo (strinfo *si)
221 if (si->next == 0)
222 return NULL;
223 strinfo *nextsi = get_strinfo (si->next);
224 if (nextsi == NULL || nextsi->first != si->first || nextsi->prev != si->idx)
225 return NULL;
226 return nextsi;
229 /* Helper function for get_stridx. Return the strinfo index of the address
230 of EXP, which is available in PTR if nonnull. If OFFSET_OUT, it is
231 OK to return the index for some X <= &EXP and store &EXP - X in
232 *OFFSET_OUT. */
234 static int
235 get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out)
237 HOST_WIDE_INT off;
238 struct stridxlist *list, *last = NULL;
239 tree base;
241 if (!decl_to_stridxlist_htab)
242 return 0;
244 poly_int64 poff;
245 base = get_addr_base_and_unit_offset (exp, &poff);
246 if (base == NULL || !DECL_P (base) || !poff.is_constant (&off))
247 return 0;
249 list = decl_to_stridxlist_htab->get (base);
250 if (list == NULL)
251 return 0;
255 if (list->offset == off)
257 if (offset_out)
258 *offset_out = 0;
259 return list->idx;
261 if (list->offset > off)
262 return 0;
263 last = list;
264 list = list->next;
266 while (list);
268 if ((offset_out || ptr) && last && last->idx > 0)
270 unsigned HOST_WIDE_INT rel_off
271 = (unsigned HOST_WIDE_INT) off - last->offset;
272 strinfo *si = get_strinfo (last->idx);
273 if (si && compare_nonzero_chars (si, rel_off) >= 0)
275 if (offset_out)
277 *offset_out = rel_off;
278 return last->idx;
280 else
281 return get_stridx_plus_constant (si, rel_off, ptr);
284 return 0;
287 /* Return string index for EXP. */
289 static int
290 get_stridx (tree exp)
292 tree s, o;
294 if (TREE_CODE (exp) == SSA_NAME)
296 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
297 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
298 int i;
299 tree e = exp;
300 HOST_WIDE_INT off = 0;
301 for (i = 0; i < 5; i++)
303 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
304 if (!is_gimple_assign (def_stmt)
305 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
306 return 0;
307 tree rhs1 = gimple_assign_rhs1 (def_stmt);
308 tree rhs2 = gimple_assign_rhs2 (def_stmt);
309 if (TREE_CODE (rhs1) != SSA_NAME
310 || !tree_fits_shwi_p (rhs2))
311 return 0;
312 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
313 if (this_off < 0)
314 return 0;
315 off = (unsigned HOST_WIDE_INT) off + this_off;
316 if (off < 0)
317 return 0;
318 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
320 strinfo *si
321 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
322 if (si && compare_nonzero_chars (si, off) >= 0)
323 return get_stridx_plus_constant (si, off, exp);
325 e = rhs1;
327 return 0;
330 if (TREE_CODE (exp) == ADDR_EXPR)
332 int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp, NULL);
333 if (idx != 0)
334 return idx;
337 s = string_constant (exp, &o);
338 if (s != NULL_TREE
339 && (o == NULL_TREE || tree_fits_shwi_p (o))
340 && TREE_STRING_LENGTH (s) > 0)
342 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
343 const char *p = TREE_STRING_POINTER (s);
344 int max = TREE_STRING_LENGTH (s) - 1;
346 if (p[max] == '\0' && offset >= 0 && offset <= max)
347 return ~(int) strlen (p + offset);
349 return 0;
352 /* Return true if strinfo vector is shared with the immediate dominator. */
354 static inline bool
355 strinfo_shared (void)
357 return vec_safe_length (stridx_to_strinfo)
358 && (*stridx_to_strinfo)[0] != NULL;
361 /* Unshare strinfo vector that is shared with the immediate dominator. */
363 static void
364 unshare_strinfo_vec (void)
366 strinfo *si;
367 unsigned int i = 0;
369 gcc_assert (strinfo_shared ());
370 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
371 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
372 if (si != NULL)
373 si->refcount++;
374 (*stridx_to_strinfo)[0] = NULL;
377 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
378 Return a pointer to the location where the string index can
379 be stored (if 0) or is stored, or NULL if this can't be tracked. */
381 static int *
382 addr_stridxptr (tree exp)
384 HOST_WIDE_INT off;
386 poly_int64 poff;
387 tree base = get_addr_base_and_unit_offset (exp, &poff);
388 if (base == NULL_TREE || !DECL_P (base) || !poff.is_constant (&off))
389 return NULL;
391 if (!decl_to_stridxlist_htab)
393 decl_to_stridxlist_htab
394 = new hash_map<tree_decl_hash, stridxlist> (64);
395 gcc_obstack_init (&stridx_obstack);
398 bool existed;
399 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
400 if (existed)
402 int i;
403 stridxlist *before = NULL;
404 for (i = 0; i < 32; i++)
406 if (list->offset == off)
407 return &list->idx;
408 if (list->offset > off && before == NULL)
409 before = list;
410 if (list->next == NULL)
411 break;
412 list = list->next;
414 if (i == 32)
415 return NULL;
416 if (before)
418 list = before;
419 before = XOBNEW (&stridx_obstack, struct stridxlist);
420 *before = *list;
421 list->next = before;
422 list->offset = off;
423 list->idx = 0;
424 return &list->idx;
426 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
427 list = list->next;
430 list->next = NULL;
431 list->offset = off;
432 list->idx = 0;
433 return &list->idx;
436 /* Create a new string index, or return 0 if reached limit. */
438 static int
439 new_stridx (tree exp)
441 int idx;
442 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
443 return 0;
444 if (TREE_CODE (exp) == SSA_NAME)
446 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
447 return 0;
448 idx = max_stridx++;
449 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
450 return idx;
452 if (TREE_CODE (exp) == ADDR_EXPR)
454 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
455 if (pidx != NULL)
457 gcc_assert (*pidx == 0);
458 *pidx = max_stridx++;
459 return *pidx;
462 return 0;
465 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
467 static int
468 new_addr_stridx (tree exp)
470 int *pidx;
471 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
472 return 0;
473 pidx = addr_stridxptr (exp);
474 if (pidx != NULL)
476 gcc_assert (*pidx == 0);
477 *pidx = max_stridx++;
478 return *pidx;
480 return 0;
483 /* Create a new strinfo. */
485 static strinfo *
486 new_strinfo (tree ptr, int idx, tree nonzero_chars, bool full_string_p)
488 strinfo *si = strinfo_pool.allocate ();
489 si->nonzero_chars = nonzero_chars;
490 si->ptr = ptr;
491 si->stmt = NULL;
492 si->endptr = NULL_TREE;
493 si->refcount = 1;
494 si->idx = idx;
495 si->first = 0;
496 si->prev = 0;
497 si->next = 0;
498 si->writable = false;
499 si->dont_invalidate = false;
500 si->full_string_p = full_string_p;
501 return si;
504 /* Decrease strinfo refcount and free it if not referenced anymore. */
506 static inline void
507 free_strinfo (strinfo *si)
509 if (si && --si->refcount == 0)
510 strinfo_pool.remove (si);
513 /* Set strinfo in the vector entry IDX to SI. */
515 static inline void
516 set_strinfo (int idx, strinfo *si)
518 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
519 unshare_strinfo_vec ();
520 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
521 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
522 (*stridx_to_strinfo)[idx] = si;
525 /* Return the first strinfo in the related strinfo chain
526 if all strinfos in between belong to the chain, otherwise NULL. */
528 static strinfo *
529 verify_related_strinfos (strinfo *origsi)
531 strinfo *si = origsi, *psi;
533 if (origsi->first == 0)
534 return NULL;
535 for (; si->prev; si = psi)
537 if (si->first != origsi->first)
538 return NULL;
539 psi = get_strinfo (si->prev);
540 if (psi == NULL)
541 return NULL;
542 if (psi->next != si->idx)
543 return NULL;
545 if (si->idx != si->first)
546 return NULL;
547 return si;
550 /* Set SI's endptr to ENDPTR and compute its length based on SI->ptr.
551 Use LOC for folding. */
553 static void
554 set_endptr_and_length (location_t loc, strinfo *si, tree endptr)
556 si->endptr = endptr;
557 si->stmt = NULL;
558 tree start_as_size = fold_convert_loc (loc, size_type_node, si->ptr);
559 tree end_as_size = fold_convert_loc (loc, size_type_node, endptr);
560 si->nonzero_chars = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
561 end_as_size, start_as_size);
562 si->full_string_p = true;
565 /* Return string length, or NULL if it can't be computed. */
567 static tree
568 get_string_length (strinfo *si)
570 if (si->nonzero_chars)
571 return si->full_string_p ? si->nonzero_chars : NULL;
573 if (si->stmt)
575 gimple *stmt = si->stmt, *lenstmt;
576 bool with_bounds = gimple_call_with_bounds_p (stmt);
577 tree callee, lhs, fn, tem;
578 location_t loc;
579 gimple_stmt_iterator gsi;
581 gcc_assert (is_gimple_call (stmt));
582 callee = gimple_call_fndecl (stmt);
583 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
584 lhs = gimple_call_lhs (stmt);
585 /* unshare_strinfo is intentionally not called here. The (delayed)
586 transformation of strcpy or strcat into stpcpy is done at the place
587 of the former strcpy/strcat call and so can affect all the strinfos
588 with the same stmt. If they were unshared before and transformation
589 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
590 just compute the right length. */
591 switch (DECL_FUNCTION_CODE (callee))
593 case BUILT_IN_STRCAT:
594 case BUILT_IN_STRCAT_CHK:
595 case BUILT_IN_STRCAT_CHKP:
596 case BUILT_IN_STRCAT_CHK_CHKP:
597 gsi = gsi_for_stmt (stmt);
598 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
599 gcc_assert (lhs == NULL_TREE);
600 tem = unshare_expr (gimple_call_arg (stmt, 0));
601 if (with_bounds)
603 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
604 2, tem, gimple_call_arg (stmt, 1));
605 gimple_call_set_with_bounds (lenstmt, true);
607 else
608 lenstmt = gimple_build_call (fn, 1, tem);
609 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
610 gimple_call_set_lhs (lenstmt, lhs);
611 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
612 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
613 tem = gimple_call_arg (stmt, 0);
614 if (!ptrofftype_p (TREE_TYPE (lhs)))
616 lhs = convert_to_ptrofftype (lhs);
617 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
618 true, GSI_SAME_STMT);
620 lenstmt = gimple_build_assign
621 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
622 POINTER_PLUS_EXPR,tem, lhs);
623 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
624 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
625 lhs = NULL_TREE;
626 /* FALLTHRU */
627 case BUILT_IN_STRCPY:
628 case BUILT_IN_STRCPY_CHK:
629 case BUILT_IN_STRCPY_CHKP:
630 case BUILT_IN_STRCPY_CHK_CHKP:
631 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
632 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
633 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
634 else
635 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
636 if (with_bounds)
637 fn = chkp_maybe_create_clone (fn)->decl;
638 gcc_assert (lhs == NULL_TREE);
639 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
641 fprintf (dump_file, "Optimizing: ");
642 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
644 gimple_call_set_fndecl (stmt, fn);
645 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
646 gimple_call_set_lhs (stmt, lhs);
647 update_stmt (stmt);
648 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
650 fprintf (dump_file, "into: ");
651 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
653 /* FALLTHRU */
654 case BUILT_IN_STPCPY:
655 case BUILT_IN_STPCPY_CHK:
656 case BUILT_IN_STPCPY_CHKP:
657 case BUILT_IN_STPCPY_CHK_CHKP:
658 gcc_assert (lhs != NULL_TREE);
659 loc = gimple_location (stmt);
660 set_endptr_and_length (loc, si, lhs);
661 for (strinfo *chainsi = verify_related_strinfos (si);
662 chainsi != NULL;
663 chainsi = get_next_strinfo (chainsi))
664 if (chainsi->nonzero_chars == NULL)
665 set_endptr_and_length (loc, chainsi, lhs);
666 break;
667 case BUILT_IN_MALLOC:
668 break;
669 /* BUILT_IN_CALLOC always has si->nonzero_chars set. */
670 default:
671 gcc_unreachable ();
672 break;
676 return si->nonzero_chars;
679 /* Invalidate string length information for strings whose length
680 might change due to stores in stmt. */
682 static bool
683 maybe_invalidate (gimple *stmt)
685 strinfo *si;
686 unsigned int i;
687 bool nonempty = false;
689 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
690 if (si != NULL)
692 if (!si->dont_invalidate)
694 ao_ref r;
695 /* Do not use si->nonzero_chars. */
696 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
697 if (stmt_may_clobber_ref_p_1 (stmt, &r))
699 set_strinfo (i, NULL);
700 free_strinfo (si);
701 continue;
704 si->dont_invalidate = false;
705 nonempty = true;
707 return nonempty;
710 /* Unshare strinfo record SI, if it has refcount > 1 or
711 if stridx_to_strinfo vector is shared with some other
712 bbs. */
714 static strinfo *
715 unshare_strinfo (strinfo *si)
717 strinfo *nsi;
719 if (si->refcount == 1 && !strinfo_shared ())
720 return si;
722 nsi = new_strinfo (si->ptr, si->idx, si->nonzero_chars, si->full_string_p);
723 nsi->stmt = si->stmt;
724 nsi->endptr = si->endptr;
725 nsi->first = si->first;
726 nsi->prev = si->prev;
727 nsi->next = si->next;
728 nsi->writable = si->writable;
729 set_strinfo (si->idx, nsi);
730 free_strinfo (si);
731 return nsi;
734 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
735 strinfo if there is any. Return it's idx, or 0 if no strinfo has
736 been created. */
738 static int
739 get_stridx_plus_constant (strinfo *basesi, unsigned HOST_WIDE_INT off,
740 tree ptr)
742 if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
743 return 0;
745 if (compare_nonzero_chars (basesi, off) < 0
746 || !tree_fits_uhwi_p (basesi->nonzero_chars))
747 return 0;
749 unsigned HOST_WIDE_INT nonzero_chars
750 = tree_to_uhwi (basesi->nonzero_chars) - off;
751 strinfo *si = basesi, *chainsi;
752 if (si->first || si->prev || si->next)
753 si = verify_related_strinfos (basesi);
754 if (si == NULL
755 || si->nonzero_chars == NULL_TREE
756 || TREE_CODE (si->nonzero_chars) != INTEGER_CST)
757 return 0;
759 if (TREE_CODE (ptr) == SSA_NAME
760 && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
761 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
763 gcc_checking_assert (compare_tree_int (si->nonzero_chars, off) != -1);
764 for (chainsi = si; chainsi->next; chainsi = si)
766 si = get_next_strinfo (chainsi);
767 if (si == NULL
768 || si->nonzero_chars == NULL_TREE
769 || TREE_CODE (si->nonzero_chars) != INTEGER_CST)
770 break;
771 int r = compare_tree_int (si->nonzero_chars, nonzero_chars);
772 if (r != 1)
774 if (r == 0)
776 if (TREE_CODE (ptr) == SSA_NAME)
777 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
778 else
780 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
781 if (pidx != NULL && *pidx == 0)
782 *pidx = si->idx;
784 return si->idx;
786 break;
790 int idx = new_stridx (ptr);
791 if (idx == 0)
792 return 0;
793 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, nonzero_chars),
794 basesi->full_string_p);
795 set_strinfo (idx, si);
796 if (chainsi->next)
798 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
799 si->next = nextsi->idx;
800 nextsi->prev = idx;
802 chainsi = unshare_strinfo (chainsi);
803 if (chainsi->first == 0)
804 chainsi->first = chainsi->idx;
805 chainsi->next = idx;
806 if (chainsi->endptr == NULL_TREE && zero_length_string_p (si))
807 chainsi->endptr = ptr;
808 si->endptr = chainsi->endptr;
809 si->prev = chainsi->idx;
810 si->first = chainsi->first;
811 si->writable = chainsi->writable;
812 return si->idx;
815 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
816 to a zero-length string and if possible chain it to a related strinfo
817 chain whose part is or might be CHAINSI. */
819 static strinfo *
820 zero_length_string (tree ptr, strinfo *chainsi)
822 strinfo *si;
823 int idx;
824 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
825 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
826 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
827 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
829 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
830 return NULL;
831 if (chainsi != NULL)
833 si = verify_related_strinfos (chainsi);
834 if (si)
838 /* We shouldn't mix delayed and non-delayed lengths. */
839 gcc_assert (si->full_string_p);
840 if (si->endptr == NULL_TREE)
842 si = unshare_strinfo (si);
843 si->endptr = ptr;
845 chainsi = si;
846 si = get_next_strinfo (si);
848 while (si != NULL);
849 if (zero_length_string_p (chainsi))
851 if (chainsi->next)
853 chainsi = unshare_strinfo (chainsi);
854 chainsi->next = 0;
856 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
857 return chainsi;
860 else
862 /* We shouldn't mix delayed and non-delayed lengths. */
863 gcc_assert (chainsi->full_string_p);
864 if (chainsi->first || chainsi->prev || chainsi->next)
866 chainsi = unshare_strinfo (chainsi);
867 chainsi->first = 0;
868 chainsi->prev = 0;
869 chainsi->next = 0;
873 idx = new_stridx (ptr);
874 if (idx == 0)
875 return NULL;
876 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0), true);
877 set_strinfo (idx, si);
878 si->endptr = ptr;
879 if (chainsi != NULL)
881 chainsi = unshare_strinfo (chainsi);
882 if (chainsi->first == 0)
883 chainsi->first = chainsi->idx;
884 chainsi->next = idx;
885 if (chainsi->endptr == NULL_TREE)
886 chainsi->endptr = ptr;
887 si->prev = chainsi->idx;
888 si->first = chainsi->first;
889 si->writable = chainsi->writable;
891 return si;
894 /* For strinfo ORIGSI whose length has been just updated, adjust other
895 related strinfos so that they match the new ORIGSI. This involves:
897 - adding ADJ to the nonzero_chars fields
898 - copying full_string_p from the new ORIGSI. */
900 static void
901 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
903 strinfo *si = verify_related_strinfos (origsi);
905 if (si == NULL)
906 return;
908 while (1)
910 strinfo *nsi;
912 if (si != origsi)
914 tree tem;
916 si = unshare_strinfo (si);
917 /* We shouldn't see delayed lengths here; the caller must have
918 calculated the old length in order to calculate the
919 adjustment. */
920 gcc_assert (si->nonzero_chars);
921 tem = fold_convert_loc (loc, TREE_TYPE (si->nonzero_chars), adj);
922 si->nonzero_chars = fold_build2_loc (loc, PLUS_EXPR,
923 TREE_TYPE (si->nonzero_chars),
924 si->nonzero_chars, tem);
925 si->full_string_p = origsi->full_string_p;
927 si->endptr = NULL_TREE;
928 si->dont_invalidate = true;
930 nsi = get_next_strinfo (si);
931 if (nsi == NULL)
932 return;
933 si = nsi;
937 /* Find if there are other SSA_NAME pointers equal to PTR
938 for which we don't track their string lengths yet. If so, use
939 IDX for them. */
941 static void
942 find_equal_ptrs (tree ptr, int idx)
944 if (TREE_CODE (ptr) != SSA_NAME)
945 return;
946 while (1)
948 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
949 if (!is_gimple_assign (stmt))
950 return;
951 ptr = gimple_assign_rhs1 (stmt);
952 switch (gimple_assign_rhs_code (stmt))
954 case SSA_NAME:
955 break;
956 CASE_CONVERT:
957 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
958 return;
959 if (TREE_CODE (ptr) == SSA_NAME)
960 break;
961 if (TREE_CODE (ptr) != ADDR_EXPR)
962 return;
963 /* FALLTHRU */
964 case ADDR_EXPR:
966 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
967 if (pidx != NULL && *pidx == 0)
968 *pidx = idx;
969 return;
971 default:
972 return;
975 /* We might find an endptr created in this pass. Grow the
976 vector in that case. */
977 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
978 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
980 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
981 return;
982 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
986 /* Return true if STMT is a call to a builtin function with the right
987 arguments and attributes that should be considered for optimization
988 by this pass. */
990 static bool
991 valid_builtin_call (gimple *stmt)
993 if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
994 return false;
996 tree callee = gimple_call_fndecl (stmt);
997 switch (DECL_FUNCTION_CODE (callee))
999 case BUILT_IN_MEMCMP:
1000 case BUILT_IN_MEMCMP_EQ:
1001 case BUILT_IN_STRCHR:
1002 case BUILT_IN_STRCHR_CHKP:
1003 case BUILT_IN_STRLEN:
1004 case BUILT_IN_STRLEN_CHKP:
1005 /* The above functions should be pure. Punt if they aren't. */
1006 if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
1007 return false;
1008 break;
1010 case BUILT_IN_CALLOC:
1011 case BUILT_IN_MALLOC:
1012 case BUILT_IN_MEMCPY:
1013 case BUILT_IN_MEMCPY_CHK:
1014 case BUILT_IN_MEMCPY_CHKP:
1015 case BUILT_IN_MEMCPY_CHK_CHKP:
1016 case BUILT_IN_MEMPCPY:
1017 case BUILT_IN_MEMPCPY_CHK:
1018 case BUILT_IN_MEMPCPY_CHKP:
1019 case BUILT_IN_MEMPCPY_CHK_CHKP:
1020 case BUILT_IN_MEMSET:
1021 case BUILT_IN_STPCPY:
1022 case BUILT_IN_STPCPY_CHK:
1023 case BUILT_IN_STPCPY_CHKP:
1024 case BUILT_IN_STPCPY_CHK_CHKP:
1025 case BUILT_IN_STRCAT:
1026 case BUILT_IN_STRCAT_CHK:
1027 case BUILT_IN_STRCAT_CHKP:
1028 case BUILT_IN_STRCAT_CHK_CHKP:
1029 case BUILT_IN_STRCPY:
1030 case BUILT_IN_STRCPY_CHK:
1031 case BUILT_IN_STRCPY_CHKP:
1032 case BUILT_IN_STRCPY_CHK_CHKP:
1033 /* The above functions should be neither const nor pure. Punt if they
1034 aren't. */
1035 if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
1036 return false;
1037 break;
1039 default:
1040 break;
1043 return true;
1046 /* If the last .MEM setter statement before STMT is
1047 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
1048 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
1049 just memcpy (x, y, strlen (y)). SI must be the zero length
1050 strinfo. */
1052 static void
1053 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
1055 tree vuse, callee, len;
1056 struct laststmt_struct last = laststmt;
1057 strinfo *lastsi, *firstsi;
1058 unsigned len_arg_no = 2;
1060 laststmt.stmt = NULL;
1061 laststmt.len = NULL_TREE;
1062 laststmt.stridx = 0;
1064 if (last.stmt == NULL)
1065 return;
1067 vuse = gimple_vuse (stmt);
1068 if (vuse == NULL_TREE
1069 || SSA_NAME_DEF_STMT (vuse) != last.stmt
1070 || !has_single_use (vuse))
1071 return;
1073 gcc_assert (last.stridx > 0);
1074 lastsi = get_strinfo (last.stridx);
1075 if (lastsi == NULL)
1076 return;
1078 if (lastsi != si)
1080 if (lastsi->first == 0 || lastsi->first != si->first)
1081 return;
1083 firstsi = verify_related_strinfos (si);
1084 if (firstsi == NULL)
1085 return;
1086 while (firstsi != lastsi)
1088 firstsi = get_next_strinfo (firstsi);
1089 if (firstsi == NULL)
1090 return;
1094 if (!is_strcat && !zero_length_string_p (si))
1095 return;
1097 if (is_gimple_assign (last.stmt))
1099 gimple_stmt_iterator gsi;
1101 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
1102 return;
1103 if (stmt_could_throw_p (last.stmt))
1104 return;
1105 gsi = gsi_for_stmt (last.stmt);
1106 unlink_stmt_vdef (last.stmt);
1107 release_defs (last.stmt);
1108 gsi_remove (&gsi, true);
1109 return;
1112 if (!valid_builtin_call (last.stmt))
1113 return;
1115 callee = gimple_call_fndecl (last.stmt);
1116 switch (DECL_FUNCTION_CODE (callee))
1118 case BUILT_IN_MEMCPY:
1119 case BUILT_IN_MEMCPY_CHK:
1120 break;
1121 case BUILT_IN_MEMCPY_CHKP:
1122 case BUILT_IN_MEMCPY_CHK_CHKP:
1123 len_arg_no = 4;
1124 break;
1125 default:
1126 return;
1129 len = gimple_call_arg (last.stmt, len_arg_no);
1130 if (tree_fits_uhwi_p (len))
1132 if (!tree_fits_uhwi_p (last.len)
1133 || integer_zerop (len)
1134 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1135 return;
1136 /* Don't adjust the length if it is divisible by 4, it is more efficient
1137 to store the extra '\0' in that case. */
1138 if ((tree_to_uhwi (len) & 3) == 0)
1139 return;
1141 else if (TREE_CODE (len) == SSA_NAME)
1143 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1144 if (!is_gimple_assign (def_stmt)
1145 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1146 || gimple_assign_rhs1 (def_stmt) != last.len
1147 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1148 return;
1150 else
1151 return;
1153 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1154 update_stmt (last.stmt);
1157 /* For an LHS that is an SSA_NAME and for strlen() argument SRC, set
1158 LHS range info to [0, N] if SRC refers to a character array A[N]
1159 with unknown length bounded by N. */
1161 static void
1162 maybe_set_strlen_range (tree lhs, tree src)
1164 if (TREE_CODE (lhs) != SSA_NAME)
1165 return;
1167 if (TREE_CODE (src) == SSA_NAME)
1169 gimple *def = SSA_NAME_DEF_STMT (src);
1170 if (is_gimple_assign (def)
1171 && gimple_assign_rhs_code (def) == ADDR_EXPR)
1172 src = gimple_assign_rhs1 (def);
1175 if (TREE_CODE (src) != ADDR_EXPR)
1176 return;
1178 /* The last array member of a struct can be bigger than its size
1179 suggests if it's treated as a poor-man's flexible array member. */
1180 src = TREE_OPERAND (src, 0);
1181 if (TREE_CODE (TREE_TYPE (src)) != ARRAY_TYPE
1182 || array_at_struct_end_p (src))
1183 return;
1185 tree type = TREE_TYPE (src);
1186 if (tree dom = TYPE_DOMAIN (type))
1187 if (tree maxval = TYPE_MAX_VALUE (dom))
1189 wide_int max = wi::to_wide (maxval);
1190 wide_int min = wi::zero (max.get_precision ());
1191 set_range_info (lhs, VR_RANGE, min, max);
1195 /* Handle a strlen call. If strlen of the argument is known, replace
1196 the strlen call with the known value, otherwise remember that strlen
1197 of the argument is stored in the lhs SSA_NAME. */
1199 static void
1200 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1202 int idx;
1203 tree src;
1204 gimple *stmt = gsi_stmt (*gsi);
1205 tree lhs = gimple_call_lhs (stmt);
1207 if (lhs == NULL_TREE)
1208 return;
1210 src = gimple_call_arg (stmt, 0);
1211 idx = get_stridx (src);
1212 if (idx)
1214 strinfo *si = NULL;
1215 tree rhs;
1217 if (idx < 0)
1218 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1219 else
1221 rhs = NULL_TREE;
1222 si = get_strinfo (idx);
1223 if (si != NULL)
1224 rhs = get_string_length (si);
1226 if (rhs != NULL_TREE)
1228 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1230 fprintf (dump_file, "Optimizing: ");
1231 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1233 rhs = unshare_expr (rhs);
1234 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1235 rhs = fold_convert_loc (gimple_location (stmt),
1236 TREE_TYPE (lhs), rhs);
1237 if (!update_call_from_tree (gsi, rhs))
1238 gimplify_and_update_call_from_tree (gsi, rhs);
1239 stmt = gsi_stmt (*gsi);
1240 update_stmt (stmt);
1241 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1243 fprintf (dump_file, "into: ");
1244 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1246 if (si != NULL
1247 && TREE_CODE (si->nonzero_chars) != SSA_NAME
1248 && TREE_CODE (si->nonzero_chars) != INTEGER_CST
1249 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1251 si = unshare_strinfo (si);
1252 si->nonzero_chars = lhs;
1253 gcc_assert (si->full_string_p);
1256 if (strlen_to_stridx)
1258 location_t loc = gimple_location (stmt);
1259 strlen_to_stridx->put (lhs, stridx_strlenloc (idx, loc));
1261 return;
1264 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1265 return;
1266 if (idx == 0)
1267 idx = new_stridx (src);
1268 else
1270 strinfo *si = get_strinfo (idx);
1271 if (si != NULL)
1273 if (!si->full_string_p && !si->stmt)
1275 /* Until now we only had a lower bound on the string length.
1276 Install LHS as the actual length. */
1277 si = unshare_strinfo (si);
1278 tree old = si->nonzero_chars;
1279 si->nonzero_chars = lhs;
1280 si->full_string_p = true;
1281 if (TREE_CODE (old) == INTEGER_CST)
1283 location_t loc = gimple_location (stmt);
1284 old = fold_convert_loc (loc, TREE_TYPE (lhs), old);
1285 tree adj = fold_build2_loc (loc, MINUS_EXPR,
1286 TREE_TYPE (lhs), lhs, old);
1287 adjust_related_strinfos (loc, si, adj);
1289 else
1291 si->first = 0;
1292 si->prev = 0;
1293 si->next = 0;
1296 return;
1299 if (idx)
1301 strinfo *si = new_strinfo (src, idx, lhs, true);
1302 set_strinfo (idx, si);
1303 find_equal_ptrs (src, idx);
1305 /* For SRC that is an array of N elements, set LHS's range
1306 to [0, N]. */
1307 maybe_set_strlen_range (lhs, src);
1309 if (strlen_to_stridx)
1311 location_t loc = gimple_location (stmt);
1312 strlen_to_stridx->put (lhs, stridx_strlenloc (idx, loc));
1317 /* Handle a strchr call. If strlen of the first argument is known, replace
1318 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1319 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1321 static void
1322 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1324 int idx;
1325 tree src;
1326 gimple *stmt = gsi_stmt (*gsi);
1327 tree lhs = gimple_call_lhs (stmt);
1328 bool with_bounds = gimple_call_with_bounds_p (stmt);
1330 if (lhs == NULL_TREE)
1331 return;
1333 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1334 return;
1336 src = gimple_call_arg (stmt, 0);
1337 idx = get_stridx (src);
1338 if (idx)
1340 strinfo *si = NULL;
1341 tree rhs;
1343 if (idx < 0)
1344 rhs = build_int_cst (size_type_node, ~idx);
1345 else
1347 rhs = NULL_TREE;
1348 si = get_strinfo (idx);
1349 if (si != NULL)
1350 rhs = get_string_length (si);
1352 if (rhs != NULL_TREE)
1354 location_t loc = gimple_location (stmt);
1356 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1358 fprintf (dump_file, "Optimizing: ");
1359 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1361 if (si != NULL && si->endptr != NULL_TREE)
1363 rhs = unshare_expr (si->endptr);
1364 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1365 TREE_TYPE (rhs)))
1366 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1368 else
1370 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1371 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1372 TREE_TYPE (src), src, rhs);
1373 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1374 TREE_TYPE (rhs)))
1375 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1377 if (!update_call_from_tree (gsi, rhs))
1378 gimplify_and_update_call_from_tree (gsi, rhs);
1379 stmt = gsi_stmt (*gsi);
1380 update_stmt (stmt);
1381 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1383 fprintf (dump_file, "into: ");
1384 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1386 if (si != NULL
1387 && si->endptr == NULL_TREE
1388 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1390 si = unshare_strinfo (si);
1391 si->endptr = lhs;
1393 zero_length_string (lhs, si);
1394 return;
1397 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1398 return;
1399 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1401 if (idx == 0)
1402 idx = new_stridx (src);
1403 else if (get_strinfo (idx) != NULL)
1405 zero_length_string (lhs, NULL);
1406 return;
1408 if (idx)
1410 location_t loc = gimple_location (stmt);
1411 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1412 tree srcu = fold_convert_loc (loc, size_type_node, src);
1413 tree length = fold_build2_loc (loc, MINUS_EXPR,
1414 size_type_node, lhsu, srcu);
1415 strinfo *si = new_strinfo (src, idx, length, true);
1416 si->endptr = lhs;
1417 set_strinfo (idx, si);
1418 find_equal_ptrs (src, idx);
1419 zero_length_string (lhs, si);
1422 else
1423 zero_length_string (lhs, NULL);
1426 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1427 If strlen of the second argument is known, strlen of the first argument
1428 is the same after this call. Furthermore, attempt to convert it to
1429 memcpy. */
1431 static void
1432 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1434 int idx, didx;
1435 tree src, dst, srclen, len, lhs, type, fn, oldlen;
1436 bool success;
1437 gimple *stmt = gsi_stmt (*gsi);
1438 strinfo *si, *dsi, *olddsi, *zsi;
1439 location_t loc;
1440 bool with_bounds = gimple_call_with_bounds_p (stmt);
1442 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1443 dst = gimple_call_arg (stmt, 0);
1444 lhs = gimple_call_lhs (stmt);
1445 idx = get_stridx (src);
1446 si = NULL;
1447 if (idx > 0)
1448 si = get_strinfo (idx);
1450 didx = get_stridx (dst);
1451 olddsi = NULL;
1452 oldlen = NULL_TREE;
1453 if (didx > 0)
1454 olddsi = get_strinfo (didx);
1455 else if (didx < 0)
1456 return;
1458 if (olddsi != NULL)
1459 adjust_last_stmt (olddsi, stmt, false);
1461 srclen = NULL_TREE;
1462 if (si != NULL)
1463 srclen = get_string_length (si);
1464 else if (idx < 0)
1465 srclen = build_int_cst (size_type_node, ~idx);
1467 loc = gimple_location (stmt);
1468 if (srclen == NULL_TREE)
1469 switch (bcode)
1471 case BUILT_IN_STRCPY:
1472 case BUILT_IN_STRCPY_CHK:
1473 case BUILT_IN_STRCPY_CHKP:
1474 case BUILT_IN_STRCPY_CHK_CHKP:
1475 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1476 return;
1477 break;
1478 case BUILT_IN_STPCPY:
1479 case BUILT_IN_STPCPY_CHK:
1480 case BUILT_IN_STPCPY_CHKP:
1481 case BUILT_IN_STPCPY_CHK_CHKP:
1482 if (lhs == NULL_TREE)
1483 return;
1484 else
1486 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1487 srclen = fold_convert_loc (loc, size_type_node, dst);
1488 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1489 lhsuint, srclen);
1491 break;
1492 default:
1493 gcc_unreachable ();
1496 if (didx == 0)
1498 didx = new_stridx (dst);
1499 if (didx == 0)
1500 return;
1502 if (olddsi != NULL)
1504 oldlen = olddsi->nonzero_chars;
1505 dsi = unshare_strinfo (olddsi);
1506 dsi->nonzero_chars = srclen;
1507 dsi->full_string_p = (srclen != NULL_TREE);
1508 /* Break the chain, so adjust_related_strinfo on later pointers in
1509 the chain won't adjust this one anymore. */
1510 dsi->next = 0;
1511 dsi->stmt = NULL;
1512 dsi->endptr = NULL_TREE;
1514 else
1516 dsi = new_strinfo (dst, didx, srclen, srclen != NULL_TREE);
1517 set_strinfo (didx, dsi);
1518 find_equal_ptrs (dst, didx);
1520 dsi->writable = true;
1521 dsi->dont_invalidate = true;
1523 if (dsi->nonzero_chars == NULL_TREE)
1525 strinfo *chainsi;
1527 /* If string length of src is unknown, use delayed length
1528 computation. If string lenth of dst will be needed, it
1529 can be computed by transforming this strcpy call into
1530 stpcpy and subtracting dst from the return value. */
1532 /* Look for earlier strings whose length could be determined if
1533 this strcpy is turned into an stpcpy. */
1535 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1537 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1539 /* When setting a stmt for delayed length computation
1540 prevent all strinfos through dsi from being
1541 invalidated. */
1542 chainsi = unshare_strinfo (chainsi);
1543 chainsi->stmt = stmt;
1544 chainsi->nonzero_chars = NULL_TREE;
1545 chainsi->full_string_p = false;
1546 chainsi->endptr = NULL_TREE;
1547 chainsi->dont_invalidate = true;
1550 dsi->stmt = stmt;
1552 /* Try to detect overlap before returning. This catches cases
1553 like strcpy (d, d + n) where n is non-constant whose range
1554 is such that (n <= strlen (d) holds).
1556 OLDDSI->NONZERO_chars may have been reset by this point with
1557 oldlen holding it original value. */
1558 if (olddsi && oldlen)
1560 /* Add 1 for the terminating NUL. */
1561 tree type = TREE_TYPE (oldlen);
1562 oldlen = fold_build2 (PLUS_EXPR, type, oldlen,
1563 build_int_cst (type, 1));
1564 check_bounds_or_overlap (as_a <gcall *>(stmt), olddsi->ptr, src,
1565 oldlen, NULL_TREE);
1568 return;
1571 if (olddsi != NULL)
1573 tree adj = NULL_TREE;
1574 if (oldlen == NULL_TREE)
1576 else if (integer_zerop (oldlen))
1577 adj = srclen;
1578 else if (TREE_CODE (oldlen) == INTEGER_CST
1579 || TREE_CODE (srclen) == INTEGER_CST)
1580 adj = fold_build2_loc (loc, MINUS_EXPR,
1581 TREE_TYPE (srclen), srclen,
1582 fold_convert_loc (loc, TREE_TYPE (srclen),
1583 oldlen));
1584 if (adj != NULL_TREE)
1585 adjust_related_strinfos (loc, dsi, adj);
1586 else
1587 dsi->prev = 0;
1589 /* strcpy src may not overlap dst, so src doesn't need to be
1590 invalidated either. */
1591 if (si != NULL)
1592 si->dont_invalidate = true;
1594 fn = NULL_TREE;
1595 zsi = NULL;
1596 switch (bcode)
1598 case BUILT_IN_STRCPY:
1599 case BUILT_IN_STRCPY_CHKP:
1600 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1601 if (lhs)
1602 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1603 break;
1604 case BUILT_IN_STRCPY_CHK:
1605 case BUILT_IN_STRCPY_CHK_CHKP:
1606 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1607 if (lhs)
1608 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1609 break;
1610 case BUILT_IN_STPCPY:
1611 case BUILT_IN_STPCPY_CHKP:
1612 /* This would need adjustment of the lhs (subtract one),
1613 or detection that the trailing '\0' doesn't need to be
1614 written, if it will be immediately overwritten.
1615 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1616 if (lhs)
1618 dsi->endptr = lhs;
1619 zsi = zero_length_string (lhs, dsi);
1621 break;
1622 case BUILT_IN_STPCPY_CHK:
1623 case BUILT_IN_STPCPY_CHK_CHKP:
1624 /* This would need adjustment of the lhs (subtract one),
1625 or detection that the trailing '\0' doesn't need to be
1626 written, if it will be immediately overwritten.
1627 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1628 if (lhs)
1630 dsi->endptr = lhs;
1631 zsi = zero_length_string (lhs, dsi);
1633 break;
1634 default:
1635 gcc_unreachable ();
1637 if (zsi != NULL)
1638 zsi->dont_invalidate = true;
1640 if (fn)
1642 tree args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1643 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1645 else
1646 type = size_type_node;
1648 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1649 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1651 /* Set the no-warning bit on the transformed statement? */
1652 bool set_no_warning = false;
1654 if (const strinfo *chksi = olddsi ? olddsi : dsi)
1655 if (si
1656 && !check_bounds_or_overlap (as_a <gcall *>(stmt), chksi->ptr, si->ptr,
1657 NULL_TREE, len))
1659 gimple_set_no_warning (stmt, true);
1660 set_no_warning = true;
1663 if (fn == NULL_TREE)
1664 return;
1666 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1667 GSI_SAME_STMT);
1668 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1670 fprintf (dump_file, "Optimizing: ");
1671 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1673 if (with_bounds)
1675 fn = chkp_maybe_create_clone (fn)->decl;
1676 if (gimple_call_num_args (stmt) == 4)
1677 success = update_gimple_call (gsi, fn, 5, dst,
1678 gimple_call_arg (stmt, 1),
1679 src,
1680 gimple_call_arg (stmt, 3),
1681 len);
1682 else
1683 success = update_gimple_call (gsi, fn, 6, dst,
1684 gimple_call_arg (stmt, 1),
1685 src,
1686 gimple_call_arg (stmt, 3),
1687 len,
1688 gimple_call_arg (stmt, 4));
1690 else
1691 if (gimple_call_num_args (stmt) == 2)
1692 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1693 else
1694 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1695 gimple_call_arg (stmt, 2));
1696 if (success)
1698 stmt = gsi_stmt (*gsi);
1699 gimple_call_set_with_bounds (stmt, with_bounds);
1700 update_stmt (stmt);
1701 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1703 fprintf (dump_file, "into: ");
1704 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1706 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1707 laststmt.stmt = stmt;
1708 laststmt.len = srclen;
1709 laststmt.stridx = dsi->idx;
1711 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1712 fprintf (dump_file, "not possible.\n");
1714 if (set_no_warning)
1715 gimple_set_no_warning (stmt, true);
1718 /* Check the size argument to the built-in forms of stpncpy and strncpy
1719 for out-of-bounds offsets or overlapping access, and to see if the
1720 size argument is derived from a call to strlen() on the source argument,
1721 and if so, issue an appropriate warning. */
1723 static void
1724 handle_builtin_strncat (built_in_function bcode, gimple_stmt_iterator *gsi)
1726 /* Same as stxncpy(). */
1727 handle_builtin_stxncpy (bcode, gsi);
1730 /* Return true if LEN depends on a call to strlen(SRC) in an interesting
1731 way. LEN can either be an integer expression, or a pointer (to char).
1732 When it is the latter (such as in recursive calls to self) is is
1733 assumed to be the argument in some call to strlen() whose relationship
1734 to SRC is being ascertained. */
1736 static bool
1737 is_strlen_related_p (tree src, tree len)
1739 if (TREE_CODE (TREE_TYPE (len)) == POINTER_TYPE
1740 && operand_equal_p (src, len, 0))
1741 return true;
1743 if (TREE_CODE (len) != SSA_NAME)
1744 return false;
1746 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1747 if (!def_stmt)
1748 return false;
1750 if (is_gimple_call (def_stmt))
1752 tree func = gimple_call_fndecl (def_stmt);
1753 if (!valid_builtin_call (def_stmt)
1754 || DECL_FUNCTION_CODE (func) != BUILT_IN_STRLEN)
1755 return false;
1757 tree arg = gimple_call_arg (def_stmt, 0);
1758 return is_strlen_related_p (src, arg);
1761 if (!is_gimple_assign (def_stmt))
1762 return false;
1764 tree_code code = gimple_assign_rhs_code (def_stmt);
1765 tree rhs1 = gimple_assign_rhs1 (def_stmt);
1766 tree rhstype = TREE_TYPE (rhs1);
1768 if ((TREE_CODE (rhstype) == POINTER_TYPE && code == POINTER_PLUS_EXPR)
1769 || (INTEGRAL_TYPE_P (rhstype)
1770 && (code == BIT_AND_EXPR
1771 || code == NOP_EXPR)))
1773 /* Pointer plus (an integer) and integer cast or truncation are
1774 considered among the (potentially) related expressions to strlen.
1775 Others are not. */
1776 return is_strlen_related_p (src, rhs1);
1779 return false;
1782 /* A helper of handle_builtin_stxncpy. Check to see if the specified
1783 bound is a) equal to the size of the destination DST and if so, b)
1784 if it's immediately followed by DST[CNT - 1] = '\0'. If a) holds
1785 and b) does not, warn. Otherwise, do nothing. Return true if
1786 diagnostic has been issued.
1788 The purpose is to diagnose calls to strncpy and stpncpy that do
1789 not nul-terminate the copy while allowing for the idiom where
1790 such a call is immediately followed by setting the last element
1791 to nul, as in:
1792 char a[32];
1793 strncpy (a, s, sizeof a);
1794 a[sizeof a - 1] = '\0';
1797 static bool
1798 maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
1800 gimple *stmt = gsi_stmt (gsi);
1802 wide_int cntrange[2];
1804 if (TREE_CODE (cnt) == INTEGER_CST)
1805 cntrange[0] = cntrange[1] = wi::to_wide (cnt);
1806 else if (TREE_CODE (cnt) == SSA_NAME)
1808 enum value_range_type rng = get_range_info (cnt, cntrange, cntrange + 1);
1809 if (rng == VR_RANGE)
1811 else if (rng == VR_ANTI_RANGE)
1813 wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
1815 if (wi::ltu_p (cntrange[1], maxobjsize))
1817 cntrange[0] = cntrange[1] + 1;
1818 cntrange[1] = maxobjsize;
1820 else
1822 cntrange[1] = cntrange[0] - 1;
1823 cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
1826 else
1827 return false;
1829 else
1830 return false;
1832 /* Negative value is the constant string length. If it's less than
1833 the lower bound there is no truncation. */
1834 int sidx = get_stridx (src);
1835 if (sidx < 0 && wi::gtu_p (cntrange[0], ~sidx))
1836 return false;
1838 tree dst = gimple_call_arg (stmt, 0);
1839 tree dstdecl = dst;
1840 if (TREE_CODE (dstdecl) == ADDR_EXPR)
1841 dstdecl = TREE_OPERAND (dstdecl, 0);
1843 /* If the destination refers to a an array/pointer declared nonstring
1844 return early. */
1845 tree ref = NULL_TREE;
1846 if (get_attr_nonstring_decl (dstdecl, &ref))
1847 return false;
1849 /* Look for dst[i] = '\0'; after the stxncpy() call and if found
1850 avoid the truncation warning. */
1851 gsi_next (&gsi);
1852 gimple *next_stmt = gsi_stmt (gsi);
1854 if (!gsi_end_p (gsi) && is_gimple_assign (next_stmt))
1856 tree lhs = gimple_assign_lhs (next_stmt);
1857 tree_code code = TREE_CODE (lhs);
1858 if (code == ARRAY_REF || code == MEM_REF)
1859 lhs = TREE_OPERAND (lhs, 0);
1861 tree func = gimple_call_fndecl (stmt);
1862 if (DECL_FUNCTION_CODE (func) == BUILT_IN_STPNCPY)
1864 tree ret = gimple_call_lhs (stmt);
1865 if (ret && operand_equal_p (ret, lhs, 0))
1866 return false;
1869 /* Determine the base address and offset of the reference,
1870 ignoring the innermost array index. */
1871 if (TREE_CODE (ref) == ARRAY_REF)
1872 ref = TREE_OPERAND (ref, 0);
1874 poly_int64 dstoff;
1875 tree dstbase = get_addr_base_and_unit_offset (ref, &dstoff);
1877 poly_int64 lhsoff;
1878 tree lhsbase = get_addr_base_and_unit_offset (lhs, &lhsoff);
1879 if (lhsbase
1880 && known_eq (dstoff, lhsoff)
1881 && operand_equal_p (dstbase, lhsbase, 0))
1882 return false;
1885 int prec = TYPE_PRECISION (TREE_TYPE (cnt));
1886 wide_int lenrange[2];
1887 if (strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL)
1889 lenrange[0] = (sisrc->nonzero_chars
1890 && TREE_CODE (sisrc->nonzero_chars) == INTEGER_CST
1891 ? wi::to_wide (sisrc->nonzero_chars)
1892 : wi::zero (prec));
1893 lenrange[1] = lenrange[0];
1895 else if (sidx < 0)
1896 lenrange[0] = lenrange[1] = wi::shwi (~sidx, prec);
1897 else
1899 tree range[2];
1900 get_range_strlen (src, range);
1901 if (range[0])
1903 lenrange[0] = wi::to_wide (range[0], prec);
1904 lenrange[1] = wi::to_wide (range[1], prec);
1906 else
1908 lenrange[0] = wi::shwi (0, prec);
1909 lenrange[1] = wi::shwi (-1, prec);
1913 location_t callloc = gimple_location (stmt);
1914 tree func = gimple_call_fndecl (stmt);
1916 if (lenrange[0] != 0 || !wi::neg_p (lenrange[1]))
1918 /* If the longest source string is shorter than the lower bound
1919 of the specified count the copy is definitely nul-terminated. */
1920 if (wi::ltu_p (lenrange[1], cntrange[0]))
1921 return false;
1923 if (wi::neg_p (lenrange[1]))
1925 /* The length of one of the strings is unknown but at least
1926 one has non-zero length and that length is stored in
1927 LENRANGE[1]. Swap the bounds to force a "may be truncated"
1928 warning below. */
1929 lenrange[1] = lenrange[0];
1930 lenrange[0] = wi::shwi (0, prec);
1933 if (wi::geu_p (lenrange[0], cntrange[1]))
1935 /* The shortest string is longer than the upper bound of
1936 the count so the truncation is certain. */
1937 if (cntrange[0] == cntrange[1])
1938 return warning_at (callloc, OPT_Wstringop_truncation,
1939 integer_onep (cnt)
1940 ? G_("%qD output truncated copying %E byte "
1941 "from a string of length %wu")
1942 : G_("%qD output truncated copying %E bytes "
1943 "from a string of length %wu"),
1944 func, cnt, lenrange[0].to_uhwi ());
1946 return warning_at (callloc, OPT_Wstringop_truncation,
1947 "%qD output truncated copying between %wu "
1948 "and %wu bytes from a string of length %wu",
1949 func, cntrange[0].to_uhwi (),
1950 cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
1952 else if (wi::geu_p (lenrange[1], cntrange[1]))
1954 /* The longest string is longer than the upper bound of
1955 the count so the truncation is possible. */
1956 if (cntrange[0] == cntrange[1])
1957 return warning_at (callloc, OPT_Wstringop_truncation,
1958 integer_onep (cnt)
1959 ? G_("%qD output may be truncated copying %E "
1960 "byte from a string of length %wu")
1961 : G_("%qD output may be truncated copying %E "
1962 "bytes from a string of length %wu"),
1963 func, cnt, lenrange[1].to_uhwi ());
1965 return warning_at (callloc, OPT_Wstringop_truncation,
1966 "%qD output may be truncated copying between %wu "
1967 "and %wu bytes from a string of length %wu",
1968 func, cntrange[0].to_uhwi (),
1969 cntrange[1].to_uhwi (), lenrange[1].to_uhwi ());
1972 if (cntrange[0] != cntrange[1]
1973 && wi::leu_p (cntrange[0], lenrange[0])
1974 && wi::leu_p (cntrange[1], lenrange[0] + 1))
1976 /* If the source (including the terminating nul) is longer than
1977 the lower bound of the specified count but shorter than the
1978 upper bound the copy may (but need not) be truncated. */
1979 return warning_at (callloc, OPT_Wstringop_truncation,
1980 "%qD output may be truncated copying between %wu "
1981 "and %wu bytes from a string of length %wu",
1982 func, cntrange[0].to_uhwi (),
1983 cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
1987 if (tree dstsize = compute_objsize (dst, 1))
1989 /* The source length is uknown. Try to determine the destination
1990 size and see if it matches the specified bound. If not, bail.
1991 Otherwise go on to see if it should be diagnosed for possible
1992 truncation. */
1993 if (!dstsize)
1994 return false;
1996 if (wi::to_wide (dstsize) != cntrange[1])
1997 return false;
1999 if (cntrange[0] == cntrange[1])
2000 return warning_at (callloc, OPT_Wstringop_truncation,
2001 "%qD specified bound %E equals destination size",
2002 func, cnt);
2005 return false;
2008 /* Check the arguments to the built-in forms of stpncpy and strncpy for
2009 out-of-bounds offsets or overlapping access, and to see if the size
2010 is derived from calling strlen() on the source argument, and if so,
2011 issue the appropriate warning. */
2013 static void
2014 handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
2016 if (!strlen_to_stridx)
2017 return;
2019 gimple *stmt = gsi_stmt (*gsi);
2021 bool with_bounds = gimple_call_with_bounds_p (stmt);
2023 tree dst = gimple_call_arg (stmt, with_bounds ? 1 : 0);
2024 tree src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2025 tree len = gimple_call_arg (stmt, with_bounds ? 3 : 2);
2026 tree dstsize = NULL_TREE, srcsize = NULL_TREE;
2028 int didx = get_stridx (dst);
2029 if (strinfo *sidst = didx > 0 ? get_strinfo (didx) : NULL)
2031 /* Compute the size of the destination string including the NUL. */
2032 if (sidst->nonzero_chars)
2034 tree type = TREE_TYPE (sidst->nonzero_chars);
2035 dstsize = fold_build2 (PLUS_EXPR, type, sidst->nonzero_chars,
2036 build_int_cst (type, 1));
2038 dst = sidst->ptr;
2041 int sidx = get_stridx (src);
2042 strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL;
2043 if (sisrc)
2045 /* strncat() and strncpy() can modify the source string by writing
2046 over the terminating nul so SISRC->DONT_INVALIDATE must be left
2047 clear. */
2049 /* Compute the size of the source string including the NUL. */
2050 if (sisrc->nonzero_chars)
2052 tree type = TREE_TYPE (sisrc->nonzero_chars);
2053 srcsize = fold_build2 (PLUS_EXPR, type, sisrc->nonzero_chars,
2054 build_int_cst (type, 1));
2057 src = sisrc->ptr;
2059 else
2060 srcsize = NULL_TREE;
2062 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, src,
2063 dstsize, srcsize))
2065 gimple_set_no_warning (stmt, true);
2066 return;
2069 /* If the length argument was computed from strlen(S) for some string
2070 S retrieve the strinfo index for the string (PSS->FIRST) alonng with
2071 the location of the strlen() call (PSS->SECOND). */
2072 stridx_strlenloc *pss = strlen_to_stridx->get (len);
2073 if (!pss || pss->first <= 0)
2075 if (maybe_diag_stxncpy_trunc (*gsi, src, len))
2076 gimple_set_no_warning (stmt, true);
2078 return;
2081 /* Retrieve the strinfo data for the string S that LEN was computed
2082 from as some function F of strlen (S) (i.e., LEN need not be equal
2083 to strlen(S)). */
2084 strinfo *silen = get_strinfo (pss->first);
2086 location_t callloc = gimple_location (stmt);
2088 tree func = gimple_call_fndecl (stmt);
2090 bool warned = false;
2092 /* When -Wstringop-truncation is set, try to determine truncation
2093 before diagnosing possible overflow. Truncation is implied by
2094 the LEN argument being equal to strlen(SRC), regardless of
2095 whether its value is known. Otherwise, issue the more generic
2096 -Wstringop-overflow which triggers for LEN arguments that in
2097 any meaningful way depend on strlen(SRC). */
2098 if (sisrc == silen
2099 && is_strlen_related_p (src, len)
2100 && warning_at (callloc, OPT_Wstringop_truncation,
2101 "%qD output truncated before terminating nul "
2102 "copying as many bytes from a string as its length",
2103 func))
2104 warned = true;
2105 else if (silen && is_strlen_related_p (src, silen->ptr))
2106 warned = warning_at (callloc, OPT_Wstringop_overflow_,
2107 "%qD specified bound depends on the length "
2108 "of the source argument", func);
2109 if (warned)
2111 location_t strlenloc = pss->second;
2112 if (strlenloc != UNKNOWN_LOCATION && strlenloc != callloc)
2113 inform (strlenloc, "length computed here");
2117 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
2118 If strlen of the second argument is known and length of the third argument
2119 is that plus one, strlen of the first argument is the same after this
2120 call. */
2122 static void
2123 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2125 int idx, didx;
2126 tree src, dst, len, lhs, oldlen, newlen;
2127 gimple *stmt = gsi_stmt (*gsi);
2128 strinfo *si, *dsi, *olddsi;
2129 bool with_bounds = gimple_call_with_bounds_p (stmt);
2131 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
2132 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2133 dst = gimple_call_arg (stmt, 0);
2134 idx = get_stridx (src);
2135 if (idx == 0)
2136 return;
2138 didx = get_stridx (dst);
2139 olddsi = NULL;
2140 if (didx > 0)
2141 olddsi = get_strinfo (didx);
2142 else if (didx < 0)
2143 return;
2145 if (olddsi != NULL
2146 && tree_fits_uhwi_p (len)
2147 && !integer_zerop (len))
2148 adjust_last_stmt (olddsi, stmt, false);
2150 bool full_string_p;
2151 if (idx > 0)
2153 gimple *def_stmt;
2155 /* Handle memcpy (x, y, l) where l's relationship with strlen (y)
2156 is known. */
2157 si = get_strinfo (idx);
2158 if (si == NULL || si->nonzero_chars == NULL_TREE)
2159 return;
2160 if (TREE_CODE (len) == INTEGER_CST
2161 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
2163 if (tree_int_cst_le (len, si->nonzero_chars))
2165 /* Copying LEN nonzero characters, where LEN is constant. */
2166 newlen = len;
2167 full_string_p = false;
2169 else
2171 /* Copying the whole of the analyzed part of SI. */
2172 newlen = si->nonzero_chars;
2173 full_string_p = si->full_string_p;
2176 else
2178 if (!si->full_string_p)
2179 return;
2180 if (TREE_CODE (len) != SSA_NAME)
2181 return;
2182 def_stmt = SSA_NAME_DEF_STMT (len);
2183 if (!is_gimple_assign (def_stmt)
2184 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
2185 || gimple_assign_rhs1 (def_stmt) != si->nonzero_chars
2186 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
2187 return;
2188 /* Copying variable-length string SI (and no more). */
2189 newlen = si->nonzero_chars;
2190 full_string_p = true;
2193 else
2195 si = NULL;
2196 /* Handle memcpy (x, "abcd", 5) or
2197 memcpy (x, "abc\0uvw", 7). */
2198 if (!tree_fits_uhwi_p (len))
2199 return;
2201 unsigned HOST_WIDE_INT clen = tree_to_uhwi (len);
2202 unsigned HOST_WIDE_INT nonzero_chars = ~idx;
2203 newlen = build_int_cst (size_type_node, MIN (nonzero_chars, clen));
2204 full_string_p = clen > nonzero_chars;
2207 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
2208 adjust_last_stmt (olddsi, stmt, false);
2210 if (didx == 0)
2212 didx = new_stridx (dst);
2213 if (didx == 0)
2214 return;
2216 oldlen = NULL_TREE;
2217 if (olddsi != NULL)
2219 dsi = unshare_strinfo (olddsi);
2220 oldlen = olddsi->nonzero_chars;
2221 dsi->nonzero_chars = newlen;
2222 dsi->full_string_p = full_string_p;
2223 /* Break the chain, so adjust_related_strinfo on later pointers in
2224 the chain won't adjust this one anymore. */
2225 dsi->next = 0;
2226 dsi->stmt = NULL;
2227 dsi->endptr = NULL_TREE;
2229 else
2231 dsi = new_strinfo (dst, didx, newlen, full_string_p);
2232 set_strinfo (didx, dsi);
2233 find_equal_ptrs (dst, didx);
2235 dsi->writable = true;
2236 dsi->dont_invalidate = true;
2237 if (olddsi != NULL)
2239 tree adj = NULL_TREE;
2240 location_t loc = gimple_location (stmt);
2241 if (oldlen == NULL_TREE)
2243 else if (integer_zerop (oldlen))
2244 adj = newlen;
2245 else if (TREE_CODE (oldlen) == INTEGER_CST
2246 || TREE_CODE (newlen) == INTEGER_CST)
2247 adj = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (newlen), newlen,
2248 fold_convert_loc (loc, TREE_TYPE (newlen),
2249 oldlen));
2250 if (adj != NULL_TREE)
2251 adjust_related_strinfos (loc, dsi, adj);
2252 else
2253 dsi->prev = 0;
2255 /* memcpy src may not overlap dst, so src doesn't need to be
2256 invalidated either. */
2257 if (si != NULL)
2258 si->dont_invalidate = true;
2260 if (full_string_p)
2262 lhs = gimple_call_lhs (stmt);
2263 switch (bcode)
2265 case BUILT_IN_MEMCPY:
2266 case BUILT_IN_MEMCPY_CHK:
2267 case BUILT_IN_MEMCPY_CHKP:
2268 case BUILT_IN_MEMCPY_CHK_CHKP:
2269 /* Allow adjust_last_stmt to decrease this memcpy's size. */
2270 laststmt.stmt = stmt;
2271 laststmt.len = dsi->nonzero_chars;
2272 laststmt.stridx = dsi->idx;
2273 if (lhs)
2274 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
2275 break;
2276 case BUILT_IN_MEMPCPY:
2277 case BUILT_IN_MEMPCPY_CHK:
2278 case BUILT_IN_MEMPCPY_CHKP:
2279 case BUILT_IN_MEMPCPY_CHK_CHKP:
2280 break;
2281 default:
2282 gcc_unreachable ();
2287 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
2288 If strlen of the second argument is known, strlen of the first argument
2289 is increased by the length of the second argument. Furthermore, attempt
2290 to convert it to memcpy/strcpy if the length of the first argument
2291 is known. */
2293 static void
2294 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2296 int idx, didx;
2297 tree srclen, args, type, fn, objsz, endptr;
2298 bool success;
2299 gimple *stmt = gsi_stmt (*gsi);
2300 strinfo *si, *dsi;
2301 location_t loc = gimple_location (stmt);
2302 bool with_bounds = gimple_call_with_bounds_p (stmt);
2304 tree src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2305 tree dst = gimple_call_arg (stmt, 0);
2307 /* Bail if the source is the same as destination. It will be diagnosed
2308 elsewhere. */
2309 if (operand_equal_p (src, dst, 0))
2310 return;
2312 tree lhs = gimple_call_lhs (stmt);
2314 didx = get_stridx (dst);
2315 if (didx < 0)
2316 return;
2318 dsi = NULL;
2319 if (didx > 0)
2320 dsi = get_strinfo (didx);
2322 srclen = NULL_TREE;
2323 si = NULL;
2324 idx = get_stridx (src);
2325 if (idx < 0)
2326 srclen = build_int_cst (size_type_node, ~idx);
2327 else if (idx > 0)
2329 si = get_strinfo (idx);
2330 if (si != NULL)
2331 srclen = get_string_length (si);
2334 /* Set the no-warning bit on the transformed statement? */
2335 bool set_no_warning = false;
2337 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
2340 /* The concatenation always involves copying at least one byte
2341 (the terminating nul), even if the source string is empty.
2342 If the source is unknown assume it's one character long and
2343 used that as both sizes. */
2344 tree slen = srclen;
2345 if (slen)
2347 tree type = TREE_TYPE (slen);
2348 slen = fold_build2 (PLUS_EXPR, type, slen, build_int_cst (type, 1));
2351 tree sptr = si && si->ptr ? si->ptr : src;
2353 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, sptr,
2354 NULL_TREE, slen))
2356 gimple_set_no_warning (stmt, true);
2357 set_no_warning = true;
2361 /* strcat (p, q) can be transformed into
2362 tmp = p + strlen (p); endptr = stpcpy (tmp, q);
2363 with length endptr - p if we need to compute the length
2364 later on. Don't do this transformation if we don't need
2365 it. */
2366 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
2368 if (didx == 0)
2370 didx = new_stridx (dst);
2371 if (didx == 0)
2372 return;
2374 if (dsi == NULL)
2376 dsi = new_strinfo (dst, didx, NULL_TREE, false);
2377 set_strinfo (didx, dsi);
2378 find_equal_ptrs (dst, didx);
2380 else
2382 dsi = unshare_strinfo (dsi);
2383 dsi->nonzero_chars = NULL_TREE;
2384 dsi->full_string_p = false;
2385 dsi->next = 0;
2386 dsi->endptr = NULL_TREE;
2388 dsi->writable = true;
2389 dsi->stmt = stmt;
2390 dsi->dont_invalidate = true;
2392 return;
2395 tree dstlen = dsi->nonzero_chars;
2396 endptr = dsi->endptr;
2398 dsi = unshare_strinfo (dsi);
2399 dsi->endptr = NULL_TREE;
2400 dsi->stmt = NULL;
2401 dsi->writable = true;
2403 if (srclen != NULL_TREE)
2405 dsi->nonzero_chars = fold_build2_loc (loc, PLUS_EXPR,
2406 TREE_TYPE (dsi->nonzero_chars),
2407 dsi->nonzero_chars, srclen);
2408 gcc_assert (dsi->full_string_p);
2409 adjust_related_strinfos (loc, dsi, srclen);
2410 dsi->dont_invalidate = true;
2412 else
2414 dsi->nonzero_chars = NULL;
2415 dsi->full_string_p = false;
2416 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
2417 dsi->dont_invalidate = true;
2420 if (si != NULL)
2421 /* strcat src may not overlap dst, so src doesn't need to be
2422 invalidated either. */
2423 si->dont_invalidate = true;
2425 /* For now. Could remove the lhs from the call and add
2426 lhs = dst; afterwards. */
2427 if (lhs)
2428 return;
2430 fn = NULL_TREE;
2431 objsz = NULL_TREE;
2432 switch (bcode)
2434 case BUILT_IN_STRCAT:
2435 case BUILT_IN_STRCAT_CHKP:
2436 if (srclen != NULL_TREE)
2437 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
2438 else
2439 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
2440 break;
2441 case BUILT_IN_STRCAT_CHK:
2442 case BUILT_IN_STRCAT_CHK_CHKP:
2443 if (srclen != NULL_TREE)
2444 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
2445 else
2446 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
2447 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
2448 break;
2449 default:
2450 gcc_unreachable ();
2453 if (fn == NULL_TREE)
2454 return;
2456 if (dsi && dstlen)
2458 tree type = TREE_TYPE (dstlen);
2460 /* Compute the size of the source sequence, including the nul. */
2461 tree srcsize = srclen ? srclen : size_zero_node;
2462 srcsize = fold_build2 (PLUS_EXPR, type, srcsize, build_int_cst (type, 1));
2464 tree sptr = si && si->ptr ? si->ptr : src;
2466 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, sptr,
2467 dstlen, srcsize))
2469 gimple_set_no_warning (stmt, true);
2470 set_no_warning = true;
2474 tree len = NULL_TREE;
2475 if (srclen != NULL_TREE)
2477 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
2478 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
2480 len = fold_convert_loc (loc, type, unshare_expr (srclen));
2481 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
2482 build_int_cst (type, 1));
2483 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
2484 GSI_SAME_STMT);
2486 if (endptr)
2487 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
2488 else
2489 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
2490 TREE_TYPE (dst), unshare_expr (dst),
2491 fold_convert_loc (loc, sizetype,
2492 unshare_expr (dstlen)));
2493 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
2494 GSI_SAME_STMT);
2495 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2497 fprintf (dump_file, "Optimizing: ");
2498 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
2500 if (with_bounds)
2502 fn = chkp_maybe_create_clone (fn)->decl;
2503 if (srclen != NULL_TREE)
2504 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
2505 dst,
2506 gimple_call_arg (stmt, 1),
2507 src,
2508 gimple_call_arg (stmt, 3),
2509 len, objsz);
2510 else
2511 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
2512 dst,
2513 gimple_call_arg (stmt, 1),
2514 src,
2515 gimple_call_arg (stmt, 3),
2516 objsz);
2518 else
2519 if (srclen != NULL_TREE)
2520 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
2521 dst, src, len, objsz);
2522 else
2523 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
2524 dst, src, objsz);
2525 if (success)
2527 stmt = gsi_stmt (*gsi);
2528 gimple_call_set_with_bounds (stmt, with_bounds);
2529 update_stmt (stmt);
2530 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2532 fprintf (dump_file, "into: ");
2533 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
2535 /* If srclen == NULL, note that current string length can be
2536 computed by transforming this strcpy into stpcpy. */
2537 if (srclen == NULL_TREE && dsi->dont_invalidate)
2538 dsi->stmt = stmt;
2539 adjust_last_stmt (dsi, stmt, true);
2540 if (srclen != NULL_TREE)
2542 laststmt.stmt = stmt;
2543 laststmt.len = srclen;
2544 laststmt.stridx = dsi->idx;
2547 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2548 fprintf (dump_file, "not possible.\n");
2550 if (set_no_warning)
2551 gimple_set_no_warning (stmt, true);
2554 /* Handle a call to malloc or calloc. */
2556 static void
2557 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2559 gimple *stmt = gsi_stmt (*gsi);
2560 tree lhs = gimple_call_lhs (stmt);
2561 if (lhs == NULL_TREE)
2562 return;
2564 gcc_assert (get_stridx (lhs) == 0);
2565 int idx = new_stridx (lhs);
2566 tree length = NULL_TREE;
2567 if (bcode == BUILT_IN_CALLOC)
2568 length = build_int_cst (size_type_node, 0);
2569 strinfo *si = new_strinfo (lhs, idx, length, length != NULL_TREE);
2570 if (bcode == BUILT_IN_CALLOC)
2571 si->endptr = lhs;
2572 set_strinfo (idx, si);
2573 si->writable = true;
2574 si->stmt = stmt;
2575 si->dont_invalidate = true;
2578 /* Handle a call to memset.
2579 After a call to calloc, memset(,0,) is unnecessary.
2580 memset(malloc(n),0,n) is calloc(n,1). */
2582 static bool
2583 handle_builtin_memset (gimple_stmt_iterator *gsi)
2585 gimple *stmt2 = gsi_stmt (*gsi);
2586 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
2587 return true;
2588 tree ptr = gimple_call_arg (stmt2, 0);
2589 int idx1 = get_stridx (ptr);
2590 if (idx1 <= 0)
2591 return true;
2592 strinfo *si1 = get_strinfo (idx1);
2593 if (!si1)
2594 return true;
2595 gimple *stmt1 = si1->stmt;
2596 if (!stmt1 || !is_gimple_call (stmt1))
2597 return true;
2598 tree callee1 = gimple_call_fndecl (stmt1);
2599 if (!valid_builtin_call (stmt1))
2600 return true;
2601 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
2602 tree size = gimple_call_arg (stmt2, 2);
2603 if (code1 == BUILT_IN_CALLOC)
2604 /* Not touching stmt1 */ ;
2605 else if (code1 == BUILT_IN_MALLOC
2606 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
2608 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
2609 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
2610 size, build_one_cst (size_type_node));
2611 si1->nonzero_chars = build_int_cst (size_type_node, 0);
2612 si1->full_string_p = true;
2613 si1->stmt = gsi_stmt (gsi1);
2615 else
2616 return true;
2617 tree lhs = gimple_call_lhs (stmt2);
2618 unlink_stmt_vdef (stmt2);
2619 if (lhs)
2621 gimple *assign = gimple_build_assign (lhs, ptr);
2622 gsi_replace (gsi, assign, false);
2624 else
2626 gsi_remove (gsi, true);
2627 release_defs (stmt2);
2630 return false;
2633 /* Handle a call to memcmp. We try to handle small comparisons by
2634 converting them to load and compare, and replacing the call to memcmp
2635 with a __builtin_memcmp_eq call where possible. */
2637 static bool
2638 handle_builtin_memcmp (gimple_stmt_iterator *gsi)
2640 gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
2641 tree res = gimple_call_lhs (stmt2);
2642 tree arg1 = gimple_call_arg (stmt2, 0);
2643 tree arg2 = gimple_call_arg (stmt2, 1);
2644 tree len = gimple_call_arg (stmt2, 2);
2645 unsigned HOST_WIDE_INT leni;
2646 use_operand_p use_p;
2647 imm_use_iterator iter;
2649 if (!res)
2650 return true;
2652 FOR_EACH_IMM_USE_FAST (use_p, iter, res)
2654 gimple *ustmt = USE_STMT (use_p);
2656 if (is_gimple_debug (ustmt))
2657 continue;
2658 if (gimple_code (ustmt) == GIMPLE_ASSIGN)
2660 gassign *asgn = as_a <gassign *> (ustmt);
2661 tree_code code = gimple_assign_rhs_code (asgn);
2662 if ((code != EQ_EXPR && code != NE_EXPR)
2663 || !integer_zerop (gimple_assign_rhs2 (asgn)))
2664 return true;
2666 else if (gimple_code (ustmt) == GIMPLE_COND)
2668 tree_code code = gimple_cond_code (ustmt);
2669 if ((code != EQ_EXPR && code != NE_EXPR)
2670 || !integer_zerop (gimple_cond_rhs (ustmt)))
2671 return true;
2673 else
2674 return true;
2677 if (tree_fits_uhwi_p (len)
2678 && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
2679 && pow2p_hwi (leni))
2681 leni *= CHAR_TYPE_SIZE;
2682 unsigned align1 = get_pointer_alignment (arg1);
2683 unsigned align2 = get_pointer_alignment (arg2);
2684 unsigned align = MIN (align1, align2);
2685 scalar_int_mode mode;
2686 if (int_mode_for_size (leni, 1).exists (&mode)
2687 && (align >= leni || !targetm.slow_unaligned_access (mode, align)))
2689 location_t loc = gimple_location (stmt2);
2690 tree type, off;
2691 type = build_nonstandard_integer_type (leni, 1);
2692 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
2693 tree ptrtype = build_pointer_type_for_mode (char_type_node,
2694 ptr_mode, true);
2695 off = build_int_cst (ptrtype, 0);
2696 arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
2697 arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
2698 tree tem1 = fold_const_aggregate_ref (arg1);
2699 if (tem1)
2700 arg1 = tem1;
2701 tree tem2 = fold_const_aggregate_ref (arg2);
2702 if (tem2)
2703 arg2 = tem2;
2704 res = fold_convert_loc (loc, TREE_TYPE (res),
2705 fold_build2_loc (loc, NE_EXPR,
2706 boolean_type_node,
2707 arg1, arg2));
2708 gimplify_and_update_call_from_tree (gsi, res);
2709 return false;
2713 gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
2714 return false;
2717 /* Handle a POINTER_PLUS_EXPR statement.
2718 For p = "abcd" + 2; compute associated length, or if
2719 p = q + off is pointing to a '\0' character of a string, call
2720 zero_length_string on it. */
2722 static void
2723 handle_pointer_plus (gimple_stmt_iterator *gsi)
2725 gimple *stmt = gsi_stmt (*gsi);
2726 tree lhs = gimple_assign_lhs (stmt), off;
2727 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2728 strinfo *si, *zsi;
2730 if (idx == 0)
2731 return;
2733 if (idx < 0)
2735 tree off = gimple_assign_rhs2 (stmt);
2736 if (tree_fits_uhwi_p (off)
2737 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
2738 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
2739 = ~(~idx - (int) tree_to_uhwi (off));
2740 return;
2743 si = get_strinfo (idx);
2744 if (si == NULL || si->nonzero_chars == NULL_TREE)
2745 return;
2747 off = gimple_assign_rhs2 (stmt);
2748 zsi = NULL;
2749 if (si->full_string_p && operand_equal_p (si->nonzero_chars, off, 0))
2750 zsi = zero_length_string (lhs, si);
2751 else if (TREE_CODE (off) == SSA_NAME)
2753 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
2754 if (gimple_assign_single_p (def_stmt)
2755 && si->full_string_p
2756 && operand_equal_p (si->nonzero_chars,
2757 gimple_assign_rhs1 (def_stmt), 0))
2758 zsi = zero_length_string (lhs, si);
2760 if (zsi != NULL
2761 && si->endptr != NULL_TREE
2762 && si->endptr != lhs
2763 && TREE_CODE (si->endptr) == SSA_NAME)
2765 enum tree_code rhs_code
2766 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
2767 ? SSA_NAME : NOP_EXPR;
2768 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
2769 gcc_assert (gsi_stmt (*gsi) == stmt);
2770 update_stmt (stmt);
2774 /* Handle a single character store. */
2776 static bool
2777 handle_char_store (gimple_stmt_iterator *gsi)
2779 int idx = -1;
2780 strinfo *si = NULL;
2781 gimple *stmt = gsi_stmt (*gsi);
2782 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
2783 tree rhs = gimple_assign_rhs1 (stmt);
2784 unsigned HOST_WIDE_INT offset = 0;
2786 if (TREE_CODE (lhs) == MEM_REF
2787 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
2789 tree mem_offset = TREE_OPERAND (lhs, 1);
2790 if (tree_fits_uhwi_p (mem_offset))
2792 /* Get the strinfo for the base, and use it if it starts with at
2793 least OFFSET nonzero characters. This is trivially true if
2794 OFFSET is zero. */
2795 offset = tree_to_uhwi (mem_offset);
2796 idx = get_stridx (TREE_OPERAND (lhs, 0));
2797 if (idx > 0)
2798 si = get_strinfo (idx);
2799 if (offset == 0)
2800 ssaname = TREE_OPERAND (lhs, 0);
2801 else if (si == NULL || compare_nonzero_chars (si, offset) < 0)
2802 return true;
2805 else
2807 idx = get_addr_stridx (lhs, NULL_TREE, &offset);
2808 if (idx > 0)
2809 si = get_strinfo (idx);
2812 bool storing_zero_p = initializer_zerop (rhs);
2813 bool storing_nonzero_p = (!storing_zero_p
2814 && TREE_CODE (rhs) == INTEGER_CST
2815 && integer_nonzerop (rhs));
2817 if (si != NULL)
2819 int cmp = compare_nonzero_chars (si, offset);
2820 gcc_assert (offset == 0 || cmp >= 0);
2821 if (storing_zero_p && cmp == 0 && si->full_string_p)
2823 /* When overwriting a '\0' with a '\0', the store can be removed
2824 if we know it has been stored in the current function. */
2825 if (!stmt_could_throw_p (stmt) && si->writable)
2827 unlink_stmt_vdef (stmt);
2828 release_defs (stmt);
2829 gsi_remove (gsi, true);
2830 return false;
2832 else
2834 si->writable = true;
2835 gsi_next (gsi);
2836 return false;
2839 /* If si->nonzero_chars > OFFSET, we aren't overwriting '\0',
2840 and if we aren't storing '\0', we know that the length of the
2841 string and any other zero terminated string in memory remains
2842 the same. In that case we move to the next gimple statement and
2843 return to signal the caller that it shouldn't invalidate anything.
2845 This is benefical for cases like:
2847 char p[20];
2848 void foo (char *q)
2850 strcpy (p, "foobar");
2851 size_t len = strlen (p); // This can be optimized into 6
2852 size_t len2 = strlen (q); // This has to be computed
2853 p[0] = 'X';
2854 size_t len3 = strlen (p); // This can be optimized into 6
2855 size_t len4 = strlen (q); // This can be optimized into len2
2856 bar (len, len2, len3, len4);
2859 else if (storing_nonzero_p && cmp > 0)
2861 gsi_next (gsi);
2862 return false;
2864 else if (storing_zero_p || storing_nonzero_p || (offset != 0 && cmp > 0))
2866 /* When storing_nonzero_p, we know that the string now starts
2867 with OFFSET + 1 nonzero characters, but don't know whether
2868 there's a following nul terminator.
2870 When storing_zero_p, we know that the string is now OFFSET
2871 characters long.
2873 Otherwise, we're storing an unknown value at offset OFFSET,
2874 so need to clip the nonzero_chars to OFFSET. */
2875 location_t loc = gimple_location (stmt);
2876 tree oldlen = si->nonzero_chars;
2877 if (cmp == 0 && si->full_string_p)
2878 /* We're overwriting the nul terminator with a nonzero or
2879 unknown character. If the previous stmt was a memcpy,
2880 its length may be decreased. */
2881 adjust_last_stmt (si, stmt, false);
2882 si = unshare_strinfo (si);
2883 if (storing_nonzero_p)
2884 si->nonzero_chars = build_int_cst (size_type_node, offset + 1);
2885 else
2886 si->nonzero_chars = build_int_cst (size_type_node, offset);
2887 si->full_string_p = storing_zero_p;
2888 if (storing_zero_p
2889 && ssaname
2890 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2891 si->endptr = ssaname;
2892 else
2893 si->endptr = NULL;
2894 si->next = 0;
2895 si->stmt = NULL;
2896 si->writable = true;
2897 si->dont_invalidate = true;
2898 if (oldlen)
2900 tree adj = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
2901 si->nonzero_chars, oldlen);
2902 adjust_related_strinfos (loc, si, adj);
2904 else
2905 si->prev = 0;
2908 else if (idx == 0 && (storing_zero_p || storing_nonzero_p))
2910 if (ssaname)
2911 idx = new_stridx (ssaname);
2912 else
2913 idx = new_addr_stridx (lhs);
2914 if (idx != 0)
2916 tree ptr = (ssaname ? ssaname : build_fold_addr_expr (lhs));
2917 tree len = storing_nonzero_p ? size_one_node : size_zero_node;
2918 si = new_strinfo (ptr, idx, len, storing_zero_p);
2919 set_strinfo (idx, si);
2920 if (storing_zero_p
2921 && ssaname
2922 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2923 si->endptr = ssaname;
2924 si->dont_invalidate = true;
2925 si->writable = true;
2928 else if (idx == 0
2929 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2930 && ssaname == NULL_TREE
2931 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2933 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2934 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2935 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2937 int idx = new_addr_stridx (lhs);
2938 if (idx != 0)
2940 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2941 build_int_cst (size_type_node, l), true);
2942 set_strinfo (idx, si);
2943 si->dont_invalidate = true;
2948 if (si != NULL && offset == 0 && storing_zero_p)
2950 /* Allow adjust_last_stmt to remove it if the stored '\0'
2951 is immediately overwritten. */
2952 laststmt.stmt = stmt;
2953 laststmt.len = build_int_cst (size_type_node, 1);
2954 laststmt.stridx = si->idx;
2956 return true;
2959 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0. */
2961 static void
2962 fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
2964 if (TREE_CODE (rhs1) != SSA_NAME
2965 || TREE_CODE (rhs2) != SSA_NAME)
2966 return;
2968 gimple *call_stmt = NULL;
2969 for (int pass = 0; pass < 2; pass++)
2971 gimple *g = SSA_NAME_DEF_STMT (rhs1);
2972 if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
2973 && has_single_use (rhs1)
2974 && gimple_call_arg (g, 0) == rhs2)
2976 call_stmt = g;
2977 break;
2979 std::swap (rhs1, rhs2);
2982 if (call_stmt)
2984 tree arg0 = gimple_call_arg (call_stmt, 0);
2986 if (arg0 == rhs2)
2988 tree arg1 = gimple_call_arg (call_stmt, 1);
2989 tree arg1_len = NULL_TREE;
2990 int idx = get_stridx (arg1);
2992 if (idx)
2994 if (idx < 0)
2995 arg1_len = build_int_cst (size_type_node, ~idx);
2996 else
2998 strinfo *si = get_strinfo (idx);
2999 if (si)
3000 arg1_len = get_string_length (si);
3004 if (arg1_len != NULL_TREE)
3006 gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
3007 tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
3009 if (!is_gimple_val (arg1_len))
3011 tree arg1_len_tmp = make_ssa_name (TREE_TYPE (arg1_len));
3012 gassign *arg1_stmt = gimple_build_assign (arg1_len_tmp,
3013 arg1_len);
3014 gsi_insert_before (&gsi, arg1_stmt, GSI_SAME_STMT);
3015 arg1_len = arg1_len_tmp;
3018 gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
3019 arg0, arg1, arg1_len);
3020 tree strncmp_lhs = make_ssa_name (integer_type_node);
3021 gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
3022 gimple_call_set_lhs (strncmp_call, strncmp_lhs);
3023 gsi_remove (&gsi, true);
3024 gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
3025 tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
3027 if (is_gimple_assign (stmt))
3029 if (gimple_assign_rhs_code (stmt) == COND_EXPR)
3031 tree cond = gimple_assign_rhs1 (stmt);
3032 TREE_OPERAND (cond, 0) = strncmp_lhs;
3033 TREE_OPERAND (cond, 1) = zero;
3035 else
3037 gimple_assign_set_rhs1 (stmt, strncmp_lhs);
3038 gimple_assign_set_rhs2 (stmt, zero);
3041 else
3043 gcond *cond = as_a<gcond *> (stmt);
3044 gimple_cond_set_lhs (cond, strncmp_lhs);
3045 gimple_cond_set_rhs (cond, zero);
3047 update_stmt (stmt);
3053 /* Attempt to check for validity of the performed access a single statement
3054 at *GSI using string length knowledge, and to optimize it. */
3056 static bool
3057 strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi)
3059 gimple *stmt = gsi_stmt (*gsi);
3061 if (is_gimple_call (stmt))
3063 tree callee = gimple_call_fndecl (stmt);
3064 if (valid_builtin_call (stmt))
3065 switch (DECL_FUNCTION_CODE (callee))
3067 case BUILT_IN_STRLEN:
3068 case BUILT_IN_STRLEN_CHKP:
3069 handle_builtin_strlen (gsi);
3070 break;
3071 case BUILT_IN_STRCHR:
3072 case BUILT_IN_STRCHR_CHKP:
3073 handle_builtin_strchr (gsi);
3074 break;
3075 case BUILT_IN_STRCPY:
3076 case BUILT_IN_STRCPY_CHK:
3077 case BUILT_IN_STPCPY:
3078 case BUILT_IN_STPCPY_CHK:
3079 case BUILT_IN_STRCPY_CHKP:
3080 case BUILT_IN_STRCPY_CHK_CHKP:
3081 case BUILT_IN_STPCPY_CHKP:
3082 case BUILT_IN_STPCPY_CHK_CHKP:
3083 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
3084 break;
3086 case BUILT_IN_STRNCAT:
3087 case BUILT_IN_STRNCAT_CHK:
3088 handle_builtin_strncat (DECL_FUNCTION_CODE (callee), gsi);
3089 break;
3091 case BUILT_IN_STPNCPY:
3092 case BUILT_IN_STPNCPY_CHK:
3093 case BUILT_IN_STRNCPY:
3094 case BUILT_IN_STRNCPY_CHK:
3095 handle_builtin_stxncpy (DECL_FUNCTION_CODE (callee), gsi);
3096 break;
3098 case BUILT_IN_MEMCPY:
3099 case BUILT_IN_MEMCPY_CHK:
3100 case BUILT_IN_MEMPCPY:
3101 case BUILT_IN_MEMPCPY_CHK:
3102 case BUILT_IN_MEMCPY_CHKP:
3103 case BUILT_IN_MEMCPY_CHK_CHKP:
3104 case BUILT_IN_MEMPCPY_CHKP:
3105 case BUILT_IN_MEMPCPY_CHK_CHKP:
3106 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
3107 break;
3108 case BUILT_IN_STRCAT:
3109 case BUILT_IN_STRCAT_CHK:
3110 case BUILT_IN_STRCAT_CHKP:
3111 case BUILT_IN_STRCAT_CHK_CHKP:
3112 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
3113 break;
3114 case BUILT_IN_MALLOC:
3115 case BUILT_IN_CALLOC:
3116 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
3117 break;
3118 case BUILT_IN_MEMSET:
3119 if (!handle_builtin_memset (gsi))
3120 return false;
3121 break;
3122 case BUILT_IN_MEMCMP:
3123 if (!handle_builtin_memcmp (gsi))
3124 return false;
3125 break;
3126 default:
3127 break;
3130 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
3132 tree lhs = gimple_assign_lhs (stmt);
3134 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
3136 if (gimple_assign_single_p (stmt)
3137 || (gimple_assign_cast_p (stmt)
3138 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
3140 int idx = get_stridx (gimple_assign_rhs1 (stmt));
3141 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
3143 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
3144 handle_pointer_plus (gsi);
3146 else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
3148 enum tree_code code = gimple_assign_rhs_code (stmt);
3149 if (code == COND_EXPR)
3151 tree cond = gimple_assign_rhs1 (stmt);
3152 enum tree_code cond_code = TREE_CODE (cond);
3154 if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
3155 fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
3156 TREE_OPERAND (cond, 1), stmt);
3158 else if (code == EQ_EXPR || code == NE_EXPR)
3159 fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
3160 gimple_assign_rhs2 (stmt), stmt);
3161 else if (gimple_assign_load_p (stmt)
3162 && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE
3163 && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (char_type_node)
3164 && (TYPE_PRECISION (TREE_TYPE (lhs))
3165 == TYPE_PRECISION (char_type_node))
3166 && !gimple_has_volatile_ops (stmt))
3168 tree off = integer_zero_node;
3169 unsigned HOST_WIDE_INT coff = 0;
3170 int idx = 0;
3171 tree rhs1 = gimple_assign_rhs1 (stmt);
3172 if (code == MEM_REF)
3174 idx = get_stridx (TREE_OPERAND (rhs1, 0));
3175 if (idx > 0)
3177 strinfo *si = get_strinfo (idx);
3178 if (si
3179 && si->nonzero_chars
3180 && TREE_CODE (si->nonzero_chars) == INTEGER_CST
3181 && (wi::to_widest (si->nonzero_chars)
3182 >= wi::to_widest (off)))
3183 off = TREE_OPERAND (rhs1, 1);
3184 else
3185 /* This case is not useful. See if get_addr_stridx
3186 returns something usable. */
3187 idx = 0;
3190 if (idx <= 0)
3191 idx = get_addr_stridx (rhs1, NULL_TREE, &coff);
3192 if (idx > 0)
3194 strinfo *si = get_strinfo (idx);
3195 if (si
3196 && si->nonzero_chars
3197 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
3199 widest_int w1 = wi::to_widest (si->nonzero_chars);
3200 widest_int w2 = wi::to_widest (off) + coff;
3201 if (w1 == w2
3202 && si->full_string_p)
3204 /* Reading the final '\0' character. */
3205 tree zero = build_int_cst (TREE_TYPE (lhs), 0);
3206 gimple_set_vuse (stmt, NULL_TREE);
3207 gimple_assign_set_rhs_from_tree (gsi, zero);
3208 update_stmt (gsi_stmt (*gsi));
3210 else if (w1 > w2)
3212 /* Reading a character before the final '\0'
3213 character. Just set the value range to ~[0, 0]
3214 if we don't have anything better. */
3215 wide_int min, max;
3216 tree type = TREE_TYPE (lhs);
3217 enum value_range_type vr
3218 = get_range_info (lhs, &min, &max);
3219 if (vr == VR_VARYING
3220 || (vr == VR_RANGE
3221 && min == wi::min_value (TYPE_PRECISION (type),
3222 TYPE_SIGN (type))
3223 && max == wi::max_value (TYPE_PRECISION (type),
3224 TYPE_SIGN (type))))
3225 set_range_info (lhs, VR_ANTI_RANGE,
3226 wi::zero (TYPE_PRECISION (type)),
3227 wi::zero (TYPE_PRECISION (type)));
3233 if (strlen_to_stridx)
3235 tree rhs1 = gimple_assign_rhs1 (stmt);
3236 if (stridx_strlenloc *ps = strlen_to_stridx->get (rhs1))
3237 strlen_to_stridx->put (lhs, stridx_strlenloc (*ps));
3240 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
3242 tree type = TREE_TYPE (lhs);
3243 if (TREE_CODE (type) == ARRAY_TYPE)
3244 type = TREE_TYPE (type);
3245 if (TREE_CODE (type) == INTEGER_TYPE
3246 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
3247 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
3249 if (! handle_char_store (gsi))
3250 return false;
3254 else if (gcond *cond = dyn_cast<gcond *> (stmt))
3256 enum tree_code code = gimple_cond_code (cond);
3257 if (code == EQ_EXPR || code == NE_EXPR)
3258 fold_strstr_to_strncmp (gimple_cond_lhs (stmt),
3259 gimple_cond_rhs (stmt), stmt);
3262 if (gimple_vdef (stmt))
3263 maybe_invalidate (stmt);
3264 return true;
3267 /* Recursively call maybe_invalidate on stmts that might be executed
3268 in between dombb and current bb and that contain a vdef. Stop when
3269 *count stmts are inspected, or if the whole strinfo vector has
3270 been invalidated. */
3272 static void
3273 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
3275 unsigned int i, n = gimple_phi_num_args (phi);
3277 for (i = 0; i < n; i++)
3279 tree vuse = gimple_phi_arg_def (phi, i);
3280 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
3281 basic_block bb = gimple_bb (stmt);
3282 if (bb == NULL
3283 || bb == dombb
3284 || !bitmap_set_bit (visited, bb->index)
3285 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
3286 continue;
3287 while (1)
3289 if (gimple_code (stmt) == GIMPLE_PHI)
3291 do_invalidate (dombb, stmt, visited, count);
3292 if (*count == 0)
3293 return;
3294 break;
3296 if (--*count == 0)
3297 return;
3298 if (!maybe_invalidate (stmt))
3300 *count = 0;
3301 return;
3303 vuse = gimple_vuse (stmt);
3304 stmt = SSA_NAME_DEF_STMT (vuse);
3305 if (gimple_bb (stmt) != bb)
3307 bb = gimple_bb (stmt);
3308 if (bb == NULL
3309 || bb == dombb
3310 || !bitmap_set_bit (visited, bb->index)
3311 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
3312 break;
3318 class strlen_dom_walker : public dom_walker
3320 public:
3321 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
3323 virtual edge before_dom_children (basic_block);
3324 virtual void after_dom_children (basic_block);
3327 /* Callback for walk_dominator_tree. Attempt to optimize various
3328 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */
3330 edge
3331 strlen_dom_walker::before_dom_children (basic_block bb)
3333 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
3335 if (dombb == NULL)
3336 stridx_to_strinfo = NULL;
3337 else
3339 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
3340 if (stridx_to_strinfo)
3342 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
3343 gsi_next (&gsi))
3345 gphi *phi = gsi.phi ();
3346 if (virtual_operand_p (gimple_phi_result (phi)))
3348 bitmap visited = BITMAP_ALLOC (NULL);
3349 int count_vdef = 100;
3350 do_invalidate (dombb, phi, visited, &count_vdef);
3351 BITMAP_FREE (visited);
3352 if (count_vdef == 0)
3354 /* If there were too many vdefs in between immediate
3355 dominator and current bb, invalidate everything.
3356 If stridx_to_strinfo has been unshared, we need
3357 to free it, otherwise just set it to NULL. */
3358 if (!strinfo_shared ())
3360 unsigned int i;
3361 strinfo *si;
3363 for (i = 1;
3364 vec_safe_iterate (stridx_to_strinfo, i, &si);
3365 ++i)
3367 free_strinfo (si);
3368 (*stridx_to_strinfo)[i] = NULL;
3371 else
3372 stridx_to_strinfo = NULL;
3374 break;
3380 /* If all PHI arguments have the same string index, the PHI result
3381 has it as well. */
3382 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
3383 gsi_next (&gsi))
3385 gphi *phi = gsi.phi ();
3386 tree result = gimple_phi_result (phi);
3387 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
3389 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
3390 if (idx != 0)
3392 unsigned int i, n = gimple_phi_num_args (phi);
3393 for (i = 1; i < n; i++)
3394 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
3395 break;
3396 if (i == n)
3397 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
3402 /* Attempt to optimize individual statements. */
3403 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
3404 if (strlen_check_and_optimize_stmt (&gsi))
3405 gsi_next (&gsi);
3407 bb->aux = stridx_to_strinfo;
3408 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
3409 (*stridx_to_strinfo)[0] = (strinfo *) bb;
3410 return NULL;
3413 /* Callback for walk_dominator_tree. Free strinfo vector if it is
3414 owned by the current bb, clear bb->aux. */
3416 void
3417 strlen_dom_walker::after_dom_children (basic_block bb)
3419 if (bb->aux)
3421 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
3422 if (vec_safe_length (stridx_to_strinfo)
3423 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
3425 unsigned int i;
3426 strinfo *si;
3428 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
3429 free_strinfo (si);
3430 vec_free (stridx_to_strinfo);
3432 bb->aux = NULL;
3436 /* Main entry point. */
3438 namespace {
3440 const pass_data pass_data_strlen =
3442 GIMPLE_PASS, /* type */
3443 "strlen", /* name */
3444 OPTGROUP_NONE, /* optinfo_flags */
3445 TV_TREE_STRLEN, /* tv_id */
3446 ( PROP_cfg | PROP_ssa ), /* properties_required */
3447 0, /* properties_provided */
3448 0, /* properties_destroyed */
3449 0, /* todo_flags_start */
3450 0, /* todo_flags_finish */
3453 class pass_strlen : public gimple_opt_pass
3455 public:
3456 pass_strlen (gcc::context *ctxt)
3457 : gimple_opt_pass (pass_data_strlen, ctxt)
3460 /* opt_pass methods: */
3461 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
3462 virtual unsigned int execute (function *);
3464 }; // class pass_strlen
3466 unsigned int
3467 pass_strlen::execute (function *fun)
3469 gcc_assert (!strlen_to_stridx);
3470 if (warn_stringop_overflow || warn_stringop_truncation)
3471 strlen_to_stridx = new hash_map<tree, stridx_strlenloc> ();
3473 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
3474 max_stridx = 1;
3476 calculate_dominance_info (CDI_DOMINATORS);
3478 /* String length optimization is implemented as a walk of the dominator
3479 tree and a forward walk of statements within each block. */
3480 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
3482 ssa_ver_to_stridx.release ();
3483 strinfo_pool.release ();
3484 if (decl_to_stridxlist_htab)
3486 obstack_free (&stridx_obstack, NULL);
3487 delete decl_to_stridxlist_htab;
3488 decl_to_stridxlist_htab = NULL;
3490 laststmt.stmt = NULL;
3491 laststmt.len = NULL_TREE;
3492 laststmt.stridx = 0;
3494 if (strlen_to_stridx)
3496 strlen_to_stridx->empty ();
3497 delete strlen_to_stridx;
3498 strlen_to_stridx = NULL;
3501 return 0;
3504 } // anon namespace
3506 gimple_opt_pass *
3507 make_pass_strlen (gcc::context *ctxt)
3509 return new pass_strlen (ctxt);