PR tree-optimization/84740
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob72f6a17cd322ca387d56ed4f58e1e6241bc2b52a
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-cfg.h"
43 #include "tree-dfa.h"
44 #include "domwalk.h"
45 #include "tree-ssa-alias.h"
46 #include "tree-ssa-propagate.h"
47 #include "tree-ssa-strlen.h"
48 #include "params.h"
49 #include "ipa-chkp.h"
50 #include "tree-hash-traits.h"
51 #include "builtins.h"
52 #include "target.h"
53 #include "diagnostic-core.h"
54 #include "diagnostic.h"
55 #include "intl.h"
56 #include "attribs.h"
57 #include "calls.h"
59 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
60 is an index into strinfo vector, negative value stands for
61 string length of a string literal (~strlen). */
62 static vec<int> ssa_ver_to_stridx;
64 /* Number of currently active string indexes plus one. */
65 static int max_stridx;
67 /* String information record. */
68 struct strinfo
70 /* Number of leading characters that are known to be nonzero. This is
71 also the length of the string if FULL_STRING_P.
73 The values in a list of related string pointers must be consistent;
74 that is, if strinfo B comes X bytes after strinfo A, it must be
75 the case that A->nonzero_chars == X + B->nonzero_chars. */
76 tree nonzero_chars;
77 /* Any of the corresponding pointers for querying alias oracle. */
78 tree ptr;
79 /* This is used for two things:
81 - To record the statement that should be used for delayed length
82 computations. We maintain the invariant that all related strinfos
83 have delayed lengths or none do.
85 - To record the malloc or calloc call that produced this result. */
86 gimple *stmt;
87 /* Pointer to '\0' if known, if NULL, it can be computed as
88 ptr + length. */
89 tree endptr;
90 /* Reference count. Any changes to strinfo entry possibly shared
91 with dominating basic blocks need unshare_strinfo first, except
92 for dont_invalidate which affects only the immediately next
93 maybe_invalidate. */
94 int refcount;
95 /* Copy of index. get_strinfo (si->idx) should return si; */
96 int idx;
97 /* These 3 fields are for chaining related string pointers together.
98 E.g. for
99 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
100 strcpy (c, d); e = c + dl;
101 strinfo(a) -> strinfo(c) -> strinfo(e)
102 All have ->first field equal to strinfo(a)->idx and are doubly
103 chained through prev/next fields. The later strinfos are required
104 to point into the same string with zero or more bytes after
105 the previous pointer and all bytes in between the two pointers
106 must be non-zero. Functions like strcpy or memcpy are supposed
107 to adjust all previous strinfo lengths, but not following strinfo
108 lengths (those are uncertain, usually invalidated during
109 maybe_invalidate, except when the alias oracle knows better).
110 Functions like strcat on the other side adjust the whole
111 related strinfo chain.
112 They are updated lazily, so to use the chain the same first fields
113 and si->prev->next == si->idx needs to be verified. */
114 int first;
115 int next;
116 int prev;
117 /* A flag whether the string is known to be written in the current
118 function. */
119 bool writable;
120 /* A flag for the next maybe_invalidate that this strinfo shouldn't
121 be invalidated. Always cleared by maybe_invalidate. */
122 bool dont_invalidate;
123 /* True if the string is known to be nul-terminated after NONZERO_CHARS
124 characters. False is useful when detecting strings that are built
125 up via successive memcpys. */
126 bool full_string_p;
129 /* Pool for allocating strinfo_struct entries. */
130 static object_allocator<strinfo> strinfo_pool ("strinfo pool");
132 /* Vector mapping positive string indexes to strinfo, for the
133 current basic block. The first pointer in the vector is special,
134 it is either NULL, meaning the vector isn't shared, or it is
135 a basic block pointer to the owner basic_block if shared.
136 If some other bb wants to modify the vector, the vector needs
137 to be unshared first, and only the owner bb is supposed to free it. */
138 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
140 /* One OFFSET->IDX mapping. */
141 struct stridxlist
143 struct stridxlist *next;
144 HOST_WIDE_INT offset;
145 int idx;
148 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
149 struct decl_stridxlist_map
151 struct tree_map_base base;
152 struct stridxlist list;
155 /* Hash table for mapping decls to a chained list of offset -> idx
156 mappings. */
157 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
159 /* Hash table mapping strlen calls to stridx instances describing
160 the calls' arguments. Non-null only when warn_stringop_truncation
161 is non-zero. */
162 typedef std::pair<int, location_t> stridx_strlenloc;
163 static hash_map<tree, stridx_strlenloc> *strlen_to_stridx;
165 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
166 static struct obstack stridx_obstack;
168 /* Last memcpy statement if it could be adjusted if the trailing
169 '\0' written is immediately overwritten, or
170 *x = '\0' store that could be removed if it is immediately overwritten. */
171 struct laststmt_struct
173 gimple *stmt;
174 tree len;
175 int stridx;
176 } laststmt;
178 static int get_stridx_plus_constant (strinfo *, unsigned HOST_WIDE_INT, tree);
179 static void handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *);
181 /* Return:
183 - 1 if SI is known to start with more than OFF nonzero characters.
185 - 0 if SI is known to start with OFF nonzero characters,
186 but is not known to start with more.
188 - -1 if SI might not start with OFF nonzero characters. */
190 static inline int
191 compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off)
193 if (si->nonzero_chars
194 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
195 return compare_tree_int (si->nonzero_chars, off);
196 else
197 return -1;
200 /* Return true if SI is known to be a zero-length string. */
202 static inline bool
203 zero_length_string_p (strinfo *si)
205 return si->full_string_p && integer_zerop (si->nonzero_chars);
208 /* Return strinfo vector entry IDX. */
210 static inline strinfo *
211 get_strinfo (int idx)
213 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
214 return NULL;
215 return (*stridx_to_strinfo)[idx];
218 /* Get the next strinfo in the chain after SI, or null if none. */
220 static inline strinfo *
221 get_next_strinfo (strinfo *si)
223 if (si->next == 0)
224 return NULL;
225 strinfo *nextsi = get_strinfo (si->next);
226 if (nextsi == NULL || nextsi->first != si->first || nextsi->prev != si->idx)
227 return NULL;
228 return nextsi;
231 /* Helper function for get_stridx. Return the strinfo index of the address
232 of EXP, which is available in PTR if nonnull. If OFFSET_OUT, it is
233 OK to return the index for some X <= &EXP and store &EXP - X in
234 *OFFSET_OUT. */
236 static int
237 get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out)
239 HOST_WIDE_INT off;
240 struct stridxlist *list, *last = NULL;
241 tree base;
243 if (!decl_to_stridxlist_htab)
244 return 0;
246 poly_int64 poff;
247 base = get_addr_base_and_unit_offset (exp, &poff);
248 if (base == NULL || !DECL_P (base) || !poff.is_constant (&off))
249 return 0;
251 list = decl_to_stridxlist_htab->get (base);
252 if (list == NULL)
253 return 0;
257 if (list->offset == off)
259 if (offset_out)
260 *offset_out = 0;
261 return list->idx;
263 if (list->offset > off)
264 return 0;
265 last = list;
266 list = list->next;
268 while (list);
270 if ((offset_out || ptr) && last && last->idx > 0)
272 unsigned HOST_WIDE_INT rel_off
273 = (unsigned HOST_WIDE_INT) off - last->offset;
274 strinfo *si = get_strinfo (last->idx);
275 if (si && compare_nonzero_chars (si, rel_off) >= 0)
277 if (offset_out)
279 *offset_out = rel_off;
280 return last->idx;
282 else
283 return get_stridx_plus_constant (si, rel_off, ptr);
286 return 0;
289 /* Return string index for EXP. */
291 static int
292 get_stridx (tree exp)
294 tree s, o;
296 if (TREE_CODE (exp) == SSA_NAME)
298 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
299 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
300 int i;
301 tree e = exp;
302 HOST_WIDE_INT off = 0;
303 for (i = 0; i < 5; i++)
305 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
306 if (!is_gimple_assign (def_stmt)
307 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
308 return 0;
309 tree rhs1 = gimple_assign_rhs1 (def_stmt);
310 tree rhs2 = gimple_assign_rhs2 (def_stmt);
311 if (TREE_CODE (rhs1) != SSA_NAME
312 || !tree_fits_shwi_p (rhs2))
313 return 0;
314 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
315 if (this_off < 0)
316 return 0;
317 off = (unsigned HOST_WIDE_INT) off + this_off;
318 if (off < 0)
319 return 0;
320 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
322 strinfo *si
323 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
324 if (si && compare_nonzero_chars (si, off) >= 0)
325 return get_stridx_plus_constant (si, off, exp);
327 e = rhs1;
329 return 0;
332 if (TREE_CODE (exp) == ADDR_EXPR)
334 int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp, NULL);
335 if (idx != 0)
336 return idx;
339 s = string_constant (exp, &o);
340 if (s != NULL_TREE
341 && (o == NULL_TREE || tree_fits_shwi_p (o))
342 && TREE_STRING_LENGTH (s) > 0)
344 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
345 const char *p = TREE_STRING_POINTER (s);
346 int max = TREE_STRING_LENGTH (s) - 1;
348 if (p[max] == '\0' && offset >= 0 && offset <= max)
349 return ~(int) strlen (p + offset);
351 return 0;
354 /* Return true if strinfo vector is shared with the immediate dominator. */
356 static inline bool
357 strinfo_shared (void)
359 return vec_safe_length (stridx_to_strinfo)
360 && (*stridx_to_strinfo)[0] != NULL;
363 /* Unshare strinfo vector that is shared with the immediate dominator. */
365 static void
366 unshare_strinfo_vec (void)
368 strinfo *si;
369 unsigned int i = 0;
371 gcc_assert (strinfo_shared ());
372 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
373 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
374 if (si != NULL)
375 si->refcount++;
376 (*stridx_to_strinfo)[0] = NULL;
379 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
380 Return a pointer to the location where the string index can
381 be stored (if 0) or is stored, or NULL if this can't be tracked. */
383 static int *
384 addr_stridxptr (tree exp)
386 HOST_WIDE_INT off;
388 poly_int64 poff;
389 tree base = get_addr_base_and_unit_offset (exp, &poff);
390 if (base == NULL_TREE || !DECL_P (base) || !poff.is_constant (&off))
391 return NULL;
393 if (!decl_to_stridxlist_htab)
395 decl_to_stridxlist_htab
396 = new hash_map<tree_decl_hash, stridxlist> (64);
397 gcc_obstack_init (&stridx_obstack);
400 bool existed;
401 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
402 if (existed)
404 int i;
405 stridxlist *before = NULL;
406 for (i = 0; i < 32; i++)
408 if (list->offset == off)
409 return &list->idx;
410 if (list->offset > off && before == NULL)
411 before = list;
412 if (list->next == NULL)
413 break;
414 list = list->next;
416 if (i == 32)
417 return NULL;
418 if (before)
420 list = before;
421 before = XOBNEW (&stridx_obstack, struct stridxlist);
422 *before = *list;
423 list->next = before;
424 list->offset = off;
425 list->idx = 0;
426 return &list->idx;
428 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
429 list = list->next;
432 list->next = NULL;
433 list->offset = off;
434 list->idx = 0;
435 return &list->idx;
438 /* Create a new string index, or return 0 if reached limit. */
440 static int
441 new_stridx (tree exp)
443 int idx;
444 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
445 return 0;
446 if (TREE_CODE (exp) == SSA_NAME)
448 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
449 return 0;
450 idx = max_stridx++;
451 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
452 return idx;
454 if (TREE_CODE (exp) == ADDR_EXPR)
456 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
457 if (pidx != NULL)
459 gcc_assert (*pidx == 0);
460 *pidx = max_stridx++;
461 return *pidx;
464 return 0;
467 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
469 static int
470 new_addr_stridx (tree exp)
472 int *pidx;
473 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
474 return 0;
475 pidx = addr_stridxptr (exp);
476 if (pidx != NULL)
478 gcc_assert (*pidx == 0);
479 *pidx = max_stridx++;
480 return *pidx;
482 return 0;
485 /* Create a new strinfo. */
487 static strinfo *
488 new_strinfo (tree ptr, int idx, tree nonzero_chars, bool full_string_p)
490 strinfo *si = strinfo_pool.allocate ();
491 si->nonzero_chars = nonzero_chars;
492 si->ptr = ptr;
493 si->stmt = NULL;
494 si->endptr = NULL_TREE;
495 si->refcount = 1;
496 si->idx = idx;
497 si->first = 0;
498 si->prev = 0;
499 si->next = 0;
500 si->writable = false;
501 si->dont_invalidate = false;
502 si->full_string_p = full_string_p;
503 return si;
506 /* Decrease strinfo refcount and free it if not referenced anymore. */
508 static inline void
509 free_strinfo (strinfo *si)
511 if (si && --si->refcount == 0)
512 strinfo_pool.remove (si);
515 /* Set strinfo in the vector entry IDX to SI. */
517 static inline void
518 set_strinfo (int idx, strinfo *si)
520 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
521 unshare_strinfo_vec ();
522 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
523 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
524 (*stridx_to_strinfo)[idx] = si;
527 /* Return the first strinfo in the related strinfo chain
528 if all strinfos in between belong to the chain, otherwise NULL. */
530 static strinfo *
531 verify_related_strinfos (strinfo *origsi)
533 strinfo *si = origsi, *psi;
535 if (origsi->first == 0)
536 return NULL;
537 for (; si->prev; si = psi)
539 if (si->first != origsi->first)
540 return NULL;
541 psi = get_strinfo (si->prev);
542 if (psi == NULL)
543 return NULL;
544 if (psi->next != si->idx)
545 return NULL;
547 if (si->idx != si->first)
548 return NULL;
549 return si;
552 /* Set SI's endptr to ENDPTR and compute its length based on SI->ptr.
553 Use LOC for folding. */
555 static void
556 set_endptr_and_length (location_t loc, strinfo *si, tree endptr)
558 si->endptr = endptr;
559 si->stmt = NULL;
560 tree start_as_size = fold_convert_loc (loc, size_type_node, si->ptr);
561 tree end_as_size = fold_convert_loc (loc, size_type_node, endptr);
562 si->nonzero_chars = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
563 end_as_size, start_as_size);
564 si->full_string_p = true;
567 /* Return string length, or NULL if it can't be computed. */
569 static tree
570 get_string_length (strinfo *si)
572 if (si->nonzero_chars)
573 return si->full_string_p ? si->nonzero_chars : NULL;
575 if (si->stmt)
577 gimple *stmt = si->stmt, *lenstmt;
578 bool with_bounds = gimple_call_with_bounds_p (stmt);
579 tree callee, lhs, fn, tem;
580 location_t loc;
581 gimple_stmt_iterator gsi;
583 gcc_assert (is_gimple_call (stmt));
584 callee = gimple_call_fndecl (stmt);
585 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
586 lhs = gimple_call_lhs (stmt);
587 /* unshare_strinfo is intentionally not called here. The (delayed)
588 transformation of strcpy or strcat into stpcpy is done at the place
589 of the former strcpy/strcat call and so can affect all the strinfos
590 with the same stmt. If they were unshared before and transformation
591 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
592 just compute the right length. */
593 switch (DECL_FUNCTION_CODE (callee))
595 case BUILT_IN_STRCAT:
596 case BUILT_IN_STRCAT_CHK:
597 case BUILT_IN_STRCAT_CHKP:
598 case BUILT_IN_STRCAT_CHK_CHKP:
599 gsi = gsi_for_stmt (stmt);
600 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
601 gcc_assert (lhs == NULL_TREE);
602 tem = unshare_expr (gimple_call_arg (stmt, 0));
603 if (with_bounds)
605 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
606 2, tem, gimple_call_arg (stmt, 1));
607 gimple_call_set_with_bounds (lenstmt, true);
609 else
610 lenstmt = gimple_build_call (fn, 1, tem);
611 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
612 gimple_call_set_lhs (lenstmt, lhs);
613 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
614 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
615 tem = gimple_call_arg (stmt, 0);
616 if (!ptrofftype_p (TREE_TYPE (lhs)))
618 lhs = convert_to_ptrofftype (lhs);
619 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
620 true, GSI_SAME_STMT);
622 lenstmt = gimple_build_assign
623 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
624 POINTER_PLUS_EXPR,tem, lhs);
625 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
626 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
627 lhs = NULL_TREE;
628 /* FALLTHRU */
629 case BUILT_IN_STRCPY:
630 case BUILT_IN_STRCPY_CHK:
631 case BUILT_IN_STRCPY_CHKP:
632 case BUILT_IN_STRCPY_CHK_CHKP:
633 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
634 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
635 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
636 else
637 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
638 if (with_bounds)
639 fn = chkp_maybe_create_clone (fn)->decl;
640 gcc_assert (lhs == NULL_TREE);
641 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
643 fprintf (dump_file, "Optimizing: ");
644 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
646 gimple_call_set_fndecl (stmt, fn);
647 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
648 gimple_call_set_lhs (stmt, lhs);
649 update_stmt (stmt);
650 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
652 fprintf (dump_file, "into: ");
653 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
655 /* FALLTHRU */
656 case BUILT_IN_STPCPY:
657 case BUILT_IN_STPCPY_CHK:
658 case BUILT_IN_STPCPY_CHKP:
659 case BUILT_IN_STPCPY_CHK_CHKP:
660 gcc_assert (lhs != NULL_TREE);
661 loc = gimple_location (stmt);
662 set_endptr_and_length (loc, si, lhs);
663 for (strinfo *chainsi = verify_related_strinfos (si);
664 chainsi != NULL;
665 chainsi = get_next_strinfo (chainsi))
666 if (chainsi->nonzero_chars == NULL)
667 set_endptr_and_length (loc, chainsi, lhs);
668 break;
669 case BUILT_IN_MALLOC:
670 break;
671 /* BUILT_IN_CALLOC always has si->nonzero_chars set. */
672 default:
673 gcc_unreachable ();
674 break;
678 return si->nonzero_chars;
681 /* Invalidate string length information for strings whose length
682 might change due to stores in stmt. */
684 static bool
685 maybe_invalidate (gimple *stmt)
687 strinfo *si;
688 unsigned int i;
689 bool nonempty = false;
691 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
692 if (si != NULL)
694 if (!si->dont_invalidate)
696 ao_ref r;
697 /* Do not use si->nonzero_chars. */
698 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
699 if (stmt_may_clobber_ref_p_1 (stmt, &r))
701 set_strinfo (i, NULL);
702 free_strinfo (si);
703 continue;
706 si->dont_invalidate = false;
707 nonempty = true;
709 return nonempty;
712 /* Unshare strinfo record SI, if it has refcount > 1 or
713 if stridx_to_strinfo vector is shared with some other
714 bbs. */
716 static strinfo *
717 unshare_strinfo (strinfo *si)
719 strinfo *nsi;
721 if (si->refcount == 1 && !strinfo_shared ())
722 return si;
724 nsi = new_strinfo (si->ptr, si->idx, si->nonzero_chars, si->full_string_p);
725 nsi->stmt = si->stmt;
726 nsi->endptr = si->endptr;
727 nsi->first = si->first;
728 nsi->prev = si->prev;
729 nsi->next = si->next;
730 nsi->writable = si->writable;
731 set_strinfo (si->idx, nsi);
732 free_strinfo (si);
733 return nsi;
736 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
737 strinfo if there is any. Return it's idx, or 0 if no strinfo has
738 been created. */
740 static int
741 get_stridx_plus_constant (strinfo *basesi, unsigned HOST_WIDE_INT off,
742 tree ptr)
744 if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
745 return 0;
747 if (compare_nonzero_chars (basesi, off) < 0
748 || !tree_fits_uhwi_p (basesi->nonzero_chars))
749 return 0;
751 unsigned HOST_WIDE_INT nonzero_chars
752 = tree_to_uhwi (basesi->nonzero_chars) - off;
753 strinfo *si = basesi, *chainsi;
754 if (si->first || si->prev || si->next)
755 si = verify_related_strinfos (basesi);
756 if (si == NULL
757 || si->nonzero_chars == NULL_TREE
758 || TREE_CODE (si->nonzero_chars) != INTEGER_CST)
759 return 0;
761 if (TREE_CODE (ptr) == SSA_NAME
762 && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
763 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
765 gcc_checking_assert (compare_tree_int (si->nonzero_chars, off) != -1);
766 for (chainsi = si; chainsi->next; chainsi = si)
768 si = get_next_strinfo (chainsi);
769 if (si == NULL
770 || si->nonzero_chars == NULL_TREE
771 || TREE_CODE (si->nonzero_chars) != INTEGER_CST)
772 break;
773 int r = compare_tree_int (si->nonzero_chars, nonzero_chars);
774 if (r != 1)
776 if (r == 0)
778 if (TREE_CODE (ptr) == SSA_NAME)
779 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
780 else
782 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
783 if (pidx != NULL && *pidx == 0)
784 *pidx = si->idx;
786 return si->idx;
788 break;
792 int idx = new_stridx (ptr);
793 if (idx == 0)
794 return 0;
795 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, nonzero_chars),
796 basesi->full_string_p);
797 set_strinfo (idx, si);
798 if (chainsi->next)
800 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
801 si->next = nextsi->idx;
802 nextsi->prev = idx;
804 chainsi = unshare_strinfo (chainsi);
805 if (chainsi->first == 0)
806 chainsi->first = chainsi->idx;
807 chainsi->next = idx;
808 if (chainsi->endptr == NULL_TREE && zero_length_string_p (si))
809 chainsi->endptr = ptr;
810 si->endptr = chainsi->endptr;
811 si->prev = chainsi->idx;
812 si->first = chainsi->first;
813 si->writable = chainsi->writable;
814 return si->idx;
817 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
818 to a zero-length string and if possible chain it to a related strinfo
819 chain whose part is or might be CHAINSI. */
821 static strinfo *
822 zero_length_string (tree ptr, strinfo *chainsi)
824 strinfo *si;
825 int idx;
826 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
827 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
828 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
829 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
831 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
832 return NULL;
833 if (chainsi != NULL)
835 si = verify_related_strinfos (chainsi);
836 if (si)
840 /* We shouldn't mix delayed and non-delayed lengths. */
841 gcc_assert (si->full_string_p);
842 if (si->endptr == NULL_TREE)
844 si = unshare_strinfo (si);
845 si->endptr = ptr;
847 chainsi = si;
848 si = get_next_strinfo (si);
850 while (si != NULL);
851 if (zero_length_string_p (chainsi))
853 if (chainsi->next)
855 chainsi = unshare_strinfo (chainsi);
856 chainsi->next = 0;
858 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
859 return chainsi;
862 else
864 /* We shouldn't mix delayed and non-delayed lengths. */
865 gcc_assert (chainsi->full_string_p);
866 if (chainsi->first || chainsi->prev || chainsi->next)
868 chainsi = unshare_strinfo (chainsi);
869 chainsi->first = 0;
870 chainsi->prev = 0;
871 chainsi->next = 0;
875 idx = new_stridx (ptr);
876 if (idx == 0)
877 return NULL;
878 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0), true);
879 set_strinfo (idx, si);
880 si->endptr = ptr;
881 if (chainsi != NULL)
883 chainsi = unshare_strinfo (chainsi);
884 if (chainsi->first == 0)
885 chainsi->first = chainsi->idx;
886 chainsi->next = idx;
887 if (chainsi->endptr == NULL_TREE)
888 chainsi->endptr = ptr;
889 si->prev = chainsi->idx;
890 si->first = chainsi->first;
891 si->writable = chainsi->writable;
893 return si;
896 /* For strinfo ORIGSI whose length has been just updated, adjust other
897 related strinfos so that they match the new ORIGSI. This involves:
899 - adding ADJ to the nonzero_chars fields
900 - copying full_string_p from the new ORIGSI. */
902 static void
903 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
905 strinfo *si = verify_related_strinfos (origsi);
907 if (si == NULL)
908 return;
910 while (1)
912 strinfo *nsi;
914 if (si != origsi)
916 tree tem;
918 si = unshare_strinfo (si);
919 /* We shouldn't see delayed lengths here; the caller must have
920 calculated the old length in order to calculate the
921 adjustment. */
922 gcc_assert (si->nonzero_chars);
923 tem = fold_convert_loc (loc, TREE_TYPE (si->nonzero_chars), adj);
924 si->nonzero_chars = fold_build2_loc (loc, PLUS_EXPR,
925 TREE_TYPE (si->nonzero_chars),
926 si->nonzero_chars, tem);
927 si->full_string_p = origsi->full_string_p;
929 si->endptr = NULL_TREE;
930 si->dont_invalidate = true;
932 nsi = get_next_strinfo (si);
933 if (nsi == NULL)
934 return;
935 si = nsi;
939 /* Find if there are other SSA_NAME pointers equal to PTR
940 for which we don't track their string lengths yet. If so, use
941 IDX for them. */
943 static void
944 find_equal_ptrs (tree ptr, int idx)
946 if (TREE_CODE (ptr) != SSA_NAME)
947 return;
948 while (1)
950 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
951 if (!is_gimple_assign (stmt))
952 return;
953 ptr = gimple_assign_rhs1 (stmt);
954 switch (gimple_assign_rhs_code (stmt))
956 case SSA_NAME:
957 break;
958 CASE_CONVERT:
959 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
960 return;
961 if (TREE_CODE (ptr) == SSA_NAME)
962 break;
963 if (TREE_CODE (ptr) != ADDR_EXPR)
964 return;
965 /* FALLTHRU */
966 case ADDR_EXPR:
968 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
969 if (pidx != NULL && *pidx == 0)
970 *pidx = idx;
971 return;
973 default:
974 return;
977 /* We might find an endptr created in this pass. Grow the
978 vector in that case. */
979 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
980 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
982 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
983 return;
984 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
988 /* Return true if STMT is a call to a builtin function with the right
989 arguments and attributes that should be considered for optimization
990 by this pass. */
992 static bool
993 valid_builtin_call (gimple *stmt)
995 if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
996 return false;
998 tree callee = gimple_call_fndecl (stmt);
999 switch (DECL_FUNCTION_CODE (callee))
1001 case BUILT_IN_MEMCMP:
1002 case BUILT_IN_MEMCMP_EQ:
1003 case BUILT_IN_STRCHR:
1004 case BUILT_IN_STRCHR_CHKP:
1005 case BUILT_IN_STRLEN:
1006 case BUILT_IN_STRLEN_CHKP:
1007 /* The above functions should be pure. Punt if they aren't. */
1008 if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
1009 return false;
1010 break;
1012 case BUILT_IN_CALLOC:
1013 case BUILT_IN_MALLOC:
1014 case BUILT_IN_MEMCPY:
1015 case BUILT_IN_MEMCPY_CHK:
1016 case BUILT_IN_MEMCPY_CHKP:
1017 case BUILT_IN_MEMCPY_CHK_CHKP:
1018 case BUILT_IN_MEMPCPY:
1019 case BUILT_IN_MEMPCPY_CHK:
1020 case BUILT_IN_MEMPCPY_CHKP:
1021 case BUILT_IN_MEMPCPY_CHK_CHKP:
1022 case BUILT_IN_MEMSET:
1023 case BUILT_IN_STPCPY:
1024 case BUILT_IN_STPCPY_CHK:
1025 case BUILT_IN_STPCPY_CHKP:
1026 case BUILT_IN_STPCPY_CHK_CHKP:
1027 case BUILT_IN_STRCAT:
1028 case BUILT_IN_STRCAT_CHK:
1029 case BUILT_IN_STRCAT_CHKP:
1030 case BUILT_IN_STRCAT_CHK_CHKP:
1031 case BUILT_IN_STRCPY:
1032 case BUILT_IN_STRCPY_CHK:
1033 case BUILT_IN_STRCPY_CHKP:
1034 case BUILT_IN_STRCPY_CHK_CHKP:
1035 /* The above functions should be neither const nor pure. Punt if they
1036 aren't. */
1037 if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
1038 return false;
1039 break;
1041 default:
1042 break;
1045 return true;
1048 /* If the last .MEM setter statement before STMT is
1049 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
1050 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
1051 just memcpy (x, y, strlen (y)). SI must be the zero length
1052 strinfo. */
1054 static void
1055 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
1057 tree vuse, callee, len;
1058 struct laststmt_struct last = laststmt;
1059 strinfo *lastsi, *firstsi;
1060 unsigned len_arg_no = 2;
1062 laststmt.stmt = NULL;
1063 laststmt.len = NULL_TREE;
1064 laststmt.stridx = 0;
1066 if (last.stmt == NULL)
1067 return;
1069 vuse = gimple_vuse (stmt);
1070 if (vuse == NULL_TREE
1071 || SSA_NAME_DEF_STMT (vuse) != last.stmt
1072 || !has_single_use (vuse))
1073 return;
1075 gcc_assert (last.stridx > 0);
1076 lastsi = get_strinfo (last.stridx);
1077 if (lastsi == NULL)
1078 return;
1080 if (lastsi != si)
1082 if (lastsi->first == 0 || lastsi->first != si->first)
1083 return;
1085 firstsi = verify_related_strinfos (si);
1086 if (firstsi == NULL)
1087 return;
1088 while (firstsi != lastsi)
1090 firstsi = get_next_strinfo (firstsi);
1091 if (firstsi == NULL)
1092 return;
1096 if (!is_strcat && !zero_length_string_p (si))
1097 return;
1099 if (is_gimple_assign (last.stmt))
1101 gimple_stmt_iterator gsi;
1103 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
1104 return;
1105 if (stmt_could_throw_p (last.stmt))
1106 return;
1107 gsi = gsi_for_stmt (last.stmt);
1108 unlink_stmt_vdef (last.stmt);
1109 release_defs (last.stmt);
1110 gsi_remove (&gsi, true);
1111 return;
1114 if (!valid_builtin_call (last.stmt))
1115 return;
1117 callee = gimple_call_fndecl (last.stmt);
1118 switch (DECL_FUNCTION_CODE (callee))
1120 case BUILT_IN_MEMCPY:
1121 case BUILT_IN_MEMCPY_CHK:
1122 break;
1123 case BUILT_IN_MEMCPY_CHKP:
1124 case BUILT_IN_MEMCPY_CHK_CHKP:
1125 len_arg_no = 4;
1126 break;
1127 default:
1128 return;
1131 len = gimple_call_arg (last.stmt, len_arg_no);
1132 if (tree_fits_uhwi_p (len))
1134 if (!tree_fits_uhwi_p (last.len)
1135 || integer_zerop (len)
1136 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1137 return;
1138 /* Don't adjust the length if it is divisible by 4, it is more efficient
1139 to store the extra '\0' in that case. */
1140 if ((tree_to_uhwi (len) & 3) == 0)
1141 return;
1143 else if (TREE_CODE (len) == SSA_NAME)
1145 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1146 if (!is_gimple_assign (def_stmt)
1147 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1148 || gimple_assign_rhs1 (def_stmt) != last.len
1149 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1150 return;
1152 else
1153 return;
1155 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1156 update_stmt (last.stmt);
1159 /* For an LHS that is an SSA_NAME and for strlen() argument SRC, set
1160 LHS range info to [0, N] if SRC refers to a character array A[N]
1161 with unknown length bounded by N. */
1163 static void
1164 maybe_set_strlen_range (tree lhs, tree src)
1166 if (TREE_CODE (lhs) != SSA_NAME)
1167 return;
1169 if (TREE_CODE (src) == SSA_NAME)
1171 gimple *def = SSA_NAME_DEF_STMT (src);
1172 if (is_gimple_assign (def)
1173 && gimple_assign_rhs_code (def) == ADDR_EXPR)
1174 src = gimple_assign_rhs1 (def);
1177 if (TREE_CODE (src) != ADDR_EXPR)
1178 return;
1180 /* The last array member of a struct can be bigger than its size
1181 suggests if it's treated as a poor-man's flexible array member. */
1182 src = TREE_OPERAND (src, 0);
1183 if (TREE_CODE (TREE_TYPE (src)) != ARRAY_TYPE
1184 || array_at_struct_end_p (src))
1185 return;
1187 tree type = TREE_TYPE (src);
1188 if (tree dom = TYPE_DOMAIN (type))
1189 if (tree maxval = TYPE_MAX_VALUE (dom))
1191 wide_int max = wi::to_wide (maxval);
1192 wide_int min = wi::zero (max.get_precision ());
1193 set_range_info (lhs, VR_RANGE, min, max);
1197 /* Handle a strlen call. If strlen of the argument is known, replace
1198 the strlen call with the known value, otherwise remember that strlen
1199 of the argument is stored in the lhs SSA_NAME. */
1201 static void
1202 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1204 int idx;
1205 tree src;
1206 gimple *stmt = gsi_stmt (*gsi);
1207 tree lhs = gimple_call_lhs (stmt);
1209 if (lhs == NULL_TREE)
1210 return;
1212 src = gimple_call_arg (stmt, 0);
1213 idx = get_stridx (src);
1214 if (idx)
1216 strinfo *si = NULL;
1217 tree rhs;
1219 if (idx < 0)
1220 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1221 else
1223 rhs = NULL_TREE;
1224 si = get_strinfo (idx);
1225 if (si != NULL)
1226 rhs = get_string_length (si);
1228 if (rhs != NULL_TREE)
1230 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1232 fprintf (dump_file, "Optimizing: ");
1233 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1235 rhs = unshare_expr (rhs);
1236 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1237 rhs = fold_convert_loc (gimple_location (stmt),
1238 TREE_TYPE (lhs), rhs);
1239 if (!update_call_from_tree (gsi, rhs))
1240 gimplify_and_update_call_from_tree (gsi, rhs);
1241 stmt = gsi_stmt (*gsi);
1242 update_stmt (stmt);
1243 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1245 fprintf (dump_file, "into: ");
1246 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1248 if (si != NULL
1249 && TREE_CODE (si->nonzero_chars) != SSA_NAME
1250 && TREE_CODE (si->nonzero_chars) != INTEGER_CST
1251 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1253 si = unshare_strinfo (si);
1254 si->nonzero_chars = lhs;
1255 gcc_assert (si->full_string_p);
1258 if (strlen_to_stridx)
1260 location_t loc = gimple_location (stmt);
1261 strlen_to_stridx->put (lhs, stridx_strlenloc (idx, loc));
1263 return;
1266 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1267 return;
1268 if (idx == 0)
1269 idx = new_stridx (src);
1270 else
1272 strinfo *si = get_strinfo (idx);
1273 if (si != NULL)
1275 if (!si->full_string_p && !si->stmt)
1277 /* Until now we only had a lower bound on the string length.
1278 Install LHS as the actual length. */
1279 si = unshare_strinfo (si);
1280 tree old = si->nonzero_chars;
1281 si->nonzero_chars = lhs;
1282 si->full_string_p = true;
1283 if (TREE_CODE (old) == INTEGER_CST)
1285 location_t loc = gimple_location (stmt);
1286 old = fold_convert_loc (loc, TREE_TYPE (lhs), old);
1287 tree adj = fold_build2_loc (loc, MINUS_EXPR,
1288 TREE_TYPE (lhs), lhs, old);
1289 adjust_related_strinfos (loc, si, adj);
1291 else
1293 si->first = 0;
1294 si->prev = 0;
1295 si->next = 0;
1298 return;
1301 if (idx)
1303 strinfo *si = new_strinfo (src, idx, lhs, true);
1304 set_strinfo (idx, si);
1305 find_equal_ptrs (src, idx);
1307 /* For SRC that is an array of N elements, set LHS's range
1308 to [0, N]. */
1309 maybe_set_strlen_range (lhs, src);
1311 if (strlen_to_stridx)
1313 location_t loc = gimple_location (stmt);
1314 strlen_to_stridx->put (lhs, stridx_strlenloc (idx, loc));
1319 /* Handle a strchr call. If strlen of the first argument is known, replace
1320 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1321 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1323 static void
1324 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1326 int idx;
1327 tree src;
1328 gimple *stmt = gsi_stmt (*gsi);
1329 tree lhs = gimple_call_lhs (stmt);
1330 bool with_bounds = gimple_call_with_bounds_p (stmt);
1332 if (lhs == NULL_TREE)
1333 return;
1335 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1336 return;
1338 src = gimple_call_arg (stmt, 0);
1339 idx = get_stridx (src);
1340 if (idx)
1342 strinfo *si = NULL;
1343 tree rhs;
1345 if (idx < 0)
1346 rhs = build_int_cst (size_type_node, ~idx);
1347 else
1349 rhs = NULL_TREE;
1350 si = get_strinfo (idx);
1351 if (si != NULL)
1352 rhs = get_string_length (si);
1354 if (rhs != NULL_TREE)
1356 location_t loc = gimple_location (stmt);
1358 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1360 fprintf (dump_file, "Optimizing: ");
1361 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1363 if (si != NULL && si->endptr != NULL_TREE)
1365 rhs = unshare_expr (si->endptr);
1366 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1367 TREE_TYPE (rhs)))
1368 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1370 else
1372 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1373 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1374 TREE_TYPE (src), src, rhs);
1375 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1376 TREE_TYPE (rhs)))
1377 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1379 if (!update_call_from_tree (gsi, rhs))
1380 gimplify_and_update_call_from_tree (gsi, rhs);
1381 stmt = gsi_stmt (*gsi);
1382 update_stmt (stmt);
1383 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1385 fprintf (dump_file, "into: ");
1386 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1388 if (si != NULL
1389 && si->endptr == NULL_TREE
1390 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1392 si = unshare_strinfo (si);
1393 si->endptr = lhs;
1395 zero_length_string (lhs, si);
1396 return;
1399 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1400 return;
1401 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1403 if (idx == 0)
1404 idx = new_stridx (src);
1405 else if (get_strinfo (idx) != NULL)
1407 zero_length_string (lhs, NULL);
1408 return;
1410 if (idx)
1412 location_t loc = gimple_location (stmt);
1413 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1414 tree srcu = fold_convert_loc (loc, size_type_node, src);
1415 tree length = fold_build2_loc (loc, MINUS_EXPR,
1416 size_type_node, lhsu, srcu);
1417 strinfo *si = new_strinfo (src, idx, length, true);
1418 si->endptr = lhs;
1419 set_strinfo (idx, si);
1420 find_equal_ptrs (src, idx);
1421 zero_length_string (lhs, si);
1424 else
1425 zero_length_string (lhs, NULL);
1428 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1429 If strlen of the second argument is known, strlen of the first argument
1430 is the same after this call. Furthermore, attempt to convert it to
1431 memcpy. */
1433 static void
1434 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1436 int idx, didx;
1437 tree src, dst, srclen, len, lhs, type, fn, oldlen;
1438 bool success;
1439 gimple *stmt = gsi_stmt (*gsi);
1440 strinfo *si, *dsi, *olddsi, *zsi;
1441 location_t loc;
1442 bool with_bounds = gimple_call_with_bounds_p (stmt);
1444 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1445 dst = gimple_call_arg (stmt, 0);
1446 lhs = gimple_call_lhs (stmt);
1447 idx = get_stridx (src);
1448 si = NULL;
1449 if (idx > 0)
1450 si = get_strinfo (idx);
1452 didx = get_stridx (dst);
1453 olddsi = NULL;
1454 oldlen = NULL_TREE;
1455 if (didx > 0)
1456 olddsi = get_strinfo (didx);
1457 else if (didx < 0)
1458 return;
1460 if (olddsi != NULL)
1461 adjust_last_stmt (olddsi, stmt, false);
1463 srclen = NULL_TREE;
1464 if (si != NULL)
1465 srclen = get_string_length (si);
1466 else if (idx < 0)
1467 srclen = build_int_cst (size_type_node, ~idx);
1469 loc = gimple_location (stmt);
1470 if (srclen == NULL_TREE)
1471 switch (bcode)
1473 case BUILT_IN_STRCPY:
1474 case BUILT_IN_STRCPY_CHK:
1475 case BUILT_IN_STRCPY_CHKP:
1476 case BUILT_IN_STRCPY_CHK_CHKP:
1477 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1478 return;
1479 break;
1480 case BUILT_IN_STPCPY:
1481 case BUILT_IN_STPCPY_CHK:
1482 case BUILT_IN_STPCPY_CHKP:
1483 case BUILT_IN_STPCPY_CHK_CHKP:
1484 if (lhs == NULL_TREE)
1485 return;
1486 else
1488 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1489 srclen = fold_convert_loc (loc, size_type_node, dst);
1490 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1491 lhsuint, srclen);
1493 break;
1494 default:
1495 gcc_unreachable ();
1498 if (didx == 0)
1500 didx = new_stridx (dst);
1501 if (didx == 0)
1502 return;
1504 if (olddsi != NULL)
1506 oldlen = olddsi->nonzero_chars;
1507 dsi = unshare_strinfo (olddsi);
1508 dsi->nonzero_chars = srclen;
1509 dsi->full_string_p = (srclen != NULL_TREE);
1510 /* Break the chain, so adjust_related_strinfo on later pointers in
1511 the chain won't adjust this one anymore. */
1512 dsi->next = 0;
1513 dsi->stmt = NULL;
1514 dsi->endptr = NULL_TREE;
1516 else
1518 dsi = new_strinfo (dst, didx, srclen, srclen != NULL_TREE);
1519 set_strinfo (didx, dsi);
1520 find_equal_ptrs (dst, didx);
1522 dsi->writable = true;
1523 dsi->dont_invalidate = true;
1525 if (dsi->nonzero_chars == NULL_TREE)
1527 strinfo *chainsi;
1529 /* If string length of src is unknown, use delayed length
1530 computation. If string lenth of dst will be needed, it
1531 can be computed by transforming this strcpy call into
1532 stpcpy and subtracting dst from the return value. */
1534 /* Look for earlier strings whose length could be determined if
1535 this strcpy is turned into an stpcpy. */
1537 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1539 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1541 /* When setting a stmt for delayed length computation
1542 prevent all strinfos through dsi from being
1543 invalidated. */
1544 chainsi = unshare_strinfo (chainsi);
1545 chainsi->stmt = stmt;
1546 chainsi->nonzero_chars = NULL_TREE;
1547 chainsi->full_string_p = false;
1548 chainsi->endptr = NULL_TREE;
1549 chainsi->dont_invalidate = true;
1552 dsi->stmt = stmt;
1554 /* Try to detect overlap before returning. This catches cases
1555 like strcpy (d, d + n) where n is non-constant whose range
1556 is such that (n <= strlen (d) holds).
1558 OLDDSI->NONZERO_chars may have been reset by this point with
1559 oldlen holding it original value. */
1560 if (olddsi && oldlen)
1562 /* Add 1 for the terminating NUL. */
1563 tree type = TREE_TYPE (oldlen);
1564 oldlen = fold_build2 (PLUS_EXPR, type, oldlen,
1565 build_int_cst (type, 1));
1566 check_bounds_or_overlap (as_a <gcall *>(stmt), olddsi->ptr, src,
1567 oldlen, NULL_TREE);
1570 return;
1573 if (olddsi != NULL)
1575 tree adj = NULL_TREE;
1576 if (oldlen == NULL_TREE)
1578 else if (integer_zerop (oldlen))
1579 adj = srclen;
1580 else if (TREE_CODE (oldlen) == INTEGER_CST
1581 || TREE_CODE (srclen) == INTEGER_CST)
1582 adj = fold_build2_loc (loc, MINUS_EXPR,
1583 TREE_TYPE (srclen), srclen,
1584 fold_convert_loc (loc, TREE_TYPE (srclen),
1585 oldlen));
1586 if (adj != NULL_TREE)
1587 adjust_related_strinfos (loc, dsi, adj);
1588 else
1589 dsi->prev = 0;
1591 /* strcpy src may not overlap dst, so src doesn't need to be
1592 invalidated either. */
1593 if (si != NULL)
1594 si->dont_invalidate = true;
1596 fn = NULL_TREE;
1597 zsi = NULL;
1598 switch (bcode)
1600 case BUILT_IN_STRCPY:
1601 case BUILT_IN_STRCPY_CHKP:
1602 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1603 if (lhs)
1604 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1605 break;
1606 case BUILT_IN_STRCPY_CHK:
1607 case BUILT_IN_STRCPY_CHK_CHKP:
1608 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1609 if (lhs)
1610 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1611 break;
1612 case BUILT_IN_STPCPY:
1613 case BUILT_IN_STPCPY_CHKP:
1614 /* This would need adjustment of the lhs (subtract one),
1615 or detection that the trailing '\0' doesn't need to be
1616 written, if it will be immediately overwritten.
1617 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1618 if (lhs)
1620 dsi->endptr = lhs;
1621 zsi = zero_length_string (lhs, dsi);
1623 break;
1624 case BUILT_IN_STPCPY_CHK:
1625 case BUILT_IN_STPCPY_CHK_CHKP:
1626 /* This would need adjustment of the lhs (subtract one),
1627 or detection that the trailing '\0' doesn't need to be
1628 written, if it will be immediately overwritten.
1629 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1630 if (lhs)
1632 dsi->endptr = lhs;
1633 zsi = zero_length_string (lhs, dsi);
1635 break;
1636 default:
1637 gcc_unreachable ();
1639 if (zsi != NULL)
1640 zsi->dont_invalidate = true;
1642 if (fn)
1644 tree args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1645 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1647 else
1648 type = size_type_node;
1650 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1651 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1653 /* Set the no-warning bit on the transformed statement? */
1654 bool set_no_warning = false;
1656 if (const strinfo *chksi = olddsi ? olddsi : dsi)
1657 if (si
1658 && !check_bounds_or_overlap (as_a <gcall *>(stmt), chksi->ptr, si->ptr,
1659 NULL_TREE, len))
1661 gimple_set_no_warning (stmt, true);
1662 set_no_warning = true;
1665 if (fn == NULL_TREE)
1666 return;
1668 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1669 GSI_SAME_STMT);
1670 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1672 fprintf (dump_file, "Optimizing: ");
1673 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1675 if (with_bounds)
1677 fn = chkp_maybe_create_clone (fn)->decl;
1678 if (gimple_call_num_args (stmt) == 4)
1679 success = update_gimple_call (gsi, fn, 5, dst,
1680 gimple_call_arg (stmt, 1),
1681 src,
1682 gimple_call_arg (stmt, 3),
1683 len);
1684 else
1685 success = update_gimple_call (gsi, fn, 6, dst,
1686 gimple_call_arg (stmt, 1),
1687 src,
1688 gimple_call_arg (stmt, 3),
1689 len,
1690 gimple_call_arg (stmt, 4));
1692 else
1693 if (gimple_call_num_args (stmt) == 2)
1694 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1695 else
1696 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1697 gimple_call_arg (stmt, 2));
1698 if (success)
1700 stmt = gsi_stmt (*gsi);
1701 gimple_call_set_with_bounds (stmt, with_bounds);
1702 update_stmt (stmt);
1703 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1705 fprintf (dump_file, "into: ");
1706 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1708 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1709 laststmt.stmt = stmt;
1710 laststmt.len = srclen;
1711 laststmt.stridx = dsi->idx;
1713 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1714 fprintf (dump_file, "not possible.\n");
1716 if (set_no_warning)
1717 gimple_set_no_warning (stmt, true);
1720 /* Check the size argument to the built-in forms of stpncpy and strncpy
1721 for out-of-bounds offsets or overlapping access, and to see if the
1722 size argument is derived from a call to strlen() on the source argument,
1723 and if so, issue an appropriate warning. */
1725 static void
1726 handle_builtin_strncat (built_in_function bcode, gimple_stmt_iterator *gsi)
1728 /* Same as stxncpy(). */
1729 handle_builtin_stxncpy (bcode, gsi);
1732 /* Return true if LEN depends on a call to strlen(SRC) in an interesting
1733 way. LEN can either be an integer expression, or a pointer (to char).
1734 When it is the latter (such as in recursive calls to self) is is
1735 assumed to be the argument in some call to strlen() whose relationship
1736 to SRC is being ascertained. */
1738 static bool
1739 is_strlen_related_p (tree src, tree len)
1741 if (TREE_CODE (TREE_TYPE (len)) == POINTER_TYPE
1742 && operand_equal_p (src, len, 0))
1743 return true;
1745 if (TREE_CODE (len) != SSA_NAME)
1746 return false;
1748 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1749 if (!def_stmt)
1750 return false;
1752 if (is_gimple_call (def_stmt))
1754 tree func = gimple_call_fndecl (def_stmt);
1755 if (!valid_builtin_call (def_stmt)
1756 || DECL_FUNCTION_CODE (func) != BUILT_IN_STRLEN)
1757 return false;
1759 tree arg = gimple_call_arg (def_stmt, 0);
1760 return is_strlen_related_p (src, arg);
1763 if (!is_gimple_assign (def_stmt))
1764 return false;
1766 tree_code code = gimple_assign_rhs_code (def_stmt);
1767 tree rhs1 = gimple_assign_rhs1 (def_stmt);
1768 tree rhstype = TREE_TYPE (rhs1);
1770 if ((TREE_CODE (rhstype) == POINTER_TYPE && code == POINTER_PLUS_EXPR)
1771 || (INTEGRAL_TYPE_P (rhstype)
1772 && (code == BIT_AND_EXPR
1773 || code == NOP_EXPR)))
1775 /* Pointer plus (an integer) and integer cast or truncation are
1776 considered among the (potentially) related expressions to strlen.
1777 Others are not. */
1778 return is_strlen_related_p (src, rhs1);
1781 return false;
1784 /* Called by handle_builtin_stxncpy and by gimple_fold_builtin_strncpy
1785 in gimple-fold.c.
1786 Check to see if the specified bound is a) equal to the size of
1787 the destination DST and if so, b) if it's immediately followed by
1788 DST[CNT - 1] = '\0'. If a) holds and b) does not, warn. Otherwise,
1789 do nothing. Return true if diagnostic has been issued.
1791 The purpose is to diagnose calls to strncpy and stpncpy that do
1792 not nul-terminate the copy while allowing for the idiom where
1793 such a call is immediately followed by setting the last element
1794 to nul, as in:
1795 char a[32];
1796 strncpy (a, s, sizeof a);
1797 a[sizeof a - 1] = '\0';
1800 bool
1801 maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
1803 gimple *stmt = gsi_stmt (gsi);
1805 wide_int cntrange[2];
1807 if (TREE_CODE (cnt) == INTEGER_CST)
1808 cntrange[0] = cntrange[1] = wi::to_wide (cnt);
1809 else if (TREE_CODE (cnt) == SSA_NAME)
1811 enum value_range_type rng = get_range_info (cnt, cntrange, cntrange + 1);
1812 if (rng == VR_RANGE)
1814 else if (rng == VR_ANTI_RANGE)
1816 wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
1818 if (wi::ltu_p (cntrange[1], maxobjsize))
1820 cntrange[0] = cntrange[1] + 1;
1821 cntrange[1] = maxobjsize;
1823 else
1825 cntrange[1] = cntrange[0] - 1;
1826 cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
1829 else
1830 return false;
1832 else
1833 return false;
1835 /* Negative value is the constant string length. If it's less than
1836 the lower bound there is no truncation. Avoid calling get_stridx()
1837 when ssa_ver_to_stridx is empty. That implies the caller isn't
1838 running under the control of this pass and ssa_ver_to_stridx hasn't
1839 been created yet. */
1840 int sidx = ssa_ver_to_stridx.length () ? get_stridx (src) : 0;
1841 if (sidx < 0 && wi::gtu_p (cntrange[0], ~sidx))
1842 return false;
1844 tree dst = gimple_call_arg (stmt, 0);
1845 tree dstdecl = dst;
1846 if (TREE_CODE (dstdecl) == ADDR_EXPR)
1847 dstdecl = TREE_OPERAND (dstdecl, 0);
1849 /* If the destination refers to a an array/pointer declared nonstring
1850 return early. */
1851 tree ref = NULL_TREE;
1852 if (get_attr_nonstring_decl (dstdecl, &ref))
1853 return false;
1855 /* Look for dst[i] = '\0'; after the stxncpy() call and if found
1856 avoid the truncation warning. */
1857 gsi_next_nondebug (&gsi);
1858 gimple *next_stmt = gsi_stmt (gsi);
1859 if (!next_stmt)
1861 /* When there is no statement in the same basic block check
1862 the immediate successor block. */
1863 if (basic_block bb = gimple_bb (stmt))
1865 if (single_succ_p (bb))
1867 /* For simplicity, ignore blocks with multiple outgoing
1868 edges for now and only consider successor blocks along
1869 normal edges. */
1870 edge e = EDGE_SUCC (bb, 0);
1871 if (!(e->flags & EDGE_ABNORMAL))
1873 gsi = gsi_start_bb (e->dest);
1874 next_stmt = gsi_stmt (gsi);
1875 if (next_stmt && is_gimple_debug (next_stmt))
1877 gsi_next_nondebug (&gsi);
1878 next_stmt = gsi_stmt (gsi);
1885 if (next_stmt && is_gimple_assign (next_stmt))
1887 tree lhs = gimple_assign_lhs (next_stmt);
1888 tree_code code = TREE_CODE (lhs);
1889 if (code == ARRAY_REF || code == MEM_REF)
1890 lhs = TREE_OPERAND (lhs, 0);
1892 tree func = gimple_call_fndecl (stmt);
1893 if (DECL_FUNCTION_CODE (func) == BUILT_IN_STPNCPY)
1895 tree ret = gimple_call_lhs (stmt);
1896 if (ret && operand_equal_p (ret, lhs, 0))
1897 return false;
1900 /* Determine the base address and offset of the reference,
1901 ignoring the innermost array index. */
1902 if (TREE_CODE (ref) == ARRAY_REF)
1903 ref = TREE_OPERAND (ref, 0);
1905 poly_int64 dstoff;
1906 tree dstbase = get_addr_base_and_unit_offset (ref, &dstoff);
1908 poly_int64 lhsoff;
1909 tree lhsbase = get_addr_base_and_unit_offset (lhs, &lhsoff);
1910 if (lhsbase
1911 && dstbase
1912 && known_eq (dstoff, lhsoff)
1913 && operand_equal_p (dstbase, lhsbase, 0))
1914 return false;
1917 int prec = TYPE_PRECISION (TREE_TYPE (cnt));
1918 wide_int lenrange[2];
1919 if (strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL)
1921 lenrange[0] = (sisrc->nonzero_chars
1922 && TREE_CODE (sisrc->nonzero_chars) == INTEGER_CST
1923 ? wi::to_wide (sisrc->nonzero_chars)
1924 : wi::zero (prec));
1925 lenrange[1] = lenrange[0];
1927 else if (sidx < 0)
1928 lenrange[0] = lenrange[1] = wi::shwi (~sidx, prec);
1929 else
1931 tree range[2];
1932 get_range_strlen (src, range);
1933 if (range[0] != NULL_TREE
1934 && TREE_CODE (range[0]) == INTEGER_CST
1935 && range[1] != NULL_TREE
1936 && TREE_CODE (range[1]) == INTEGER_CST)
1938 lenrange[0] = wi::to_wide (range[0], prec);
1939 lenrange[1] = wi::to_wide (range[1], prec);
1941 else
1943 lenrange[0] = wi::shwi (0, prec);
1944 lenrange[1] = wi::shwi (-1, prec);
1948 location_t callloc = gimple_location (stmt);
1949 tree func = gimple_call_fndecl (stmt);
1951 if (lenrange[0] != 0 || !wi::neg_p (lenrange[1]))
1953 /* If the longest source string is shorter than the lower bound
1954 of the specified count the copy is definitely nul-terminated. */
1955 if (wi::ltu_p (lenrange[1], cntrange[0]))
1956 return false;
1958 if (wi::neg_p (lenrange[1]))
1960 /* The length of one of the strings is unknown but at least
1961 one has non-zero length and that length is stored in
1962 LENRANGE[1]. Swap the bounds to force a "may be truncated"
1963 warning below. */
1964 lenrange[1] = lenrange[0];
1965 lenrange[0] = wi::shwi (0, prec);
1968 gcall *call = as_a <gcall *> (stmt);
1970 if (lenrange[0] == cntrange[1] && cntrange[0] == cntrange[1])
1971 return warning_n (callloc, OPT_Wstringop_truncation,
1972 cntrange[0].to_uhwi (),
1973 "%G%qD output truncated before terminating "
1974 "nul copying %E byte from a string of the "
1975 "same length",
1976 "%G%qD output truncated before terminating nul "
1977 "copying %E bytes from a string of the same "
1978 "length",
1979 call, func, cnt);
1980 else if (wi::geu_p (lenrange[0], cntrange[1]))
1982 /* The shortest string is longer than the upper bound of
1983 the count so the truncation is certain. */
1984 if (cntrange[0] == cntrange[1])
1985 return warning_n (callloc, OPT_Wstringop_truncation,
1986 cntrange[0].to_uhwi (),
1987 "%G%qD output truncated copying %E byte "
1988 "from a string of length %wu",
1989 "%G%qD output truncated copying %E bytes "
1990 "from a string of length %wu",
1991 call, func, cnt, lenrange[0].to_uhwi ());
1993 return warning_at (callloc, OPT_Wstringop_truncation,
1994 "%G%qD output truncated copying between %wu "
1995 "and %wu bytes from a string of length %wu",
1996 call, func, cntrange[0].to_uhwi (),
1997 cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
1999 else if (wi::geu_p (lenrange[1], cntrange[1]))
2001 /* The longest string is longer than the upper bound of
2002 the count so the truncation is possible. */
2003 if (cntrange[0] == cntrange[1])
2004 return warning_n (callloc, OPT_Wstringop_truncation,
2005 cntrange[0].to_uhwi (),
2006 "%G%qD output may be truncated copying %E "
2007 "byte from a string of length %wu",
2008 "%G%qD output may be truncated copying %E "
2009 "bytes from a string of length %wu",
2010 call, func, cnt, lenrange[1].to_uhwi ());
2012 return warning_at (callloc, OPT_Wstringop_truncation,
2013 "%G%qD output may be truncated copying between %wu "
2014 "and %wu bytes from a string of length %wu",
2015 call, func, cntrange[0].to_uhwi (),
2016 cntrange[1].to_uhwi (), lenrange[1].to_uhwi ());
2019 if (cntrange[0] != cntrange[1]
2020 && wi::leu_p (cntrange[0], lenrange[0])
2021 && wi::leu_p (cntrange[1], lenrange[0] + 1))
2023 /* If the source (including the terminating nul) is longer than
2024 the lower bound of the specified count but shorter than the
2025 upper bound the copy may (but need not) be truncated. */
2026 return warning_at (callloc, OPT_Wstringop_truncation,
2027 "%G%qD output may be truncated copying between "
2028 "%wu and %wu bytes from a string of length %wu",
2029 call, func, cntrange[0].to_uhwi (),
2030 cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
2034 if (tree dstsize = compute_objsize (dst, 1))
2036 /* The source length is uknown. Try to determine the destination
2037 size and see if it matches the specified bound. If not, bail.
2038 Otherwise go on to see if it should be diagnosed for possible
2039 truncation. */
2040 if (!dstsize)
2041 return false;
2043 if (wi::to_wide (dstsize) != cntrange[1])
2044 return false;
2046 if (cntrange[0] == cntrange[1])
2047 return warning_at (callloc, OPT_Wstringop_truncation,
2048 "%G%qD specified bound %E equals destination size",
2049 as_a <gcall *> (stmt), func, cnt);
2052 return false;
2055 /* Check the arguments to the built-in forms of stpncpy and strncpy for
2056 out-of-bounds offsets or overlapping access, and to see if the size
2057 is derived from calling strlen() on the source argument, and if so,
2058 issue the appropriate warning. */
2060 static void
2061 handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
2063 if (!strlen_to_stridx)
2064 return;
2066 gimple *stmt = gsi_stmt (*gsi);
2068 bool with_bounds = gimple_call_with_bounds_p (stmt);
2070 tree dst = gimple_call_arg (stmt, with_bounds ? 1 : 0);
2071 tree src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2072 tree len = gimple_call_arg (stmt, with_bounds ? 3 : 2);
2073 tree dstsize = NULL_TREE, srcsize = NULL_TREE;
2075 int didx = get_stridx (dst);
2076 if (strinfo *sidst = didx > 0 ? get_strinfo (didx) : NULL)
2078 /* Compute the size of the destination string including the NUL. */
2079 if (sidst->nonzero_chars)
2081 tree type = TREE_TYPE (sidst->nonzero_chars);
2082 dstsize = fold_build2 (PLUS_EXPR, type, sidst->nonzero_chars,
2083 build_int_cst (type, 1));
2085 dst = sidst->ptr;
2088 int sidx = get_stridx (src);
2089 strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL;
2090 if (sisrc)
2092 /* strncat() and strncpy() can modify the source string by writing
2093 over the terminating nul so SISRC->DONT_INVALIDATE must be left
2094 clear. */
2096 /* Compute the size of the source string including the NUL. */
2097 if (sisrc->nonzero_chars)
2099 tree type = TREE_TYPE (sisrc->nonzero_chars);
2100 srcsize = fold_build2 (PLUS_EXPR, type, sisrc->nonzero_chars,
2101 build_int_cst (type, 1));
2104 src = sisrc->ptr;
2106 else
2107 srcsize = NULL_TREE;
2109 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, src,
2110 dstsize, srcsize))
2112 gimple_set_no_warning (stmt, true);
2113 return;
2116 /* If the length argument was computed from strlen(S) for some string
2117 S retrieve the strinfo index for the string (PSS->FIRST) alonng with
2118 the location of the strlen() call (PSS->SECOND). */
2119 stridx_strlenloc *pss = strlen_to_stridx->get (len);
2120 if (!pss || pss->first <= 0)
2122 if (maybe_diag_stxncpy_trunc (*gsi, src, len))
2123 gimple_set_no_warning (stmt, true);
2125 return;
2128 /* Retrieve the strinfo data for the string S that LEN was computed
2129 from as some function F of strlen (S) (i.e., LEN need not be equal
2130 to strlen(S)). */
2131 strinfo *silen = get_strinfo (pss->first);
2133 location_t callloc = gimple_location (stmt);
2135 tree func = gimple_call_fndecl (stmt);
2137 bool warned = false;
2139 /* When -Wstringop-truncation is set, try to determine truncation
2140 before diagnosing possible overflow. Truncation is implied by
2141 the LEN argument being equal to strlen(SRC), regardless of
2142 whether its value is known. Otherwise, issue the more generic
2143 -Wstringop-overflow which triggers for LEN arguments that in
2144 any meaningful way depend on strlen(SRC). */
2145 if (sisrc == silen
2146 && is_strlen_related_p (src, len)
2147 && warning_at (callloc, OPT_Wstringop_truncation,
2148 "%G%qD output truncated before terminating nul "
2149 "copying as many bytes from a string as its length",
2150 as_a <gcall *>(stmt), func))
2151 warned = true;
2152 else if (silen && is_strlen_related_p (src, silen->ptr))
2153 warned = warning_at (callloc, OPT_Wstringop_overflow_,
2154 "%G%qD specified bound depends on the length "
2155 "of the source argument",
2156 as_a <gcall *>(stmt), func);
2157 if (warned)
2159 location_t strlenloc = pss->second;
2160 if (strlenloc != UNKNOWN_LOCATION && strlenloc != callloc)
2161 inform (strlenloc, "length computed here");
2165 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
2166 If strlen of the second argument is known and length of the third argument
2167 is that plus one, strlen of the first argument is the same after this
2168 call. */
2170 static void
2171 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2173 int idx, didx;
2174 tree src, dst, len, lhs, oldlen, newlen;
2175 gimple *stmt = gsi_stmt (*gsi);
2176 strinfo *si, *dsi, *olddsi;
2177 bool with_bounds = gimple_call_with_bounds_p (stmt);
2179 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
2180 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2181 dst = gimple_call_arg (stmt, 0);
2182 idx = get_stridx (src);
2183 if (idx == 0)
2184 return;
2186 didx = get_stridx (dst);
2187 olddsi = NULL;
2188 if (didx > 0)
2189 olddsi = get_strinfo (didx);
2190 else if (didx < 0)
2191 return;
2193 if (olddsi != NULL
2194 && tree_fits_uhwi_p (len)
2195 && !integer_zerop (len))
2196 adjust_last_stmt (olddsi, stmt, false);
2198 bool full_string_p;
2199 if (idx > 0)
2201 gimple *def_stmt;
2203 /* Handle memcpy (x, y, l) where l's relationship with strlen (y)
2204 is known. */
2205 si = get_strinfo (idx);
2206 if (si == NULL || si->nonzero_chars == NULL_TREE)
2207 return;
2208 if (TREE_CODE (len) == INTEGER_CST
2209 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
2211 if (tree_int_cst_le (len, si->nonzero_chars))
2213 /* Copying LEN nonzero characters, where LEN is constant. */
2214 newlen = len;
2215 full_string_p = false;
2217 else
2219 /* Copying the whole of the analyzed part of SI. */
2220 newlen = si->nonzero_chars;
2221 full_string_p = si->full_string_p;
2224 else
2226 if (!si->full_string_p)
2227 return;
2228 if (TREE_CODE (len) != SSA_NAME)
2229 return;
2230 def_stmt = SSA_NAME_DEF_STMT (len);
2231 if (!is_gimple_assign (def_stmt)
2232 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
2233 || gimple_assign_rhs1 (def_stmt) != si->nonzero_chars
2234 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
2235 return;
2236 /* Copying variable-length string SI (and no more). */
2237 newlen = si->nonzero_chars;
2238 full_string_p = true;
2241 else
2243 si = NULL;
2244 /* Handle memcpy (x, "abcd", 5) or
2245 memcpy (x, "abc\0uvw", 7). */
2246 if (!tree_fits_uhwi_p (len))
2247 return;
2249 unsigned HOST_WIDE_INT clen = tree_to_uhwi (len);
2250 unsigned HOST_WIDE_INT nonzero_chars = ~idx;
2251 newlen = build_int_cst (size_type_node, MIN (nonzero_chars, clen));
2252 full_string_p = clen > nonzero_chars;
2255 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
2256 adjust_last_stmt (olddsi, stmt, false);
2258 if (didx == 0)
2260 didx = new_stridx (dst);
2261 if (didx == 0)
2262 return;
2264 oldlen = NULL_TREE;
2265 if (olddsi != NULL)
2267 dsi = unshare_strinfo (olddsi);
2268 oldlen = olddsi->nonzero_chars;
2269 dsi->nonzero_chars = newlen;
2270 dsi->full_string_p = full_string_p;
2271 /* Break the chain, so adjust_related_strinfo on later pointers in
2272 the chain won't adjust this one anymore. */
2273 dsi->next = 0;
2274 dsi->stmt = NULL;
2275 dsi->endptr = NULL_TREE;
2277 else
2279 dsi = new_strinfo (dst, didx, newlen, full_string_p);
2280 set_strinfo (didx, dsi);
2281 find_equal_ptrs (dst, didx);
2283 dsi->writable = true;
2284 dsi->dont_invalidate = true;
2285 if (olddsi != NULL)
2287 tree adj = NULL_TREE;
2288 location_t loc = gimple_location (stmt);
2289 if (oldlen == NULL_TREE)
2291 else if (integer_zerop (oldlen))
2292 adj = newlen;
2293 else if (TREE_CODE (oldlen) == INTEGER_CST
2294 || TREE_CODE (newlen) == INTEGER_CST)
2295 adj = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (newlen), newlen,
2296 fold_convert_loc (loc, TREE_TYPE (newlen),
2297 oldlen));
2298 if (adj != NULL_TREE)
2299 adjust_related_strinfos (loc, dsi, adj);
2300 else
2301 dsi->prev = 0;
2303 /* memcpy src may not overlap dst, so src doesn't need to be
2304 invalidated either. */
2305 if (si != NULL)
2306 si->dont_invalidate = true;
2308 if (full_string_p)
2310 lhs = gimple_call_lhs (stmt);
2311 switch (bcode)
2313 case BUILT_IN_MEMCPY:
2314 case BUILT_IN_MEMCPY_CHK:
2315 case BUILT_IN_MEMCPY_CHKP:
2316 case BUILT_IN_MEMCPY_CHK_CHKP:
2317 /* Allow adjust_last_stmt to decrease this memcpy's size. */
2318 laststmt.stmt = stmt;
2319 laststmt.len = dsi->nonzero_chars;
2320 laststmt.stridx = dsi->idx;
2321 if (lhs)
2322 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
2323 break;
2324 case BUILT_IN_MEMPCPY:
2325 case BUILT_IN_MEMPCPY_CHK:
2326 case BUILT_IN_MEMPCPY_CHKP:
2327 case BUILT_IN_MEMPCPY_CHK_CHKP:
2328 break;
2329 default:
2330 gcc_unreachable ();
2335 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
2336 If strlen of the second argument is known, strlen of the first argument
2337 is increased by the length of the second argument. Furthermore, attempt
2338 to convert it to memcpy/strcpy if the length of the first argument
2339 is known. */
2341 static void
2342 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2344 int idx, didx;
2345 tree srclen, args, type, fn, objsz, endptr;
2346 bool success;
2347 gimple *stmt = gsi_stmt (*gsi);
2348 strinfo *si, *dsi;
2349 location_t loc = gimple_location (stmt);
2350 bool with_bounds = gimple_call_with_bounds_p (stmt);
2352 tree src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2353 tree dst = gimple_call_arg (stmt, 0);
2355 /* Bail if the source is the same as destination. It will be diagnosed
2356 elsewhere. */
2357 if (operand_equal_p (src, dst, 0))
2358 return;
2360 tree lhs = gimple_call_lhs (stmt);
2362 didx = get_stridx (dst);
2363 if (didx < 0)
2364 return;
2366 dsi = NULL;
2367 if (didx > 0)
2368 dsi = get_strinfo (didx);
2370 srclen = NULL_TREE;
2371 si = NULL;
2372 idx = get_stridx (src);
2373 if (idx < 0)
2374 srclen = build_int_cst (size_type_node, ~idx);
2375 else if (idx > 0)
2377 si = get_strinfo (idx);
2378 if (si != NULL)
2379 srclen = get_string_length (si);
2382 /* Set the no-warning bit on the transformed statement? */
2383 bool set_no_warning = false;
2385 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
2388 /* The concatenation always involves copying at least one byte
2389 (the terminating nul), even if the source string is empty.
2390 If the source is unknown assume it's one character long and
2391 used that as both sizes. */
2392 tree slen = srclen;
2393 if (slen)
2395 tree type = TREE_TYPE (slen);
2396 slen = fold_build2 (PLUS_EXPR, type, slen, build_int_cst (type, 1));
2399 tree sptr = si && si->ptr ? si->ptr : src;
2401 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, sptr,
2402 NULL_TREE, slen))
2404 gimple_set_no_warning (stmt, true);
2405 set_no_warning = true;
2409 /* strcat (p, q) can be transformed into
2410 tmp = p + strlen (p); endptr = stpcpy (tmp, q);
2411 with length endptr - p if we need to compute the length
2412 later on. Don't do this transformation if we don't need
2413 it. */
2414 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
2416 if (didx == 0)
2418 didx = new_stridx (dst);
2419 if (didx == 0)
2420 return;
2422 if (dsi == NULL)
2424 dsi = new_strinfo (dst, didx, NULL_TREE, false);
2425 set_strinfo (didx, dsi);
2426 find_equal_ptrs (dst, didx);
2428 else
2430 dsi = unshare_strinfo (dsi);
2431 dsi->nonzero_chars = NULL_TREE;
2432 dsi->full_string_p = false;
2433 dsi->next = 0;
2434 dsi->endptr = NULL_TREE;
2436 dsi->writable = true;
2437 dsi->stmt = stmt;
2438 dsi->dont_invalidate = true;
2440 return;
2443 tree dstlen = dsi->nonzero_chars;
2444 endptr = dsi->endptr;
2446 dsi = unshare_strinfo (dsi);
2447 dsi->endptr = NULL_TREE;
2448 dsi->stmt = NULL;
2449 dsi->writable = true;
2451 if (srclen != NULL_TREE)
2453 dsi->nonzero_chars = fold_build2_loc (loc, PLUS_EXPR,
2454 TREE_TYPE (dsi->nonzero_chars),
2455 dsi->nonzero_chars, srclen);
2456 gcc_assert (dsi->full_string_p);
2457 adjust_related_strinfos (loc, dsi, srclen);
2458 dsi->dont_invalidate = true;
2460 else
2462 dsi->nonzero_chars = NULL;
2463 dsi->full_string_p = false;
2464 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
2465 dsi->dont_invalidate = true;
2468 if (si != NULL)
2469 /* strcat src may not overlap dst, so src doesn't need to be
2470 invalidated either. */
2471 si->dont_invalidate = true;
2473 /* For now. Could remove the lhs from the call and add
2474 lhs = dst; afterwards. */
2475 if (lhs)
2476 return;
2478 fn = NULL_TREE;
2479 objsz = NULL_TREE;
2480 switch (bcode)
2482 case BUILT_IN_STRCAT:
2483 case BUILT_IN_STRCAT_CHKP:
2484 if (srclen != NULL_TREE)
2485 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
2486 else
2487 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
2488 break;
2489 case BUILT_IN_STRCAT_CHK:
2490 case BUILT_IN_STRCAT_CHK_CHKP:
2491 if (srclen != NULL_TREE)
2492 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
2493 else
2494 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
2495 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
2496 break;
2497 default:
2498 gcc_unreachable ();
2501 if (fn == NULL_TREE)
2502 return;
2504 if (dsi && dstlen)
2506 tree type = TREE_TYPE (dstlen);
2508 /* Compute the size of the source sequence, including the nul. */
2509 tree srcsize = srclen ? srclen : size_zero_node;
2510 srcsize = fold_build2 (PLUS_EXPR, type, srcsize, build_int_cst (type, 1));
2512 tree sptr = si && si->ptr ? si->ptr : src;
2514 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, sptr,
2515 dstlen, srcsize))
2517 gimple_set_no_warning (stmt, true);
2518 set_no_warning = true;
2522 tree len = NULL_TREE;
2523 if (srclen != NULL_TREE)
2525 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
2526 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
2528 len = fold_convert_loc (loc, type, unshare_expr (srclen));
2529 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
2530 build_int_cst (type, 1));
2531 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
2532 GSI_SAME_STMT);
2534 if (endptr)
2535 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
2536 else
2537 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
2538 TREE_TYPE (dst), unshare_expr (dst),
2539 fold_convert_loc (loc, sizetype,
2540 unshare_expr (dstlen)));
2541 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
2542 GSI_SAME_STMT);
2543 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2545 fprintf (dump_file, "Optimizing: ");
2546 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
2548 if (with_bounds)
2550 fn = chkp_maybe_create_clone (fn)->decl;
2551 if (srclen != NULL_TREE)
2552 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
2553 dst,
2554 gimple_call_arg (stmt, 1),
2555 src,
2556 gimple_call_arg (stmt, 3),
2557 len, objsz);
2558 else
2559 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
2560 dst,
2561 gimple_call_arg (stmt, 1),
2562 src,
2563 gimple_call_arg (stmt, 3),
2564 objsz);
2566 else
2567 if (srclen != NULL_TREE)
2568 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
2569 dst, src, len, objsz);
2570 else
2571 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
2572 dst, src, objsz);
2573 if (success)
2575 stmt = gsi_stmt (*gsi);
2576 gimple_call_set_with_bounds (stmt, with_bounds);
2577 update_stmt (stmt);
2578 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2580 fprintf (dump_file, "into: ");
2581 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
2583 /* If srclen == NULL, note that current string length can be
2584 computed by transforming this strcpy into stpcpy. */
2585 if (srclen == NULL_TREE && dsi->dont_invalidate)
2586 dsi->stmt = stmt;
2587 adjust_last_stmt (dsi, stmt, true);
2588 if (srclen != NULL_TREE)
2590 laststmt.stmt = stmt;
2591 laststmt.len = srclen;
2592 laststmt.stridx = dsi->idx;
2595 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2596 fprintf (dump_file, "not possible.\n");
2598 if (set_no_warning)
2599 gimple_set_no_warning (stmt, true);
2602 /* Handle a call to malloc or calloc. */
2604 static void
2605 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2607 gimple *stmt = gsi_stmt (*gsi);
2608 tree lhs = gimple_call_lhs (stmt);
2609 if (lhs == NULL_TREE)
2610 return;
2612 gcc_assert (get_stridx (lhs) == 0);
2613 int idx = new_stridx (lhs);
2614 tree length = NULL_TREE;
2615 if (bcode == BUILT_IN_CALLOC)
2616 length = build_int_cst (size_type_node, 0);
2617 strinfo *si = new_strinfo (lhs, idx, length, length != NULL_TREE);
2618 if (bcode == BUILT_IN_CALLOC)
2619 si->endptr = lhs;
2620 set_strinfo (idx, si);
2621 si->writable = true;
2622 si->stmt = stmt;
2623 si->dont_invalidate = true;
2626 /* Handle a call to memset.
2627 After a call to calloc, memset(,0,) is unnecessary.
2628 memset(malloc(n),0,n) is calloc(n,1). */
2630 static bool
2631 handle_builtin_memset (gimple_stmt_iterator *gsi)
2633 gimple *stmt2 = gsi_stmt (*gsi);
2634 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
2635 return true;
2636 tree ptr = gimple_call_arg (stmt2, 0);
2637 int idx1 = get_stridx (ptr);
2638 if (idx1 <= 0)
2639 return true;
2640 strinfo *si1 = get_strinfo (idx1);
2641 if (!si1)
2642 return true;
2643 gimple *stmt1 = si1->stmt;
2644 if (!stmt1 || !is_gimple_call (stmt1))
2645 return true;
2646 tree callee1 = gimple_call_fndecl (stmt1);
2647 if (!valid_builtin_call (stmt1))
2648 return true;
2649 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
2650 tree size = gimple_call_arg (stmt2, 2);
2651 if (code1 == BUILT_IN_CALLOC)
2652 /* Not touching stmt1 */ ;
2653 else if (code1 == BUILT_IN_MALLOC
2654 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
2656 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
2657 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
2658 size, build_one_cst (size_type_node));
2659 si1->nonzero_chars = build_int_cst (size_type_node, 0);
2660 si1->full_string_p = true;
2661 si1->stmt = gsi_stmt (gsi1);
2663 else
2664 return true;
2665 tree lhs = gimple_call_lhs (stmt2);
2666 unlink_stmt_vdef (stmt2);
2667 if (lhs)
2669 gimple *assign = gimple_build_assign (lhs, ptr);
2670 gsi_replace (gsi, assign, false);
2672 else
2674 gsi_remove (gsi, true);
2675 release_defs (stmt2);
2678 return false;
2681 /* Handle a call to memcmp. We try to handle small comparisons by
2682 converting them to load and compare, and replacing the call to memcmp
2683 with a __builtin_memcmp_eq call where possible. */
2685 static bool
2686 handle_builtin_memcmp (gimple_stmt_iterator *gsi)
2688 gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
2689 tree res = gimple_call_lhs (stmt2);
2690 tree arg1 = gimple_call_arg (stmt2, 0);
2691 tree arg2 = gimple_call_arg (stmt2, 1);
2692 tree len = gimple_call_arg (stmt2, 2);
2693 unsigned HOST_WIDE_INT leni;
2694 use_operand_p use_p;
2695 imm_use_iterator iter;
2697 if (!res)
2698 return true;
2700 FOR_EACH_IMM_USE_FAST (use_p, iter, res)
2702 gimple *ustmt = USE_STMT (use_p);
2704 if (is_gimple_debug (ustmt))
2705 continue;
2706 if (gimple_code (ustmt) == GIMPLE_ASSIGN)
2708 gassign *asgn = as_a <gassign *> (ustmt);
2709 tree_code code = gimple_assign_rhs_code (asgn);
2710 if ((code != EQ_EXPR && code != NE_EXPR)
2711 || !integer_zerop (gimple_assign_rhs2 (asgn)))
2712 return true;
2714 else if (gimple_code (ustmt) == GIMPLE_COND)
2716 tree_code code = gimple_cond_code (ustmt);
2717 if ((code != EQ_EXPR && code != NE_EXPR)
2718 || !integer_zerop (gimple_cond_rhs (ustmt)))
2719 return true;
2721 else
2722 return true;
2725 if (tree_fits_uhwi_p (len)
2726 && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
2727 && pow2p_hwi (leni))
2729 leni *= CHAR_TYPE_SIZE;
2730 unsigned align1 = get_pointer_alignment (arg1);
2731 unsigned align2 = get_pointer_alignment (arg2);
2732 unsigned align = MIN (align1, align2);
2733 scalar_int_mode mode;
2734 if (int_mode_for_size (leni, 1).exists (&mode)
2735 && (align >= leni || !targetm.slow_unaligned_access (mode, align)))
2737 location_t loc = gimple_location (stmt2);
2738 tree type, off;
2739 type = build_nonstandard_integer_type (leni, 1);
2740 gcc_assert (known_eq (GET_MODE_BITSIZE (TYPE_MODE (type)), leni));
2741 tree ptrtype = build_pointer_type_for_mode (char_type_node,
2742 ptr_mode, true);
2743 off = build_int_cst (ptrtype, 0);
2744 arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
2745 arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
2746 tree tem1 = fold_const_aggregate_ref (arg1);
2747 if (tem1)
2748 arg1 = tem1;
2749 tree tem2 = fold_const_aggregate_ref (arg2);
2750 if (tem2)
2751 arg2 = tem2;
2752 res = fold_convert_loc (loc, TREE_TYPE (res),
2753 fold_build2_loc (loc, NE_EXPR,
2754 boolean_type_node,
2755 arg1, arg2));
2756 gimplify_and_update_call_from_tree (gsi, res);
2757 return false;
2761 gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
2762 return false;
2765 /* Handle a POINTER_PLUS_EXPR statement.
2766 For p = "abcd" + 2; compute associated length, or if
2767 p = q + off is pointing to a '\0' character of a string, call
2768 zero_length_string on it. */
2770 static void
2771 handle_pointer_plus (gimple_stmt_iterator *gsi)
2773 gimple *stmt = gsi_stmt (*gsi);
2774 tree lhs = gimple_assign_lhs (stmt), off;
2775 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2776 strinfo *si, *zsi;
2778 if (idx == 0)
2779 return;
2781 if (idx < 0)
2783 tree off = gimple_assign_rhs2 (stmt);
2784 if (tree_fits_uhwi_p (off)
2785 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
2786 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
2787 = ~(~idx - (int) tree_to_uhwi (off));
2788 return;
2791 si = get_strinfo (idx);
2792 if (si == NULL || si->nonzero_chars == NULL_TREE)
2793 return;
2795 off = gimple_assign_rhs2 (stmt);
2796 zsi = NULL;
2797 if (si->full_string_p && operand_equal_p (si->nonzero_chars, off, 0))
2798 zsi = zero_length_string (lhs, si);
2799 else if (TREE_CODE (off) == SSA_NAME)
2801 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
2802 if (gimple_assign_single_p (def_stmt)
2803 && si->full_string_p
2804 && operand_equal_p (si->nonzero_chars,
2805 gimple_assign_rhs1 (def_stmt), 0))
2806 zsi = zero_length_string (lhs, si);
2808 if (zsi != NULL
2809 && si->endptr != NULL_TREE
2810 && si->endptr != lhs
2811 && TREE_CODE (si->endptr) == SSA_NAME)
2813 enum tree_code rhs_code
2814 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
2815 ? SSA_NAME : NOP_EXPR;
2816 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
2817 gcc_assert (gsi_stmt (*gsi) == stmt);
2818 update_stmt (stmt);
2822 /* If RHS, either directly or indirectly, refers to a string of constant
2823 length, return it. Otherwise return a negative value. */
2825 static HOST_WIDE_INT
2826 get_string_cst_length (tree rhs)
2828 if (TREE_CODE (rhs) == MEM_REF
2829 && integer_zerop (TREE_OPERAND (rhs, 1)))
2831 rhs = TREE_OPERAND (rhs, 0);
2832 if (TREE_CODE (rhs) == ADDR_EXPR)
2834 tree rhs_addr = rhs;
2836 rhs = TREE_OPERAND (rhs, 0);
2837 if (TREE_CODE (rhs) != STRING_CST)
2839 int idx = get_stridx (rhs_addr);
2840 if (idx > 0)
2842 strinfo *si = get_strinfo (idx);
2843 if (si
2844 && si->full_string_p
2845 && tree_fits_shwi_p (si->nonzero_chars))
2846 return tree_to_shwi (si->nonzero_chars);
2852 if (TREE_CODE (rhs) == VAR_DECL
2853 && TREE_READONLY (rhs))
2854 rhs = DECL_INITIAL (rhs);
2856 if (rhs && TREE_CODE (rhs) == STRING_CST)
2857 return strlen (TREE_STRING_POINTER (rhs));
2859 return -1;
2862 /* Handle a single character store. */
2864 static bool
2865 handle_char_store (gimple_stmt_iterator *gsi)
2867 int idx = -1;
2868 strinfo *si = NULL;
2869 gimple *stmt = gsi_stmt (*gsi);
2870 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
2871 tree rhs = gimple_assign_rhs1 (stmt);
2872 unsigned HOST_WIDE_INT offset = 0;
2874 if (TREE_CODE (lhs) == MEM_REF
2875 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
2877 tree mem_offset = TREE_OPERAND (lhs, 1);
2878 if (tree_fits_uhwi_p (mem_offset))
2880 /* Get the strinfo for the base, and use it if it starts with at
2881 least OFFSET nonzero characters. This is trivially true if
2882 OFFSET is zero. */
2883 offset = tree_to_uhwi (mem_offset);
2884 idx = get_stridx (TREE_OPERAND (lhs, 0));
2885 if (idx > 0)
2886 si = get_strinfo (idx);
2887 if (offset == 0)
2888 ssaname = TREE_OPERAND (lhs, 0);
2889 else if (si == NULL || compare_nonzero_chars (si, offset) < 0)
2890 return true;
2893 else
2895 idx = get_addr_stridx (lhs, NULL_TREE, &offset);
2896 if (idx > 0)
2897 si = get_strinfo (idx);
2900 bool storing_zero_p = initializer_zerop (rhs);
2901 bool storing_nonzero_p = (!storing_zero_p
2902 && TREE_CODE (rhs) == INTEGER_CST
2903 && integer_nonzerop (rhs));
2904 /* Set to the length of the string being assigned if known. */
2905 HOST_WIDE_INT rhslen;
2907 if (si != NULL)
2909 int cmp = compare_nonzero_chars (si, offset);
2910 gcc_assert (offset == 0 || cmp >= 0);
2911 if (storing_zero_p && cmp == 0 && si->full_string_p)
2913 /* When overwriting a '\0' with a '\0', the store can be removed
2914 if we know it has been stored in the current function. */
2915 if (!stmt_could_throw_p (stmt) && si->writable)
2917 unlink_stmt_vdef (stmt);
2918 release_defs (stmt);
2919 gsi_remove (gsi, true);
2920 return false;
2922 else
2924 si->writable = true;
2925 gsi_next (gsi);
2926 return false;
2929 /* If si->nonzero_chars > OFFSET, we aren't overwriting '\0',
2930 and if we aren't storing '\0', we know that the length of the
2931 string and any other zero terminated string in memory remains
2932 the same. In that case we move to the next gimple statement and
2933 return to signal the caller that it shouldn't invalidate anything.
2935 This is benefical for cases like:
2937 char p[20];
2938 void foo (char *q)
2940 strcpy (p, "foobar");
2941 size_t len = strlen (p); // This can be optimized into 6
2942 size_t len2 = strlen (q); // This has to be computed
2943 p[0] = 'X';
2944 size_t len3 = strlen (p); // This can be optimized into 6
2945 size_t len4 = strlen (q); // This can be optimized into len2
2946 bar (len, len2, len3, len4);
2949 else if (storing_nonzero_p && cmp > 0)
2951 gsi_next (gsi);
2952 return false;
2954 else if (storing_zero_p || storing_nonzero_p || (offset != 0 && cmp > 0))
2956 /* When storing_nonzero_p, we know that the string now starts
2957 with OFFSET + 1 nonzero characters, but don't know whether
2958 there's a following nul terminator.
2960 When storing_zero_p, we know that the string is now OFFSET
2961 characters long.
2963 Otherwise, we're storing an unknown value at offset OFFSET,
2964 so need to clip the nonzero_chars to OFFSET. */
2965 location_t loc = gimple_location (stmt);
2966 tree oldlen = si->nonzero_chars;
2967 if (cmp == 0 && si->full_string_p)
2968 /* We're overwriting the nul terminator with a nonzero or
2969 unknown character. If the previous stmt was a memcpy,
2970 its length may be decreased. */
2971 adjust_last_stmt (si, stmt, false);
2972 si = unshare_strinfo (si);
2973 if (storing_nonzero_p)
2974 si->nonzero_chars = build_int_cst (size_type_node, offset + 1);
2975 else
2976 si->nonzero_chars = build_int_cst (size_type_node, offset);
2977 si->full_string_p = storing_zero_p;
2978 if (storing_zero_p
2979 && ssaname
2980 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2981 si->endptr = ssaname;
2982 else
2983 si->endptr = NULL;
2984 si->next = 0;
2985 si->stmt = NULL;
2986 si->writable = true;
2987 si->dont_invalidate = true;
2988 if (oldlen)
2990 tree adj = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
2991 si->nonzero_chars, oldlen);
2992 adjust_related_strinfos (loc, si, adj);
2994 else
2995 si->prev = 0;
2998 else if (idx == 0 && (storing_zero_p || storing_nonzero_p))
3000 if (ssaname)
3001 idx = new_stridx (ssaname);
3002 else
3003 idx = new_addr_stridx (lhs);
3004 if (idx != 0)
3006 tree ptr = (ssaname ? ssaname : build_fold_addr_expr (lhs));
3007 tree len = storing_nonzero_p ? size_one_node : size_zero_node;
3008 si = new_strinfo (ptr, idx, len, storing_zero_p);
3009 set_strinfo (idx, si);
3010 if (storing_zero_p
3011 && ssaname
3012 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
3013 si->endptr = ssaname;
3014 si->dont_invalidate = true;
3015 si->writable = true;
3018 else if (idx == 0
3019 && (rhslen = get_string_cst_length (gimple_assign_rhs1 (stmt))) >= 0
3020 && ssaname == NULL_TREE
3021 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
3023 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
3024 if (a > 0 && (unsigned HOST_WIDE_INT) a > (unsigned HOST_WIDE_INT) rhslen)
3026 int idx = new_addr_stridx (lhs);
3027 if (idx != 0)
3029 si = new_strinfo (build_fold_addr_expr (lhs), idx,
3030 build_int_cst (size_type_node, rhslen), true);
3031 set_strinfo (idx, si);
3032 si->dont_invalidate = true;
3037 if (si != NULL && offset == 0 && storing_zero_p)
3039 /* Allow adjust_last_stmt to remove it if the stored '\0'
3040 is immediately overwritten. */
3041 laststmt.stmt = stmt;
3042 laststmt.len = build_int_cst (size_type_node, 1);
3043 laststmt.stridx = si->idx;
3045 return true;
3048 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0. */
3050 static void
3051 fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
3053 if (TREE_CODE (rhs1) != SSA_NAME
3054 || TREE_CODE (rhs2) != SSA_NAME)
3055 return;
3057 gimple *call_stmt = NULL;
3058 for (int pass = 0; pass < 2; pass++)
3060 gimple *g = SSA_NAME_DEF_STMT (rhs1);
3061 if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
3062 && has_single_use (rhs1)
3063 && gimple_call_arg (g, 0) == rhs2)
3065 call_stmt = g;
3066 break;
3068 std::swap (rhs1, rhs2);
3071 if (call_stmt)
3073 tree arg0 = gimple_call_arg (call_stmt, 0);
3075 if (arg0 == rhs2)
3077 tree arg1 = gimple_call_arg (call_stmt, 1);
3078 tree arg1_len = NULL_TREE;
3079 int idx = get_stridx (arg1);
3081 if (idx)
3083 if (idx < 0)
3084 arg1_len = build_int_cst (size_type_node, ~idx);
3085 else
3087 strinfo *si = get_strinfo (idx);
3088 if (si)
3089 arg1_len = get_string_length (si);
3093 if (arg1_len != NULL_TREE)
3095 gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
3096 tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
3098 if (!is_gimple_val (arg1_len))
3100 tree arg1_len_tmp = make_ssa_name (TREE_TYPE (arg1_len));
3101 gassign *arg1_stmt = gimple_build_assign (arg1_len_tmp,
3102 arg1_len);
3103 gsi_insert_before (&gsi, arg1_stmt, GSI_SAME_STMT);
3104 arg1_len = arg1_len_tmp;
3107 gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
3108 arg0, arg1, arg1_len);
3109 tree strncmp_lhs = make_ssa_name (integer_type_node);
3110 gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
3111 gimple_call_set_lhs (strncmp_call, strncmp_lhs);
3112 gsi_remove (&gsi, true);
3113 gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
3114 tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
3116 if (is_gimple_assign (stmt))
3118 if (gimple_assign_rhs_code (stmt) == COND_EXPR)
3120 tree cond = gimple_assign_rhs1 (stmt);
3121 TREE_OPERAND (cond, 0) = strncmp_lhs;
3122 TREE_OPERAND (cond, 1) = zero;
3124 else
3126 gimple_assign_set_rhs1 (stmt, strncmp_lhs);
3127 gimple_assign_set_rhs2 (stmt, zero);
3130 else
3132 gcond *cond = as_a<gcond *> (stmt);
3133 gimple_cond_set_lhs (cond, strncmp_lhs);
3134 gimple_cond_set_rhs (cond, zero);
3136 update_stmt (stmt);
3142 /* Attempt to check for validity of the performed access a single statement
3143 at *GSI using string length knowledge, and to optimize it.
3144 If the given basic block needs clean-up of EH, CLEANUP_EH is set to
3145 true. */
3147 static bool
3148 strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh)
3150 gimple *stmt = gsi_stmt (*gsi);
3152 if (is_gimple_call (stmt))
3154 tree callee = gimple_call_fndecl (stmt);
3155 if (valid_builtin_call (stmt))
3156 switch (DECL_FUNCTION_CODE (callee))
3158 case BUILT_IN_STRLEN:
3159 case BUILT_IN_STRLEN_CHKP:
3160 handle_builtin_strlen (gsi);
3161 break;
3162 case BUILT_IN_STRCHR:
3163 case BUILT_IN_STRCHR_CHKP:
3164 handle_builtin_strchr (gsi);
3165 break;
3166 case BUILT_IN_STRCPY:
3167 case BUILT_IN_STRCPY_CHK:
3168 case BUILT_IN_STPCPY:
3169 case BUILT_IN_STPCPY_CHK:
3170 case BUILT_IN_STRCPY_CHKP:
3171 case BUILT_IN_STRCPY_CHK_CHKP:
3172 case BUILT_IN_STPCPY_CHKP:
3173 case BUILT_IN_STPCPY_CHK_CHKP:
3174 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
3175 break;
3177 case BUILT_IN_STRNCAT:
3178 case BUILT_IN_STRNCAT_CHK:
3179 handle_builtin_strncat (DECL_FUNCTION_CODE (callee), gsi);
3180 break;
3182 case BUILT_IN_STPNCPY:
3183 case BUILT_IN_STPNCPY_CHK:
3184 case BUILT_IN_STRNCPY:
3185 case BUILT_IN_STRNCPY_CHK:
3186 handle_builtin_stxncpy (DECL_FUNCTION_CODE (callee), gsi);
3187 break;
3189 case BUILT_IN_MEMCPY:
3190 case BUILT_IN_MEMCPY_CHK:
3191 case BUILT_IN_MEMPCPY:
3192 case BUILT_IN_MEMPCPY_CHK:
3193 case BUILT_IN_MEMCPY_CHKP:
3194 case BUILT_IN_MEMCPY_CHK_CHKP:
3195 case BUILT_IN_MEMPCPY_CHKP:
3196 case BUILT_IN_MEMPCPY_CHK_CHKP:
3197 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
3198 break;
3199 case BUILT_IN_STRCAT:
3200 case BUILT_IN_STRCAT_CHK:
3201 case BUILT_IN_STRCAT_CHKP:
3202 case BUILT_IN_STRCAT_CHK_CHKP:
3203 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
3204 break;
3205 case BUILT_IN_MALLOC:
3206 case BUILT_IN_CALLOC:
3207 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
3208 break;
3209 case BUILT_IN_MEMSET:
3210 if (!handle_builtin_memset (gsi))
3211 return false;
3212 break;
3213 case BUILT_IN_MEMCMP:
3214 if (!handle_builtin_memcmp (gsi))
3215 return false;
3216 break;
3217 default:
3218 break;
3221 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
3223 tree lhs = gimple_assign_lhs (stmt);
3225 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
3227 if (gimple_assign_single_p (stmt)
3228 || (gimple_assign_cast_p (stmt)
3229 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
3231 int idx = get_stridx (gimple_assign_rhs1 (stmt));
3232 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
3234 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
3235 handle_pointer_plus (gsi);
3237 else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
3239 enum tree_code code = gimple_assign_rhs_code (stmt);
3240 if (code == COND_EXPR)
3242 tree cond = gimple_assign_rhs1 (stmt);
3243 enum tree_code cond_code = TREE_CODE (cond);
3245 if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
3246 fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
3247 TREE_OPERAND (cond, 1), stmt);
3249 else if (code == EQ_EXPR || code == NE_EXPR)
3250 fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
3251 gimple_assign_rhs2 (stmt), stmt);
3252 else if (gimple_assign_load_p (stmt)
3253 && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE
3254 && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (char_type_node)
3255 && (TYPE_PRECISION (TREE_TYPE (lhs))
3256 == TYPE_PRECISION (char_type_node))
3257 && !gimple_has_volatile_ops (stmt))
3259 tree off = integer_zero_node;
3260 unsigned HOST_WIDE_INT coff = 0;
3261 int idx = 0;
3262 tree rhs1 = gimple_assign_rhs1 (stmt);
3263 if (code == MEM_REF)
3265 idx = get_stridx (TREE_OPERAND (rhs1, 0));
3266 if (idx > 0)
3268 strinfo *si = get_strinfo (idx);
3269 if (si
3270 && si->nonzero_chars
3271 && TREE_CODE (si->nonzero_chars) == INTEGER_CST
3272 && (wi::to_widest (si->nonzero_chars)
3273 >= wi::to_widest (off)))
3274 off = TREE_OPERAND (rhs1, 1);
3275 else
3276 /* This case is not useful. See if get_addr_stridx
3277 returns something usable. */
3278 idx = 0;
3281 if (idx <= 0)
3282 idx = get_addr_stridx (rhs1, NULL_TREE, &coff);
3283 if (idx > 0)
3285 strinfo *si = get_strinfo (idx);
3286 if (si
3287 && si->nonzero_chars
3288 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
3290 widest_int w1 = wi::to_widest (si->nonzero_chars);
3291 widest_int w2 = wi::to_widest (off) + coff;
3292 if (w1 == w2
3293 && si->full_string_p)
3295 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
3297 fprintf (dump_file, "Optimizing: ");
3298 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
3301 /* Reading the final '\0' character. */
3302 tree zero = build_int_cst (TREE_TYPE (lhs), 0);
3303 gimple_set_vuse (stmt, NULL_TREE);
3304 gimple_assign_set_rhs_from_tree (gsi, zero);
3305 *cleanup_eh
3306 |= maybe_clean_or_replace_eh_stmt (stmt,
3307 gsi_stmt (*gsi));
3308 stmt = gsi_stmt (*gsi);
3309 update_stmt (stmt);
3311 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
3313 fprintf (dump_file, "into: ");
3314 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
3317 else if (w1 > w2)
3319 /* Reading a character before the final '\0'
3320 character. Just set the value range to ~[0, 0]
3321 if we don't have anything better. */
3322 wide_int min, max;
3323 tree type = TREE_TYPE (lhs);
3324 enum value_range_type vr
3325 = get_range_info (lhs, &min, &max);
3326 if (vr == VR_VARYING
3327 || (vr == VR_RANGE
3328 && min == wi::min_value (TYPE_PRECISION (type),
3329 TYPE_SIGN (type))
3330 && max == wi::max_value (TYPE_PRECISION (type),
3331 TYPE_SIGN (type))))
3332 set_range_info (lhs, VR_ANTI_RANGE,
3333 wi::zero (TYPE_PRECISION (type)),
3334 wi::zero (TYPE_PRECISION (type)));
3340 if (strlen_to_stridx)
3342 tree rhs1 = gimple_assign_rhs1 (stmt);
3343 if (stridx_strlenloc *ps = strlen_to_stridx->get (rhs1))
3344 strlen_to_stridx->put (lhs, stridx_strlenloc (*ps));
3347 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
3349 tree type = TREE_TYPE (lhs);
3350 if (TREE_CODE (type) == ARRAY_TYPE)
3351 type = TREE_TYPE (type);
3352 if (TREE_CODE (type) == INTEGER_TYPE
3353 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
3354 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
3356 if (! handle_char_store (gsi))
3357 return false;
3361 else if (gcond *cond = dyn_cast<gcond *> (stmt))
3363 enum tree_code code = gimple_cond_code (cond);
3364 if (code == EQ_EXPR || code == NE_EXPR)
3365 fold_strstr_to_strncmp (gimple_cond_lhs (stmt),
3366 gimple_cond_rhs (stmt), stmt);
3369 if (gimple_vdef (stmt))
3370 maybe_invalidate (stmt);
3371 return true;
3374 /* Recursively call maybe_invalidate on stmts that might be executed
3375 in between dombb and current bb and that contain a vdef. Stop when
3376 *count stmts are inspected, or if the whole strinfo vector has
3377 been invalidated. */
3379 static void
3380 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
3382 unsigned int i, n = gimple_phi_num_args (phi);
3384 for (i = 0; i < n; i++)
3386 tree vuse = gimple_phi_arg_def (phi, i);
3387 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
3388 basic_block bb = gimple_bb (stmt);
3389 if (bb == NULL
3390 || bb == dombb
3391 || !bitmap_set_bit (visited, bb->index)
3392 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
3393 continue;
3394 while (1)
3396 if (gimple_code (stmt) == GIMPLE_PHI)
3398 do_invalidate (dombb, stmt, visited, count);
3399 if (*count == 0)
3400 return;
3401 break;
3403 if (--*count == 0)
3404 return;
3405 if (!maybe_invalidate (stmt))
3407 *count = 0;
3408 return;
3410 vuse = gimple_vuse (stmt);
3411 stmt = SSA_NAME_DEF_STMT (vuse);
3412 if (gimple_bb (stmt) != bb)
3414 bb = gimple_bb (stmt);
3415 if (bb == NULL
3416 || bb == dombb
3417 || !bitmap_set_bit (visited, bb->index)
3418 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
3419 break;
3425 class strlen_dom_walker : public dom_walker
3427 public:
3428 strlen_dom_walker (cdi_direction direction)
3429 : dom_walker (direction), m_cleanup_cfg (false)
3432 virtual edge before_dom_children (basic_block);
3433 virtual void after_dom_children (basic_block);
3435 /* Flag that will trigger TODO_cleanup_cfg to be returned in strlen
3436 execute function. */
3437 bool m_cleanup_cfg;
3440 /* Callback for walk_dominator_tree. Attempt to optimize various
3441 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */
3443 edge
3444 strlen_dom_walker::before_dom_children (basic_block bb)
3446 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
3448 if (dombb == NULL)
3449 stridx_to_strinfo = NULL;
3450 else
3452 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
3453 if (stridx_to_strinfo)
3455 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
3456 gsi_next (&gsi))
3458 gphi *phi = gsi.phi ();
3459 if (virtual_operand_p (gimple_phi_result (phi)))
3461 bitmap visited = BITMAP_ALLOC (NULL);
3462 int count_vdef = 100;
3463 do_invalidate (dombb, phi, visited, &count_vdef);
3464 BITMAP_FREE (visited);
3465 if (count_vdef == 0)
3467 /* If there were too many vdefs in between immediate
3468 dominator and current bb, invalidate everything.
3469 If stridx_to_strinfo has been unshared, we need
3470 to free it, otherwise just set it to NULL. */
3471 if (!strinfo_shared ())
3473 unsigned int i;
3474 strinfo *si;
3476 for (i = 1;
3477 vec_safe_iterate (stridx_to_strinfo, i, &si);
3478 ++i)
3480 free_strinfo (si);
3481 (*stridx_to_strinfo)[i] = NULL;
3484 else
3485 stridx_to_strinfo = NULL;
3487 break;
3493 /* If all PHI arguments have the same string index, the PHI result
3494 has it as well. */
3495 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
3496 gsi_next (&gsi))
3498 gphi *phi = gsi.phi ();
3499 tree result = gimple_phi_result (phi);
3500 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
3502 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
3503 if (idx != 0)
3505 unsigned int i, n = gimple_phi_num_args (phi);
3506 for (i = 1; i < n; i++)
3507 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
3508 break;
3509 if (i == n)
3510 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
3515 bool cleanup_eh = false;
3517 /* Attempt to optimize individual statements. */
3518 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
3519 if (strlen_check_and_optimize_stmt (&gsi, &cleanup_eh))
3520 gsi_next (&gsi);
3522 if (cleanup_eh && gimple_purge_dead_eh_edges (bb))
3523 m_cleanup_cfg = true;
3525 bb->aux = stridx_to_strinfo;
3526 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
3527 (*stridx_to_strinfo)[0] = (strinfo *) bb;
3528 return NULL;
3531 /* Callback for walk_dominator_tree. Free strinfo vector if it is
3532 owned by the current bb, clear bb->aux. */
3534 void
3535 strlen_dom_walker::after_dom_children (basic_block bb)
3537 if (bb->aux)
3539 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
3540 if (vec_safe_length (stridx_to_strinfo)
3541 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
3543 unsigned int i;
3544 strinfo *si;
3546 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
3547 free_strinfo (si);
3548 vec_free (stridx_to_strinfo);
3550 bb->aux = NULL;
3554 /* Main entry point. */
3556 namespace {
3558 const pass_data pass_data_strlen =
3560 GIMPLE_PASS, /* type */
3561 "strlen", /* name */
3562 OPTGROUP_NONE, /* optinfo_flags */
3563 TV_TREE_STRLEN, /* tv_id */
3564 ( PROP_cfg | PROP_ssa ), /* properties_required */
3565 0, /* properties_provided */
3566 0, /* properties_destroyed */
3567 0, /* todo_flags_start */
3568 0, /* todo_flags_finish */
3571 class pass_strlen : public gimple_opt_pass
3573 public:
3574 pass_strlen (gcc::context *ctxt)
3575 : gimple_opt_pass (pass_data_strlen, ctxt)
3578 /* opt_pass methods: */
3579 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
3580 virtual unsigned int execute (function *);
3582 }; // class pass_strlen
3584 unsigned int
3585 pass_strlen::execute (function *fun)
3587 gcc_assert (!strlen_to_stridx);
3588 if (warn_stringop_overflow || warn_stringop_truncation)
3589 strlen_to_stridx = new hash_map<tree, stridx_strlenloc> ();
3591 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
3592 max_stridx = 1;
3594 calculate_dominance_info (CDI_DOMINATORS);
3596 /* String length optimization is implemented as a walk of the dominator
3597 tree and a forward walk of statements within each block. */
3598 strlen_dom_walker walker (CDI_DOMINATORS);
3599 walker.walk (fun->cfg->x_entry_block_ptr);
3601 ssa_ver_to_stridx.release ();
3602 strinfo_pool.release ();
3603 if (decl_to_stridxlist_htab)
3605 obstack_free (&stridx_obstack, NULL);
3606 delete decl_to_stridxlist_htab;
3607 decl_to_stridxlist_htab = NULL;
3609 laststmt.stmt = NULL;
3610 laststmt.len = NULL_TREE;
3611 laststmt.stridx = 0;
3613 if (strlen_to_stridx)
3615 strlen_to_stridx->empty ();
3616 delete strlen_to_stridx;
3617 strlen_to_stridx = NULL;
3620 return walker.m_cleanup_cfg ? TODO_cleanup_cfg : 0;
3623 } // anon namespace
3625 gimple_opt_pass *
3626 make_pass_strlen (gcc::context *ctxt)
3628 return new pass_strlen (ctxt);