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