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