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