]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/tree-ssa-strlen.c
gcc/ada/
[thirdparty/gcc.git] / gcc / tree-ssa-strlen.c
1 /* String length optimization
2 Copyright (C) 2011-2013 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along 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"
24 #include "tree.h"
25 #include "hash-table.h"
26 #include "bitmap.h"
27 #include "gimple.h"
28 #include "gimplify.h"
29 #include "gimple-iterator.h"
30 #include "gimplify-me.h"
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"
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"
42 #include "expr.h"
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). */
47 static vec<int> ssa_ver_to_stridx;
48
49 /* Number of currently active string indexes plus one. */
50 static int max_stridx;
51
52 /* String information record. */
53 typedef 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;
98
99 /* Pool for allocating strinfo_struct entries. */
100 static 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. */
108 static vec<strinfo, va_heap, vl_embed> *stridx_to_strinfo;
109
110 /* One OFFSET->IDX mapping. */
111 struct 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. */
119 struct decl_stridxlist_map
120 {
121 struct tree_map_base base;
122 struct stridxlist list;
123 };
124
125 /* stridxlist hashtable helpers. */
126
127 struct 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
137 inline hashval_t
138 stridxlist_hasher::hash (const value_type *item)
139 {
140 return DECL_UID (item->base.from);
141 }
142
143 inline bool
144 stridxlist_hasher::equal (const value_type *v, const compare_type *c)
145 {
146 return tree_map_base_eq (&v->base, &c->base);
147 }
148
149 /* Hash table for mapping decls to a chained list of offset -> idx
150 mappings. */
151 static hash_table <stridxlist_hasher> decl_to_stridxlist_htab;
152
153 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
154 static 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. */
159 struct laststmt_struct
160 {
161 gimple stmt;
162 tree len;
163 int stridx;
164 } laststmt;
165
166 /* Helper function for get_stridx. */
167
168 static int
169 get_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
176 if (!decl_to_stridxlist_htab.is_created ())
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;
184 e = decl_to_stridxlist_htab.find_with_hash (&ent, DECL_UID (base));
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
201 static int
202 get_stridx (tree exp)
203 {
204 tree s, o;
205
206 if (TREE_CODE (exp) == SSA_NAME)
207 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
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
216 s = string_constant (exp, &o);
217 if (s != NULL_TREE
218 && (o == NULL_TREE || tree_fits_shwi_p (o))
219 && TREE_STRING_LENGTH (s) > 0)
220 {
221 HOST_WIDE_INT offset = o ? tree_low_cst (o, 0) : 0;
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);
227 }
228 return 0;
229 }
230
231 /* Return true if strinfo vector is shared with the immediate dominator. */
232
233 static inline bool
234 strinfo_shared (void)
235 {
236 return vec_safe_length (stridx_to_strinfo)
237 && (*stridx_to_strinfo)[0] != NULL;
238 }
239
240 /* Unshare strinfo vector that is shared with the immediate dominator. */
241
242 static void
243 unshare_strinfo_vec (void)
244 {
245 strinfo si;
246 unsigned int i = 0;
247
248 gcc_assert (strinfo_shared ());
249 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
250 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
251 if (si != NULL)
252 si->refcount++;
253 (*stridx_to_strinfo)[0] = NULL;
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
260 static int *
261 addr_stridxptr (tree exp)
262 {
263 decl_stridxlist_map **slot;
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
272 if (!decl_to_stridxlist_htab.is_created ())
273 {
274 decl_to_stridxlist_htab.create (64);
275 gcc_obstack_init (&stridx_obstack);
276 }
277 ent.base.from = base;
278 slot = decl_to_stridxlist_htab.find_slot_with_hash (&ent, DECL_UID (base),
279 INSERT);
280 if (*slot)
281 {
282 int i;
283 list = &(*slot)->list;
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;
301 *slot = e;
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
312 static int
313 new_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++;
323 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
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
341 static int
342 new_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
359 static strinfo
360 new_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
379 static inline void
380 free_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
388 static inline strinfo
389 get_strinfo (int idx)
390 {
391 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
392 return NULL;
393 return (*stridx_to_strinfo)[idx];
394 }
395
396 /* Set strinfo in the vector entry IDX to SI. */
397
398 static inline void
399 set_strinfo (int idx, strinfo si)
400 {
401 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
402 unshare_strinfo_vec ();
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;
406 }
407
408 /* Return string length, or NULL if it can't be computed. */
409
410 static tree
411 get_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;
419 tree callee, lhs, fn, tem;
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);
427 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
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);
439 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
440 gcc_assert (lhs == NULL_TREE);
441 tem = unshare_expr (gimple_call_arg (stmt, 0));
442 lenstmt = gimple_build_call (fn, 1, tem);
443 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
444 gimple_call_set_lhs (lenstmt, lhs);
445 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
446 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
447 tem = gimple_call_arg (stmt, 0);
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 }
454 lenstmt
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);
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)
466 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
467 else
468 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
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);
476 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
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
508 static bool
509 maybe_invalidate (gimple stmt)
510 {
511 strinfo si;
512 unsigned int i;
513 bool nonempty = false;
514
515 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
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
539 static strinfo
540 unshare_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
563 static strinfo
564 verify_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
589 static strinfo
590 zero_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 }
618 gcc_assert (chainsi->length || chainsi->stmt);
619 if (chainsi->endptr == NULL_TREE)
620 {
621 chainsi = unshare_strinfo (chainsi);
622 chainsi->endptr = ptr;
623 }
624 if (chainsi->length && integer_zerop (chainsi->length))
625 {
626 if (chainsi->next)
627 {
628 chainsi = unshare_strinfo (chainsi);
629 chainsi->next = 0;
630 }
631 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
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;
655 if (chainsi->endptr == NULL_TREE)
656 chainsi->endptr = ptr;
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
668 static void
669 adjust_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);
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
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
716 static void
717 find_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;
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 */
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 }
746 default:
747 return;
748 }
749
750 /* We might find an endptr created in this pass. Grow the
751 vector in that case. */
752 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
753 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
754
755 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
756 return;
757 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
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
767 static void
768 adjust_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
835 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
836 return;
837
838 callee = gimple_call_fndecl (last.stmt);
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);
849 if (host_integerp (len, 1))
850 {
851 if (!host_integerp (last.len, 1)
852 || integer_zerop (len)
853 || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
854 != (unsigned HOST_WIDE_INT) tree_low_cst (last.len, 1) + 1)
855 return;
856 /* Don't adjust the length if it is divisible by 4, it is more efficient
857 to store the extra '\0' in that case. */
858 if ((((unsigned HOST_WIDE_INT) tree_low_cst (len, 1)) & 3) == 0)
859 return;
860 }
861 else if (TREE_CODE (len) == SSA_NAME)
862 {
863 gimple def_stmt = SSA_NAME_DEF_STMT (len);
864 if (!is_gimple_assign (def_stmt)
865 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
866 || gimple_assign_rhs1 (def_stmt) != last.len
867 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
868 return;
869 }
870 else
871 return;
872
873 gimple_call_set_arg (last.stmt, 2, last.len);
874 update_stmt (last.stmt);
875 }
876
877 /* Handle a strlen call. If strlen of the argument is known, replace
878 the strlen call with the known value, otherwise remember that strlen
879 of the argument is stored in the lhs SSA_NAME. */
880
881 static void
882 handle_builtin_strlen (gimple_stmt_iterator *gsi)
883 {
884 int idx;
885 tree src;
886 gimple stmt = gsi_stmt (*gsi);
887 tree lhs = gimple_call_lhs (stmt);
888
889 if (lhs == NULL_TREE)
890 return;
891
892 src = gimple_call_arg (stmt, 0);
893 idx = get_stridx (src);
894 if (idx)
895 {
896 strinfo si = NULL;
897 tree rhs;
898
899 if (idx < 0)
900 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
901 else
902 {
903 rhs = NULL_TREE;
904 si = get_strinfo (idx);
905 if (si != NULL)
906 rhs = get_string_length (si);
907 }
908 if (rhs != NULL_TREE)
909 {
910 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
911 {
912 fprintf (dump_file, "Optimizing: ");
913 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
914 }
915 rhs = unshare_expr (rhs);
916 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
917 rhs = fold_convert_loc (gimple_location (stmt),
918 TREE_TYPE (lhs), rhs);
919 if (!update_call_from_tree (gsi, rhs))
920 gimplify_and_update_call_from_tree (gsi, rhs);
921 stmt = gsi_stmt (*gsi);
922 update_stmt (stmt);
923 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
924 {
925 fprintf (dump_file, "into: ");
926 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
927 }
928 if (si != NULL
929 && TREE_CODE (si->length) != SSA_NAME
930 && TREE_CODE (si->length) != INTEGER_CST
931 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
932 {
933 si = unshare_strinfo (si);
934 si->length = lhs;
935 }
936 return;
937 }
938 }
939 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
940 return;
941 if (idx == 0)
942 idx = new_stridx (src);
943 else if (get_strinfo (idx) != NULL)
944 return;
945 if (idx)
946 {
947 strinfo si = new_strinfo (src, idx, lhs);
948 set_strinfo (idx, si);
949 find_equal_ptrs (src, idx);
950 }
951 }
952
953 /* Handle a strchr call. If strlen of the first argument is known, replace
954 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
955 that lhs of the call is endptr and strlen of the argument is endptr - x. */
956
957 static void
958 handle_builtin_strchr (gimple_stmt_iterator *gsi)
959 {
960 int idx;
961 tree src;
962 gimple stmt = gsi_stmt (*gsi);
963 tree lhs = gimple_call_lhs (stmt);
964
965 if (lhs == NULL_TREE)
966 return;
967
968 if (!integer_zerop (gimple_call_arg (stmt, 1)))
969 return;
970
971 src = gimple_call_arg (stmt, 0);
972 idx = get_stridx (src);
973 if (idx)
974 {
975 strinfo si = NULL;
976 tree rhs;
977
978 if (idx < 0)
979 rhs = build_int_cst (size_type_node, ~idx);
980 else
981 {
982 rhs = NULL_TREE;
983 si = get_strinfo (idx);
984 if (si != NULL)
985 rhs = get_string_length (si);
986 }
987 if (rhs != NULL_TREE)
988 {
989 location_t loc = gimple_location (stmt);
990
991 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
992 {
993 fprintf (dump_file, "Optimizing: ");
994 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
995 }
996 if (si != NULL && si->endptr != NULL_TREE)
997 {
998 rhs = unshare_expr (si->endptr);
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 else
1004 {
1005 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1006 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1007 TREE_TYPE (src), src, rhs);
1008 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1009 TREE_TYPE (rhs)))
1010 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1011 }
1012 if (!update_call_from_tree (gsi, rhs))
1013 gimplify_and_update_call_from_tree (gsi, rhs);
1014 stmt = gsi_stmt (*gsi);
1015 update_stmt (stmt);
1016 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1017 {
1018 fprintf (dump_file, "into: ");
1019 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1020 }
1021 if (si != NULL
1022 && si->endptr == NULL_TREE
1023 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1024 {
1025 si = unshare_strinfo (si);
1026 si->endptr = lhs;
1027 }
1028 zero_length_string (lhs, si);
1029 return;
1030 }
1031 }
1032 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1033 return;
1034 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1035 {
1036 if (idx == 0)
1037 idx = new_stridx (src);
1038 else if (get_strinfo (idx) != NULL)
1039 {
1040 zero_length_string (lhs, NULL);
1041 return;
1042 }
1043 if (idx)
1044 {
1045 location_t loc = gimple_location (stmt);
1046 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1047 tree srcu = fold_convert_loc (loc, size_type_node, src);
1048 tree length = fold_build2_loc (loc, MINUS_EXPR,
1049 size_type_node, lhsu, srcu);
1050 strinfo si = new_strinfo (src, idx, length);
1051 si->endptr = lhs;
1052 set_strinfo (idx, si);
1053 find_equal_ptrs (src, idx);
1054 zero_length_string (lhs, si);
1055 }
1056 }
1057 else
1058 zero_length_string (lhs, NULL);
1059 }
1060
1061 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1062 If strlen of the second argument is known, strlen of the first argument
1063 is the same after this call. Furthermore, attempt to convert it to
1064 memcpy. */
1065
1066 static void
1067 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1068 {
1069 int idx, didx;
1070 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1071 bool success;
1072 gimple stmt = gsi_stmt (*gsi);
1073 strinfo si, dsi, olddsi, zsi;
1074 location_t loc;
1075
1076 src = gimple_call_arg (stmt, 1);
1077 dst = gimple_call_arg (stmt, 0);
1078 lhs = gimple_call_lhs (stmt);
1079 idx = get_stridx (src);
1080 si = NULL;
1081 if (idx > 0)
1082 si = get_strinfo (idx);
1083
1084 didx = get_stridx (dst);
1085 olddsi = NULL;
1086 oldlen = NULL_TREE;
1087 if (didx > 0)
1088 olddsi = get_strinfo (didx);
1089 else if (didx < 0)
1090 return;
1091
1092 if (olddsi != NULL)
1093 adjust_last_stmt (olddsi, stmt, false);
1094
1095 srclen = NULL_TREE;
1096 if (si != NULL)
1097 srclen = get_string_length (si);
1098 else if (idx < 0)
1099 srclen = build_int_cst (size_type_node, ~idx);
1100
1101 loc = gimple_location (stmt);
1102 if (srclen == NULL_TREE)
1103 switch (bcode)
1104 {
1105 case BUILT_IN_STRCPY:
1106 case BUILT_IN_STRCPY_CHK:
1107 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1108 return;
1109 break;
1110 case BUILT_IN_STPCPY:
1111 case BUILT_IN_STPCPY_CHK:
1112 if (lhs == NULL_TREE)
1113 return;
1114 else
1115 {
1116 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1117 srclen = fold_convert_loc (loc, size_type_node, dst);
1118 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1119 lhsuint, srclen);
1120 }
1121 break;
1122 default:
1123 gcc_unreachable ();
1124 }
1125
1126 if (didx == 0)
1127 {
1128 didx = new_stridx (dst);
1129 if (didx == 0)
1130 return;
1131 }
1132 if (olddsi != NULL)
1133 {
1134 oldlen = olddsi->length;
1135 dsi = unshare_strinfo (olddsi);
1136 dsi->length = srclen;
1137 /* Break the chain, so adjust_related_strinfo on later pointers in
1138 the chain won't adjust this one anymore. */
1139 dsi->next = 0;
1140 dsi->stmt = NULL;
1141 dsi->endptr = NULL_TREE;
1142 }
1143 else
1144 {
1145 dsi = new_strinfo (dst, didx, srclen);
1146 set_strinfo (didx, dsi);
1147 find_equal_ptrs (dst, didx);
1148 }
1149 dsi->writable = true;
1150 dsi->dont_invalidate = true;
1151
1152 if (dsi->length == NULL_TREE)
1153 {
1154 strinfo chainsi;
1155
1156 /* If string length of src is unknown, use delayed length
1157 computation. If string lenth of dst will be needed, it
1158 can be computed by transforming this strcpy call into
1159 stpcpy and subtracting dst from the return value. */
1160
1161 /* Look for earlier strings whose length could be determined if
1162 this strcpy is turned into an stpcpy. */
1163
1164 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1165 {
1166 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1167 {
1168 /* When setting a stmt for delayed length computation
1169 prevent all strinfos through dsi from being
1170 invalidated. */
1171 chainsi = unshare_strinfo (chainsi);
1172 chainsi->stmt = stmt;
1173 chainsi->length = NULL_TREE;
1174 chainsi->endptr = NULL_TREE;
1175 chainsi->dont_invalidate = true;
1176 }
1177 }
1178 dsi->stmt = stmt;
1179 return;
1180 }
1181
1182 if (olddsi != NULL)
1183 {
1184 tree adj = NULL_TREE;
1185 if (oldlen == NULL_TREE)
1186 ;
1187 else if (integer_zerop (oldlen))
1188 adj = srclen;
1189 else if (TREE_CODE (oldlen) == INTEGER_CST
1190 || TREE_CODE (srclen) == INTEGER_CST)
1191 adj = fold_build2_loc (loc, MINUS_EXPR,
1192 TREE_TYPE (srclen), srclen,
1193 fold_convert_loc (loc, TREE_TYPE (srclen),
1194 oldlen));
1195 if (adj != NULL_TREE)
1196 adjust_related_strinfos (loc, dsi, adj);
1197 else
1198 dsi->prev = 0;
1199 }
1200 /* strcpy src may not overlap dst, so src doesn't need to be
1201 invalidated either. */
1202 if (si != NULL)
1203 si->dont_invalidate = true;
1204
1205 fn = NULL_TREE;
1206 zsi = NULL;
1207 switch (bcode)
1208 {
1209 case BUILT_IN_STRCPY:
1210 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1211 if (lhs)
1212 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1213 break;
1214 case BUILT_IN_STRCPY_CHK:
1215 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1216 if (lhs)
1217 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1218 break;
1219 case BUILT_IN_STPCPY:
1220 /* This would need adjustment of the lhs (subtract one),
1221 or detection that the trailing '\0' doesn't need to be
1222 written, if it will be immediately overwritten.
1223 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1224 if (lhs)
1225 {
1226 dsi->endptr = lhs;
1227 zsi = zero_length_string (lhs, dsi);
1228 }
1229 break;
1230 case BUILT_IN_STPCPY_CHK:
1231 /* This would need adjustment of the lhs (subtract one),
1232 or detection that the trailing '\0' doesn't need to be
1233 written, if it will be immediately overwritten.
1234 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1235 if (lhs)
1236 {
1237 dsi->endptr = lhs;
1238 zsi = zero_length_string (lhs, dsi);
1239 }
1240 break;
1241 default:
1242 gcc_unreachable ();
1243 }
1244 if (zsi != NULL)
1245 zsi->dont_invalidate = true;
1246
1247 if (fn == NULL_TREE)
1248 return;
1249
1250 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1251 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1252
1253 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1254 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1255 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1256 GSI_SAME_STMT);
1257 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1258 {
1259 fprintf (dump_file, "Optimizing: ");
1260 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1261 }
1262 if (gimple_call_num_args (stmt) == 2)
1263 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1264 else
1265 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1266 gimple_call_arg (stmt, 2));
1267 if (success)
1268 {
1269 stmt = gsi_stmt (*gsi);
1270 update_stmt (stmt);
1271 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1272 {
1273 fprintf (dump_file, "into: ");
1274 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1275 }
1276 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1277 laststmt.stmt = stmt;
1278 laststmt.len = srclen;
1279 laststmt.stridx = dsi->idx;
1280 }
1281 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1282 fprintf (dump_file, "not possible.\n");
1283 }
1284
1285 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1286 If strlen of the second argument is known and length of the third argument
1287 is that plus one, strlen of the first argument is the same after this
1288 call. */
1289
1290 static void
1291 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1292 {
1293 int idx, didx;
1294 tree src, dst, len, lhs, oldlen, newlen;
1295 gimple stmt = gsi_stmt (*gsi);
1296 strinfo si, dsi, olddsi;
1297
1298 len = gimple_call_arg (stmt, 2);
1299 src = gimple_call_arg (stmt, 1);
1300 dst = gimple_call_arg (stmt, 0);
1301 idx = get_stridx (src);
1302 if (idx == 0)
1303 return;
1304
1305 didx = get_stridx (dst);
1306 olddsi = NULL;
1307 if (didx > 0)
1308 olddsi = get_strinfo (didx);
1309 else if (didx < 0)
1310 return;
1311
1312 if (olddsi != NULL
1313 && host_integerp (len, 1)
1314 && !integer_zerop (len))
1315 adjust_last_stmt (olddsi, stmt, false);
1316
1317 if (idx > 0)
1318 {
1319 gimple def_stmt;
1320
1321 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1322 si = get_strinfo (idx);
1323 if (si == NULL || si->length == NULL_TREE)
1324 return;
1325 if (TREE_CODE (len) != SSA_NAME)
1326 return;
1327 def_stmt = SSA_NAME_DEF_STMT (len);
1328 if (!is_gimple_assign (def_stmt)
1329 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1330 || gimple_assign_rhs1 (def_stmt) != si->length
1331 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1332 return;
1333 }
1334 else
1335 {
1336 si = NULL;
1337 /* Handle memcpy (x, "abcd", 5) or
1338 memcpy (x, "abc\0uvw", 7). */
1339 if (!host_integerp (len, 1)
1340 || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
1341 <= (unsigned HOST_WIDE_INT) ~idx)
1342 return;
1343 }
1344
1345 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1346 adjust_last_stmt (olddsi, stmt, false);
1347
1348 if (didx == 0)
1349 {
1350 didx = new_stridx (dst);
1351 if (didx == 0)
1352 return;
1353 }
1354 if (si != NULL)
1355 newlen = si->length;
1356 else
1357 newlen = build_int_cst (size_type_node, ~idx);
1358 oldlen = NULL_TREE;
1359 if (olddsi != NULL)
1360 {
1361 dsi = unshare_strinfo (olddsi);
1362 oldlen = olddsi->length;
1363 dsi->length = newlen;
1364 /* Break the chain, so adjust_related_strinfo on later pointers in
1365 the chain won't adjust this one anymore. */
1366 dsi->next = 0;
1367 dsi->stmt = NULL;
1368 dsi->endptr = NULL_TREE;
1369 }
1370 else
1371 {
1372 dsi = new_strinfo (dst, didx, newlen);
1373 set_strinfo (didx, dsi);
1374 find_equal_ptrs (dst, didx);
1375 }
1376 dsi->writable = true;
1377 dsi->dont_invalidate = true;
1378 if (olddsi != NULL)
1379 {
1380 tree adj = NULL_TREE;
1381 location_t loc = gimple_location (stmt);
1382 if (oldlen == NULL_TREE)
1383 ;
1384 else if (integer_zerop (oldlen))
1385 adj = dsi->length;
1386 else if (TREE_CODE (oldlen) == INTEGER_CST
1387 || TREE_CODE (dsi->length) == INTEGER_CST)
1388 adj = fold_build2_loc (loc, MINUS_EXPR,
1389 TREE_TYPE (dsi->length), dsi->length,
1390 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1391 oldlen));
1392 if (adj != NULL_TREE)
1393 adjust_related_strinfos (loc, dsi, adj);
1394 else
1395 dsi->prev = 0;
1396 }
1397 /* memcpy src may not overlap dst, so src doesn't need to be
1398 invalidated either. */
1399 if (si != NULL)
1400 si->dont_invalidate = true;
1401
1402 lhs = gimple_call_lhs (stmt);
1403 switch (bcode)
1404 {
1405 case BUILT_IN_MEMCPY:
1406 case BUILT_IN_MEMCPY_CHK:
1407 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1408 laststmt.stmt = stmt;
1409 laststmt.len = dsi->length;
1410 laststmt.stridx = dsi->idx;
1411 if (lhs)
1412 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1413 break;
1414 case BUILT_IN_MEMPCPY:
1415 case BUILT_IN_MEMPCPY_CHK:
1416 break;
1417 default:
1418 gcc_unreachable ();
1419 }
1420 }
1421
1422 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1423 If strlen of the second argument is known, strlen of the first argument
1424 is increased by the length of the second argument. Furthermore, attempt
1425 to convert it to memcpy/strcpy if the length of the first argument
1426 is known. */
1427
1428 static void
1429 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1430 {
1431 int idx, didx;
1432 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1433 bool success;
1434 gimple stmt = gsi_stmt (*gsi);
1435 strinfo si, dsi;
1436 location_t loc;
1437
1438 src = gimple_call_arg (stmt, 1);
1439 dst = gimple_call_arg (stmt, 0);
1440 lhs = gimple_call_lhs (stmt);
1441
1442 didx = get_stridx (dst);
1443 if (didx < 0)
1444 return;
1445
1446 dsi = NULL;
1447 if (didx > 0)
1448 dsi = get_strinfo (didx);
1449 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1450 {
1451 /* strcat (p, q) can be transformed into
1452 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1453 with length endptr - p if we need to compute the length
1454 later on. Don't do this transformation if we don't need
1455 it. */
1456 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1457 {
1458 if (didx == 0)
1459 {
1460 didx = new_stridx (dst);
1461 if (didx == 0)
1462 return;
1463 }
1464 if (dsi == NULL)
1465 {
1466 dsi = new_strinfo (dst, didx, NULL_TREE);
1467 set_strinfo (didx, dsi);
1468 find_equal_ptrs (dst, didx);
1469 }
1470 else
1471 {
1472 dsi = unshare_strinfo (dsi);
1473 dsi->length = NULL_TREE;
1474 dsi->next = 0;
1475 dsi->endptr = NULL_TREE;
1476 }
1477 dsi->writable = true;
1478 dsi->stmt = stmt;
1479 dsi->dont_invalidate = true;
1480 }
1481 return;
1482 }
1483
1484 srclen = NULL_TREE;
1485 si = NULL;
1486 idx = get_stridx (src);
1487 if (idx < 0)
1488 srclen = build_int_cst (size_type_node, ~idx);
1489 else if (idx > 0)
1490 {
1491 si = get_strinfo (idx);
1492 if (si != NULL)
1493 srclen = get_string_length (si);
1494 }
1495
1496 loc = gimple_location (stmt);
1497 dstlen = dsi->length;
1498 endptr = dsi->endptr;
1499
1500 dsi = unshare_strinfo (dsi);
1501 dsi->endptr = NULL_TREE;
1502 dsi->stmt = NULL;
1503 dsi->writable = true;
1504
1505 if (srclen != NULL_TREE)
1506 {
1507 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1508 dsi->length, srclen);
1509 adjust_related_strinfos (loc, dsi, srclen);
1510 dsi->dont_invalidate = true;
1511 }
1512 else
1513 {
1514 dsi->length = NULL;
1515 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1516 dsi->dont_invalidate = true;
1517 }
1518
1519 if (si != NULL)
1520 /* strcat src may not overlap dst, so src doesn't need to be
1521 invalidated either. */
1522 si->dont_invalidate = true;
1523
1524 /* For now. Could remove the lhs from the call and add
1525 lhs = dst; afterwards. */
1526 if (lhs)
1527 return;
1528
1529 fn = NULL_TREE;
1530 objsz = NULL_TREE;
1531 switch (bcode)
1532 {
1533 case BUILT_IN_STRCAT:
1534 if (srclen != NULL_TREE)
1535 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1536 else
1537 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1538 break;
1539 case BUILT_IN_STRCAT_CHK:
1540 if (srclen != NULL_TREE)
1541 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1542 else
1543 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1544 objsz = gimple_call_arg (stmt, 2);
1545 break;
1546 default:
1547 gcc_unreachable ();
1548 }
1549
1550 if (fn == NULL_TREE)
1551 return;
1552
1553 len = NULL_TREE;
1554 if (srclen != NULL_TREE)
1555 {
1556 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1557 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1558
1559 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1560 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1561 build_int_cst (type, 1));
1562 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1563 GSI_SAME_STMT);
1564 }
1565 if (endptr)
1566 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1567 else
1568 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1569 TREE_TYPE (dst), unshare_expr (dst),
1570 fold_convert_loc (loc, sizetype,
1571 unshare_expr (dstlen)));
1572 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1573 GSI_SAME_STMT);
1574 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1575 {
1576 fprintf (dump_file, "Optimizing: ");
1577 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1578 }
1579 if (srclen != NULL_TREE)
1580 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1581 dst, src, len, objsz);
1582 else
1583 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1584 dst, src, objsz);
1585 if (success)
1586 {
1587 stmt = gsi_stmt (*gsi);
1588 update_stmt (stmt);
1589 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1590 {
1591 fprintf (dump_file, "into: ");
1592 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1593 }
1594 /* If srclen == NULL, note that current string length can be
1595 computed by transforming this strcpy into stpcpy. */
1596 if (srclen == NULL_TREE && dsi->dont_invalidate)
1597 dsi->stmt = stmt;
1598 adjust_last_stmt (dsi, stmt, true);
1599 if (srclen != NULL_TREE)
1600 {
1601 laststmt.stmt = stmt;
1602 laststmt.len = srclen;
1603 laststmt.stridx = dsi->idx;
1604 }
1605 }
1606 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1607 fprintf (dump_file, "not possible.\n");
1608 }
1609
1610 /* Handle a POINTER_PLUS_EXPR statement.
1611 For p = "abcd" + 2; compute associated length, or if
1612 p = q + off is pointing to a '\0' character of a string, call
1613 zero_length_string on it. */
1614
1615 static void
1616 handle_pointer_plus (gimple_stmt_iterator *gsi)
1617 {
1618 gimple stmt = gsi_stmt (*gsi);
1619 tree lhs = gimple_assign_lhs (stmt), off;
1620 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1621 strinfo si, zsi;
1622
1623 if (idx == 0)
1624 return;
1625
1626 if (idx < 0)
1627 {
1628 tree off = gimple_assign_rhs2 (stmt);
1629 if (host_integerp (off, 1)
1630 && (unsigned HOST_WIDE_INT) tree_low_cst (off, 1)
1631 <= (unsigned HOST_WIDE_INT) ~idx)
1632 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1633 = ~(~idx - (int) tree_low_cst (off, 1));
1634 return;
1635 }
1636
1637 si = get_strinfo (idx);
1638 if (si == NULL || si->length == NULL_TREE)
1639 return;
1640
1641 off = gimple_assign_rhs2 (stmt);
1642 zsi = NULL;
1643 if (operand_equal_p (si->length, off, 0))
1644 zsi = zero_length_string (lhs, si);
1645 else if (TREE_CODE (off) == SSA_NAME)
1646 {
1647 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1648 if (gimple_assign_single_p (def_stmt)
1649 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1650 zsi = zero_length_string (lhs, si);
1651 }
1652 if (zsi != NULL
1653 && si->endptr != NULL_TREE
1654 && si->endptr != lhs
1655 && TREE_CODE (si->endptr) == SSA_NAME)
1656 {
1657 enum tree_code rhs_code
1658 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1659 ? SSA_NAME : NOP_EXPR;
1660 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr, NULL_TREE);
1661 gcc_assert (gsi_stmt (*gsi) == stmt);
1662 update_stmt (stmt);
1663 }
1664 }
1665
1666 /* Handle a single character store. */
1667
1668 static bool
1669 handle_char_store (gimple_stmt_iterator *gsi)
1670 {
1671 int idx = -1;
1672 strinfo si = NULL;
1673 gimple stmt = gsi_stmt (*gsi);
1674 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1675
1676 if (TREE_CODE (lhs) == MEM_REF
1677 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1678 {
1679 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1680 {
1681 ssaname = TREE_OPERAND (lhs, 0);
1682 idx = get_stridx (ssaname);
1683 }
1684 }
1685 else
1686 idx = get_addr_stridx (lhs);
1687
1688 if (idx > 0)
1689 {
1690 si = get_strinfo (idx);
1691 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1692 {
1693 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1694 {
1695 /* When storing '\0', the store can be removed
1696 if we know it has been stored in the current function. */
1697 if (!stmt_could_throw_p (stmt) && si->writable)
1698 {
1699 unlink_stmt_vdef (stmt);
1700 release_defs (stmt);
1701 gsi_remove (gsi, true);
1702 return false;
1703 }
1704 else
1705 {
1706 si->writable = true;
1707 gsi_next (gsi);
1708 return false;
1709 }
1710 }
1711 else
1712 /* Otherwise this statement overwrites the '\0' with
1713 something, if the previous stmt was a memcpy,
1714 its length may be decreased. */
1715 adjust_last_stmt (si, stmt, false);
1716 }
1717 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1718 {
1719 si = unshare_strinfo (si);
1720 si->length = build_int_cst (size_type_node, 0);
1721 si->endptr = NULL;
1722 si->prev = 0;
1723 si->next = 0;
1724 si->stmt = NULL;
1725 si->first = 0;
1726 si->writable = true;
1727 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1728 si->endptr = ssaname;
1729 si->dont_invalidate = true;
1730 }
1731 /* If si->length is non-zero constant, we aren't overwriting '\0',
1732 and if we aren't storing '\0', we know that the length of the
1733 string and any other zero terminated string in memory remains
1734 the same. In that case we move to the next gimple statement and
1735 return to signal the caller that it shouldn't invalidate anything.
1736
1737 This is benefical for cases like:
1738
1739 char p[20];
1740 void foo (char *q)
1741 {
1742 strcpy (p, "foobar");
1743 size_t len = strlen (p); // This can be optimized into 6
1744 size_t len2 = strlen (q); // This has to be computed
1745 p[0] = 'X';
1746 size_t len3 = strlen (p); // This can be optimized into 6
1747 size_t len4 = strlen (q); // This can be optimized into len2
1748 bar (len, len2, len3, len4);
1749 }
1750 */
1751 else if (si != NULL && si->length != NULL_TREE
1752 && TREE_CODE (si->length) == INTEGER_CST
1753 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
1754 {
1755 gsi_next (gsi);
1756 return false;
1757 }
1758 }
1759 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1760 {
1761 if (ssaname)
1762 {
1763 si = zero_length_string (ssaname, NULL);
1764 if (si != NULL)
1765 si->dont_invalidate = true;
1766 }
1767 else
1768 {
1769 int idx = new_addr_stridx (lhs);
1770 if (idx != 0)
1771 {
1772 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1773 build_int_cst (size_type_node, 0));
1774 set_strinfo (idx, si);
1775 si->dont_invalidate = true;
1776 }
1777 }
1778 if (si != NULL)
1779 si->writable = true;
1780 }
1781 else if (idx == 0
1782 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
1783 && ssaname == NULL_TREE
1784 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
1785 {
1786 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
1787 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
1788 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
1789 {
1790 int idx = new_addr_stridx (lhs);
1791 if (idx != 0)
1792 {
1793 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1794 build_int_cst (size_type_node, l));
1795 set_strinfo (idx, si);
1796 si->dont_invalidate = true;
1797 }
1798 }
1799 }
1800
1801 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
1802 {
1803 /* Allow adjust_last_stmt to remove it if the stored '\0'
1804 is immediately overwritten. */
1805 laststmt.stmt = stmt;
1806 laststmt.len = build_int_cst (size_type_node, 1);
1807 laststmt.stridx = si->idx;
1808 }
1809 return true;
1810 }
1811
1812 /* Attempt to optimize a single statement at *GSI using string length
1813 knowledge. */
1814
1815 static bool
1816 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
1817 {
1818 gimple stmt = gsi_stmt (*gsi);
1819
1820 if (is_gimple_call (stmt))
1821 {
1822 tree callee = gimple_call_fndecl (stmt);
1823 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
1824 switch (DECL_FUNCTION_CODE (callee))
1825 {
1826 case BUILT_IN_STRLEN:
1827 handle_builtin_strlen (gsi);
1828 break;
1829 case BUILT_IN_STRCHR:
1830 handle_builtin_strchr (gsi);
1831 break;
1832 case BUILT_IN_STRCPY:
1833 case BUILT_IN_STRCPY_CHK:
1834 case BUILT_IN_STPCPY:
1835 case BUILT_IN_STPCPY_CHK:
1836 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
1837 break;
1838 case BUILT_IN_MEMCPY:
1839 case BUILT_IN_MEMCPY_CHK:
1840 case BUILT_IN_MEMPCPY:
1841 case BUILT_IN_MEMPCPY_CHK:
1842 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
1843 break;
1844 case BUILT_IN_STRCAT:
1845 case BUILT_IN_STRCAT_CHK:
1846 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
1847 break;
1848 default:
1849 break;
1850 }
1851 }
1852 else if (is_gimple_assign (stmt))
1853 {
1854 tree lhs = gimple_assign_lhs (stmt);
1855
1856 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
1857 {
1858 if (gimple_assign_single_p (stmt)
1859 || (gimple_assign_cast_p (stmt)
1860 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
1861 {
1862 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1863 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
1864 }
1865 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1866 handle_pointer_plus (gsi);
1867 }
1868 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
1869 {
1870 tree type = TREE_TYPE (lhs);
1871 if (TREE_CODE (type) == ARRAY_TYPE)
1872 type = TREE_TYPE (type);
1873 if (TREE_CODE (type) == INTEGER_TYPE
1874 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
1875 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
1876 {
1877 if (! handle_char_store (gsi))
1878 return false;
1879 }
1880 }
1881 }
1882
1883 if (gimple_vdef (stmt))
1884 maybe_invalidate (stmt);
1885 return true;
1886 }
1887
1888 /* Recursively call maybe_invalidate on stmts that might be executed
1889 in between dombb and current bb and that contain a vdef. Stop when
1890 *count stmts are inspected, or if the whole strinfo vector has
1891 been invalidated. */
1892
1893 static void
1894 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
1895 {
1896 unsigned int i, n = gimple_phi_num_args (phi);
1897
1898 for (i = 0; i < n; i++)
1899 {
1900 tree vuse = gimple_phi_arg_def (phi, i);
1901 gimple stmt = SSA_NAME_DEF_STMT (vuse);
1902 basic_block bb = gimple_bb (stmt);
1903 if (bb == NULL
1904 || bb == dombb
1905 || !bitmap_set_bit (visited, bb->index)
1906 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1907 continue;
1908 while (1)
1909 {
1910 if (gimple_code (stmt) == GIMPLE_PHI)
1911 {
1912 do_invalidate (dombb, stmt, visited, count);
1913 if (*count == 0)
1914 return;
1915 break;
1916 }
1917 if (--*count == 0)
1918 return;
1919 if (!maybe_invalidate (stmt))
1920 {
1921 *count = 0;
1922 return;
1923 }
1924 vuse = gimple_vuse (stmt);
1925 stmt = SSA_NAME_DEF_STMT (vuse);
1926 if (gimple_bb (stmt) != bb)
1927 {
1928 bb = gimple_bb (stmt);
1929 if (bb == NULL
1930 || bb == dombb
1931 || !bitmap_set_bit (visited, bb->index)
1932 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1933 break;
1934 }
1935 }
1936 }
1937 }
1938
1939 class strlen_dom_walker : public dom_walker
1940 {
1941 public:
1942 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
1943
1944 virtual void before_dom_children (basic_block);
1945 virtual void after_dom_children (basic_block);
1946 };
1947
1948 /* Callback for walk_dominator_tree. Attempt to optimize various
1949 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1950
1951 void
1952 strlen_dom_walker::before_dom_children (basic_block bb)
1953 {
1954 gimple_stmt_iterator gsi;
1955 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
1956
1957 if (dombb == NULL)
1958 stridx_to_strinfo = NULL;
1959 else
1960 {
1961 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) dombb->aux);
1962 if (stridx_to_strinfo)
1963 {
1964 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1965 {
1966 gimple phi = gsi_stmt (gsi);
1967 if (virtual_operand_p (gimple_phi_result (phi)))
1968 {
1969 bitmap visited = BITMAP_ALLOC (NULL);
1970 int count_vdef = 100;
1971 do_invalidate (dombb, phi, visited, &count_vdef);
1972 BITMAP_FREE (visited);
1973 if (count_vdef == 0)
1974 {
1975 /* If there were too many vdefs in between immediate
1976 dominator and current bb, invalidate everything.
1977 If stridx_to_strinfo has been unshared, we need
1978 to free it, otherwise just set it to NULL. */
1979 if (!strinfo_shared ())
1980 {
1981 unsigned int i;
1982 strinfo si;
1983
1984 for (i = 1;
1985 vec_safe_iterate (stridx_to_strinfo, i, &si);
1986 ++i)
1987 {
1988 free_strinfo (si);
1989 (*stridx_to_strinfo)[i] = NULL;
1990 }
1991 }
1992 else
1993 stridx_to_strinfo = NULL;
1994 }
1995 break;
1996 }
1997 }
1998 }
1999 }
2000
2001 /* If all PHI arguments have the same string index, the PHI result
2002 has it as well. */
2003 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2004 {
2005 gimple phi = gsi_stmt (gsi);
2006 tree result = gimple_phi_result (phi);
2007 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2008 {
2009 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2010 if (idx != 0)
2011 {
2012 unsigned int i, n = gimple_phi_num_args (phi);
2013 for (i = 1; i < n; i++)
2014 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2015 break;
2016 if (i == n)
2017 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2018 }
2019 }
2020 }
2021
2022 /* Attempt to optimize individual statements. */
2023 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2024 if (strlen_optimize_stmt (&gsi))
2025 gsi_next (&gsi);
2026
2027 bb->aux = stridx_to_strinfo;
2028 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2029 (*stridx_to_strinfo)[0] = (strinfo) bb;
2030 }
2031
2032 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2033 owned by the current bb, clear bb->aux. */
2034
2035 void
2036 strlen_dom_walker::after_dom_children (basic_block bb)
2037 {
2038 if (bb->aux)
2039 {
2040 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux);
2041 if (vec_safe_length (stridx_to_strinfo)
2042 && (*stridx_to_strinfo)[0] == (strinfo) bb)
2043 {
2044 unsigned int i;
2045 strinfo si;
2046
2047 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2048 free_strinfo (si);
2049 vec_free (stridx_to_strinfo);
2050 }
2051 bb->aux = NULL;
2052 }
2053 }
2054
2055 /* Main entry point. */
2056
2057 static unsigned int
2058 tree_ssa_strlen (void)
2059 {
2060 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2061 max_stridx = 1;
2062 strinfo_pool = create_alloc_pool ("strinfo_struct pool",
2063 sizeof (struct strinfo_struct), 64);
2064
2065 calculate_dominance_info (CDI_DOMINATORS);
2066
2067 /* String length optimization is implemented as a walk of the dominator
2068 tree and a forward walk of statements within each block. */
2069 strlen_dom_walker (CDI_DOMINATORS).walk (cfun->cfg->x_entry_block_ptr);
2070
2071 ssa_ver_to_stridx.release ();
2072 free_alloc_pool (strinfo_pool);
2073 if (decl_to_stridxlist_htab.is_created ())
2074 {
2075 obstack_free (&stridx_obstack, NULL);
2076 decl_to_stridxlist_htab.dispose ();
2077 }
2078 laststmt.stmt = NULL;
2079 laststmt.len = NULL_TREE;
2080 laststmt.stridx = 0;
2081
2082 return 0;
2083 }
2084
2085 static bool
2086 gate_strlen (void)
2087 {
2088 return flag_optimize_strlen != 0;
2089 }
2090
2091 namespace {
2092
2093 const pass_data pass_data_strlen =
2094 {
2095 GIMPLE_PASS, /* type */
2096 "strlen", /* name */
2097 OPTGROUP_NONE, /* optinfo_flags */
2098 true, /* has_gate */
2099 true, /* has_execute */
2100 TV_TREE_STRLEN, /* tv_id */
2101 ( PROP_cfg | PROP_ssa ), /* properties_required */
2102 0, /* properties_provided */
2103 0, /* properties_destroyed */
2104 0, /* todo_flags_start */
2105 TODO_verify_ssa, /* todo_flags_finish */
2106 };
2107
2108 class pass_strlen : public gimple_opt_pass
2109 {
2110 public:
2111 pass_strlen (gcc::context *ctxt)
2112 : gimple_opt_pass (pass_data_strlen, ctxt)
2113 {}
2114
2115 /* opt_pass methods: */
2116 bool gate () { return gate_strlen (); }
2117 unsigned int execute () { return tree_ssa_strlen (); }
2118
2119 }; // class pass_strlen
2120
2121 } // anon namespace
2122
2123 gimple_opt_pass *
2124 make_pass_strlen (gcc::context *ctxt)
2125 {
2126 return new pass_strlen (ctxt);
2127 }