]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/tree-ssa-strlen.c
poly_int: get_addr_base_and_unit_offset
[thirdparty/gcc.git] / gcc / tree-ssa-strlen.c
CommitLineData
8b57bfeb 1/* String length optimization
cbe34bb5 2 Copyright (C) 2011-2017 Free Software Foundation, Inc.
8b57bfeb
JJ
3 Contributed by Jakub Jelinek <jakub@redhat.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
c7131fb2 24#include "backend.h"
957060b5 25#include "rtl.h"
4d648807 26#include "tree.h"
c7131fb2 27#include "gimple.h"
957060b5
AM
28#include "alloc-pool.h"
29#include "tree-pass.h"
c7131fb2 30#include "ssa.h"
957060b5
AM
31#include "cgraph.h"
32#include "gimple-pretty-print.h"
cc8bea0a 33#include "gimple-ssa-warn-restrict.h"
40e23961 34#include "fold-const.h"
d8a2d370 35#include "stor-layout.h"
2fb9a547
AM
36#include "gimple-fold.h"
37#include "tree-eh.h"
45b0be94 38#include "gimplify.h"
5be5c238 39#include "gimple-iterator.h"
18f429e2 40#include "gimplify-me.h"
d8a2d370 41#include "expr.h"
442b4905 42#include "tree-dfa.h"
8b57bfeb 43#include "domwalk.h"
025d57f0 44#include "tree-ssa-alias.h"
8b57bfeb 45#include "tree-ssa-propagate.h"
8b57bfeb 46#include "params.h"
f5fc4a04 47#include "ipa-chkp.h"
910ee068 48#include "tree-hash-traits.h"
36b85e43 49#include "builtins.h"
e0bd6c9f 50#include "target.h"
025d57f0
MS
51#include "diagnostic-core.h"
52#include "diagnostic.h"
53#include "intl.h"
54#include "attribs.h"
6a33d0ff 55#include "calls.h"
8b57bfeb
JJ
56
57/* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
58 is an index into strinfo vector, negative value stands for
59 string length of a string literal (~strlen). */
9771b263 60static vec<int> ssa_ver_to_stridx;
8b57bfeb
JJ
61
62/* Number of currently active string indexes plus one. */
63static int max_stridx;
64
65/* String information record. */
526ceb68 66struct strinfo
8b57bfeb 67{
e3f9a279
RS
68 /* Number of leading characters that are known to be nonzero. This is
69 also the length of the string if FULL_STRING_P.
70
71 The values in a list of related string pointers must be consistent;
72 that is, if strinfo B comes X bytes after strinfo A, it must be
73 the case that A->nonzero_chars == X + B->nonzero_chars. */
74 tree nonzero_chars;
8b57bfeb
JJ
75 /* Any of the corresponding pointers for querying alias oracle. */
76 tree ptr;
862088aa
RS
77 /* This is used for two things:
78
79 - To record the statement that should be used for delayed length
80 computations. We maintain the invariant that all related strinfos
81 have delayed lengths or none do.
82
83 - To record the malloc or calloc call that produced this result. */
355fe088 84 gimple *stmt;
8b57bfeb
JJ
85 /* Pointer to '\0' if known, if NULL, it can be computed as
86 ptr + length. */
87 tree endptr;
88 /* Reference count. Any changes to strinfo entry possibly shared
89 with dominating basic blocks need unshare_strinfo first, except
90 for dont_invalidate which affects only the immediately next
91 maybe_invalidate. */
92 int refcount;
93 /* Copy of index. get_strinfo (si->idx) should return si; */
94 int idx;
95 /* These 3 fields are for chaining related string pointers together.
96 E.g. for
97 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
98 strcpy (c, d); e = c + dl;
99 strinfo(a) -> strinfo(c) -> strinfo(e)
100 All have ->first field equal to strinfo(a)->idx and are doubly
101 chained through prev/next fields. The later strinfos are required
102 to point into the same string with zero or more bytes after
103 the previous pointer and all bytes in between the two pointers
104 must be non-zero. Functions like strcpy or memcpy are supposed
105 to adjust all previous strinfo lengths, but not following strinfo
106 lengths (those are uncertain, usually invalidated during
107 maybe_invalidate, except when the alias oracle knows better).
108 Functions like strcat on the other side adjust the whole
109 related strinfo chain.
110 They are updated lazily, so to use the chain the same first fields
111 and si->prev->next == si->idx needs to be verified. */
112 int first;
113 int next;
114 int prev;
115 /* A flag whether the string is known to be written in the current
116 function. */
117 bool writable;
118 /* A flag for the next maybe_invalidate that this strinfo shouldn't
119 be invalidated. Always cleared by maybe_invalidate. */
120 bool dont_invalidate;
e3f9a279
RS
121 /* True if the string is known to be nul-terminated after NONZERO_CHARS
122 characters. False is useful when detecting strings that are built
123 up via successive memcpys. */
124 bool full_string_p;
526ceb68 125};
8b57bfeb
JJ
126
127/* Pool for allocating strinfo_struct entries. */
526ceb68 128static object_allocator<strinfo> strinfo_pool ("strinfo pool");
8b57bfeb
JJ
129
130/* Vector mapping positive string indexes to strinfo, for the
131 current basic block. The first pointer in the vector is special,
132 it is either NULL, meaning the vector isn't shared, or it is
133 a basic block pointer to the owner basic_block if shared.
134 If some other bb wants to modify the vector, the vector needs
135 to be unshared first, and only the owner bb is supposed to free it. */
526ceb68 136static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
8b57bfeb
JJ
137
138/* One OFFSET->IDX mapping. */
139struct stridxlist
140{
141 struct stridxlist *next;
142 HOST_WIDE_INT offset;
143 int idx;
144};
145
146/* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
147struct decl_stridxlist_map
148{
149 struct tree_map_base base;
150 struct stridxlist list;
151};
152
153/* Hash table for mapping decls to a chained list of offset -> idx
154 mappings. */
fb5c464a 155static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
8b57bfeb 156
6a33d0ff
MS
157/* Hash table mapping strlen calls to stridx instances describing
158 the calls' arguments. Non-null only when warn_stringop_truncation
159 is non-zero. */
025d57f0 160typedef std::pair<int, location_t> stridx_strlenloc;
6a33d0ff 161static hash_map<tree, stridx_strlenloc> *strlen_to_stridx;
025d57f0 162
8b57bfeb
JJ
163/* Obstack for struct stridxlist and struct decl_stridxlist_map. */
164static struct obstack stridx_obstack;
165
166/* Last memcpy statement if it could be adjusted if the trailing
167 '\0' written is immediately overwritten, or
168 *x = '\0' store that could be removed if it is immediately overwritten. */
169struct laststmt_struct
170{
355fe088 171 gimple *stmt;
8b57bfeb
JJ
172 tree len;
173 int stridx;
174} laststmt;
175
e3f9a279 176static int get_stridx_plus_constant (strinfo *, unsigned HOST_WIDE_INT, tree);
cc8bea0a 177static void handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *);
e3f9a279
RS
178
179/* Return:
180
181 - 1 if SI is known to start with more than OFF nonzero characters.
182
183 - 0 if SI is known to start with OFF nonzero characters,
184 but is not known to start with more.
185
186 - -1 if SI might not start with OFF nonzero characters. */
187
188static inline int
189compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off)
190{
191 if (si->nonzero_chars
192 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
193 return compare_tree_int (si->nonzero_chars, off);
194 else
195 return -1;
196}
197
198/* Return true if SI is known to be a zero-length string. */
199
200static inline bool
201zero_length_string_p (strinfo *si)
202{
203 return si->full_string_p && integer_zerop (si->nonzero_chars);
204}
204a913b
JJ
205
206/* Return strinfo vector entry IDX. */
207
526ceb68 208static inline strinfo *
204a913b
JJ
209get_strinfo (int idx)
210{
211 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
212 return NULL;
213 return (*stridx_to_strinfo)[idx];
214}
215
bde63fde
RS
216/* Get the next strinfo in the chain after SI, or null if none. */
217
218static inline strinfo *
219get_next_strinfo (strinfo *si)
220{
221 if (si->next == 0)
222 return NULL;
223 strinfo *nextsi = get_strinfo (si->next);
224 if (nextsi == NULL || nextsi->first != si->first || nextsi->prev != si->idx)
225 return NULL;
226 return nextsi;
227}
228
e3f9a279
RS
229/* Helper function for get_stridx. Return the strinfo index of the address
230 of EXP, which is available in PTR if nonnull. If OFFSET_OUT, it is
231 OK to return the index for some X <= &EXP and store &EXP - X in
232 *OFFSET_OUT. */
8b57bfeb
JJ
233
234static int
e3f9a279 235get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out)
8b57bfeb
JJ
236{
237 HOST_WIDE_INT off;
5f3cd7c3 238 struct stridxlist *list, *last = NULL;
8b57bfeb
JJ
239 tree base;
240
c203e8a7 241 if (!decl_to_stridxlist_htab)
8b57bfeb
JJ
242 return 0;
243
a90c8804
RS
244 poly_int64 poff;
245 base = get_addr_base_and_unit_offset (exp, &poff);
246 if (base == NULL || !DECL_P (base) || !poff.is_constant (&off))
8b57bfeb
JJ
247 return 0;
248
1eb68d2d
TS
249 list = decl_to_stridxlist_htab->get (base);
250 if (list == NULL)
8b57bfeb
JJ
251 return 0;
252
8b57bfeb
JJ
253 do
254 {
255 if (list->offset == off)
e3f9a279
RS
256 {
257 if (offset_out)
258 *offset_out = 0;
259 return list->idx;
260 }
5f3cd7c3
JJ
261 if (list->offset > off)
262 return 0;
263 last = list;
8b57bfeb
JJ
264 list = list->next;
265 }
266 while (list);
5f3cd7c3 267
e3f9a279 268 if ((offset_out || ptr) && last && last->idx > 0)
5f3cd7c3 269 {
e3f9a279
RS
270 unsigned HOST_WIDE_INT rel_off
271 = (unsigned HOST_WIDE_INT) off - last->offset;
5f3cd7c3 272 strinfo *si = get_strinfo (last->idx);
e3f9a279
RS
273 if (si && compare_nonzero_chars (si, rel_off) >= 0)
274 {
275 if (offset_out)
276 {
277 *offset_out = rel_off;
278 return last->idx;
279 }
280 else
281 return get_stridx_plus_constant (si, rel_off, ptr);
282 }
5f3cd7c3 283 }
8b57bfeb
JJ
284 return 0;
285}
286
287/* Return string index for EXP. */
288
289static int
290get_stridx (tree exp)
291{
b3c3685a 292 tree s, o;
8b57bfeb
JJ
293
294 if (TREE_CODE (exp) == SSA_NAME)
204a913b
JJ
295 {
296 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
297 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
298 int i;
299 tree e = exp;
300 HOST_WIDE_INT off = 0;
301 for (i = 0; i < 5; i++)
302 {
355fe088 303 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
204a913b
JJ
304 if (!is_gimple_assign (def_stmt)
305 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
306 return 0;
307 tree rhs1 = gimple_assign_rhs1 (def_stmt);
308 tree rhs2 = gimple_assign_rhs2 (def_stmt);
309 if (TREE_CODE (rhs1) != SSA_NAME
310 || !tree_fits_shwi_p (rhs2))
311 return 0;
312 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
313 if (this_off < 0)
314 return 0;
315 off = (unsigned HOST_WIDE_INT) off + this_off;
316 if (off < 0)
317 return 0;
318 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
319 {
526ceb68 320 strinfo *si
204a913b 321 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
e3f9a279 322 if (si && compare_nonzero_chars (si, off) >= 0)
204a913b
JJ
323 return get_stridx_plus_constant (si, off, exp);
324 }
325 e = rhs1;
326 }
327 return 0;
328 }
8b57bfeb
JJ
329
330 if (TREE_CODE (exp) == ADDR_EXPR)
331 {
e3f9a279 332 int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp, NULL);
8b57bfeb
JJ
333 if (idx != 0)
334 return idx;
335 }
336
b3c3685a
JJ
337 s = string_constant (exp, &o);
338 if (s != NULL_TREE
9541ffee 339 && (o == NULL_TREE || tree_fits_shwi_p (o))
b3c3685a 340 && TREE_STRING_LENGTH (s) > 0)
8b57bfeb 341 {
9439e9a1 342 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
b3c3685a
JJ
343 const char *p = TREE_STRING_POINTER (s);
344 int max = TREE_STRING_LENGTH (s) - 1;
345
346 if (p[max] == '\0' && offset >= 0 && offset <= max)
347 return ~(int) strlen (p + offset);
8b57bfeb
JJ
348 }
349 return 0;
350}
351
352/* Return true if strinfo vector is shared with the immediate dominator. */
353
354static inline bool
355strinfo_shared (void)
356{
9771b263
DN
357 return vec_safe_length (stridx_to_strinfo)
358 && (*stridx_to_strinfo)[0] != NULL;
8b57bfeb
JJ
359}
360
361/* Unshare strinfo vector that is shared with the immediate dominator. */
362
363static void
364unshare_strinfo_vec (void)
365{
526ceb68 366 strinfo *si;
8b57bfeb
JJ
367 unsigned int i = 0;
368
369 gcc_assert (strinfo_shared ());
9771b263
DN
370 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
371 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
8b57bfeb
JJ
372 if (si != NULL)
373 si->refcount++;
9771b263 374 (*stridx_to_strinfo)[0] = NULL;
8b57bfeb
JJ
375}
376
377/* Attempt to create a string index for exp, ADDR_EXPR's operand.
378 Return a pointer to the location where the string index can
379 be stored (if 0) or is stored, or NULL if this can't be tracked. */
380
381static int *
382addr_stridxptr (tree exp)
383{
8b57bfeb
JJ
384 HOST_WIDE_INT off;
385
a90c8804
RS
386 poly_int64 poff;
387 tree base = get_addr_base_and_unit_offset (exp, &poff);
388 if (base == NULL_TREE || !DECL_P (base) || !poff.is_constant (&off))
8b57bfeb
JJ
389 return NULL;
390
c203e8a7 391 if (!decl_to_stridxlist_htab)
8b57bfeb 392 {
1eb68d2d 393 decl_to_stridxlist_htab
fb5c464a 394 = new hash_map<tree_decl_hash, stridxlist> (64);
8b57bfeb
JJ
395 gcc_obstack_init (&stridx_obstack);
396 }
1eb68d2d
TS
397
398 bool existed;
399 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
400 if (existed)
8b57bfeb
JJ
401 {
402 int i;
5f3cd7c3
JJ
403 stridxlist *before = NULL;
404 for (i = 0; i < 32; i++)
8b57bfeb
JJ
405 {
406 if (list->offset == off)
407 return &list->idx;
5f3cd7c3
JJ
408 if (list->offset > off && before == NULL)
409 before = list;
8b57bfeb
JJ
410 if (list->next == NULL)
411 break;
5f3cd7c3 412 list = list->next;
8b57bfeb 413 }
5f3cd7c3 414 if (i == 32)
8b57bfeb 415 return NULL;
5f3cd7c3
JJ
416 if (before)
417 {
418 list = before;
419 before = XOBNEW (&stridx_obstack, struct stridxlist);
420 *before = *list;
421 list->next = before;
422 list->offset = off;
423 list->idx = 0;
424 return &list->idx;
425 }
8b57bfeb
JJ
426 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
427 list = list->next;
428 }
1eb68d2d 429
8b57bfeb
JJ
430 list->next = NULL;
431 list->offset = off;
432 list->idx = 0;
433 return &list->idx;
434}
435
436/* Create a new string index, or return 0 if reached limit. */
437
438static int
439new_stridx (tree exp)
440{
441 int idx;
442 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
443 return 0;
444 if (TREE_CODE (exp) == SSA_NAME)
445 {
446 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
447 return 0;
448 idx = max_stridx++;
9771b263 449 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
8b57bfeb
JJ
450 return idx;
451 }
452 if (TREE_CODE (exp) == ADDR_EXPR)
453 {
454 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
455 if (pidx != NULL)
456 {
457 gcc_assert (*pidx == 0);
458 *pidx = max_stridx++;
459 return *pidx;
460 }
461 }
462 return 0;
463}
464
465/* Like new_stridx, but for ADDR_EXPR's operand instead. */
466
467static int
468new_addr_stridx (tree exp)
469{
470 int *pidx;
471 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
472 return 0;
473 pidx = addr_stridxptr (exp);
474 if (pidx != NULL)
475 {
476 gcc_assert (*pidx == 0);
477 *pidx = max_stridx++;
478 return *pidx;
479 }
480 return 0;
481}
482
483/* Create a new strinfo. */
484
526ceb68 485static strinfo *
e3f9a279 486new_strinfo (tree ptr, int idx, tree nonzero_chars, bool full_string_p)
8b57bfeb 487{
526ceb68 488 strinfo *si = strinfo_pool.allocate ();
e3f9a279 489 si->nonzero_chars = nonzero_chars;
8b57bfeb
JJ
490 si->ptr = ptr;
491 si->stmt = NULL;
492 si->endptr = NULL_TREE;
493 si->refcount = 1;
494 si->idx = idx;
495 si->first = 0;
496 si->prev = 0;
497 si->next = 0;
498 si->writable = false;
499 si->dont_invalidate = false;
e3f9a279 500 si->full_string_p = full_string_p;
8b57bfeb
JJ
501 return si;
502}
503
504/* Decrease strinfo refcount and free it if not referenced anymore. */
505
506static inline void
526ceb68 507free_strinfo (strinfo *si)
8b57bfeb
JJ
508{
509 if (si && --si->refcount == 0)
33e7d32e 510 strinfo_pool.remove (si);
8b57bfeb
JJ
511}
512
8b57bfeb
JJ
513/* Set strinfo in the vector entry IDX to SI. */
514
515static inline void
526ceb68 516set_strinfo (int idx, strinfo *si)
8b57bfeb 517{
9771b263 518 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
8b57bfeb 519 unshare_strinfo_vec ();
9771b263
DN
520 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
521 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
522 (*stridx_to_strinfo)[idx] = si;
8b57bfeb
JJ
523}
524
862088aa
RS
525/* Return the first strinfo in the related strinfo chain
526 if all strinfos in between belong to the chain, otherwise NULL. */
527
528static strinfo *
529verify_related_strinfos (strinfo *origsi)
530{
531 strinfo *si = origsi, *psi;
532
533 if (origsi->first == 0)
534 return NULL;
535 for (; si->prev; si = psi)
536 {
537 if (si->first != origsi->first)
538 return NULL;
539 psi = get_strinfo (si->prev);
540 if (psi == NULL)
541 return NULL;
542 if (psi->next != si->idx)
543 return NULL;
544 }
545 if (si->idx != si->first)
546 return NULL;
547 return si;
548}
549
550/* Set SI's endptr to ENDPTR and compute its length based on SI->ptr.
551 Use LOC for folding. */
552
553static void
554set_endptr_and_length (location_t loc, strinfo *si, tree endptr)
555{
556 si->endptr = endptr;
557 si->stmt = NULL;
558 tree start_as_size = fold_convert_loc (loc, size_type_node, si->ptr);
559 tree end_as_size = fold_convert_loc (loc, size_type_node, endptr);
e3f9a279
RS
560 si->nonzero_chars = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
561 end_as_size, start_as_size);
562 si->full_string_p = true;
862088aa
RS
563}
564
8b57bfeb
JJ
565/* Return string length, or NULL if it can't be computed. */
566
567static tree
526ceb68 568get_string_length (strinfo *si)
8b57bfeb 569{
e3f9a279
RS
570 if (si->nonzero_chars)
571 return si->full_string_p ? si->nonzero_chars : NULL;
8b57bfeb
JJ
572
573 if (si->stmt)
574 {
355fe088 575 gimple *stmt = si->stmt, *lenstmt;
f5fc4a04 576 bool with_bounds = gimple_call_with_bounds_p (stmt);
83d5977e 577 tree callee, lhs, fn, tem;
8b57bfeb
JJ
578 location_t loc;
579 gimple_stmt_iterator gsi;
580
581 gcc_assert (is_gimple_call (stmt));
582 callee = gimple_call_fndecl (stmt);
583 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
584 lhs = gimple_call_lhs (stmt);
8b57bfeb
JJ
585 /* unshare_strinfo is intentionally not called here. The (delayed)
586 transformation of strcpy or strcat into stpcpy is done at the place
587 of the former strcpy/strcat call and so can affect all the strinfos
588 with the same stmt. If they were unshared before and transformation
589 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
590 just compute the right length. */
591 switch (DECL_FUNCTION_CODE (callee))
592 {
593 case BUILT_IN_STRCAT:
594 case BUILT_IN_STRCAT_CHK:
f5fc4a04
IE
595 case BUILT_IN_STRCAT_CHKP:
596 case BUILT_IN_STRCAT_CHK_CHKP:
8b57bfeb 597 gsi = gsi_for_stmt (stmt);
e79983f4 598 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
8b57bfeb 599 gcc_assert (lhs == NULL_TREE);
8b57bfeb 600 tem = unshare_expr (gimple_call_arg (stmt, 0));
f5fc4a04
IE
601 if (with_bounds)
602 {
603 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
604 2, tem, gimple_call_arg (stmt, 1));
605 gimple_call_set_with_bounds (lenstmt, true);
606 }
607 else
608 lenstmt = gimple_build_call (fn, 1, tem);
83d5977e 609 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
8b57bfeb
JJ
610 gimple_call_set_lhs (lenstmt, lhs);
611 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
612 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
8b57bfeb 613 tem = gimple_call_arg (stmt, 0);
33960e2e
TG
614 if (!ptrofftype_p (TREE_TYPE (lhs)))
615 {
616 lhs = convert_to_ptrofftype (lhs);
617 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
618 true, GSI_SAME_STMT);
619 }
0d0e4a03
JJ
620 lenstmt = gimple_build_assign
621 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
622 POINTER_PLUS_EXPR,tem, lhs);
8b57bfeb
JJ
623 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
624 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
625 lhs = NULL_TREE;
626 /* FALLTHRU */
627 case BUILT_IN_STRCPY:
628 case BUILT_IN_STRCPY_CHK:
f5fc4a04
IE
629 case BUILT_IN_STRCPY_CHKP:
630 case BUILT_IN_STRCPY_CHK_CHKP:
1e762c6a 631 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
f5fc4a04 632 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
e79983f4 633 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
8b57bfeb 634 else
e79983f4 635 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
f5fc4a04
IE
636 if (with_bounds)
637 fn = chkp_maybe_create_clone (fn)->decl;
8b57bfeb
JJ
638 gcc_assert (lhs == NULL_TREE);
639 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
640 {
641 fprintf (dump_file, "Optimizing: ");
642 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
643 }
644 gimple_call_set_fndecl (stmt, fn);
83d5977e 645 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
8b57bfeb
JJ
646 gimple_call_set_lhs (stmt, lhs);
647 update_stmt (stmt);
648 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
649 {
650 fprintf (dump_file, "into: ");
651 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
652 }
653 /* FALLTHRU */
654 case BUILT_IN_STPCPY:
655 case BUILT_IN_STPCPY_CHK:
f5fc4a04
IE
656 case BUILT_IN_STPCPY_CHKP:
657 case BUILT_IN_STPCPY_CHK_CHKP:
8b57bfeb
JJ
658 gcc_assert (lhs != NULL_TREE);
659 loc = gimple_location (stmt);
862088aa
RS
660 set_endptr_and_length (loc, si, lhs);
661 for (strinfo *chainsi = verify_related_strinfos (si);
662 chainsi != NULL;
663 chainsi = get_next_strinfo (chainsi))
e3f9a279 664 if (chainsi->nonzero_chars == NULL)
862088aa 665 set_endptr_and_length (loc, chainsi, lhs);
8b57bfeb 666 break;
24314386
MG
667 case BUILT_IN_MALLOC:
668 break;
e3f9a279 669 /* BUILT_IN_CALLOC always has si->nonzero_chars set. */
8b57bfeb
JJ
670 default:
671 gcc_unreachable ();
672 break;
673 }
674 }
675
e3f9a279 676 return si->nonzero_chars;
8b57bfeb
JJ
677}
678
679/* Invalidate string length information for strings whose length
680 might change due to stores in stmt. */
681
682static bool
355fe088 683maybe_invalidate (gimple *stmt)
8b57bfeb 684{
526ceb68 685 strinfo *si;
8b57bfeb
JJ
686 unsigned int i;
687 bool nonempty = false;
688
9771b263 689 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
8b57bfeb
JJ
690 if (si != NULL)
691 {
692 if (!si->dont_invalidate)
693 {
694 ao_ref r;
e3f9a279 695 /* Do not use si->nonzero_chars. */
8b57bfeb
JJ
696 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
697 if (stmt_may_clobber_ref_p_1 (stmt, &r))
698 {
699 set_strinfo (i, NULL);
700 free_strinfo (si);
701 continue;
702 }
703 }
704 si->dont_invalidate = false;
705 nonempty = true;
706 }
707 return nonempty;
708}
709
204a913b 710/* Unshare strinfo record SI, if it has refcount > 1 or
8b57bfeb
JJ
711 if stridx_to_strinfo vector is shared with some other
712 bbs. */
713
526ceb68
TS
714static strinfo *
715unshare_strinfo (strinfo *si)
8b57bfeb 716{
526ceb68 717 strinfo *nsi;
8b57bfeb
JJ
718
719 if (si->refcount == 1 && !strinfo_shared ())
720 return si;
721
e3f9a279 722 nsi = new_strinfo (si->ptr, si->idx, si->nonzero_chars, si->full_string_p);
8b57bfeb
JJ
723 nsi->stmt = si->stmt;
724 nsi->endptr = si->endptr;
725 nsi->first = si->first;
726 nsi->prev = si->prev;
727 nsi->next = si->next;
728 nsi->writable = si->writable;
729 set_strinfo (si->idx, nsi);
730 free_strinfo (si);
731 return nsi;
732}
733
204a913b
JJ
734/* Attempt to create a new strinfo for BASESI + OFF, or find existing
735 strinfo if there is any. Return it's idx, or 0 if no strinfo has
736 been created. */
737
738static int
e3f9a279
RS
739get_stridx_plus_constant (strinfo *basesi, unsigned HOST_WIDE_INT off,
740 tree ptr)
204a913b 741{
5f3cd7c3 742 if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
204a913b
JJ
743 return 0;
744
e3f9a279
RS
745 if (compare_nonzero_chars (basesi, off) < 0
746 || !tree_fits_uhwi_p (basesi->nonzero_chars))
204a913b
JJ
747 return 0;
748
e3f9a279
RS
749 unsigned HOST_WIDE_INT nonzero_chars
750 = tree_to_uhwi (basesi->nonzero_chars) - off;
526ceb68 751 strinfo *si = basesi, *chainsi;
204a913b
JJ
752 if (si->first || si->prev || si->next)
753 si = verify_related_strinfos (basesi);
754 if (si == NULL
e3f9a279
RS
755 || si->nonzero_chars == NULL_TREE
756 || TREE_CODE (si->nonzero_chars) != INTEGER_CST)
204a913b
JJ
757 return 0;
758
5f3cd7c3
JJ
759 if (TREE_CODE (ptr) == SSA_NAME
760 && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
204a913b
JJ
761 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
762
e3f9a279 763 gcc_checking_assert (compare_tree_int (si->nonzero_chars, off) != -1);
204a913b
JJ
764 for (chainsi = si; chainsi->next; chainsi = si)
765 {
bde63fde 766 si = get_next_strinfo (chainsi);
204a913b 767 if (si == NULL
e3f9a279
RS
768 || si->nonzero_chars == NULL_TREE
769 || TREE_CODE (si->nonzero_chars) != INTEGER_CST)
204a913b 770 break;
e3f9a279 771 int r = compare_tree_int (si->nonzero_chars, nonzero_chars);
204a913b
JJ
772 if (r != 1)
773 {
774 if (r == 0)
775 {
55a0f21a
JJ
776 if (TREE_CODE (ptr) == SSA_NAME)
777 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
778 else
779 {
780 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
781 if (pidx != NULL && *pidx == 0)
782 *pidx = si->idx;
783 }
204a913b
JJ
784 return si->idx;
785 }
786 break;
787 }
788 }
789
790 int idx = new_stridx (ptr);
791 if (idx == 0)
792 return 0;
e3f9a279
RS
793 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, nonzero_chars),
794 basesi->full_string_p);
204a913b
JJ
795 set_strinfo (idx, si);
796 if (chainsi->next)
797 {
526ceb68 798 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
204a913b
JJ
799 si->next = nextsi->idx;
800 nextsi->prev = idx;
801 }
802 chainsi = unshare_strinfo (chainsi);
803 if (chainsi->first == 0)
804 chainsi->first = chainsi->idx;
805 chainsi->next = idx;
e3f9a279 806 if (chainsi->endptr == NULL_TREE && zero_length_string_p (si))
204a913b
JJ
807 chainsi->endptr = ptr;
808 si->endptr = chainsi->endptr;
809 si->prev = chainsi->idx;
810 si->first = chainsi->first;
811 si->writable = chainsi->writable;
812 return si->idx;
813}
814
8b57bfeb
JJ
815/* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
816 to a zero-length string and if possible chain it to a related strinfo
817 chain whose part is or might be CHAINSI. */
818
526ceb68
TS
819static strinfo *
820zero_length_string (tree ptr, strinfo *chainsi)
8b57bfeb 821{
526ceb68 822 strinfo *si;
8b57bfeb 823 int idx;
204a913b
JJ
824 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
825 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
8b57bfeb 826 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
204a913b 827 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
8b57bfeb
JJ
828
829 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
830 return NULL;
831 if (chainsi != NULL)
832 {
833 si = verify_related_strinfos (chainsi);
834 if (si)
835 {
bde63fde 836 do
8b57bfeb 837 {
862088aa 838 /* We shouldn't mix delayed and non-delayed lengths. */
e3f9a279 839 gcc_assert (si->full_string_p);
bde63fde 840 if (si->endptr == NULL_TREE)
8b57bfeb 841 {
bde63fde
RS
842 si = unshare_strinfo (si);
843 si->endptr = ptr;
8b57bfeb 844 }
bde63fde
RS
845 chainsi = si;
846 si = get_next_strinfo (si);
8b57bfeb 847 }
bde63fde 848 while (si != NULL);
e3f9a279 849 if (zero_length_string_p (chainsi))
8b57bfeb
JJ
850 {
851 if (chainsi->next)
852 {
853 chainsi = unshare_strinfo (chainsi);
854 chainsi->next = 0;
855 }
9771b263 856 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
8b57bfeb
JJ
857 return chainsi;
858 }
859 }
862088aa 860 else
8b57bfeb 861 {
862088aa 862 /* We shouldn't mix delayed and non-delayed lengths. */
e3f9a279 863 gcc_assert (chainsi->full_string_p);
862088aa
RS
864 if (chainsi->first || chainsi->prev || chainsi->next)
865 {
866 chainsi = unshare_strinfo (chainsi);
867 chainsi->first = 0;
868 chainsi->prev = 0;
869 chainsi->next = 0;
870 }
8b57bfeb
JJ
871 }
872 }
873 idx = new_stridx (ptr);
874 if (idx == 0)
875 return NULL;
e3f9a279 876 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0), true);
8b57bfeb
JJ
877 set_strinfo (idx, si);
878 si->endptr = ptr;
879 if (chainsi != NULL)
880 {
881 chainsi = unshare_strinfo (chainsi);
882 if (chainsi->first == 0)
883 chainsi->first = chainsi->idx;
884 chainsi->next = idx;
93a90db6
AK
885 if (chainsi->endptr == NULL_TREE)
886 chainsi->endptr = ptr;
8b57bfeb
JJ
887 si->prev = chainsi->idx;
888 si->first = chainsi->first;
889 si->writable = chainsi->writable;
890 }
891 return si;
892}
893
e3f9a279
RS
894/* For strinfo ORIGSI whose length has been just updated, adjust other
895 related strinfos so that they match the new ORIGSI. This involves:
896
897 - adding ADJ to the nonzero_chars fields
898 - copying full_string_p from the new ORIGSI. */
8b57bfeb
JJ
899
900static void
526ceb68 901adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
8b57bfeb 902{
526ceb68 903 strinfo *si = verify_related_strinfos (origsi);
8b57bfeb
JJ
904
905 if (si == NULL)
906 return;
907
908 while (1)
909 {
526ceb68 910 strinfo *nsi;
8b57bfeb
JJ
911
912 if (si != origsi)
913 {
914 tree tem;
915
916 si = unshare_strinfo (si);
862088aa
RS
917 /* We shouldn't see delayed lengths here; the caller must have
918 calculated the old length in order to calculate the
919 adjustment. */
e3f9a279
RS
920 gcc_assert (si->nonzero_chars);
921 tem = fold_convert_loc (loc, TREE_TYPE (si->nonzero_chars), adj);
922 si->nonzero_chars = fold_build2_loc (loc, PLUS_EXPR,
923 TREE_TYPE (si->nonzero_chars),
924 si->nonzero_chars, tem);
925 si->full_string_p = origsi->full_string_p;
93a90db6 926
8b57bfeb
JJ
927 si->endptr = NULL_TREE;
928 si->dont_invalidate = true;
929 }
bde63fde
RS
930 nsi = get_next_strinfo (si);
931 if (nsi == NULL)
8b57bfeb
JJ
932 return;
933 si = nsi;
934 }
935}
936
937/* Find if there are other SSA_NAME pointers equal to PTR
938 for which we don't track their string lengths yet. If so, use
939 IDX for them. */
940
941static void
942find_equal_ptrs (tree ptr, int idx)
943{
944 if (TREE_CODE (ptr) != SSA_NAME)
945 return;
946 while (1)
947 {
355fe088 948 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
8b57bfeb
JJ
949 if (!is_gimple_assign (stmt))
950 return;
951 ptr = gimple_assign_rhs1 (stmt);
952 switch (gimple_assign_rhs_code (stmt))
953 {
954 case SSA_NAME:
955 break;
97246d78
JJ
956 CASE_CONVERT:
957 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
958 return;
959 if (TREE_CODE (ptr) == SSA_NAME)
960 break;
961 if (TREE_CODE (ptr) != ADDR_EXPR)
962 return;
963 /* FALLTHRU */
8b57bfeb
JJ
964 case ADDR_EXPR:
965 {
966 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
967 if (pidx != NULL && *pidx == 0)
968 *pidx = idx;
969 return;
970 }
8b57bfeb
JJ
971 default:
972 return;
973 }
974
975 /* We might find an endptr created in this pass. Grow the
976 vector in that case. */
9771b263
DN
977 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
978 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
8b57bfeb 979
9771b263 980 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
8b57bfeb 981 return;
9771b263 982 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
8b57bfeb
JJ
983 }
984}
985
0ad84f34
JJ
986/* Return true if STMT is a call to a builtin function with the right
987 arguments and attributes that should be considered for optimization
988 by this pass. */
989
990static bool
991valid_builtin_call (gimple *stmt)
992{
993 if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
994 return false;
995
996 tree callee = gimple_call_fndecl (stmt);
997 switch (DECL_FUNCTION_CODE (callee))
998 {
999 case BUILT_IN_MEMCMP:
1000 case BUILT_IN_MEMCMP_EQ:
1001 case BUILT_IN_STRCHR:
1002 case BUILT_IN_STRCHR_CHKP:
1003 case BUILT_IN_STRLEN:
1004 case BUILT_IN_STRLEN_CHKP:
1005 /* The above functions should be pure. Punt if they aren't. */
1006 if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
1007 return false;
1008 break;
1009
1010 case BUILT_IN_CALLOC:
1011 case BUILT_IN_MALLOC:
1012 case BUILT_IN_MEMCPY:
1013 case BUILT_IN_MEMCPY_CHK:
1014 case BUILT_IN_MEMCPY_CHKP:
1015 case BUILT_IN_MEMCPY_CHK_CHKP:
1016 case BUILT_IN_MEMPCPY:
1017 case BUILT_IN_MEMPCPY_CHK:
1018 case BUILT_IN_MEMPCPY_CHKP:
1019 case BUILT_IN_MEMPCPY_CHK_CHKP:
1020 case BUILT_IN_MEMSET:
1021 case BUILT_IN_STPCPY:
1022 case BUILT_IN_STPCPY_CHK:
1023 case BUILT_IN_STPCPY_CHKP:
1024 case BUILT_IN_STPCPY_CHK_CHKP:
1025 case BUILT_IN_STRCAT:
1026 case BUILT_IN_STRCAT_CHK:
1027 case BUILT_IN_STRCAT_CHKP:
1028 case BUILT_IN_STRCAT_CHK_CHKP:
1029 case BUILT_IN_STRCPY:
1030 case BUILT_IN_STRCPY_CHK:
1031 case BUILT_IN_STRCPY_CHKP:
1032 case BUILT_IN_STRCPY_CHK_CHKP:
1033 /* The above functions should be neither const nor pure. Punt if they
1034 aren't. */
1035 if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
1036 return false;
1037 break;
1038
1039 default:
1040 break;
1041 }
1042
1043 return true;
1044}
1045
8b57bfeb
JJ
1046/* If the last .MEM setter statement before STMT is
1047 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
1048 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
1049 just memcpy (x, y, strlen (y)). SI must be the zero length
1050 strinfo. */
1051
1052static void
526ceb68 1053adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
8b57bfeb
JJ
1054{
1055 tree vuse, callee, len;
1056 struct laststmt_struct last = laststmt;
526ceb68 1057 strinfo *lastsi, *firstsi;
f5fc4a04 1058 unsigned len_arg_no = 2;
8b57bfeb
JJ
1059
1060 laststmt.stmt = NULL;
1061 laststmt.len = NULL_TREE;
1062 laststmt.stridx = 0;
1063
1064 if (last.stmt == NULL)
1065 return;
1066
1067 vuse = gimple_vuse (stmt);
1068 if (vuse == NULL_TREE
1069 || SSA_NAME_DEF_STMT (vuse) != last.stmt
1070 || !has_single_use (vuse))
1071 return;
1072
1073 gcc_assert (last.stridx > 0);
1074 lastsi = get_strinfo (last.stridx);
1075 if (lastsi == NULL)
1076 return;
1077
1078 if (lastsi != si)
1079 {
1080 if (lastsi->first == 0 || lastsi->first != si->first)
1081 return;
1082
1083 firstsi = verify_related_strinfos (si);
1084 if (firstsi == NULL)
1085 return;
1086 while (firstsi != lastsi)
1087 {
bde63fde
RS
1088 firstsi = get_next_strinfo (firstsi);
1089 if (firstsi == NULL)
8b57bfeb 1090 return;
8b57bfeb
JJ
1091 }
1092 }
1093
e3f9a279
RS
1094 if (!is_strcat && !zero_length_string_p (si))
1095 return;
8b57bfeb
JJ
1096
1097 if (is_gimple_assign (last.stmt))
1098 {
1099 gimple_stmt_iterator gsi;
1100
1101 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
1102 return;
1103 if (stmt_could_throw_p (last.stmt))
1104 return;
1105 gsi = gsi_for_stmt (last.stmt);
1106 unlink_stmt_vdef (last.stmt);
1107 release_defs (last.stmt);
1108 gsi_remove (&gsi, true);
1109 return;
1110 }
1111
0ad84f34 1112 if (!valid_builtin_call (last.stmt))
8b57bfeb
JJ
1113 return;
1114
3626621a 1115 callee = gimple_call_fndecl (last.stmt);
8b57bfeb
JJ
1116 switch (DECL_FUNCTION_CODE (callee))
1117 {
1118 case BUILT_IN_MEMCPY:
1119 case BUILT_IN_MEMCPY_CHK:
1120 break;
f5fc4a04
IE
1121 case BUILT_IN_MEMCPY_CHKP:
1122 case BUILT_IN_MEMCPY_CHK_CHKP:
1123 len_arg_no = 4;
1124 break;
8b57bfeb
JJ
1125 default:
1126 return;
1127 }
1128
f5fc4a04 1129 len = gimple_call_arg (last.stmt, len_arg_no);
cc269bb6 1130 if (tree_fits_uhwi_p (len))
8b57bfeb 1131 {
cc269bb6 1132 if (!tree_fits_uhwi_p (last.len)
8b57bfeb 1133 || integer_zerop (len)
7d362f6c 1134 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
8b57bfeb
JJ
1135 return;
1136 /* Don't adjust the length if it is divisible by 4, it is more efficient
1137 to store the extra '\0' in that case. */
7d362f6c 1138 if ((tree_to_uhwi (len) & 3) == 0)
8b57bfeb
JJ
1139 return;
1140 }
1141 else if (TREE_CODE (len) == SSA_NAME)
1142 {
355fe088 1143 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
8b57bfeb
JJ
1144 if (!is_gimple_assign (def_stmt)
1145 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1146 || gimple_assign_rhs1 (def_stmt) != last.len
1147 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1148 return;
1149 }
1150 else
1151 return;
1152
f5fc4a04 1153 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
8b57bfeb
JJ
1154 update_stmt (last.stmt);
1155}
1156
06199618
MS
1157/* For an LHS that is an SSA_NAME and for strlen() argument SRC, set
1158 LHS range info to [0, N] if SRC refers to a character array A[N]
1159 with unknown length bounded by N. */
1160
1161static void
1162maybe_set_strlen_range (tree lhs, tree src)
1163{
1164 if (TREE_CODE (lhs) != SSA_NAME)
1165 return;
1166
1167 if (TREE_CODE (src) == SSA_NAME)
1168 {
1169 gimple *def = SSA_NAME_DEF_STMT (src);
1170 if (is_gimple_assign (def)
1171 && gimple_assign_rhs_code (def) == ADDR_EXPR)
1172 src = gimple_assign_rhs1 (def);
1173 }
1174
1175 if (TREE_CODE (src) != ADDR_EXPR)
1176 return;
1177
1178 /* The last array member of a struct can be bigger than its size
1179 suggests if it's treated as a poor-man's flexible array member. */
1180 src = TREE_OPERAND (src, 0);
1181 if (TREE_CODE (TREE_TYPE (src)) != ARRAY_TYPE
1182 || array_at_struct_end_p (src))
1183 return;
1184
1185 tree type = TREE_TYPE (src);
1186 if (tree dom = TYPE_DOMAIN (type))
1187 if (tree maxval = TYPE_MAX_VALUE (dom))
1188 {
1189 wide_int max = wi::to_wide (maxval);
1190 wide_int min = wi::zero (max.get_precision ());
1191 set_range_info (lhs, VR_RANGE, min, max);
1192 }
1193}
1194
8b57bfeb
JJ
1195/* Handle a strlen call. If strlen of the argument is known, replace
1196 the strlen call with the known value, otherwise remember that strlen
1197 of the argument is stored in the lhs SSA_NAME. */
1198
1199static void
1200handle_builtin_strlen (gimple_stmt_iterator *gsi)
1201{
1202 int idx;
1203 tree src;
355fe088 1204 gimple *stmt = gsi_stmt (*gsi);
8b57bfeb
JJ
1205 tree lhs = gimple_call_lhs (stmt);
1206
1207 if (lhs == NULL_TREE)
1208 return;
1209
1210 src = gimple_call_arg (stmt, 0);
1211 idx = get_stridx (src);
1212 if (idx)
1213 {
526ceb68 1214 strinfo *si = NULL;
8b57bfeb
JJ
1215 tree rhs;
1216
1217 if (idx < 0)
1218 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1219 else
1220 {
1221 rhs = NULL_TREE;
1222 si = get_strinfo (idx);
1223 if (si != NULL)
1224 rhs = get_string_length (si);
1225 }
1226 if (rhs != NULL_TREE)
1227 {
1228 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1229 {
1230 fprintf (dump_file, "Optimizing: ");
1231 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1232 }
1233 rhs = unshare_expr (rhs);
1234 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1235 rhs = fold_convert_loc (gimple_location (stmt),
1236 TREE_TYPE (lhs), rhs);
1237 if (!update_call_from_tree (gsi, rhs))
1238 gimplify_and_update_call_from_tree (gsi, rhs);
1239 stmt = gsi_stmt (*gsi);
1240 update_stmt (stmt);
1241 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1242 {
1243 fprintf (dump_file, "into: ");
1244 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1245 }
1246 if (si != NULL
e3f9a279
RS
1247 && TREE_CODE (si->nonzero_chars) != SSA_NAME
1248 && TREE_CODE (si->nonzero_chars) != INTEGER_CST
8b57bfeb
JJ
1249 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1250 {
1251 si = unshare_strinfo (si);
e3f9a279
RS
1252 si->nonzero_chars = lhs;
1253 gcc_assert (si->full_string_p);
8b57bfeb 1254 }
025d57f0 1255
6a33d0ff
MS
1256 if (strlen_to_stridx)
1257 {
1258 location_t loc = gimple_location (stmt);
1259 strlen_to_stridx->put (lhs, stridx_strlenloc (idx, loc));
1260 }
8b57bfeb
JJ
1261 return;
1262 }
1263 }
1264 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1265 return;
1266 if (idx == 0)
1267 idx = new_stridx (src);
e3f9a279
RS
1268 else
1269 {
1270 strinfo *si = get_strinfo (idx);
1271 if (si != NULL)
1272 {
1273 if (!si->full_string_p && !si->stmt)
1274 {
1275 /* Until now we only had a lower bound on the string length.
1276 Install LHS as the actual length. */
1277 si = unshare_strinfo (si);
1aad7106 1278 tree old = si->nonzero_chars;
e3f9a279
RS
1279 si->nonzero_chars = lhs;
1280 si->full_string_p = true;
1aad7106
RS
1281 if (TREE_CODE (old) == INTEGER_CST)
1282 {
1283 location_t loc = gimple_location (stmt);
1284 old = fold_convert_loc (loc, TREE_TYPE (lhs), old);
1285 tree adj = fold_build2_loc (loc, MINUS_EXPR,
1286 TREE_TYPE (lhs), lhs, old);
1287 adjust_related_strinfos (loc, si, adj);
1288 }
1289 else
1290 {
1291 si->first = 0;
1292 si->prev = 0;
1293 si->next = 0;
1294 }
e3f9a279
RS
1295 }
1296 return;
1297 }
1298 }
8b57bfeb
JJ
1299 if (idx)
1300 {
e3f9a279 1301 strinfo *si = new_strinfo (src, idx, lhs, true);
8b57bfeb
JJ
1302 set_strinfo (idx, si);
1303 find_equal_ptrs (src, idx);
025d57f0 1304
06199618
MS
1305 /* For SRC that is an array of N elements, set LHS's range
1306 to [0, N]. */
1307 maybe_set_strlen_range (lhs, src);
1308
6a33d0ff
MS
1309 if (strlen_to_stridx)
1310 {
1311 location_t loc = gimple_location (stmt);
1312 strlen_to_stridx->put (lhs, stridx_strlenloc (idx, loc));
1313 }
8b57bfeb
JJ
1314 }
1315}
1316
1317/* Handle a strchr call. If strlen of the first argument is known, replace
1318 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1319 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1320
1321static void
1322handle_builtin_strchr (gimple_stmt_iterator *gsi)
1323{
1324 int idx;
1325 tree src;
355fe088 1326 gimple *stmt = gsi_stmt (*gsi);
8b57bfeb 1327 tree lhs = gimple_call_lhs (stmt);
f5fc4a04 1328 bool with_bounds = gimple_call_with_bounds_p (stmt);
8b57bfeb
JJ
1329
1330 if (lhs == NULL_TREE)
1331 return;
1332
f5fc4a04 1333 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
8b57bfeb
JJ
1334 return;
1335
1336 src = gimple_call_arg (stmt, 0);
1337 idx = get_stridx (src);
1338 if (idx)
1339 {
526ceb68 1340 strinfo *si = NULL;
8b57bfeb
JJ
1341 tree rhs;
1342
1343 if (idx < 0)
1344 rhs = build_int_cst (size_type_node, ~idx);
1345 else
1346 {
1347 rhs = NULL_TREE;
1348 si = get_strinfo (idx);
1349 if (si != NULL)
1350 rhs = get_string_length (si);
1351 }
1352 if (rhs != NULL_TREE)
1353 {
1354 location_t loc = gimple_location (stmt);
1355
1356 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1357 {
1358 fprintf (dump_file, "Optimizing: ");
1359 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1360 }
1361 if (si != NULL && si->endptr != NULL_TREE)
1362 {
1363 rhs = unshare_expr (si->endptr);
1364 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1365 TREE_TYPE (rhs)))
1366 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1367 }
1368 else
1369 {
1370 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1371 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1372 TREE_TYPE (src), src, rhs);
1373 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1374 TREE_TYPE (rhs)))
1375 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1376 }
1377 if (!update_call_from_tree (gsi, rhs))
1378 gimplify_and_update_call_from_tree (gsi, rhs);
1379 stmt = gsi_stmt (*gsi);
1380 update_stmt (stmt);
1381 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1382 {
1383 fprintf (dump_file, "into: ");
1384 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1385 }
1386 if (si != NULL
1387 && si->endptr == NULL_TREE
1388 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1389 {
1390 si = unshare_strinfo (si);
1391 si->endptr = lhs;
1392 }
1393 zero_length_string (lhs, si);
1394 return;
1395 }
1396 }
1397 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1398 return;
1399 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1400 {
1401 if (idx == 0)
1402 idx = new_stridx (src);
1403 else if (get_strinfo (idx) != NULL)
1404 {
1405 zero_length_string (lhs, NULL);
1406 return;
1407 }
1408 if (idx)
1409 {
1410 location_t loc = gimple_location (stmt);
1411 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1412 tree srcu = fold_convert_loc (loc, size_type_node, src);
1413 tree length = fold_build2_loc (loc, MINUS_EXPR,
1414 size_type_node, lhsu, srcu);
e3f9a279 1415 strinfo *si = new_strinfo (src, idx, length, true);
8b57bfeb
JJ
1416 si->endptr = lhs;
1417 set_strinfo (idx, si);
1418 find_equal_ptrs (src, idx);
1419 zero_length_string (lhs, si);
1420 }
1421 }
1422 else
1423 zero_length_string (lhs, NULL);
1424}
1425
1426/* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1427 If strlen of the second argument is known, strlen of the first argument
1428 is the same after this call. Furthermore, attempt to convert it to
1429 memcpy. */
1430
1431static void
1432handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1433{
1434 int idx, didx;
cc8bea0a 1435 tree src, dst, srclen, len, lhs, type, fn, oldlen;
8b57bfeb 1436 bool success;
355fe088 1437 gimple *stmt = gsi_stmt (*gsi);
526ceb68 1438 strinfo *si, *dsi, *olddsi, *zsi;
8b57bfeb 1439 location_t loc;
f5fc4a04 1440 bool with_bounds = gimple_call_with_bounds_p (stmt);
8b57bfeb 1441
f5fc4a04 1442 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
8b57bfeb
JJ
1443 dst = gimple_call_arg (stmt, 0);
1444 lhs = gimple_call_lhs (stmt);
1445 idx = get_stridx (src);
1446 si = NULL;
1447 if (idx > 0)
1448 si = get_strinfo (idx);
1449
1450 didx = get_stridx (dst);
1451 olddsi = NULL;
1452 oldlen = NULL_TREE;
1453 if (didx > 0)
1454 olddsi = get_strinfo (didx);
1455 else if (didx < 0)
1456 return;
1457
1458 if (olddsi != NULL)
1459 adjust_last_stmt (olddsi, stmt, false);
1460
1461 srclen = NULL_TREE;
1462 if (si != NULL)
1463 srclen = get_string_length (si);
1464 else if (idx < 0)
1465 srclen = build_int_cst (size_type_node, ~idx);
1466
1467 loc = gimple_location (stmt);
1468 if (srclen == NULL_TREE)
1469 switch (bcode)
1470 {
1471 case BUILT_IN_STRCPY:
1472 case BUILT_IN_STRCPY_CHK:
f5fc4a04
IE
1473 case BUILT_IN_STRCPY_CHKP:
1474 case BUILT_IN_STRCPY_CHK_CHKP:
e79983f4 1475 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
8b57bfeb
JJ
1476 return;
1477 break;
1478 case BUILT_IN_STPCPY:
1479 case BUILT_IN_STPCPY_CHK:
f5fc4a04
IE
1480 case BUILT_IN_STPCPY_CHKP:
1481 case BUILT_IN_STPCPY_CHK_CHKP:
8b57bfeb
JJ
1482 if (lhs == NULL_TREE)
1483 return;
1484 else
1485 {
1486 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1487 srclen = fold_convert_loc (loc, size_type_node, dst);
1488 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1489 lhsuint, srclen);
1490 }
1491 break;
1492 default:
1493 gcc_unreachable ();
1494 }
1495
1496 if (didx == 0)
1497 {
1498 didx = new_stridx (dst);
1499 if (didx == 0)
1500 return;
1501 }
1502 if (olddsi != NULL)
1503 {
e3f9a279 1504 oldlen = olddsi->nonzero_chars;
8b57bfeb 1505 dsi = unshare_strinfo (olddsi);
e3f9a279
RS
1506 dsi->nonzero_chars = srclen;
1507 dsi->full_string_p = (srclen != NULL_TREE);
8b57bfeb
JJ
1508 /* Break the chain, so adjust_related_strinfo on later pointers in
1509 the chain won't adjust this one anymore. */
1510 dsi->next = 0;
1511 dsi->stmt = NULL;
1512 dsi->endptr = NULL_TREE;
1513 }
1514 else
1515 {
e3f9a279 1516 dsi = new_strinfo (dst, didx, srclen, srclen != NULL_TREE);
8b57bfeb
JJ
1517 set_strinfo (didx, dsi);
1518 find_equal_ptrs (dst, didx);
1519 }
1520 dsi->writable = true;
1521 dsi->dont_invalidate = true;
1522
e3f9a279 1523 if (dsi->nonzero_chars == NULL_TREE)
8b57bfeb 1524 {
526ceb68 1525 strinfo *chainsi;
93a90db6 1526
8b57bfeb
JJ
1527 /* If string length of src is unknown, use delayed length
1528 computation. If string lenth of dst will be needed, it
1529 can be computed by transforming this strcpy call into
1530 stpcpy and subtracting dst from the return value. */
93a90db6
AK
1531
1532 /* Look for earlier strings whose length could be determined if
1533 this strcpy is turned into an stpcpy. */
1534
1535 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1536 {
1537 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1538 {
1539 /* When setting a stmt for delayed length computation
1540 prevent all strinfos through dsi from being
1541 invalidated. */
1542 chainsi = unshare_strinfo (chainsi);
1543 chainsi->stmt = stmt;
e3f9a279
RS
1544 chainsi->nonzero_chars = NULL_TREE;
1545 chainsi->full_string_p = false;
93a90db6
AK
1546 chainsi->endptr = NULL_TREE;
1547 chainsi->dont_invalidate = true;
1548 }
1549 }
8b57bfeb 1550 dsi->stmt = stmt;
cc8bea0a
MS
1551
1552 /* Try to detect overlap before returning. This catches cases
1553 like strcpy (d, d + n) where n is non-constant whose range
1554 is such that (n <= strlen (d) holds).
1555
1556 OLDDSI->NONZERO_chars may have been reset by this point with
1557 oldlen holding it original value. */
1558 if (olddsi && oldlen)
1559 {
1560 /* Add 1 for the terminating NUL. */
1561 tree type = TREE_TYPE (oldlen);
1562 oldlen = fold_build2 (PLUS_EXPR, type, oldlen,
1563 build_int_cst (type, 1));
1564 check_bounds_or_overlap (as_a <gcall *>(stmt), olddsi->ptr, src,
1565 oldlen, NULL_TREE);
1566 }
1567
8b57bfeb
JJ
1568 return;
1569 }
1570
1571 if (olddsi != NULL)
1572 {
1573 tree adj = NULL_TREE;
1574 if (oldlen == NULL_TREE)
1575 ;
1576 else if (integer_zerop (oldlen))
1577 adj = srclen;
1578 else if (TREE_CODE (oldlen) == INTEGER_CST
1579 || TREE_CODE (srclen) == INTEGER_CST)
1580 adj = fold_build2_loc (loc, MINUS_EXPR,
1581 TREE_TYPE (srclen), srclen,
1582 fold_convert_loc (loc, TREE_TYPE (srclen),
1583 oldlen));
1584 if (adj != NULL_TREE)
1585 adjust_related_strinfos (loc, dsi, adj);
1586 else
1587 dsi->prev = 0;
1588 }
1589 /* strcpy src may not overlap dst, so src doesn't need to be
1590 invalidated either. */
1591 if (si != NULL)
1592 si->dont_invalidate = true;
1593
1594 fn = NULL_TREE;
1595 zsi = NULL;
1596 switch (bcode)
1597 {
1598 case BUILT_IN_STRCPY:
f5fc4a04 1599 case BUILT_IN_STRCPY_CHKP:
e79983f4 1600 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
8b57bfeb 1601 if (lhs)
9771b263 1602 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
8b57bfeb
JJ
1603 break;
1604 case BUILT_IN_STRCPY_CHK:
f5fc4a04 1605 case BUILT_IN_STRCPY_CHK_CHKP:
e79983f4 1606 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
8b57bfeb 1607 if (lhs)
9771b263 1608 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
8b57bfeb
JJ
1609 break;
1610 case BUILT_IN_STPCPY:
f5fc4a04 1611 case BUILT_IN_STPCPY_CHKP:
8b57bfeb
JJ
1612 /* This would need adjustment of the lhs (subtract one),
1613 or detection that the trailing '\0' doesn't need to be
1614 written, if it will be immediately overwritten.
e79983f4 1615 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
8b57bfeb
JJ
1616 if (lhs)
1617 {
1618 dsi->endptr = lhs;
1619 zsi = zero_length_string (lhs, dsi);
1620 }
1621 break;
1622 case BUILT_IN_STPCPY_CHK:
f5fc4a04 1623 case BUILT_IN_STPCPY_CHK_CHKP:
8b57bfeb
JJ
1624 /* This would need adjustment of the lhs (subtract one),
1625 or detection that the trailing '\0' doesn't need to be
1626 written, if it will be immediately overwritten.
e79983f4 1627 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
8b57bfeb
JJ
1628 if (lhs)
1629 {
1630 dsi->endptr = lhs;
1631 zsi = zero_length_string (lhs, dsi);
1632 }
1633 break;
1634 default:
1635 gcc_unreachable ();
1636 }
1637 if (zsi != NULL)
1638 zsi->dont_invalidate = true;
1639
cc8bea0a
MS
1640 if (fn)
1641 {
1642 tree args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1643 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1644 }
1645 else
1646 type = size_type_node;
8b57bfeb
JJ
1647
1648 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1649 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
cc8bea0a
MS
1650
1651 /* Set the no-warning bit on the transformed statement? */
1652 bool set_no_warning = false;
1653
1654 if (const strinfo *chksi = olddsi ? olddsi : dsi)
1655 if (si
1656 && !check_bounds_or_overlap (as_a <gcall *>(stmt), chksi->ptr, si->ptr,
1657 NULL_TREE, len))
1658 {
1659 gimple_set_no_warning (stmt, true);
1660 set_no_warning = true;
1661 }
1662
1663 if (fn == NULL_TREE)
1664 return;
1665
8b57bfeb
JJ
1666 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1667 GSI_SAME_STMT);
1668 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1669 {
1670 fprintf (dump_file, "Optimizing: ");
1671 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1672 }
f5fc4a04
IE
1673 if (with_bounds)
1674 {
1675 fn = chkp_maybe_create_clone (fn)->decl;
1676 if (gimple_call_num_args (stmt) == 4)
1677 success = update_gimple_call (gsi, fn, 5, dst,
1678 gimple_call_arg (stmt, 1),
1679 src,
1680 gimple_call_arg (stmt, 3),
1681 len);
1682 else
1683 success = update_gimple_call (gsi, fn, 6, dst,
1684 gimple_call_arg (stmt, 1),
1685 src,
1686 gimple_call_arg (stmt, 3),
1687 len,
1688 gimple_call_arg (stmt, 4));
1689 }
8b57bfeb 1690 else
f5fc4a04
IE
1691 if (gimple_call_num_args (stmt) == 2)
1692 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1693 else
1694 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1695 gimple_call_arg (stmt, 2));
8b57bfeb
JJ
1696 if (success)
1697 {
1698 stmt = gsi_stmt (*gsi);
f5fc4a04 1699 gimple_call_set_with_bounds (stmt, with_bounds);
8b57bfeb
JJ
1700 update_stmt (stmt);
1701 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1702 {
1703 fprintf (dump_file, "into: ");
1704 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1705 }
1706 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1707 laststmt.stmt = stmt;
1708 laststmt.len = srclen;
1709 laststmt.stridx = dsi->idx;
1710 }
1711 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1712 fprintf (dump_file, "not possible.\n");
cc8bea0a
MS
1713
1714 if (set_no_warning)
1715 gimple_set_no_warning (stmt, true);
1716}
1717
1718/* Check the size argument to the built-in forms of stpncpy and strncpy
1719 for out-of-bounds offsets or overlapping access, and to see if the
1720 size argument is derived from a call to strlen() on the source argument,
1721 and if so, issue an appropriate warning. */
1722
1723static void
1724handle_builtin_strncat (built_in_function bcode, gimple_stmt_iterator *gsi)
1725{
1726 /* Same as stxncpy(). */
1727 handle_builtin_stxncpy (bcode, gsi);
8b57bfeb
JJ
1728}
1729
025d57f0
MS
1730/* Return true if LEN depends on a call to strlen(SRC) in an interesting
1731 way. LEN can either be an integer expression, or a pointer (to char).
1732 When it is the latter (such as in recursive calls to self) is is
1733 assumed to be the argument in some call to strlen() whose relationship
1734 to SRC is being ascertained. */
1735
1736static bool
1737is_strlen_related_p (tree src, tree len)
1738{
1739 if (TREE_CODE (TREE_TYPE (len)) == POINTER_TYPE
1740 && operand_equal_p (src, len, 0))
1741 return true;
1742
1743 if (TREE_CODE (len) != SSA_NAME)
1744 return false;
1745
1746 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1747 if (!def_stmt)
1748 return false;
1749
1750 if (is_gimple_call (def_stmt))
1751 {
1752 tree func = gimple_call_fndecl (def_stmt);
1753 if (!valid_builtin_call (def_stmt)
1754 || DECL_FUNCTION_CODE (func) != BUILT_IN_STRLEN)
1755 return false;
1756
1757 tree arg = gimple_call_arg (def_stmt, 0);
1758 return is_strlen_related_p (src, arg);
1759 }
1760
1761 if (!is_gimple_assign (def_stmt))
1762 return false;
1763
1764 tree_code code = gimple_assign_rhs_code (def_stmt);
1765 tree rhs1 = gimple_assign_rhs1 (def_stmt);
1766 tree rhstype = TREE_TYPE (rhs1);
1767
1768 if ((TREE_CODE (rhstype) == POINTER_TYPE && code == POINTER_PLUS_EXPR)
1769 || (INTEGRAL_TYPE_P (rhstype)
1770 && (code == BIT_AND_EXPR
1771 || code == NOP_EXPR)))
1772 {
1773 /* Pointer plus (an integer) and integer cast or truncation are
1774 considered among the (potentially) related expressions to strlen.
1775 Others are not. */
1776 return is_strlen_related_p (src, rhs1);
1777 }
1778
1779 return false;
1780}
1781
1782/* A helper of handle_builtin_stxncpy. Check to see if the specified
1783 bound is a) equal to the size of the destination DST and if so, b)
1784 if it's immediately followed by DST[CNT - 1] = '\0'. If a) holds
1785 and b) does not, warn. Otherwise, do nothing. Return true if
1786 diagnostic has been issued.
1787
1788 The purpose is to diagnose calls to strncpy and stpncpy that do
1789 not nul-terminate the copy while allowing for the idiom where
1790 such a call is immediately followed by setting the last element
1791 to nul, as in:
1792 char a[32];
1793 strncpy (a, s, sizeof a);
1794 a[sizeof a - 1] = '\0';
1795*/
1796
1797static bool
1798maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
1799{
025d57f0
MS
1800 gimple *stmt = gsi_stmt (gsi);
1801
1802 wide_int cntrange[2];
1803
1804 if (TREE_CODE (cnt) == INTEGER_CST)
1805 cntrange[0] = cntrange[1] = wi::to_wide (cnt);
1806 else if (TREE_CODE (cnt) == SSA_NAME)
1807 {
1808 enum value_range_type rng = get_range_info (cnt, cntrange, cntrange + 1);
1809 if (rng == VR_RANGE)
1810 ;
1811 else if (rng == VR_ANTI_RANGE)
1812 {
1813 wide_int maxobjsize = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
1814
1815 if (wi::ltu_p (cntrange[1], maxobjsize))
1816 {
1817 cntrange[0] = cntrange[1] + 1;
1818 cntrange[1] = maxobjsize;
1819 }
1820 else
1821 {
1822 cntrange[1] = cntrange[0] - 1;
1823 cntrange[0] = wi::zero (TYPE_PRECISION (TREE_TYPE (cnt)));
1824 }
1825 }
1826 else
1827 return false;
1828 }
1829 else
1830 return false;
1831
1832 /* Negative value is the constant string length. If it's less than
1833 the lower bound there is no truncation. */
1834 int sidx = get_stridx (src);
1835 if (sidx < 0 && wi::gtu_p (cntrange[0], ~sidx))
1836 return false;
1837
1838 tree dst = gimple_call_arg (stmt, 0);
025d57f0
MS
1839 tree dstdecl = dst;
1840 if (TREE_CODE (dstdecl) == ADDR_EXPR)
1841 dstdecl = TREE_OPERAND (dstdecl, 0);
1842
6a33d0ff
MS
1843 /* If the destination refers to a an array/pointer declared nonstring
1844 return early. */
1845 tree ref = NULL_TREE;
1846 if (get_attr_nonstring_decl (dstdecl, &ref))
1847 return false;
025d57f0
MS
1848
1849 /* Look for dst[i] = '\0'; after the stxncpy() call and if found
1850 avoid the truncation warning. */
1851 gsi_next (&gsi);
1852 gimple *next_stmt = gsi_stmt (gsi);
1853
1854 if (!gsi_end_p (gsi) && is_gimple_assign (next_stmt))
1855 {
025d57f0 1856 tree lhs = gimple_assign_lhs (next_stmt);
6a33d0ff
MS
1857 tree_code code = TREE_CODE (lhs);
1858 if (code == ARRAY_REF || code == MEM_REF)
1859 lhs = TREE_OPERAND (lhs, 0);
1860
1861 tree func = gimple_call_fndecl (stmt);
1862 if (DECL_FUNCTION_CODE (func) == BUILT_IN_STPNCPY)
1863 {
1864 tree ret = gimple_call_lhs (stmt);
1865 if (ret && operand_equal_p (ret, lhs, 0))
1866 return false;
1867 }
1868
1869 /* Determine the base address and offset of the reference,
1870 ignoring the innermost array index. */
1871 if (TREE_CODE (ref) == ARRAY_REF)
1872 ref = TREE_OPERAND (ref, 0);
1873
a90c8804 1874 poly_int64 dstoff;
6a33d0ff
MS
1875 tree dstbase = get_addr_base_and_unit_offset (ref, &dstoff);
1876
a90c8804 1877 poly_int64 lhsoff;
6a33d0ff
MS
1878 tree lhsbase = get_addr_base_and_unit_offset (lhs, &lhsoff);
1879 if (lhsbase
a90c8804 1880 && known_eq (dstoff, lhsoff)
6a33d0ff 1881 && operand_equal_p (dstbase, lhsbase, 0))
025d57f0
MS
1882 return false;
1883 }
1884
1885 int prec = TYPE_PRECISION (TREE_TYPE (cnt));
1886 wide_int lenrange[2];
1887 if (strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL)
1888 {
1889 lenrange[0] = (sisrc->nonzero_chars
1890 && TREE_CODE (sisrc->nonzero_chars) == INTEGER_CST
1891 ? wi::to_wide (sisrc->nonzero_chars)
1892 : wi::zero (prec));
1893 lenrange[1] = lenrange[0];
1894 }
1895 else if (sidx < 0)
1896 lenrange[0] = lenrange[1] = wi::shwi (~sidx, prec);
1897 else
1898 {
1899 tree range[2];
1900 get_range_strlen (src, range);
1901 if (range[0])
1902 {
1903 lenrange[0] = wi::to_wide (range[0], prec);
1904 lenrange[1] = wi::to_wide (range[1], prec);
1905 }
1906 else
1907 {
1908 lenrange[0] = wi::shwi (0, prec);
1909 lenrange[1] = wi::shwi (-1, prec);
1910 }
1911 }
1912
1913 location_t callloc = gimple_location (stmt);
1914 tree func = gimple_call_fndecl (stmt);
1915
1916 if (lenrange[0] != 0 || !wi::neg_p (lenrange[1]))
1917 {
1918 /* If the longest source string is shorter than the lower bound
1919 of the specified count the copy is definitely nul-terminated. */
1920 if (wi::ltu_p (lenrange[1], cntrange[0]))
1921 return false;
1922
1923 if (wi::neg_p (lenrange[1]))
1924 {
1925 /* The length of one of the strings is unknown but at least
1926 one has non-zero length and that length is stored in
1927 LENRANGE[1]. Swap the bounds to force a "may be truncated"
1928 warning below. */
1929 lenrange[1] = lenrange[0];
1930 lenrange[0] = wi::shwi (0, prec);
1931 }
1932
1933 if (wi::geu_p (lenrange[0], cntrange[1]))
1934 {
1935 /* The shortest string is longer than the upper bound of
1936 the count so the truncation is certain. */
1937 if (cntrange[0] == cntrange[1])
1938 return warning_at (callloc, OPT_Wstringop_truncation,
1939 integer_onep (cnt)
1940 ? G_("%qD output truncated copying %E byte "
1941 "from a string of length %wu")
1942 : G_("%qD output truncated copying %E bytes "
1943 "from a string of length %wu"),
1944 func, cnt, lenrange[0].to_uhwi ());
1945
1946 return warning_at (callloc, OPT_Wstringop_truncation,
1947 "%qD output truncated copying between %wu "
1948 "and %wu bytes from a string of length %wu",
1949 func, cntrange[0].to_uhwi (),
1950 cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
1951 }
1952 else if (wi::geu_p (lenrange[1], cntrange[1]))
1953 {
1954 /* The longest string is longer than the upper bound of
1955 the count so the truncation is possible. */
1956 if (cntrange[0] == cntrange[1])
1957 return warning_at (callloc, OPT_Wstringop_truncation,
1958 integer_onep (cnt)
1959 ? G_("%qD output may be truncated copying %E "
1960 "byte from a string of length %wu")
1961 : G_("%qD output may be truncated copying %E "
1962 "bytes from a string of length %wu"),
1963 func, cnt, lenrange[1].to_uhwi ());
1964
1965 return warning_at (callloc, OPT_Wstringop_truncation,
1966 "%qD output may be truncated copying between %wu "
1967 "and %wu bytes from a string of length %wu",
1968 func, cntrange[0].to_uhwi (),
1969 cntrange[1].to_uhwi (), lenrange[1].to_uhwi ());
1970 }
1971
1972 if (cntrange[0] != cntrange[1]
1973 && wi::leu_p (cntrange[0], lenrange[0])
1974 && wi::leu_p (cntrange[1], lenrange[0] + 1))
1975 {
1976 /* If the source (including the terminating nul) is longer than
1977 the lower bound of the specified count but shorter than the
1978 upper bound the copy may (but need not) be truncated. */
1979 return warning_at (callloc, OPT_Wstringop_truncation,
1980 "%qD output may be truncated copying between %wu "
1981 "and %wu bytes from a string of length %wu",
1982 func, cntrange[0].to_uhwi (),
1983 cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
1984 }
1985 }
1986
1987 if (tree dstsize = compute_objsize (dst, 1))
1988 {
1989 /* The source length is uknown. Try to determine the destination
1990 size and see if it matches the specified bound. If not, bail.
1991 Otherwise go on to see if it should be diagnosed for possible
1992 truncation. */
1993 if (!dstsize)
1994 return false;
1995
1996 if (wi::to_wide (dstsize) != cntrange[1])
1997 return false;
1998
1999 if (cntrange[0] == cntrange[1])
2000 return warning_at (callloc, OPT_Wstringop_truncation,
2001 "%qD specified bound %E equals destination size",
2002 func, cnt);
2003 }
2004
2005 return false;
2006}
2007
cc8bea0a
MS
2008/* Check the arguments to the built-in forms of stpncpy and strncpy for
2009 out-of-bounds offsets or overlapping access, and to see if the size
2010 is derived from calling strlen() on the source argument, and if so,
2011 issue the appropriate warning. */
025d57f0
MS
2012
2013static void
2014handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
2015{
6a33d0ff
MS
2016 if (!strlen_to_stridx)
2017 return;
2018
025d57f0
MS
2019 gimple *stmt = gsi_stmt (*gsi);
2020
2021 bool with_bounds = gimple_call_with_bounds_p (stmt);
2022
cc8bea0a 2023 tree dst = gimple_call_arg (stmt, with_bounds ? 1 : 0);
025d57f0
MS
2024 tree src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2025 tree len = gimple_call_arg (stmt, with_bounds ? 3 : 2);
cc8bea0a
MS
2026 tree dstsize = NULL_TREE, srcsize = NULL_TREE;
2027
2028 int didx = get_stridx (dst);
2029 if (strinfo *sidst = didx > 0 ? get_strinfo (didx) : NULL)
2030 {
2031 /* Compute the size of the destination string including the NUL. */
2032 if (sidst->nonzero_chars)
2033 {
2034 tree type = TREE_TYPE (sidst->nonzero_chars);
2035 dstsize = fold_build2 (PLUS_EXPR, type, sidst->nonzero_chars,
2036 build_int_cst (type, 1));
2037 }
2038 dst = sidst->ptr;
2039 }
2040
2041 int sidx = get_stridx (src);
2042 strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL;
2043 if (sisrc)
2044 {
2045 /* strncat() and strncpy() can modify the source string by writing
2046 over the terminating nul so SISRC->DONT_INVALIDATE must be left
2047 clear. */
2048
2049 /* Compute the size of the source string including the NUL. */
2050 if (sisrc->nonzero_chars)
2051 {
2052 tree type = TREE_TYPE (sisrc->nonzero_chars);
2053 srcsize = fold_build2 (PLUS_EXPR, type, sisrc->nonzero_chars,
2054 build_int_cst (type, 1));
2055 }
2056
2057 src = sisrc->ptr;
2058 }
2059 else
2060 srcsize = NULL_TREE;
2061
2062 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, src,
2063 dstsize, srcsize))
2064 {
2065 gimple_set_no_warning (stmt, true);
2066 return;
2067 }
025d57f0
MS
2068
2069 /* If the length argument was computed from strlen(S) for some string
2070 S retrieve the strinfo index for the string (PSS->FIRST) alonng with
2071 the location of the strlen() call (PSS->SECOND). */
6a33d0ff 2072 stridx_strlenloc *pss = strlen_to_stridx->get (len);
025d57f0
MS
2073 if (!pss || pss->first <= 0)
2074 {
2075 if (maybe_diag_stxncpy_trunc (*gsi, src, len))
2076 gimple_set_no_warning (stmt, true);
2077
2078 return;
2079 }
2080
025d57f0
MS
2081 /* Retrieve the strinfo data for the string S that LEN was computed
2082 from as some function F of strlen (S) (i.e., LEN need not be equal
2083 to strlen(S)). */
2084 strinfo *silen = get_strinfo (pss->first);
2085
2086 location_t callloc = gimple_location (stmt);
2087
2088 tree func = gimple_call_fndecl (stmt);
2089
2090 bool warned = false;
2091
2092 /* When -Wstringop-truncation is set, try to determine truncation
2093 before diagnosing possible overflow. Truncation is implied by
2094 the LEN argument being equal to strlen(SRC), regardless of
2095 whether its value is known. Otherwise, issue the more generic
2096 -Wstringop-overflow which triggers for LEN arguments that in
2097 any meaningful way depend on strlen(SRC). */
6a33d0ff
MS
2098 if (sisrc == silen
2099 && is_strlen_related_p (src, len)
2100 && warning_at (callloc, OPT_Wstringop_truncation,
2101 "%qD output truncated before terminating nul "
2102 "copying as many bytes from a string as its length",
2103 func))
2104 warned = true;
025d57f0
MS
2105 else if (silen && is_strlen_related_p (src, silen->ptr))
2106 warned = warning_at (callloc, OPT_Wstringop_overflow_,
2107 "%qD specified bound depends on the length "
2108 "of the source argument", func);
2109 if (warned)
2110 {
2111 location_t strlenloc = pss->second;
2112 if (strlenloc != UNKNOWN_LOCATION && strlenloc != callloc)
2113 inform (strlenloc, "length computed here");
2114 }
2115}
2116
8b57bfeb
JJ
2117/* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
2118 If strlen of the second argument is known and length of the third argument
2119 is that plus one, strlen of the first argument is the same after this
2120 call. */
2121
2122static void
2123handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2124{
2125 int idx, didx;
2126 tree src, dst, len, lhs, oldlen, newlen;
355fe088 2127 gimple *stmt = gsi_stmt (*gsi);
526ceb68 2128 strinfo *si, *dsi, *olddsi;
f5fc4a04 2129 bool with_bounds = gimple_call_with_bounds_p (stmt);
8b57bfeb 2130
f5fc4a04
IE
2131 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
2132 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
8b57bfeb
JJ
2133 dst = gimple_call_arg (stmt, 0);
2134 idx = get_stridx (src);
2135 if (idx == 0)
2136 return;
2137
2138 didx = get_stridx (dst);
2139 olddsi = NULL;
2140 if (didx > 0)
2141 olddsi = get_strinfo (didx);
2142 else if (didx < 0)
2143 return;
2144
2145 if (olddsi != NULL
cc269bb6 2146 && tree_fits_uhwi_p (len)
8b57bfeb
JJ
2147 && !integer_zerop (len))
2148 adjust_last_stmt (olddsi, stmt, false);
2149
e3f9a279 2150 bool full_string_p;
8b57bfeb
JJ
2151 if (idx > 0)
2152 {
355fe088 2153 gimple *def_stmt;
8b57bfeb 2154
e3f9a279
RS
2155 /* Handle memcpy (x, y, l) where l's relationship with strlen (y)
2156 is known. */
8b57bfeb 2157 si = get_strinfo (idx);
e3f9a279 2158 if (si == NULL || si->nonzero_chars == NULL_TREE)
8b57bfeb 2159 return;
e3f9a279
RS
2160 if (TREE_CODE (len) == INTEGER_CST
2161 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
2162 {
2163 if (tree_int_cst_le (len, si->nonzero_chars))
2164 {
2165 /* Copying LEN nonzero characters, where LEN is constant. */
2166 newlen = len;
2167 full_string_p = false;
2168 }
2169 else
2170 {
2171 /* Copying the whole of the analyzed part of SI. */
2172 newlen = si->nonzero_chars;
2173 full_string_p = si->full_string_p;
2174 }
2175 }
2176 else
2177 {
2178 if (!si->full_string_p)
2179 return;
2180 if (TREE_CODE (len) != SSA_NAME)
2181 return;
2182 def_stmt = SSA_NAME_DEF_STMT (len);
2183 if (!is_gimple_assign (def_stmt)
2184 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
2185 || gimple_assign_rhs1 (def_stmt) != si->nonzero_chars
2186 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
2187 return;
2188 /* Copying variable-length string SI (and no more). */
2189 newlen = si->nonzero_chars;
2190 full_string_p = true;
2191 }
8b57bfeb
JJ
2192 }
2193 else
2194 {
2195 si = NULL;
2196 /* Handle memcpy (x, "abcd", 5) or
2197 memcpy (x, "abc\0uvw", 7). */
e3f9a279 2198 if (!tree_fits_uhwi_p (len))
8b57bfeb 2199 return;
e3f9a279
RS
2200
2201 unsigned HOST_WIDE_INT clen = tree_to_uhwi (len);
2202 unsigned HOST_WIDE_INT nonzero_chars = ~idx;
2203 newlen = build_int_cst (size_type_node, MIN (nonzero_chars, clen));
2204 full_string_p = clen > nonzero_chars;
8b57bfeb
JJ
2205 }
2206
2207 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
2208 adjust_last_stmt (olddsi, stmt, false);
2209
2210 if (didx == 0)
2211 {
2212 didx = new_stridx (dst);
2213 if (didx == 0)
2214 return;
2215 }
8b57bfeb
JJ
2216 oldlen = NULL_TREE;
2217 if (olddsi != NULL)
2218 {
2219 dsi = unshare_strinfo (olddsi);
e3f9a279
RS
2220 oldlen = olddsi->nonzero_chars;
2221 dsi->nonzero_chars = newlen;
2222 dsi->full_string_p = full_string_p;
8b57bfeb
JJ
2223 /* Break the chain, so adjust_related_strinfo on later pointers in
2224 the chain won't adjust this one anymore. */
2225 dsi->next = 0;
2226 dsi->stmt = NULL;
2227 dsi->endptr = NULL_TREE;
2228 }
2229 else
2230 {
e3f9a279 2231 dsi = new_strinfo (dst, didx, newlen, full_string_p);
8b57bfeb
JJ
2232 set_strinfo (didx, dsi);
2233 find_equal_ptrs (dst, didx);
2234 }
2235 dsi->writable = true;
2236 dsi->dont_invalidate = true;
2237 if (olddsi != NULL)
2238 {
2239 tree adj = NULL_TREE;
2240 location_t loc = gimple_location (stmt);
2241 if (oldlen == NULL_TREE)
2242 ;
2243 else if (integer_zerop (oldlen))
e3f9a279 2244 adj = newlen;
8b57bfeb 2245 else if (TREE_CODE (oldlen) == INTEGER_CST
e3f9a279
RS
2246 || TREE_CODE (newlen) == INTEGER_CST)
2247 adj = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (newlen), newlen,
2248 fold_convert_loc (loc, TREE_TYPE (newlen),
8b57bfeb
JJ
2249 oldlen));
2250 if (adj != NULL_TREE)
2251 adjust_related_strinfos (loc, dsi, adj);
2252 else
2253 dsi->prev = 0;
2254 }
2255 /* memcpy src may not overlap dst, so src doesn't need to be
2256 invalidated either. */
2257 if (si != NULL)
2258 si->dont_invalidate = true;
2259
e3f9a279 2260 if (full_string_p)
8b57bfeb 2261 {
e3f9a279
RS
2262 lhs = gimple_call_lhs (stmt);
2263 switch (bcode)
2264 {
2265 case BUILT_IN_MEMCPY:
2266 case BUILT_IN_MEMCPY_CHK:
2267 case BUILT_IN_MEMCPY_CHKP:
2268 case BUILT_IN_MEMCPY_CHK_CHKP:
2269 /* Allow adjust_last_stmt to decrease this memcpy's size. */
2270 laststmt.stmt = stmt;
2271 laststmt.len = dsi->nonzero_chars;
2272 laststmt.stridx = dsi->idx;
2273 if (lhs)
2274 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
2275 break;
2276 case BUILT_IN_MEMPCPY:
2277 case BUILT_IN_MEMPCPY_CHK:
2278 case BUILT_IN_MEMPCPY_CHKP:
2279 case BUILT_IN_MEMPCPY_CHK_CHKP:
2280 break;
2281 default:
2282 gcc_unreachable ();
2283 }
8b57bfeb
JJ
2284 }
2285}
2286
2287/* Handle a strcat-like ({strcat,__strcat_chk}) call.
2288 If strlen of the second argument is known, strlen of the first argument
2289 is increased by the length of the second argument. Furthermore, attempt
2290 to convert it to memcpy/strcpy if the length of the first argument
2291 is known. */
2292
2293static void
2294handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2295{
2296 int idx, didx;
cc8bea0a 2297 tree srclen, args, type, fn, objsz, endptr;
8b57bfeb 2298 bool success;
355fe088 2299 gimple *stmt = gsi_stmt (*gsi);
526ceb68 2300 strinfo *si, *dsi;
cc8bea0a 2301 location_t loc = gimple_location (stmt);
f5fc4a04 2302 bool with_bounds = gimple_call_with_bounds_p (stmt);
8b57bfeb 2303
cc8bea0a
MS
2304 tree src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
2305 tree dst = gimple_call_arg (stmt, 0);
2306
2307 /* Bail if the source is the same as destination. It will be diagnosed
2308 elsewhere. */
2309 if (operand_equal_p (src, dst, 0))
2310 return;
2311
2312 tree lhs = gimple_call_lhs (stmt);
8b57bfeb
JJ
2313
2314 didx = get_stridx (dst);
2315 if (didx < 0)
2316 return;
2317
2318 dsi = NULL;
2319 if (didx > 0)
2320 dsi = get_strinfo (didx);
cc8bea0a
MS
2321
2322 srclen = NULL_TREE;
2323 si = NULL;
2324 idx = get_stridx (src);
2325 if (idx < 0)
2326 srclen = build_int_cst (size_type_node, ~idx);
2327 else if (idx > 0)
2328 {
2329 si = get_strinfo (idx);
2330 if (si != NULL)
2331 srclen = get_string_length (si);
2332 }
2333
2334 /* Set the no-warning bit on the transformed statement? */
2335 bool set_no_warning = false;
2336
8b57bfeb
JJ
2337 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
2338 {
cc8bea0a
MS
2339 {
2340 /* The concatenation always involves copying at least one byte
2341 (the terminating nul), even if the source string is empty.
2342 If the source is unknown assume it's one character long and
2343 used that as both sizes. */
2344 tree slen = srclen;
2345 if (slen)
2346 {
2347 tree type = TREE_TYPE (slen);
2348 slen = fold_build2 (PLUS_EXPR, type, slen, build_int_cst (type, 1));
2349 }
2350
2351 tree sptr = si && si->ptr ? si->ptr : src;
2352
2353 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, sptr,
2354 NULL_TREE, slen))
2355 {
2356 gimple_set_no_warning (stmt, true);
2357 set_no_warning = true;
2358 }
2359 }
2360
8b57bfeb 2361 /* strcat (p, q) can be transformed into
cc8bea0a 2362 tmp = p + strlen (p); endptr = stpcpy (tmp, q);
8b57bfeb
JJ
2363 with length endptr - p if we need to compute the length
2364 later on. Don't do this transformation if we don't need
2365 it. */
e79983f4 2366 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
8b57bfeb
JJ
2367 {
2368 if (didx == 0)
2369 {
2370 didx = new_stridx (dst);
2371 if (didx == 0)
2372 return;
2373 }
2374 if (dsi == NULL)
2375 {
e3f9a279 2376 dsi = new_strinfo (dst, didx, NULL_TREE, false);
8b57bfeb
JJ
2377 set_strinfo (didx, dsi);
2378 find_equal_ptrs (dst, didx);
2379 }
2380 else
2381 {
2382 dsi = unshare_strinfo (dsi);
e3f9a279
RS
2383 dsi->nonzero_chars = NULL_TREE;
2384 dsi->full_string_p = false;
8b57bfeb
JJ
2385 dsi->next = 0;
2386 dsi->endptr = NULL_TREE;
2387 }
2388 dsi->writable = true;
2389 dsi->stmt = stmt;
2390 dsi->dont_invalidate = true;
2391 }
2392 return;
2393 }
2394
cc8bea0a 2395 tree dstlen = dsi->nonzero_chars;
8b57bfeb
JJ
2396 endptr = dsi->endptr;
2397
2398 dsi = unshare_strinfo (dsi);
2399 dsi->endptr = NULL_TREE;
2400 dsi->stmt = NULL;
2401 dsi->writable = true;
2402
2403 if (srclen != NULL_TREE)
2404 {
e3f9a279
RS
2405 dsi->nonzero_chars = fold_build2_loc (loc, PLUS_EXPR,
2406 TREE_TYPE (dsi->nonzero_chars),
2407 dsi->nonzero_chars, srclen);
2408 gcc_assert (dsi->full_string_p);
8b57bfeb
JJ
2409 adjust_related_strinfos (loc, dsi, srclen);
2410 dsi->dont_invalidate = true;
2411 }
2412 else
2413 {
e3f9a279
RS
2414 dsi->nonzero_chars = NULL;
2415 dsi->full_string_p = false;
e79983f4 2416 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
8b57bfeb
JJ
2417 dsi->dont_invalidate = true;
2418 }
2419
2420 if (si != NULL)
2421 /* strcat src may not overlap dst, so src doesn't need to be
2422 invalidated either. */
2423 si->dont_invalidate = true;
2424
2425 /* For now. Could remove the lhs from the call and add
2426 lhs = dst; afterwards. */
2427 if (lhs)
2428 return;
2429
2430 fn = NULL_TREE;
2431 objsz = NULL_TREE;
2432 switch (bcode)
2433 {
2434 case BUILT_IN_STRCAT:
f5fc4a04 2435 case BUILT_IN_STRCAT_CHKP:
8b57bfeb 2436 if (srclen != NULL_TREE)
e79983f4 2437 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
8b57bfeb 2438 else
e79983f4 2439 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
8b57bfeb
JJ
2440 break;
2441 case BUILT_IN_STRCAT_CHK:
f5fc4a04 2442 case BUILT_IN_STRCAT_CHK_CHKP:
8b57bfeb 2443 if (srclen != NULL_TREE)
e79983f4 2444 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
8b57bfeb 2445 else
e79983f4 2446 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
f5fc4a04 2447 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
8b57bfeb
JJ
2448 break;
2449 default:
2450 gcc_unreachable ();
2451 }
2452
2453 if (fn == NULL_TREE)
2454 return;
2455
cc8bea0a
MS
2456 if (dsi && dstlen)
2457 {
2458 tree type = TREE_TYPE (dstlen);
2459
2460 /* Compute the size of the source sequence, including the nul. */
2461 tree srcsize = srclen ? srclen : size_zero_node;
2462 srcsize = fold_build2 (PLUS_EXPR, type, srcsize, build_int_cst (type, 1));
2463
2464 tree sptr = si && si->ptr ? si->ptr : src;
2465
2466 if (!check_bounds_or_overlap (as_a <gcall *>(stmt), dst, sptr,
2467 dstlen, srcsize))
2468 {
2469 gimple_set_no_warning (stmt, true);
2470 set_no_warning = true;
2471 }
2472 }
2473
2474 tree len = NULL_TREE;
8b57bfeb
JJ
2475 if (srclen != NULL_TREE)
2476 {
2477 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
2478 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
2479
2480 len = fold_convert_loc (loc, type, unshare_expr (srclen));
2481 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
2482 build_int_cst (type, 1));
2483 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
2484 GSI_SAME_STMT);
2485 }
2486 if (endptr)
2487 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
2488 else
2489 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
2490 TREE_TYPE (dst), unshare_expr (dst),
2491 fold_convert_loc (loc, sizetype,
2492 unshare_expr (dstlen)));
2493 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
2494 GSI_SAME_STMT);
2495 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2496 {
2497 fprintf (dump_file, "Optimizing: ");
2498 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
2499 }
f5fc4a04
IE
2500 if (with_bounds)
2501 {
2502 fn = chkp_maybe_create_clone (fn)->decl;
2503 if (srclen != NULL_TREE)
2504 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
2505 dst,
2506 gimple_call_arg (stmt, 1),
2507 src,
2508 gimple_call_arg (stmt, 3),
2509 len, objsz);
2510 else
2511 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
2512 dst,
2513 gimple_call_arg (stmt, 1),
2514 src,
2515 gimple_call_arg (stmt, 3),
2516 objsz);
2517 }
8b57bfeb 2518 else
f5fc4a04
IE
2519 if (srclen != NULL_TREE)
2520 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
2521 dst, src, len, objsz);
2522 else
2523 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
2524 dst, src, objsz);
8b57bfeb
JJ
2525 if (success)
2526 {
2527 stmt = gsi_stmt (*gsi);
f5fc4a04 2528 gimple_call_set_with_bounds (stmt, with_bounds);
8b57bfeb
JJ
2529 update_stmt (stmt);
2530 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2531 {
2532 fprintf (dump_file, "into: ");
2533 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
2534 }
2535 /* If srclen == NULL, note that current string length can be
2536 computed by transforming this strcpy into stpcpy. */
2537 if (srclen == NULL_TREE && dsi->dont_invalidate)
2538 dsi->stmt = stmt;
2539 adjust_last_stmt (dsi, stmt, true);
2540 if (srclen != NULL_TREE)
2541 {
2542 laststmt.stmt = stmt;
2543 laststmt.len = srclen;
2544 laststmt.stridx = dsi->idx;
2545 }
2546 }
2547 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
2548 fprintf (dump_file, "not possible.\n");
cc8bea0a
MS
2549
2550 if (set_no_warning)
2551 gimple_set_no_warning (stmt, true);
8b57bfeb
JJ
2552}
2553
24314386
MG
2554/* Handle a call to malloc or calloc. */
2555
2556static void
2557handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
2558{
355fe088 2559 gimple *stmt = gsi_stmt (*gsi);
24314386 2560 tree lhs = gimple_call_lhs (stmt);
a71dcca8
ML
2561 if (lhs == NULL_TREE)
2562 return;
2563
24314386
MG
2564 gcc_assert (get_stridx (lhs) == 0);
2565 int idx = new_stridx (lhs);
2566 tree length = NULL_TREE;
2567 if (bcode == BUILT_IN_CALLOC)
2568 length = build_int_cst (size_type_node, 0);
e3f9a279 2569 strinfo *si = new_strinfo (lhs, idx, length, length != NULL_TREE);
24314386
MG
2570 if (bcode == BUILT_IN_CALLOC)
2571 si->endptr = lhs;
2572 set_strinfo (idx, si);
2573 si->writable = true;
2574 si->stmt = stmt;
2575 si->dont_invalidate = true;
2576}
2577
2578/* Handle a call to memset.
2579 After a call to calloc, memset(,0,) is unnecessary.
2580 memset(malloc(n),0,n) is calloc(n,1). */
2581
2582static bool
2583handle_builtin_memset (gimple_stmt_iterator *gsi)
2584{
355fe088 2585 gimple *stmt2 = gsi_stmt (*gsi);
24314386
MG
2586 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
2587 return true;
2588 tree ptr = gimple_call_arg (stmt2, 0);
2589 int idx1 = get_stridx (ptr);
2590 if (idx1 <= 0)
2591 return true;
526ceb68 2592 strinfo *si1 = get_strinfo (idx1);
24314386
MG
2593 if (!si1)
2594 return true;
355fe088 2595 gimple *stmt1 = si1->stmt;
24314386
MG
2596 if (!stmt1 || !is_gimple_call (stmt1))
2597 return true;
2598 tree callee1 = gimple_call_fndecl (stmt1);
0ad84f34 2599 if (!valid_builtin_call (stmt1))
24314386
MG
2600 return true;
2601 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
2602 tree size = gimple_call_arg (stmt2, 2);
2603 if (code1 == BUILT_IN_CALLOC)
2604 /* Not touching stmt1 */ ;
2605 else if (code1 == BUILT_IN_MALLOC
2606 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
2607 {
2608 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
2609 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
2610 size, build_one_cst (size_type_node));
e3f9a279
RS
2611 si1->nonzero_chars = build_int_cst (size_type_node, 0);
2612 si1->full_string_p = true;
20cb2258 2613 si1->stmt = gsi_stmt (gsi1);
24314386
MG
2614 }
2615 else
2616 return true;
2617 tree lhs = gimple_call_lhs (stmt2);
2618 unlink_stmt_vdef (stmt2);
2619 if (lhs)
2620 {
355fe088 2621 gimple *assign = gimple_build_assign (lhs, ptr);
24314386
MG
2622 gsi_replace (gsi, assign, false);
2623 }
2624 else
2625 {
2626 gsi_remove (gsi, true);
2627 release_defs (stmt2);
2628 }
2629
2630 return false;
2631}
2632
36b85e43
BS
2633/* Handle a call to memcmp. We try to handle small comparisons by
2634 converting them to load and compare, and replacing the call to memcmp
2635 with a __builtin_memcmp_eq call where possible. */
2636
2637static bool
2638handle_builtin_memcmp (gimple_stmt_iterator *gsi)
2639{
2640 gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
2641 tree res = gimple_call_lhs (stmt2);
2642 tree arg1 = gimple_call_arg (stmt2, 0);
2643 tree arg2 = gimple_call_arg (stmt2, 1);
2644 tree len = gimple_call_arg (stmt2, 2);
2645 unsigned HOST_WIDE_INT leni;
2646 use_operand_p use_p;
2647 imm_use_iterator iter;
2648
2649 if (!res)
2650 return true;
2651
2652 FOR_EACH_IMM_USE_FAST (use_p, iter, res)
2653 {
2654 gimple *ustmt = USE_STMT (use_p);
2655
73d73b48
BS
2656 if (is_gimple_debug (ustmt))
2657 continue;
36b85e43
BS
2658 if (gimple_code (ustmt) == GIMPLE_ASSIGN)
2659 {
2660 gassign *asgn = as_a <gassign *> (ustmt);
2661 tree_code code = gimple_assign_rhs_code (asgn);
2662 if ((code != EQ_EXPR && code != NE_EXPR)
2663 || !integer_zerop (gimple_assign_rhs2 (asgn)))
2664 return true;
2665 }
2666 else if (gimple_code (ustmt) == GIMPLE_COND)
2667 {
2668 tree_code code = gimple_cond_code (ustmt);
2669 if ((code != EQ_EXPR && code != NE_EXPR)
2670 || !integer_zerop (gimple_cond_rhs (ustmt)))
2671 return true;
2672 }
2673 else
2674 return true;
2675 }
2676
2677 if (tree_fits_uhwi_p (len)
2678 && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
146ec50f 2679 && pow2p_hwi (leni))
36b85e43
BS
2680 {
2681 leni *= CHAR_TYPE_SIZE;
2682 unsigned align1 = get_pointer_alignment (arg1);
2683 unsigned align2 = get_pointer_alignment (arg2);
2684 unsigned align = MIN (align1, align2);
fffbab82
RS
2685 scalar_int_mode mode;
2686 if (int_mode_for_size (leni, 1).exists (&mode)
e0bd6c9f 2687 && (align >= leni || !targetm.slow_unaligned_access (mode, align)))
36b85e43
BS
2688 {
2689 location_t loc = gimple_location (stmt2);
2690 tree type, off;
2691 type = build_nonstandard_integer_type (leni, 1);
2692 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
2693 tree ptrtype = build_pointer_type_for_mode (char_type_node,
2694 ptr_mode, true);
2695 off = build_int_cst (ptrtype, 0);
2696 arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
2697 arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
2698 tree tem1 = fold_const_aggregate_ref (arg1);
2699 if (tem1)
2700 arg1 = tem1;
2701 tree tem2 = fold_const_aggregate_ref (arg2);
2702 if (tem2)
2703 arg2 = tem2;
2704 res = fold_convert_loc (loc, TREE_TYPE (res),
2705 fold_build2_loc (loc, NE_EXPR,
2706 boolean_type_node,
2707 arg1, arg2));
2708 gimplify_and_update_call_from_tree (gsi, res);
2709 return false;
2710 }
2711 }
2712
2713 gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
2714 return false;
2715}
2716
8b57bfeb
JJ
2717/* Handle a POINTER_PLUS_EXPR statement.
2718 For p = "abcd" + 2; compute associated length, or if
2719 p = q + off is pointing to a '\0' character of a string, call
2720 zero_length_string on it. */
2721
2722static void
2723handle_pointer_plus (gimple_stmt_iterator *gsi)
2724{
355fe088 2725 gimple *stmt = gsi_stmt (*gsi);
8b57bfeb
JJ
2726 tree lhs = gimple_assign_lhs (stmt), off;
2727 int idx = get_stridx (gimple_assign_rhs1 (stmt));
526ceb68 2728 strinfo *si, *zsi;
8b57bfeb
JJ
2729
2730 if (idx == 0)
2731 return;
2732
2733 if (idx < 0)
2734 {
2735 tree off = gimple_assign_rhs2 (stmt);
cc269bb6 2736 if (tree_fits_uhwi_p (off)
7d362f6c 2737 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
9771b263 2738 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
ae7e9ddd 2739 = ~(~idx - (int) tree_to_uhwi (off));
8b57bfeb
JJ
2740 return;
2741 }
2742
2743 si = get_strinfo (idx);
e3f9a279 2744 if (si == NULL || si->nonzero_chars == NULL_TREE)
8b57bfeb
JJ
2745 return;
2746
2747 off = gimple_assign_rhs2 (stmt);
2748 zsi = NULL;
e3f9a279 2749 if (si->full_string_p && operand_equal_p (si->nonzero_chars, off, 0))
8b57bfeb
JJ
2750 zsi = zero_length_string (lhs, si);
2751 else if (TREE_CODE (off) == SSA_NAME)
2752 {
355fe088 2753 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
8b57bfeb 2754 if (gimple_assign_single_p (def_stmt)
e3f9a279
RS
2755 && si->full_string_p
2756 && operand_equal_p (si->nonzero_chars,
2757 gimple_assign_rhs1 (def_stmt), 0))
8b57bfeb
JJ
2758 zsi = zero_length_string (lhs, si);
2759 }
2760 if (zsi != NULL
2761 && si->endptr != NULL_TREE
2762 && si->endptr != lhs
2763 && TREE_CODE (si->endptr) == SSA_NAME)
2764 {
2765 enum tree_code rhs_code
2766 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
2767 ? SSA_NAME : NOP_EXPR;
00d66391 2768 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
8b57bfeb
JJ
2769 gcc_assert (gsi_stmt (*gsi) == stmt);
2770 update_stmt (stmt);
2771 }
2772}
2773
2774/* Handle a single character store. */
2775
2776static bool
2777handle_char_store (gimple_stmt_iterator *gsi)
2778{
2779 int idx = -1;
526ceb68 2780 strinfo *si = NULL;
355fe088 2781 gimple *stmt = gsi_stmt (*gsi);
8b57bfeb 2782 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
e3f9a279
RS
2783 tree rhs = gimple_assign_rhs1 (stmt);
2784 unsigned HOST_WIDE_INT offset = 0;
8b57bfeb
JJ
2785
2786 if (TREE_CODE (lhs) == MEM_REF
2787 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
2788 {
e3f9a279
RS
2789 tree mem_offset = TREE_OPERAND (lhs, 1);
2790 if (tree_fits_uhwi_p (mem_offset))
8b57bfeb 2791 {
e3f9a279
RS
2792 /* Get the strinfo for the base, and use it if it starts with at
2793 least OFFSET nonzero characters. This is trivially true if
2794 OFFSET is zero. */
2795 offset = tree_to_uhwi (mem_offset);
2796 idx = get_stridx (TREE_OPERAND (lhs, 0));
2797 if (idx > 0)
2798 si = get_strinfo (idx);
2799 if (offset == 0)
2800 ssaname = TREE_OPERAND (lhs, 0);
2801 else if (si == NULL || compare_nonzero_chars (si, offset) < 0)
2802 return true;
8b57bfeb
JJ
2803 }
2804 }
2805 else
e3f9a279
RS
2806 {
2807 idx = get_addr_stridx (lhs, NULL_TREE, &offset);
2808 if (idx > 0)
2809 si = get_strinfo (idx);
2810 }
8b57bfeb 2811
e3f9a279
RS
2812 bool storing_zero_p = initializer_zerop (rhs);
2813 bool storing_nonzero_p = (!storing_zero_p
2814 && TREE_CODE (rhs) == INTEGER_CST
2815 && integer_nonzerop (rhs));
2816
2817 if (si != NULL)
8b57bfeb 2818 {
e3f9a279
RS
2819 int cmp = compare_nonzero_chars (si, offset);
2820 gcc_assert (offset == 0 || cmp >= 0);
2821 if (storing_zero_p && cmp == 0 && si->full_string_p)
8b57bfeb 2822 {
e3f9a279
RS
2823 /* When overwriting a '\0' with a '\0', the store can be removed
2824 if we know it has been stored in the current function. */
2825 if (!stmt_could_throw_p (stmt) && si->writable)
8b57bfeb 2826 {
e3f9a279
RS
2827 unlink_stmt_vdef (stmt);
2828 release_defs (stmt);
2829 gsi_remove (gsi, true);
2830 return false;
8b57bfeb
JJ
2831 }
2832 else
e3f9a279
RS
2833 {
2834 si->writable = true;
2835 gsi_next (gsi);
2836 return false;
2837 }
8b57bfeb 2838 }
e3f9a279 2839 /* If si->nonzero_chars > OFFSET, we aren't overwriting '\0',
5b115c1f
MP
2840 and if we aren't storing '\0', we know that the length of the
2841 string and any other zero terminated string in memory remains
2842 the same. In that case we move to the next gimple statement and
2843 return to signal the caller that it shouldn't invalidate anything.
2844
2845 This is benefical for cases like:
2846
2847 char p[20];
2848 void foo (char *q)
2849 {
2850 strcpy (p, "foobar");
2851 size_t len = strlen (p); // This can be optimized into 6
2852 size_t len2 = strlen (q); // This has to be computed
2853 p[0] = 'X';
2854 size_t len3 = strlen (p); // This can be optimized into 6
2855 size_t len4 = strlen (q); // This can be optimized into len2
2856 bar (len, len2, len3, len4);
2857 }
2858 */
e3f9a279 2859 else if (storing_nonzero_p && cmp > 0)
5b115c1f
MP
2860 {
2861 gsi_next (gsi);
2862 return false;
2863 }
e3f9a279
RS
2864 else if (storing_zero_p || storing_nonzero_p || (offset != 0 && cmp > 0))
2865 {
2866 /* When storing_nonzero_p, we know that the string now starts
2867 with OFFSET + 1 nonzero characters, but don't know whether
2868 there's a following nul terminator.
2869
2870 When storing_zero_p, we know that the string is now OFFSET
2871 characters long.
2872
2873 Otherwise, we're storing an unknown value at offset OFFSET,
2874 so need to clip the nonzero_chars to OFFSET. */
2875 location_t loc = gimple_location (stmt);
2876 tree oldlen = si->nonzero_chars;
2877 if (cmp == 0 && si->full_string_p)
2878 /* We're overwriting the nul terminator with a nonzero or
2879 unknown character. If the previous stmt was a memcpy,
2880 its length may be decreased. */
2881 adjust_last_stmt (si, stmt, false);
2882 si = unshare_strinfo (si);
2883 if (storing_nonzero_p)
2884 si->nonzero_chars = build_int_cst (size_type_node, offset + 1);
2885 else
2886 si->nonzero_chars = build_int_cst (size_type_node, offset);
2887 si->full_string_p = storing_zero_p;
2888 if (storing_zero_p
2889 && ssaname
2890 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2891 si->endptr = ssaname;
2892 else
2893 si->endptr = NULL;
2894 si->next = 0;
2895 si->stmt = NULL;
2896 si->writable = true;
2897 si->dont_invalidate = true;
2898 if (oldlen)
2899 {
2900 tree adj = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
2901 si->nonzero_chars, oldlen);
2902 adjust_related_strinfos (loc, si, adj);
2903 }
2904 else
2905 si->prev = 0;
2906 }
8b57bfeb 2907 }
e3f9a279 2908 else if (idx == 0 && (storing_zero_p || storing_nonzero_p))
8b57bfeb
JJ
2909 {
2910 if (ssaname)
e3f9a279 2911 idx = new_stridx (ssaname);
8b57bfeb 2912 else
e3f9a279
RS
2913 idx = new_addr_stridx (lhs);
2914 if (idx != 0)
8b57bfeb 2915 {
e3f9a279
RS
2916 tree ptr = (ssaname ? ssaname : build_fold_addr_expr (lhs));
2917 tree len = storing_nonzero_p ? size_one_node : size_zero_node;
2918 si = new_strinfo (ptr, idx, len, storing_zero_p);
2919 set_strinfo (idx, si);
2920 if (storing_zero_p
2921 && ssaname
2922 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2923 si->endptr = ssaname;
2924 si->dont_invalidate = true;
2925 si->writable = true;
8b57bfeb 2926 }
8b57bfeb 2927 }
198fe1bf
JJ
2928 else if (idx == 0
2929 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2930 && ssaname == NULL_TREE
2931 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2932 {
2933 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2934 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2935 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2936 {
2937 int idx = new_addr_stridx (lhs);
2938 if (idx != 0)
2939 {
2940 si = new_strinfo (build_fold_addr_expr (lhs), idx,
e3f9a279 2941 build_int_cst (size_type_node, l), true);
198fe1bf
JJ
2942 set_strinfo (idx, si);
2943 si->dont_invalidate = true;
2944 }
2945 }
2946 }
8b57bfeb 2947
e3f9a279 2948 if (si != NULL && offset == 0 && storing_zero_p)
8b57bfeb
JJ
2949 {
2950 /* Allow adjust_last_stmt to remove it if the stored '\0'
2951 is immediately overwritten. */
2952 laststmt.stmt = stmt;
2953 laststmt.len = build_int_cst (size_type_node, 1);
2954 laststmt.stridx = si->idx;
2955 }
2956 return true;
2957}
2958
f368600f 2959/* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0. */
3b1970cb
PK
2960
2961static void
f368600f 2962fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
3b1970cb
PK
2963{
2964 if (TREE_CODE (rhs1) != SSA_NAME
2965 || TREE_CODE (rhs2) != SSA_NAME)
2966 return;
2967
2968 gimple *call_stmt = NULL;
2969 for (int pass = 0; pass < 2; pass++)
2970 {
2971 gimple *g = SSA_NAME_DEF_STMT (rhs1);
2972 if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
2973 && has_single_use (rhs1)
2974 && gimple_call_arg (g, 0) == rhs2)
2975 {
2976 call_stmt = g;
2977 break;
2978 }
2979 std::swap (rhs1, rhs2);
2980 }
2981
2982 if (call_stmt)
2983 {
2984 tree arg0 = gimple_call_arg (call_stmt, 0);
2985
2986 if (arg0 == rhs2)
2987 {
2988 tree arg1 = gimple_call_arg (call_stmt, 1);
2989 tree arg1_len = NULL_TREE;
2990 int idx = get_stridx (arg1);
2991
2992 if (idx)
2993 {
2994 if (idx < 0)
2995 arg1_len = build_int_cst (size_type_node, ~idx);
2996 else
2997 {
2998 strinfo *si = get_strinfo (idx);
2999 if (si)
3000 arg1_len = get_string_length (si);
3001 }
3002 }
3003
3004 if (arg1_len != NULL_TREE)
3005 {
3006 gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
f368600f
ML
3007 tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
3008 gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
3b1970cb 3009 arg0, arg1, arg1_len);
f368600f
ML
3010 tree strncmp_lhs = make_ssa_name (integer_type_node);
3011 gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
3012 gimple_call_set_lhs (strncmp_call, strncmp_lhs);
3b1970cb 3013 gsi_remove (&gsi, true);
f368600f
ML
3014 gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
3015 tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
3b1970cb
PK
3016
3017 if (is_gimple_assign (stmt))
3018 {
3019 if (gimple_assign_rhs_code (stmt) == COND_EXPR)
3020 {
3021 tree cond = gimple_assign_rhs1 (stmt);
f368600f 3022 TREE_OPERAND (cond, 0) = strncmp_lhs;
3b1970cb
PK
3023 TREE_OPERAND (cond, 1) = zero;
3024 }
3025 else
3026 {
f368600f 3027 gimple_assign_set_rhs1 (stmt, strncmp_lhs);
3b1970cb
PK
3028 gimple_assign_set_rhs2 (stmt, zero);
3029 }
3030 }
3031 else
3032 {
3033 gcond *cond = as_a<gcond *> (stmt);
f368600f 3034 gimple_cond_set_lhs (cond, strncmp_lhs);
3b1970cb
PK
3035 gimple_cond_set_rhs (cond, zero);
3036 }
3037 update_stmt (stmt);
3038 }
3039 }
3040 }
3041}
3042
cc8bea0a
MS
3043/* Attempt to check for validity of the performed access a single statement
3044 at *GSI using string length knowledge, and to optimize it. */
8b57bfeb
JJ
3045
3046static bool
cc8bea0a 3047strlen_check_and_optimize_stmt (gimple_stmt_iterator *gsi)
8b57bfeb 3048{
355fe088 3049 gimple *stmt = gsi_stmt (*gsi);
8b57bfeb
JJ
3050
3051 if (is_gimple_call (stmt))
3052 {
3053 tree callee = gimple_call_fndecl (stmt);
0ad84f34 3054 if (valid_builtin_call (stmt))
8b57bfeb
JJ
3055 switch (DECL_FUNCTION_CODE (callee))
3056 {
3057 case BUILT_IN_STRLEN:
f5fc4a04 3058 case BUILT_IN_STRLEN_CHKP:
8b57bfeb
JJ
3059 handle_builtin_strlen (gsi);
3060 break;
3061 case BUILT_IN_STRCHR:
f5fc4a04 3062 case BUILT_IN_STRCHR_CHKP:
8b57bfeb
JJ
3063 handle_builtin_strchr (gsi);
3064 break;
3065 case BUILT_IN_STRCPY:
3066 case BUILT_IN_STRCPY_CHK:
3067 case BUILT_IN_STPCPY:
3068 case BUILT_IN_STPCPY_CHK:
f5fc4a04
IE
3069 case BUILT_IN_STRCPY_CHKP:
3070 case BUILT_IN_STRCPY_CHK_CHKP:
3071 case BUILT_IN_STPCPY_CHKP:
3072 case BUILT_IN_STPCPY_CHK_CHKP:
8b57bfeb
JJ
3073 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
3074 break;
025d57f0
MS
3075
3076 case BUILT_IN_STRNCAT:
3077 case BUILT_IN_STRNCAT_CHK:
3078 handle_builtin_strncat (DECL_FUNCTION_CODE (callee), gsi);
3079 break;
3080
3081 case BUILT_IN_STPNCPY:
3082 case BUILT_IN_STPNCPY_CHK:
3083 case BUILT_IN_STRNCPY:
3084 case BUILT_IN_STRNCPY_CHK:
3085 handle_builtin_stxncpy (DECL_FUNCTION_CODE (callee), gsi);
3086 break;
3087
8b57bfeb
JJ
3088 case BUILT_IN_MEMCPY:
3089 case BUILT_IN_MEMCPY_CHK:
3090 case BUILT_IN_MEMPCPY:
3091 case BUILT_IN_MEMPCPY_CHK:
f5fc4a04
IE
3092 case BUILT_IN_MEMCPY_CHKP:
3093 case BUILT_IN_MEMCPY_CHK_CHKP:
3094 case BUILT_IN_MEMPCPY_CHKP:
3095 case BUILT_IN_MEMPCPY_CHK_CHKP:
8b57bfeb
JJ
3096 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
3097 break;
3098 case BUILT_IN_STRCAT:
3099 case BUILT_IN_STRCAT_CHK:
f5fc4a04
IE
3100 case BUILT_IN_STRCAT_CHKP:
3101 case BUILT_IN_STRCAT_CHK_CHKP:
8b57bfeb
JJ
3102 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
3103 break;
24314386
MG
3104 case BUILT_IN_MALLOC:
3105 case BUILT_IN_CALLOC:
3106 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
3107 break;
3108 case BUILT_IN_MEMSET:
3109 if (!handle_builtin_memset (gsi))
3110 return false;
3111 break;
36b85e43
BS
3112 case BUILT_IN_MEMCMP:
3113 if (!handle_builtin_memcmp (gsi))
3114 return false;
3115 break;
8b57bfeb
JJ
3116 default:
3117 break;
3118 }
3119 }
5004bd00 3120 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
8b57bfeb
JJ
3121 {
3122 tree lhs = gimple_assign_lhs (stmt);
3123
3124 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
3125 {
3126 if (gimple_assign_single_p (stmt)
3127 || (gimple_assign_cast_p (stmt)
3128 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
3129 {
3130 int idx = get_stridx (gimple_assign_rhs1 (stmt));
9771b263 3131 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
8b57bfeb
JJ
3132 }
3133 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
3134 handle_pointer_plus (gsi);
3135 }
3b1970cb
PK
3136 else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
3137 {
3138 enum tree_code code = gimple_assign_rhs_code (stmt);
3139 if (code == COND_EXPR)
3140 {
3141 tree cond = gimple_assign_rhs1 (stmt);
3142 enum tree_code cond_code = TREE_CODE (cond);
3143
3144 if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
f368600f
ML
3145 fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
3146 TREE_OPERAND (cond, 1), stmt);
3b1970cb
PK
3147 }
3148 else if (code == EQ_EXPR || code == NE_EXPR)
f368600f
ML
3149 fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
3150 gimple_assign_rhs2 (stmt), stmt);
f744bfec
JJ
3151 else if (gimple_assign_load_p (stmt)
3152 && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE
3153 && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (char_type_node)
3154 && (TYPE_PRECISION (TREE_TYPE (lhs))
3155 == TYPE_PRECISION (char_type_node))
3156 && !gimple_has_volatile_ops (stmt))
3157 {
3158 tree off = integer_zero_node;
3159 unsigned HOST_WIDE_INT coff = 0;
ad2a970f 3160 int idx = 0;
f744bfec
JJ
3161 tree rhs1 = gimple_assign_rhs1 (stmt);
3162 if (code == MEM_REF)
3163 {
3164 idx = get_stridx (TREE_OPERAND (rhs1, 0));
ad2a970f
JJ
3165 if (idx > 0)
3166 {
3167 strinfo *si = get_strinfo (idx);
3168 if (si
3169 && si->nonzero_chars
3170 && TREE_CODE (si->nonzero_chars) == INTEGER_CST
3171 && (wi::to_widest (si->nonzero_chars)
3172 >= wi::to_widest (off)))
3173 off = TREE_OPERAND (rhs1, 1);
3174 else
3175 /* This case is not useful. See if get_addr_stridx
3176 returns something usable. */
3177 idx = 0;
3178 }
f744bfec 3179 }
ad2a970f 3180 if (idx <= 0)
f744bfec
JJ
3181 idx = get_addr_stridx (rhs1, NULL_TREE, &coff);
3182 if (idx > 0)
3183 {
3184 strinfo *si = get_strinfo (idx);
3185 if (si
3186 && si->nonzero_chars
3187 && TREE_CODE (si->nonzero_chars) == INTEGER_CST)
3188 {
3189 widest_int w1 = wi::to_widest (si->nonzero_chars);
3190 widest_int w2 = wi::to_widest (off) + coff;
3191 if (w1 == w2
3192 && si->full_string_p)
3193 {
3194 /* Reading the final '\0' character. */
3195 tree zero = build_int_cst (TREE_TYPE (lhs), 0);
3196 gimple_set_vuse (stmt, NULL_TREE);
3197 gimple_assign_set_rhs_from_tree (gsi, zero);
3198 update_stmt (gsi_stmt (*gsi));
3199 }
3200 else if (w1 > w2)
3201 {
3202 /* Reading a character before the final '\0'
3203 character. Just set the value range to ~[0, 0]
3204 if we don't have anything better. */
3205 wide_int min, max;
3206 tree type = TREE_TYPE (lhs);
3207 enum value_range_type vr
3208 = get_range_info (lhs, &min, &max);
3209 if (vr == VR_VARYING
3210 || (vr == VR_RANGE
3211 && min == wi::min_value (TYPE_PRECISION (type),
3212 TYPE_SIGN (type))
3213 && max == wi::max_value (TYPE_PRECISION (type),
3214 TYPE_SIGN (type))))
3215 set_range_info (lhs, VR_ANTI_RANGE,
3216 wi::zero (TYPE_PRECISION (type)),
3217 wi::zero (TYPE_PRECISION (type)));
3218 }
3219 }
3220 }
3221 }
025d57f0 3222
6a33d0ff
MS
3223 if (strlen_to_stridx)
3224 {
3225 tree rhs1 = gimple_assign_rhs1 (stmt);
3226 if (stridx_strlenloc *ps = strlen_to_stridx->get (rhs1))
3227 strlen_to_stridx->put (lhs, stridx_strlenloc (*ps));
3228 }
3b1970cb
PK
3229 }
3230 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
8b57bfeb
JJ
3231 {
3232 tree type = TREE_TYPE (lhs);
3233 if (TREE_CODE (type) == ARRAY_TYPE)
3234 type = TREE_TYPE (type);
3235 if (TREE_CODE (type) == INTEGER_TYPE
3236 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
3237 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
3238 {
3239 if (! handle_char_store (gsi))
3240 return false;
3241 }
3242 }
3243 }
3b1970cb
PK
3244 else if (gcond *cond = dyn_cast<gcond *> (stmt))
3245 {
3246 enum tree_code code = gimple_cond_code (cond);
3247 if (code == EQ_EXPR || code == NE_EXPR)
f368600f
ML
3248 fold_strstr_to_strncmp (gimple_cond_lhs (stmt),
3249 gimple_cond_rhs (stmt), stmt);
3b1970cb 3250 }
8b57bfeb
JJ
3251
3252 if (gimple_vdef (stmt))
3253 maybe_invalidate (stmt);
3254 return true;
3255}
3256
3257/* Recursively call maybe_invalidate on stmts that might be executed
3258 in between dombb and current bb and that contain a vdef. Stop when
3259 *count stmts are inspected, or if the whole strinfo vector has
3260 been invalidated. */
3261
3262static void
355fe088 3263do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
8b57bfeb
JJ
3264{
3265 unsigned int i, n = gimple_phi_num_args (phi);
3266
3267 for (i = 0; i < n; i++)
3268 {
3269 tree vuse = gimple_phi_arg_def (phi, i);
355fe088 3270 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
8b57bfeb
JJ
3271 basic_block bb = gimple_bb (stmt);
3272 if (bb == NULL
3273 || bb == dombb
3274 || !bitmap_set_bit (visited, bb->index)
3275 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
3276 continue;
3277 while (1)
3278 {
3279 if (gimple_code (stmt) == GIMPLE_PHI)
3280 {
3281 do_invalidate (dombb, stmt, visited, count);
3282 if (*count == 0)
3283 return;
3284 break;
3285 }
3286 if (--*count == 0)
3287 return;
3288 if (!maybe_invalidate (stmt))
3289 {
3290 *count = 0;
3291 return;
3292 }
3293 vuse = gimple_vuse (stmt);
3294 stmt = SSA_NAME_DEF_STMT (vuse);
3295 if (gimple_bb (stmt) != bb)
3296 {
3297 bb = gimple_bb (stmt);
3298 if (bb == NULL
3299 || bb == dombb
3300 || !bitmap_set_bit (visited, bb->index)
3301 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
3302 break;
3303 }
3304 }
3305 }
3306}
3307
4d9192b5
TS
3308class strlen_dom_walker : public dom_walker
3309{
3310public:
3311 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
3312
3daacdcd 3313 virtual edge before_dom_children (basic_block);
4d9192b5
TS
3314 virtual void after_dom_children (basic_block);
3315};
3316
8b57bfeb 3317/* Callback for walk_dominator_tree. Attempt to optimize various
c7880c8c 3318 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */
8b57bfeb 3319
3daacdcd 3320edge
4d9192b5 3321strlen_dom_walker::before_dom_children (basic_block bb)
8b57bfeb 3322{
8b57bfeb
JJ
3323 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
3324
3325 if (dombb == NULL)
3326 stridx_to_strinfo = NULL;
3327 else
3328 {
526ceb68 3329 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
8b57bfeb
JJ
3330 if (stridx_to_strinfo)
3331 {
538dd0b7
DM
3332 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
3333 gsi_next (&gsi))
8b57bfeb 3334 {
538dd0b7 3335 gphi *phi = gsi.phi ();
ea057359 3336 if (virtual_operand_p (gimple_phi_result (phi)))
8b57bfeb
JJ
3337 {
3338 bitmap visited = BITMAP_ALLOC (NULL);
3339 int count_vdef = 100;
3340 do_invalidate (dombb, phi, visited, &count_vdef);
3341 BITMAP_FREE (visited);
8b29fd4e
JJ
3342 if (count_vdef == 0)
3343 {
3344 /* If there were too many vdefs in between immediate
3345 dominator and current bb, invalidate everything.
3346 If stridx_to_strinfo has been unshared, we need
3347 to free it, otherwise just set it to NULL. */
3348 if (!strinfo_shared ())
3349 {
3350 unsigned int i;
526ceb68 3351 strinfo *si;
8b29fd4e
JJ
3352
3353 for (i = 1;
3354 vec_safe_iterate (stridx_to_strinfo, i, &si);
3355 ++i)
3356 {
3357 free_strinfo (si);
3358 (*stridx_to_strinfo)[i] = NULL;
3359 }
3360 }
3361 else
3362 stridx_to_strinfo = NULL;
3363 }
8b57bfeb
JJ
3364 break;
3365 }
3366 }
3367 }
3368 }
3369
3370 /* If all PHI arguments have the same string index, the PHI result
3371 has it as well. */
538dd0b7
DM
3372 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
3373 gsi_next (&gsi))
8b57bfeb 3374 {
538dd0b7 3375 gphi *phi = gsi.phi ();
8b57bfeb 3376 tree result = gimple_phi_result (phi);
ea057359 3377 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
8b57bfeb
JJ
3378 {
3379 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
3380 if (idx != 0)
3381 {
3382 unsigned int i, n = gimple_phi_num_args (phi);
3383 for (i = 1; i < n; i++)
3384 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
3385 break;
3386 if (i == n)
9771b263 3387 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
8b57bfeb
JJ
3388 }
3389 }
3390 }
3391
3392 /* Attempt to optimize individual statements. */
538dd0b7 3393 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
cc8bea0a 3394 if (strlen_check_and_optimize_stmt (&gsi))
8b57bfeb
JJ
3395 gsi_next (&gsi);
3396
3397 bb->aux = stridx_to_strinfo;
9771b263 3398 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
526ceb68 3399 (*stridx_to_strinfo)[0] = (strinfo *) bb;
3daacdcd 3400 return NULL;
8b57bfeb
JJ
3401}
3402
3403/* Callback for walk_dominator_tree. Free strinfo vector if it is
3404 owned by the current bb, clear bb->aux. */
3405
4d9192b5
TS
3406void
3407strlen_dom_walker::after_dom_children (basic_block bb)
8b57bfeb
JJ
3408{
3409 if (bb->aux)
3410 {
526ceb68 3411 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
9771b263 3412 if (vec_safe_length (stridx_to_strinfo)
526ceb68 3413 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
8b57bfeb
JJ
3414 {
3415 unsigned int i;
526ceb68 3416 strinfo *si;
8b57bfeb 3417
9771b263 3418 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
8b57bfeb 3419 free_strinfo (si);
9771b263 3420 vec_free (stridx_to_strinfo);
8b57bfeb
JJ
3421 }
3422 bb->aux = NULL;
3423 }
3424}
3425
3426/* Main entry point. */
3427
27a4cd48
DM
3428namespace {
3429
3430const pass_data pass_data_strlen =
8b57bfeb 3431{
27a4cd48
DM
3432 GIMPLE_PASS, /* type */
3433 "strlen", /* name */
3434 OPTGROUP_NONE, /* optinfo_flags */
27a4cd48
DM
3435 TV_TREE_STRLEN, /* tv_id */
3436 ( PROP_cfg | PROP_ssa ), /* properties_required */
3437 0, /* properties_provided */
3438 0, /* properties_destroyed */
3439 0, /* todo_flags_start */
3bea341f 3440 0, /* todo_flags_finish */
8b57bfeb 3441};
27a4cd48
DM
3442
3443class pass_strlen : public gimple_opt_pass
3444{
3445public:
c3284718
RS
3446 pass_strlen (gcc::context *ctxt)
3447 : gimple_opt_pass (pass_data_strlen, ctxt)
27a4cd48
DM
3448 {}
3449
3450 /* opt_pass methods: */
1a3d085c 3451 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
be55bfe6 3452 virtual unsigned int execute (function *);
27a4cd48
DM
3453
3454}; // class pass_strlen
3455
be55bfe6
TS
3456unsigned int
3457pass_strlen::execute (function *fun)
3458{
6a33d0ff
MS
3459 gcc_assert (!strlen_to_stridx);
3460 if (warn_stringop_overflow || warn_stringop_truncation)
3461 strlen_to_stridx = new hash_map<tree, stridx_strlenloc> ();
3462
be55bfe6
TS
3463 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
3464 max_stridx = 1;
be55bfe6
TS
3465
3466 calculate_dominance_info (CDI_DOMINATORS);
3467
3468 /* String length optimization is implemented as a walk of the dominator
3469 tree and a forward walk of statements within each block. */
3470 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
3471
3472 ssa_ver_to_stridx.release ();
33e7d32e 3473 strinfo_pool.release ();
c203e8a7 3474 if (decl_to_stridxlist_htab)
be55bfe6
TS
3475 {
3476 obstack_free (&stridx_obstack, NULL);
c203e8a7
TS
3477 delete decl_to_stridxlist_htab;
3478 decl_to_stridxlist_htab = NULL;
be55bfe6
TS
3479 }
3480 laststmt.stmt = NULL;
3481 laststmt.len = NULL_TREE;
3482 laststmt.stridx = 0;
3483
6a33d0ff
MS
3484 if (strlen_to_stridx)
3485 {
3486 strlen_to_stridx->empty ();
3487 delete strlen_to_stridx;
3488 strlen_to_stridx = NULL;
3489 }
025d57f0 3490
be55bfe6
TS
3491 return 0;
3492}
3493
27a4cd48
DM
3494} // anon namespace
3495
3496gimple_opt_pass *
3497make_pass_strlen (gcc::context *ctxt)
3498{
3499 return new pass_strlen (ctxt);
3500}