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