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