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