vapool.c: Include tree-ssa-alias.h, gimple.h and lto-streamer.h
[official-gcc.git] / gcc / tree-ssa-strlen.c
blobbb42cc7e2633a85e60b90d94769a047cd3a3b19e
1 /* String length optimization
2 Copyright (C) 2011-2014 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "stor-layout.h"
26 #include "hash-table.h"
27 #include "hash-map.h"
28 #include "bitmap.h"
29 #include "basic-block.h"
30 #include "tree-ssa-alias.h"
31 #include "internal-fn.h"
32 #include "gimple-fold.h"
33 #include "tree-eh.h"
34 #include "gimple-expr.h"
35 #include "is-a.h"
36 #include "gimple.h"
37 #include "gimplify.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
40 #include "gimple-ssa.h"
41 #include "tree-phinodes.h"
42 #include "ssa-iterators.h"
43 #include "stringpool.h"
44 #include "tree-ssanames.h"
45 #include "expr.h"
46 #include "tree-dfa.h"
47 #include "tree-pass.h"
48 #include "domwalk.h"
49 #include "alloc-pool.h"
50 #include "tree-ssa-propagate.h"
51 #include "gimple-pretty-print.h"
52 #include "params.h"
53 #include "expr.h"
55 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
56 is an index into strinfo vector, negative value stands for
57 string length of a string literal (~strlen). */
58 static vec<int> ssa_ver_to_stridx;
60 /* Number of currently active string indexes plus one. */
61 static int max_stridx;
63 /* String information record. */
64 typedef struct strinfo_struct
66 /* String length of this string. */
67 tree length;
68 /* Any of the corresponding pointers for querying alias oracle. */
69 tree ptr;
70 /* Statement for delayed length computation. */
71 gimple stmt;
72 /* Pointer to '\0' if known, if NULL, it can be computed as
73 ptr + length. */
74 tree endptr;
75 /* Reference count. Any changes to strinfo entry possibly shared
76 with dominating basic blocks need unshare_strinfo first, except
77 for dont_invalidate which affects only the immediately next
78 maybe_invalidate. */
79 int refcount;
80 /* Copy of index. get_strinfo (si->idx) should return si; */
81 int idx;
82 /* These 3 fields are for chaining related string pointers together.
83 E.g. for
84 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
85 strcpy (c, d); e = c + dl;
86 strinfo(a) -> strinfo(c) -> strinfo(e)
87 All have ->first field equal to strinfo(a)->idx and are doubly
88 chained through prev/next fields. The later strinfos are required
89 to point into the same string with zero or more bytes after
90 the previous pointer and all bytes in between the two pointers
91 must be non-zero. Functions like strcpy or memcpy are supposed
92 to adjust all previous strinfo lengths, but not following strinfo
93 lengths (those are uncertain, usually invalidated during
94 maybe_invalidate, except when the alias oracle knows better).
95 Functions like strcat on the other side adjust the whole
96 related strinfo chain.
97 They are updated lazily, so to use the chain the same first fields
98 and si->prev->next == si->idx needs to be verified. */
99 int first;
100 int next;
101 int prev;
102 /* A flag whether the string is known to be written in the current
103 function. */
104 bool writable;
105 /* A flag for the next maybe_invalidate that this strinfo shouldn't
106 be invalidated. Always cleared by maybe_invalidate. */
107 bool dont_invalidate;
108 } *strinfo;
110 /* Pool for allocating strinfo_struct entries. */
111 static alloc_pool strinfo_pool;
113 /* Vector mapping positive string indexes to strinfo, for the
114 current basic block. The first pointer in the vector is special,
115 it is either NULL, meaning the vector isn't shared, or it is
116 a basic block pointer to the owner basic_block if shared.
117 If some other bb wants to modify the vector, the vector needs
118 to be unshared first, and only the owner bb is supposed to free it. */
119 static vec<strinfo, va_heap, vl_embed> *stridx_to_strinfo;
121 /* One OFFSET->IDX mapping. */
122 struct stridxlist
124 struct stridxlist *next;
125 HOST_WIDE_INT offset;
126 int idx;
129 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
130 struct decl_stridxlist_map
132 struct tree_map_base base;
133 struct stridxlist list;
136 /* stridxlist hashtable helpers. */
138 struct stridxlist_hash_traits : default_hashmap_traits
140 static inline hashval_t hash (tree);
143 /* Hash a from tree in a decl_stridxlist_map. */
145 inline hashval_t
146 stridxlist_hash_traits::hash (tree item)
148 return DECL_UID (item);
151 /* Hash table for mapping decls to a chained list of offset -> idx
152 mappings. */
153 static hash_map<tree, stridxlist, stridxlist_hash_traits>
154 *decl_to_stridxlist_htab;
156 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
157 static struct obstack stridx_obstack;
159 /* Last memcpy statement if it could be adjusted if the trailing
160 '\0' written is immediately overwritten, or
161 *x = '\0' store that could be removed if it is immediately overwritten. */
162 struct laststmt_struct
164 gimple stmt;
165 tree len;
166 int stridx;
167 } laststmt;
169 /* Helper function for get_stridx. */
171 static int
172 get_addr_stridx (tree exp)
174 HOST_WIDE_INT off;
175 struct stridxlist *list;
176 tree base;
178 if (!decl_to_stridxlist_htab)
179 return 0;
181 base = get_addr_base_and_unit_offset (exp, &off);
182 if (base == NULL || !DECL_P (base))
183 return 0;
185 list = decl_to_stridxlist_htab->get (base);
186 if (list == NULL)
187 return 0;
191 if (list->offset == off)
192 return list->idx;
193 list = list->next;
195 while (list);
196 return 0;
199 /* Return string index for EXP. */
201 static int
202 get_stridx (tree exp)
204 tree s, o;
206 if (TREE_CODE (exp) == SSA_NAME)
207 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
209 if (TREE_CODE (exp) == ADDR_EXPR)
211 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
212 if (idx != 0)
213 return idx;
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)
221 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
222 const char *p = TREE_STRING_POINTER (s);
223 int max = TREE_STRING_LENGTH (s) - 1;
225 if (p[max] == '\0' && offset >= 0 && offset <= max)
226 return ~(int) strlen (p + offset);
228 return 0;
231 /* Return true if strinfo vector is shared with the immediate dominator. */
233 static inline bool
234 strinfo_shared (void)
236 return vec_safe_length (stridx_to_strinfo)
237 && (*stridx_to_strinfo)[0] != NULL;
240 /* Unshare strinfo vector that is shared with the immediate dominator. */
242 static void
243 unshare_strinfo_vec (void)
245 strinfo si;
246 unsigned int i = 0;
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;
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. */
260 static int *
261 addr_stridxptr (tree exp)
263 HOST_WIDE_INT off;
265 tree base = get_addr_base_and_unit_offset (exp, &off);
266 if (base == NULL_TREE || !DECL_P (base))
267 return NULL;
269 if (!decl_to_stridxlist_htab)
271 decl_to_stridxlist_htab
272 = new hash_map<tree, stridxlist, stridxlist_hash_traits> (64);
273 gcc_obstack_init (&stridx_obstack);
276 bool existed;
277 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
278 if (existed)
280 int i;
281 for (i = 0; i < 16; i++)
283 if (list->offset == off)
284 return &list->idx;
285 if (list->next == NULL)
286 break;
288 if (i == 16)
289 return NULL;
290 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
291 list = list->next;
294 list->next = NULL;
295 list->offset = off;
296 list->idx = 0;
297 return &list->idx;
300 /* Create a new string index, or return 0 if reached limit. */
302 static int
303 new_stridx (tree exp)
305 int idx;
306 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
307 return 0;
308 if (TREE_CODE (exp) == SSA_NAME)
310 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
311 return 0;
312 idx = max_stridx++;
313 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
314 return idx;
316 if (TREE_CODE (exp) == ADDR_EXPR)
318 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
319 if (pidx != NULL)
321 gcc_assert (*pidx == 0);
322 *pidx = max_stridx++;
323 return *pidx;
326 return 0;
329 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
331 static int
332 new_addr_stridx (tree exp)
334 int *pidx;
335 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
336 return 0;
337 pidx = addr_stridxptr (exp);
338 if (pidx != NULL)
340 gcc_assert (*pidx == 0);
341 *pidx = max_stridx++;
342 return *pidx;
344 return 0;
347 /* Create a new strinfo. */
349 static strinfo
350 new_strinfo (tree ptr, int idx, tree length)
352 strinfo si = (strinfo) pool_alloc (strinfo_pool);
353 si->length = length;
354 si->ptr = ptr;
355 si->stmt = NULL;
356 si->endptr = NULL_TREE;
357 si->refcount = 1;
358 si->idx = idx;
359 si->first = 0;
360 si->prev = 0;
361 si->next = 0;
362 si->writable = false;
363 si->dont_invalidate = false;
364 return si;
367 /* Decrease strinfo refcount and free it if not referenced anymore. */
369 static inline void
370 free_strinfo (strinfo si)
372 if (si && --si->refcount == 0)
373 pool_free (strinfo_pool, si);
376 /* Return strinfo vector entry IDX. */
378 static inline strinfo
379 get_strinfo (int idx)
381 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
382 return NULL;
383 return (*stridx_to_strinfo)[idx];
386 /* Set strinfo in the vector entry IDX to SI. */
388 static inline void
389 set_strinfo (int idx, strinfo si)
391 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
392 unshare_strinfo_vec ();
393 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
394 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
395 (*stridx_to_strinfo)[idx] = si;
398 /* Return string length, or NULL if it can't be computed. */
400 static tree
401 get_string_length (strinfo si)
403 if (si->length)
404 return si->length;
406 if (si->stmt)
408 gimple stmt = si->stmt, lenstmt;
409 tree callee, lhs, fn, tem;
410 location_t loc;
411 gimple_stmt_iterator gsi;
413 gcc_assert (is_gimple_call (stmt));
414 callee = gimple_call_fndecl (stmt);
415 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
416 lhs = gimple_call_lhs (stmt);
417 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
418 /* unshare_strinfo is intentionally not called here. The (delayed)
419 transformation of strcpy or strcat into stpcpy is done at the place
420 of the former strcpy/strcat call and so can affect all the strinfos
421 with the same stmt. If they were unshared before and transformation
422 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
423 just compute the right length. */
424 switch (DECL_FUNCTION_CODE (callee))
426 case BUILT_IN_STRCAT:
427 case BUILT_IN_STRCAT_CHK:
428 gsi = gsi_for_stmt (stmt);
429 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
430 gcc_assert (lhs == NULL_TREE);
431 tem = unshare_expr (gimple_call_arg (stmt, 0));
432 lenstmt = gimple_build_call (fn, 1, tem);
433 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
434 gimple_call_set_lhs (lenstmt, lhs);
435 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
436 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
437 tem = gimple_call_arg (stmt, 0);
438 if (!ptrofftype_p (TREE_TYPE (lhs)))
440 lhs = convert_to_ptrofftype (lhs);
441 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
442 true, GSI_SAME_STMT);
444 lenstmt
445 = gimple_build_assign_with_ops
446 (POINTER_PLUS_EXPR,
447 make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0)), NULL),
448 tem, lhs);
449 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
450 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
451 lhs = NULL_TREE;
452 /* FALLTHRU */
453 case BUILT_IN_STRCPY:
454 case BUILT_IN_STRCPY_CHK:
455 if (gimple_call_num_args (stmt) == 2)
456 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
457 else
458 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
459 gcc_assert (lhs == NULL_TREE);
460 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
462 fprintf (dump_file, "Optimizing: ");
463 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
465 gimple_call_set_fndecl (stmt, fn);
466 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
467 gimple_call_set_lhs (stmt, lhs);
468 update_stmt (stmt);
469 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
471 fprintf (dump_file, "into: ");
472 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
474 /* FALLTHRU */
475 case BUILT_IN_STPCPY:
476 case BUILT_IN_STPCPY_CHK:
477 gcc_assert (lhs != NULL_TREE);
478 loc = gimple_location (stmt);
479 si->endptr = lhs;
480 si->stmt = NULL;
481 lhs = fold_convert_loc (loc, size_type_node, lhs);
482 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
483 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
484 lhs, si->length);
485 break;
486 case BUILT_IN_MALLOC:
487 break;
488 /* BUILT_IN_CALLOC always has si->length set. */
489 default:
490 gcc_unreachable ();
491 break;
495 return si->length;
498 /* Invalidate string length information for strings whose length
499 might change due to stores in stmt. */
501 static bool
502 maybe_invalidate (gimple stmt)
504 strinfo si;
505 unsigned int i;
506 bool nonempty = false;
508 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
509 if (si != NULL)
511 if (!si->dont_invalidate)
513 ao_ref r;
514 /* Do not use si->length. */
515 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
516 if (stmt_may_clobber_ref_p_1 (stmt, &r))
518 set_strinfo (i, NULL);
519 free_strinfo (si);
520 continue;
523 si->dont_invalidate = false;
524 nonempty = true;
526 return nonempty;
529 /* Unshare strinfo record SI, if it has recount > 1 or
530 if stridx_to_strinfo vector is shared with some other
531 bbs. */
533 static strinfo
534 unshare_strinfo (strinfo si)
536 strinfo nsi;
538 if (si->refcount == 1 && !strinfo_shared ())
539 return si;
541 nsi = new_strinfo (si->ptr, si->idx, si->length);
542 nsi->stmt = si->stmt;
543 nsi->endptr = si->endptr;
544 nsi->first = si->first;
545 nsi->prev = si->prev;
546 nsi->next = si->next;
547 nsi->writable = si->writable;
548 set_strinfo (si->idx, nsi);
549 free_strinfo (si);
550 return nsi;
553 /* Return first strinfo in the related strinfo chain
554 if all strinfos in between belong to the chain, otherwise
555 NULL. */
557 static strinfo
558 verify_related_strinfos (strinfo origsi)
560 strinfo si = origsi, psi;
562 if (origsi->first == 0)
563 return NULL;
564 for (; si->prev; si = psi)
566 if (si->first != origsi->first)
567 return NULL;
568 psi = get_strinfo (si->prev);
569 if (psi == NULL)
570 return NULL;
571 if (psi->next != si->idx)
572 return NULL;
574 if (si->idx != si->first)
575 return NULL;
576 return si;
579 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
580 to a zero-length string and if possible chain it to a related strinfo
581 chain whose part is or might be CHAINSI. */
583 static strinfo
584 zero_length_string (tree ptr, strinfo chainsi)
586 strinfo si;
587 int idx;
588 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
589 && get_stridx (ptr) == 0);
591 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
592 return NULL;
593 if (chainsi != NULL)
595 si = verify_related_strinfos (chainsi);
596 if (si)
598 chainsi = si;
599 for (; chainsi->next; chainsi = si)
601 if (chainsi->endptr == NULL_TREE)
603 chainsi = unshare_strinfo (chainsi);
604 chainsi->endptr = ptr;
606 si = get_strinfo (chainsi->next);
607 if (si == NULL
608 || si->first != chainsi->first
609 || si->prev != chainsi->idx)
610 break;
612 gcc_assert (chainsi->length || chainsi->stmt);
613 if (chainsi->endptr == NULL_TREE)
615 chainsi = unshare_strinfo (chainsi);
616 chainsi->endptr = ptr;
618 if (chainsi->length && integer_zerop (chainsi->length))
620 if (chainsi->next)
622 chainsi = unshare_strinfo (chainsi);
623 chainsi->next = 0;
625 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
626 return chainsi;
629 else if (chainsi->first || chainsi->prev || chainsi->next)
631 chainsi = unshare_strinfo (chainsi);
632 chainsi->first = 0;
633 chainsi->prev = 0;
634 chainsi->next = 0;
637 idx = new_stridx (ptr);
638 if (idx == 0)
639 return NULL;
640 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
641 set_strinfo (idx, si);
642 si->endptr = ptr;
643 if (chainsi != NULL)
645 chainsi = unshare_strinfo (chainsi);
646 if (chainsi->first == 0)
647 chainsi->first = chainsi->idx;
648 chainsi->next = idx;
649 if (chainsi->endptr == NULL_TREE)
650 chainsi->endptr = ptr;
651 si->prev = chainsi->idx;
652 si->first = chainsi->first;
653 si->writable = chainsi->writable;
655 return si;
658 /* For strinfo ORIGSI whose length has been just updated
659 update also related strinfo lengths (add ADJ to each,
660 but don't adjust ORIGSI). */
662 static void
663 adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
665 strinfo si = verify_related_strinfos (origsi);
667 if (si == NULL)
668 return;
670 while (1)
672 strinfo nsi;
674 if (si != origsi)
676 tree tem;
678 si = unshare_strinfo (si);
679 if (si->length)
681 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
682 si->length = fold_build2_loc (loc, PLUS_EXPR,
683 TREE_TYPE (si->length), si->length,
684 tem);
686 else if (si->stmt != NULL)
687 /* Delayed length computation is unaffected. */
689 else
690 gcc_unreachable ();
692 si->endptr = NULL_TREE;
693 si->dont_invalidate = true;
695 if (si->next == 0)
696 return;
697 nsi = get_strinfo (si->next);
698 if (nsi == NULL
699 || nsi->first != si->first
700 || nsi->prev != si->idx)
701 return;
702 si = nsi;
706 /* Find if there are other SSA_NAME pointers equal to PTR
707 for which we don't track their string lengths yet. If so, use
708 IDX for them. */
710 static void
711 find_equal_ptrs (tree ptr, int idx)
713 if (TREE_CODE (ptr) != SSA_NAME)
714 return;
715 while (1)
717 gimple stmt = SSA_NAME_DEF_STMT (ptr);
718 if (!is_gimple_assign (stmt))
719 return;
720 ptr = gimple_assign_rhs1 (stmt);
721 switch (gimple_assign_rhs_code (stmt))
723 case SSA_NAME:
724 break;
725 CASE_CONVERT:
726 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
727 return;
728 if (TREE_CODE (ptr) == SSA_NAME)
729 break;
730 if (TREE_CODE (ptr) != ADDR_EXPR)
731 return;
732 /* FALLTHRU */
733 case ADDR_EXPR:
735 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
736 if (pidx != NULL && *pidx == 0)
737 *pidx = idx;
738 return;
740 default:
741 return;
744 /* We might find an endptr created in this pass. Grow the
745 vector in that case. */
746 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
747 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
749 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
750 return;
751 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
755 /* If the last .MEM setter statement before STMT is
756 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
757 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
758 just memcpy (x, y, strlen (y)). SI must be the zero length
759 strinfo. */
761 static void
762 adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
764 tree vuse, callee, len;
765 struct laststmt_struct last = laststmt;
766 strinfo lastsi, firstsi;
768 laststmt.stmt = NULL;
769 laststmt.len = NULL_TREE;
770 laststmt.stridx = 0;
772 if (last.stmt == NULL)
773 return;
775 vuse = gimple_vuse (stmt);
776 if (vuse == NULL_TREE
777 || SSA_NAME_DEF_STMT (vuse) != last.stmt
778 || !has_single_use (vuse))
779 return;
781 gcc_assert (last.stridx > 0);
782 lastsi = get_strinfo (last.stridx);
783 if (lastsi == NULL)
784 return;
786 if (lastsi != si)
788 if (lastsi->first == 0 || lastsi->first != si->first)
789 return;
791 firstsi = verify_related_strinfos (si);
792 if (firstsi == NULL)
793 return;
794 while (firstsi != lastsi)
796 strinfo nextsi;
797 if (firstsi->next == 0)
798 return;
799 nextsi = get_strinfo (firstsi->next);
800 if (nextsi == NULL
801 || nextsi->prev != firstsi->idx
802 || nextsi->first != si->first)
803 return;
804 firstsi = nextsi;
808 if (!is_strcat)
810 if (si->length == NULL_TREE || !integer_zerop (si->length))
811 return;
814 if (is_gimple_assign (last.stmt))
816 gimple_stmt_iterator gsi;
818 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
819 return;
820 if (stmt_could_throw_p (last.stmt))
821 return;
822 gsi = gsi_for_stmt (last.stmt);
823 unlink_stmt_vdef (last.stmt);
824 release_defs (last.stmt);
825 gsi_remove (&gsi, true);
826 return;
829 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
830 return;
832 callee = gimple_call_fndecl (last.stmt);
833 switch (DECL_FUNCTION_CODE (callee))
835 case BUILT_IN_MEMCPY:
836 case BUILT_IN_MEMCPY_CHK:
837 break;
838 default:
839 return;
842 len = gimple_call_arg (last.stmt, 2);
843 if (tree_fits_uhwi_p (len))
845 if (!tree_fits_uhwi_p (last.len)
846 || integer_zerop (len)
847 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
848 return;
849 /* Don't adjust the length if it is divisible by 4, it is more efficient
850 to store the extra '\0' in that case. */
851 if ((tree_to_uhwi (len) & 3) == 0)
852 return;
854 else if (TREE_CODE (len) == SSA_NAME)
856 gimple def_stmt = SSA_NAME_DEF_STMT (len);
857 if (!is_gimple_assign (def_stmt)
858 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
859 || gimple_assign_rhs1 (def_stmt) != last.len
860 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
861 return;
863 else
864 return;
866 gimple_call_set_arg (last.stmt, 2, last.len);
867 update_stmt (last.stmt);
870 /* Handle a strlen call. If strlen of the argument is known, replace
871 the strlen call with the known value, otherwise remember that strlen
872 of the argument is stored in the lhs SSA_NAME. */
874 static void
875 handle_builtin_strlen (gimple_stmt_iterator *gsi)
877 int idx;
878 tree src;
879 gimple stmt = gsi_stmt (*gsi);
880 tree lhs = gimple_call_lhs (stmt);
882 if (lhs == NULL_TREE)
883 return;
885 src = gimple_call_arg (stmt, 0);
886 idx = get_stridx (src);
887 if (idx)
889 strinfo si = NULL;
890 tree rhs;
892 if (idx < 0)
893 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
894 else
896 rhs = NULL_TREE;
897 si = get_strinfo (idx);
898 if (si != NULL)
899 rhs = get_string_length (si);
901 if (rhs != NULL_TREE)
903 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
905 fprintf (dump_file, "Optimizing: ");
906 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
908 rhs = unshare_expr (rhs);
909 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
910 rhs = fold_convert_loc (gimple_location (stmt),
911 TREE_TYPE (lhs), rhs);
912 if (!update_call_from_tree (gsi, rhs))
913 gimplify_and_update_call_from_tree (gsi, rhs);
914 stmt = gsi_stmt (*gsi);
915 update_stmt (stmt);
916 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
918 fprintf (dump_file, "into: ");
919 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
921 if (si != NULL
922 && TREE_CODE (si->length) != SSA_NAME
923 && TREE_CODE (si->length) != INTEGER_CST
924 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
926 si = unshare_strinfo (si);
927 si->length = lhs;
929 return;
932 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
933 return;
934 if (idx == 0)
935 idx = new_stridx (src);
936 else if (get_strinfo (idx) != NULL)
937 return;
938 if (idx)
940 strinfo si = new_strinfo (src, idx, lhs);
941 set_strinfo (idx, si);
942 find_equal_ptrs (src, idx);
946 /* Handle a strchr call. If strlen of the first argument is known, replace
947 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
948 that lhs of the call is endptr and strlen of the argument is endptr - x. */
950 static void
951 handle_builtin_strchr (gimple_stmt_iterator *gsi)
953 int idx;
954 tree src;
955 gimple stmt = gsi_stmt (*gsi);
956 tree lhs = gimple_call_lhs (stmt);
958 if (lhs == NULL_TREE)
959 return;
961 if (!integer_zerop (gimple_call_arg (stmt, 1)))
962 return;
964 src = gimple_call_arg (stmt, 0);
965 idx = get_stridx (src);
966 if (idx)
968 strinfo si = NULL;
969 tree rhs;
971 if (idx < 0)
972 rhs = build_int_cst (size_type_node, ~idx);
973 else
975 rhs = NULL_TREE;
976 si = get_strinfo (idx);
977 if (si != NULL)
978 rhs = get_string_length (si);
980 if (rhs != NULL_TREE)
982 location_t loc = gimple_location (stmt);
984 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
986 fprintf (dump_file, "Optimizing: ");
987 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
989 if (si != NULL && si->endptr != NULL_TREE)
991 rhs = unshare_expr (si->endptr);
992 if (!useless_type_conversion_p (TREE_TYPE (lhs),
993 TREE_TYPE (rhs)))
994 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
996 else
998 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
999 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1000 TREE_TYPE (src), src, rhs);
1001 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1002 TREE_TYPE (rhs)))
1003 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1005 if (!update_call_from_tree (gsi, rhs))
1006 gimplify_and_update_call_from_tree (gsi, rhs);
1007 stmt = gsi_stmt (*gsi);
1008 update_stmt (stmt);
1009 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1011 fprintf (dump_file, "into: ");
1012 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1014 if (si != NULL
1015 && si->endptr == NULL_TREE
1016 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1018 si = unshare_strinfo (si);
1019 si->endptr = lhs;
1021 zero_length_string (lhs, si);
1022 return;
1025 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1026 return;
1027 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1029 if (idx == 0)
1030 idx = new_stridx (src);
1031 else if (get_strinfo (idx) != NULL)
1033 zero_length_string (lhs, NULL);
1034 return;
1036 if (idx)
1038 location_t loc = gimple_location (stmt);
1039 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1040 tree srcu = fold_convert_loc (loc, size_type_node, src);
1041 tree length = fold_build2_loc (loc, MINUS_EXPR,
1042 size_type_node, lhsu, srcu);
1043 strinfo si = new_strinfo (src, idx, length);
1044 si->endptr = lhs;
1045 set_strinfo (idx, si);
1046 find_equal_ptrs (src, idx);
1047 zero_length_string (lhs, si);
1050 else
1051 zero_length_string (lhs, NULL);
1054 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1055 If strlen of the second argument is known, strlen of the first argument
1056 is the same after this call. Furthermore, attempt to convert it to
1057 memcpy. */
1059 static void
1060 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1062 int idx, didx;
1063 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1064 bool success;
1065 gimple stmt = gsi_stmt (*gsi);
1066 strinfo si, dsi, olddsi, zsi;
1067 location_t loc;
1069 src = gimple_call_arg (stmt, 1);
1070 dst = gimple_call_arg (stmt, 0);
1071 lhs = gimple_call_lhs (stmt);
1072 idx = get_stridx (src);
1073 si = NULL;
1074 if (idx > 0)
1075 si = get_strinfo (idx);
1077 didx = get_stridx (dst);
1078 olddsi = NULL;
1079 oldlen = NULL_TREE;
1080 if (didx > 0)
1081 olddsi = get_strinfo (didx);
1082 else if (didx < 0)
1083 return;
1085 if (olddsi != NULL)
1086 adjust_last_stmt (olddsi, stmt, false);
1088 srclen = NULL_TREE;
1089 if (si != NULL)
1090 srclen = get_string_length (si);
1091 else if (idx < 0)
1092 srclen = build_int_cst (size_type_node, ~idx);
1094 loc = gimple_location (stmt);
1095 if (srclen == NULL_TREE)
1096 switch (bcode)
1098 case BUILT_IN_STRCPY:
1099 case BUILT_IN_STRCPY_CHK:
1100 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1101 return;
1102 break;
1103 case BUILT_IN_STPCPY:
1104 case BUILT_IN_STPCPY_CHK:
1105 if (lhs == NULL_TREE)
1106 return;
1107 else
1109 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1110 srclen = fold_convert_loc (loc, size_type_node, dst);
1111 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1112 lhsuint, srclen);
1114 break;
1115 default:
1116 gcc_unreachable ();
1119 if (didx == 0)
1121 didx = new_stridx (dst);
1122 if (didx == 0)
1123 return;
1125 if (olddsi != NULL)
1127 oldlen = olddsi->length;
1128 dsi = unshare_strinfo (olddsi);
1129 dsi->length = srclen;
1130 /* Break the chain, so adjust_related_strinfo on later pointers in
1131 the chain won't adjust this one anymore. */
1132 dsi->next = 0;
1133 dsi->stmt = NULL;
1134 dsi->endptr = NULL_TREE;
1136 else
1138 dsi = new_strinfo (dst, didx, srclen);
1139 set_strinfo (didx, dsi);
1140 find_equal_ptrs (dst, didx);
1142 dsi->writable = true;
1143 dsi->dont_invalidate = true;
1145 if (dsi->length == NULL_TREE)
1147 strinfo chainsi;
1149 /* If string length of src is unknown, use delayed length
1150 computation. If string lenth of dst will be needed, it
1151 can be computed by transforming this strcpy call into
1152 stpcpy and subtracting dst from the return value. */
1154 /* Look for earlier strings whose length could be determined if
1155 this strcpy is turned into an stpcpy. */
1157 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1159 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1161 /* When setting a stmt for delayed length computation
1162 prevent all strinfos through dsi from being
1163 invalidated. */
1164 chainsi = unshare_strinfo (chainsi);
1165 chainsi->stmt = stmt;
1166 chainsi->length = NULL_TREE;
1167 chainsi->endptr = NULL_TREE;
1168 chainsi->dont_invalidate = true;
1171 dsi->stmt = stmt;
1172 return;
1175 if (olddsi != NULL)
1177 tree adj = NULL_TREE;
1178 if (oldlen == NULL_TREE)
1180 else if (integer_zerop (oldlen))
1181 adj = srclen;
1182 else if (TREE_CODE (oldlen) == INTEGER_CST
1183 || TREE_CODE (srclen) == INTEGER_CST)
1184 adj = fold_build2_loc (loc, MINUS_EXPR,
1185 TREE_TYPE (srclen), srclen,
1186 fold_convert_loc (loc, TREE_TYPE (srclen),
1187 oldlen));
1188 if (adj != NULL_TREE)
1189 adjust_related_strinfos (loc, dsi, adj);
1190 else
1191 dsi->prev = 0;
1193 /* strcpy src may not overlap dst, so src doesn't need to be
1194 invalidated either. */
1195 if (si != NULL)
1196 si->dont_invalidate = true;
1198 fn = NULL_TREE;
1199 zsi = NULL;
1200 switch (bcode)
1202 case BUILT_IN_STRCPY:
1203 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1204 if (lhs)
1205 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1206 break;
1207 case BUILT_IN_STRCPY_CHK:
1208 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1209 if (lhs)
1210 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1211 break;
1212 case BUILT_IN_STPCPY:
1213 /* This would need adjustment of the lhs (subtract one),
1214 or detection that the trailing '\0' doesn't need to be
1215 written, if it will be immediately overwritten.
1216 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1217 if (lhs)
1219 dsi->endptr = lhs;
1220 zsi = zero_length_string (lhs, dsi);
1222 break;
1223 case BUILT_IN_STPCPY_CHK:
1224 /* This would need adjustment of the lhs (subtract one),
1225 or detection that the trailing '\0' doesn't need to be
1226 written, if it will be immediately overwritten.
1227 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1228 if (lhs)
1230 dsi->endptr = lhs;
1231 zsi = zero_length_string (lhs, dsi);
1233 break;
1234 default:
1235 gcc_unreachable ();
1237 if (zsi != NULL)
1238 zsi->dont_invalidate = true;
1240 if (fn == NULL_TREE)
1241 return;
1243 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1244 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1246 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1247 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1248 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1249 GSI_SAME_STMT);
1250 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1252 fprintf (dump_file, "Optimizing: ");
1253 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1255 if (gimple_call_num_args (stmt) == 2)
1256 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1257 else
1258 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1259 gimple_call_arg (stmt, 2));
1260 if (success)
1262 stmt = gsi_stmt (*gsi);
1263 update_stmt (stmt);
1264 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1266 fprintf (dump_file, "into: ");
1267 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1269 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1270 laststmt.stmt = stmt;
1271 laststmt.len = srclen;
1272 laststmt.stridx = dsi->idx;
1274 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1275 fprintf (dump_file, "not possible.\n");
1278 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1279 If strlen of the second argument is known and length of the third argument
1280 is that plus one, strlen of the first argument is the same after this
1281 call. */
1283 static void
1284 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1286 int idx, didx;
1287 tree src, dst, len, lhs, oldlen, newlen;
1288 gimple stmt = gsi_stmt (*gsi);
1289 strinfo si, dsi, olddsi;
1291 len = gimple_call_arg (stmt, 2);
1292 src = gimple_call_arg (stmt, 1);
1293 dst = gimple_call_arg (stmt, 0);
1294 idx = get_stridx (src);
1295 if (idx == 0)
1296 return;
1298 didx = get_stridx (dst);
1299 olddsi = NULL;
1300 if (didx > 0)
1301 olddsi = get_strinfo (didx);
1302 else if (didx < 0)
1303 return;
1305 if (olddsi != NULL
1306 && tree_fits_uhwi_p (len)
1307 && !integer_zerop (len))
1308 adjust_last_stmt (olddsi, stmt, false);
1310 if (idx > 0)
1312 gimple def_stmt;
1314 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1315 si = get_strinfo (idx);
1316 if (si == NULL || si->length == NULL_TREE)
1317 return;
1318 if (TREE_CODE (len) != SSA_NAME)
1319 return;
1320 def_stmt = SSA_NAME_DEF_STMT (len);
1321 if (!is_gimple_assign (def_stmt)
1322 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1323 || gimple_assign_rhs1 (def_stmt) != si->length
1324 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1325 return;
1327 else
1329 si = NULL;
1330 /* Handle memcpy (x, "abcd", 5) or
1331 memcpy (x, "abc\0uvw", 7). */
1332 if (!tree_fits_uhwi_p (len)
1333 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1334 return;
1337 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1338 adjust_last_stmt (olddsi, stmt, false);
1340 if (didx == 0)
1342 didx = new_stridx (dst);
1343 if (didx == 0)
1344 return;
1346 if (si != NULL)
1347 newlen = si->length;
1348 else
1349 newlen = build_int_cst (size_type_node, ~idx);
1350 oldlen = NULL_TREE;
1351 if (olddsi != NULL)
1353 dsi = unshare_strinfo (olddsi);
1354 oldlen = olddsi->length;
1355 dsi->length = newlen;
1356 /* Break the chain, so adjust_related_strinfo on later pointers in
1357 the chain won't adjust this one anymore. */
1358 dsi->next = 0;
1359 dsi->stmt = NULL;
1360 dsi->endptr = NULL_TREE;
1362 else
1364 dsi = new_strinfo (dst, didx, newlen);
1365 set_strinfo (didx, dsi);
1366 find_equal_ptrs (dst, didx);
1368 dsi->writable = true;
1369 dsi->dont_invalidate = true;
1370 if (olddsi != NULL)
1372 tree adj = NULL_TREE;
1373 location_t loc = gimple_location (stmt);
1374 if (oldlen == NULL_TREE)
1376 else if (integer_zerop (oldlen))
1377 adj = dsi->length;
1378 else if (TREE_CODE (oldlen) == INTEGER_CST
1379 || TREE_CODE (dsi->length) == INTEGER_CST)
1380 adj = fold_build2_loc (loc, MINUS_EXPR,
1381 TREE_TYPE (dsi->length), dsi->length,
1382 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1383 oldlen));
1384 if (adj != NULL_TREE)
1385 adjust_related_strinfos (loc, dsi, adj);
1386 else
1387 dsi->prev = 0;
1389 /* memcpy src may not overlap dst, so src doesn't need to be
1390 invalidated either. */
1391 if (si != NULL)
1392 si->dont_invalidate = true;
1394 lhs = gimple_call_lhs (stmt);
1395 switch (bcode)
1397 case BUILT_IN_MEMCPY:
1398 case BUILT_IN_MEMCPY_CHK:
1399 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1400 laststmt.stmt = stmt;
1401 laststmt.len = dsi->length;
1402 laststmt.stridx = dsi->idx;
1403 if (lhs)
1404 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1405 break;
1406 case BUILT_IN_MEMPCPY:
1407 case BUILT_IN_MEMPCPY_CHK:
1408 break;
1409 default:
1410 gcc_unreachable ();
1414 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1415 If strlen of the second argument is known, strlen of the first argument
1416 is increased by the length of the second argument. Furthermore, attempt
1417 to convert it to memcpy/strcpy if the length of the first argument
1418 is known. */
1420 static void
1421 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1423 int idx, didx;
1424 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1425 bool success;
1426 gimple stmt = gsi_stmt (*gsi);
1427 strinfo si, dsi;
1428 location_t loc;
1430 src = gimple_call_arg (stmt, 1);
1431 dst = gimple_call_arg (stmt, 0);
1432 lhs = gimple_call_lhs (stmt);
1434 didx = get_stridx (dst);
1435 if (didx < 0)
1436 return;
1438 dsi = NULL;
1439 if (didx > 0)
1440 dsi = get_strinfo (didx);
1441 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1443 /* strcat (p, q) can be transformed into
1444 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1445 with length endptr - p if we need to compute the length
1446 later on. Don't do this transformation if we don't need
1447 it. */
1448 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1450 if (didx == 0)
1452 didx = new_stridx (dst);
1453 if (didx == 0)
1454 return;
1456 if (dsi == NULL)
1458 dsi = new_strinfo (dst, didx, NULL_TREE);
1459 set_strinfo (didx, dsi);
1460 find_equal_ptrs (dst, didx);
1462 else
1464 dsi = unshare_strinfo (dsi);
1465 dsi->length = NULL_TREE;
1466 dsi->next = 0;
1467 dsi->endptr = NULL_TREE;
1469 dsi->writable = true;
1470 dsi->stmt = stmt;
1471 dsi->dont_invalidate = true;
1473 return;
1476 srclen = NULL_TREE;
1477 si = NULL;
1478 idx = get_stridx (src);
1479 if (idx < 0)
1480 srclen = build_int_cst (size_type_node, ~idx);
1481 else if (idx > 0)
1483 si = get_strinfo (idx);
1484 if (si != NULL)
1485 srclen = get_string_length (si);
1488 loc = gimple_location (stmt);
1489 dstlen = dsi->length;
1490 endptr = dsi->endptr;
1492 dsi = unshare_strinfo (dsi);
1493 dsi->endptr = NULL_TREE;
1494 dsi->stmt = NULL;
1495 dsi->writable = true;
1497 if (srclen != NULL_TREE)
1499 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1500 dsi->length, srclen);
1501 adjust_related_strinfos (loc, dsi, srclen);
1502 dsi->dont_invalidate = true;
1504 else
1506 dsi->length = NULL;
1507 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1508 dsi->dont_invalidate = true;
1511 if (si != NULL)
1512 /* strcat src may not overlap dst, so src doesn't need to be
1513 invalidated either. */
1514 si->dont_invalidate = true;
1516 /* For now. Could remove the lhs from the call and add
1517 lhs = dst; afterwards. */
1518 if (lhs)
1519 return;
1521 fn = NULL_TREE;
1522 objsz = NULL_TREE;
1523 switch (bcode)
1525 case BUILT_IN_STRCAT:
1526 if (srclen != NULL_TREE)
1527 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1528 else
1529 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1530 break;
1531 case BUILT_IN_STRCAT_CHK:
1532 if (srclen != NULL_TREE)
1533 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1534 else
1535 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1536 objsz = gimple_call_arg (stmt, 2);
1537 break;
1538 default:
1539 gcc_unreachable ();
1542 if (fn == NULL_TREE)
1543 return;
1545 len = NULL_TREE;
1546 if (srclen != NULL_TREE)
1548 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1549 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1551 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1552 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1553 build_int_cst (type, 1));
1554 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1555 GSI_SAME_STMT);
1557 if (endptr)
1558 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1559 else
1560 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1561 TREE_TYPE (dst), unshare_expr (dst),
1562 fold_convert_loc (loc, sizetype,
1563 unshare_expr (dstlen)));
1564 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1565 GSI_SAME_STMT);
1566 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1568 fprintf (dump_file, "Optimizing: ");
1569 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1571 if (srclen != NULL_TREE)
1572 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1573 dst, src, len, objsz);
1574 else
1575 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1576 dst, src, objsz);
1577 if (success)
1579 stmt = gsi_stmt (*gsi);
1580 update_stmt (stmt);
1581 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1583 fprintf (dump_file, "into: ");
1584 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1586 /* If srclen == NULL, note that current string length can be
1587 computed by transforming this strcpy into stpcpy. */
1588 if (srclen == NULL_TREE && dsi->dont_invalidate)
1589 dsi->stmt = stmt;
1590 adjust_last_stmt (dsi, stmt, true);
1591 if (srclen != NULL_TREE)
1593 laststmt.stmt = stmt;
1594 laststmt.len = srclen;
1595 laststmt.stridx = dsi->idx;
1598 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1599 fprintf (dump_file, "not possible.\n");
1602 /* Handle a call to malloc or calloc. */
1604 static void
1605 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1607 gimple stmt = gsi_stmt (*gsi);
1608 tree lhs = gimple_call_lhs (stmt);
1609 gcc_assert (get_stridx (lhs) == 0);
1610 int idx = new_stridx (lhs);
1611 tree length = NULL_TREE;
1612 if (bcode == BUILT_IN_CALLOC)
1613 length = build_int_cst (size_type_node, 0);
1614 strinfo si = new_strinfo (lhs, idx, length);
1615 if (bcode == BUILT_IN_CALLOC)
1616 si->endptr = lhs;
1617 set_strinfo (idx, si);
1618 si->writable = true;
1619 si->stmt = stmt;
1620 si->dont_invalidate = true;
1623 /* Handle a call to memset.
1624 After a call to calloc, memset(,0,) is unnecessary.
1625 memset(malloc(n),0,n) is calloc(n,1). */
1627 static bool
1628 handle_builtin_memset (gimple_stmt_iterator *gsi)
1630 gimple stmt2 = gsi_stmt (*gsi);
1631 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1632 return true;
1633 tree ptr = gimple_call_arg (stmt2, 0);
1634 int idx1 = get_stridx (ptr);
1635 if (idx1 <= 0)
1636 return true;
1637 strinfo si1 = get_strinfo (idx1);
1638 if (!si1)
1639 return true;
1640 gimple stmt1 = si1->stmt;
1641 if (!stmt1 || !is_gimple_call (stmt1))
1642 return true;
1643 tree callee1 = gimple_call_fndecl (stmt1);
1644 if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL))
1645 return true;
1646 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1647 tree size = gimple_call_arg (stmt2, 2);
1648 if (code1 == BUILT_IN_CALLOC)
1649 /* Not touching stmt1 */ ;
1650 else if (code1 == BUILT_IN_MALLOC
1651 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1653 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1654 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1655 size, build_one_cst (size_type_node));
1656 si1->length = build_int_cst (size_type_node, 0);
1657 si1->stmt = gsi_stmt (gsi1);
1659 else
1660 return true;
1661 tree lhs = gimple_call_lhs (stmt2);
1662 unlink_stmt_vdef (stmt2);
1663 if (lhs)
1665 gimple assign = gimple_build_assign (lhs, ptr);
1666 gsi_replace (gsi, assign, false);
1668 else
1670 gsi_remove (gsi, true);
1671 release_defs (stmt2);
1674 return false;
1677 /* Handle a POINTER_PLUS_EXPR statement.
1678 For p = "abcd" + 2; compute associated length, or if
1679 p = q + off is pointing to a '\0' character of a string, call
1680 zero_length_string on it. */
1682 static void
1683 handle_pointer_plus (gimple_stmt_iterator *gsi)
1685 gimple stmt = gsi_stmt (*gsi);
1686 tree lhs = gimple_assign_lhs (stmt), off;
1687 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1688 strinfo si, zsi;
1690 if (idx == 0)
1691 return;
1693 if (idx < 0)
1695 tree off = gimple_assign_rhs2 (stmt);
1696 if (tree_fits_uhwi_p (off)
1697 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1698 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1699 = ~(~idx - (int) tree_to_uhwi (off));
1700 return;
1703 si = get_strinfo (idx);
1704 if (si == NULL || si->length == NULL_TREE)
1705 return;
1707 off = gimple_assign_rhs2 (stmt);
1708 zsi = NULL;
1709 if (operand_equal_p (si->length, off, 0))
1710 zsi = zero_length_string (lhs, si);
1711 else if (TREE_CODE (off) == SSA_NAME)
1713 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1714 if (gimple_assign_single_p (def_stmt)
1715 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1716 zsi = zero_length_string (lhs, si);
1718 if (zsi != NULL
1719 && si->endptr != NULL_TREE
1720 && si->endptr != lhs
1721 && TREE_CODE (si->endptr) == SSA_NAME)
1723 enum tree_code rhs_code
1724 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1725 ? SSA_NAME : NOP_EXPR;
1726 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr, NULL_TREE);
1727 gcc_assert (gsi_stmt (*gsi) == stmt);
1728 update_stmt (stmt);
1732 /* Handle a single character store. */
1734 static bool
1735 handle_char_store (gimple_stmt_iterator *gsi)
1737 int idx = -1;
1738 strinfo si = NULL;
1739 gimple stmt = gsi_stmt (*gsi);
1740 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1742 if (TREE_CODE (lhs) == MEM_REF
1743 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1745 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1747 ssaname = TREE_OPERAND (lhs, 0);
1748 idx = get_stridx (ssaname);
1751 else
1752 idx = get_addr_stridx (lhs);
1754 if (idx > 0)
1756 si = get_strinfo (idx);
1757 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1759 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1761 /* When storing '\0', the store can be removed
1762 if we know it has been stored in the current function. */
1763 if (!stmt_could_throw_p (stmt) && si->writable)
1765 unlink_stmt_vdef (stmt);
1766 release_defs (stmt);
1767 gsi_remove (gsi, true);
1768 return false;
1770 else
1772 si->writable = true;
1773 gsi_next (gsi);
1774 return false;
1777 else
1778 /* Otherwise this statement overwrites the '\0' with
1779 something, if the previous stmt was a memcpy,
1780 its length may be decreased. */
1781 adjust_last_stmt (si, stmt, false);
1783 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1785 si = unshare_strinfo (si);
1786 si->length = build_int_cst (size_type_node, 0);
1787 si->endptr = NULL;
1788 si->prev = 0;
1789 si->next = 0;
1790 si->stmt = NULL;
1791 si->first = 0;
1792 si->writable = true;
1793 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1794 si->endptr = ssaname;
1795 si->dont_invalidate = true;
1797 /* If si->length is non-zero constant, we aren't overwriting '\0',
1798 and if we aren't storing '\0', we know that the length of the
1799 string and any other zero terminated string in memory remains
1800 the same. In that case we move to the next gimple statement and
1801 return to signal the caller that it shouldn't invalidate anything.
1803 This is benefical for cases like:
1805 char p[20];
1806 void foo (char *q)
1808 strcpy (p, "foobar");
1809 size_t len = strlen (p); // This can be optimized into 6
1810 size_t len2 = strlen (q); // This has to be computed
1811 p[0] = 'X';
1812 size_t len3 = strlen (p); // This can be optimized into 6
1813 size_t len4 = strlen (q); // This can be optimized into len2
1814 bar (len, len2, len3, len4);
1817 else if (si != NULL && si->length != NULL_TREE
1818 && TREE_CODE (si->length) == INTEGER_CST
1819 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
1821 gsi_next (gsi);
1822 return false;
1825 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1827 if (ssaname)
1829 si = zero_length_string (ssaname, NULL);
1830 if (si != NULL)
1831 si->dont_invalidate = true;
1833 else
1835 int idx = new_addr_stridx (lhs);
1836 if (idx != 0)
1838 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1839 build_int_cst (size_type_node, 0));
1840 set_strinfo (idx, si);
1841 si->dont_invalidate = true;
1844 if (si != NULL)
1845 si->writable = true;
1847 else if (idx == 0
1848 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
1849 && ssaname == NULL_TREE
1850 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
1852 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
1853 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
1854 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
1856 int idx = new_addr_stridx (lhs);
1857 if (idx != 0)
1859 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1860 build_int_cst (size_type_node, l));
1861 set_strinfo (idx, si);
1862 si->dont_invalidate = true;
1867 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
1869 /* Allow adjust_last_stmt to remove it if the stored '\0'
1870 is immediately overwritten. */
1871 laststmt.stmt = stmt;
1872 laststmt.len = build_int_cst (size_type_node, 1);
1873 laststmt.stridx = si->idx;
1875 return true;
1878 /* Attempt to optimize a single statement at *GSI using string length
1879 knowledge. */
1881 static bool
1882 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
1884 gimple stmt = gsi_stmt (*gsi);
1886 if (is_gimple_call (stmt))
1888 tree callee = gimple_call_fndecl (stmt);
1889 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
1890 switch (DECL_FUNCTION_CODE (callee))
1892 case BUILT_IN_STRLEN:
1893 handle_builtin_strlen (gsi);
1894 break;
1895 case BUILT_IN_STRCHR:
1896 handle_builtin_strchr (gsi);
1897 break;
1898 case BUILT_IN_STRCPY:
1899 case BUILT_IN_STRCPY_CHK:
1900 case BUILT_IN_STPCPY:
1901 case BUILT_IN_STPCPY_CHK:
1902 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
1903 break;
1904 case BUILT_IN_MEMCPY:
1905 case BUILT_IN_MEMCPY_CHK:
1906 case BUILT_IN_MEMPCPY:
1907 case BUILT_IN_MEMPCPY_CHK:
1908 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
1909 break;
1910 case BUILT_IN_STRCAT:
1911 case BUILT_IN_STRCAT_CHK:
1912 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
1913 break;
1914 case BUILT_IN_MALLOC:
1915 case BUILT_IN_CALLOC:
1916 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
1917 break;
1918 case BUILT_IN_MEMSET:
1919 if (!handle_builtin_memset (gsi))
1920 return false;
1921 break;
1922 default:
1923 break;
1926 else if (is_gimple_assign (stmt))
1928 tree lhs = gimple_assign_lhs (stmt);
1930 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
1932 if (gimple_assign_single_p (stmt)
1933 || (gimple_assign_cast_p (stmt)
1934 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
1936 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1937 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
1939 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1940 handle_pointer_plus (gsi);
1942 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
1944 tree type = TREE_TYPE (lhs);
1945 if (TREE_CODE (type) == ARRAY_TYPE)
1946 type = TREE_TYPE (type);
1947 if (TREE_CODE (type) == INTEGER_TYPE
1948 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
1949 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
1951 if (! handle_char_store (gsi))
1952 return false;
1957 if (gimple_vdef (stmt))
1958 maybe_invalidate (stmt);
1959 return true;
1962 /* Recursively call maybe_invalidate on stmts that might be executed
1963 in between dombb and current bb and that contain a vdef. Stop when
1964 *count stmts are inspected, or if the whole strinfo vector has
1965 been invalidated. */
1967 static void
1968 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
1970 unsigned int i, n = gimple_phi_num_args (phi);
1972 for (i = 0; i < n; i++)
1974 tree vuse = gimple_phi_arg_def (phi, i);
1975 gimple stmt = SSA_NAME_DEF_STMT (vuse);
1976 basic_block bb = gimple_bb (stmt);
1977 if (bb == NULL
1978 || bb == dombb
1979 || !bitmap_set_bit (visited, bb->index)
1980 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1981 continue;
1982 while (1)
1984 if (gimple_code (stmt) == GIMPLE_PHI)
1986 do_invalidate (dombb, stmt, visited, count);
1987 if (*count == 0)
1988 return;
1989 break;
1991 if (--*count == 0)
1992 return;
1993 if (!maybe_invalidate (stmt))
1995 *count = 0;
1996 return;
1998 vuse = gimple_vuse (stmt);
1999 stmt = SSA_NAME_DEF_STMT (vuse);
2000 if (gimple_bb (stmt) != bb)
2002 bb = gimple_bb (stmt);
2003 if (bb == NULL
2004 || bb == dombb
2005 || !bitmap_set_bit (visited, bb->index)
2006 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2007 break;
2013 class strlen_dom_walker : public dom_walker
2015 public:
2016 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2018 virtual void before_dom_children (basic_block);
2019 virtual void after_dom_children (basic_block);
2022 /* Callback for walk_dominator_tree. Attempt to optimize various
2023 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2025 void
2026 strlen_dom_walker::before_dom_children (basic_block bb)
2028 gimple_stmt_iterator gsi;
2029 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2031 if (dombb == NULL)
2032 stridx_to_strinfo = NULL;
2033 else
2035 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) dombb->aux);
2036 if (stridx_to_strinfo)
2038 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2040 gimple phi = gsi_stmt (gsi);
2041 if (virtual_operand_p (gimple_phi_result (phi)))
2043 bitmap visited = BITMAP_ALLOC (NULL);
2044 int count_vdef = 100;
2045 do_invalidate (dombb, phi, visited, &count_vdef);
2046 BITMAP_FREE (visited);
2047 if (count_vdef == 0)
2049 /* If there were too many vdefs in between immediate
2050 dominator and current bb, invalidate everything.
2051 If stridx_to_strinfo has been unshared, we need
2052 to free it, otherwise just set it to NULL. */
2053 if (!strinfo_shared ())
2055 unsigned int i;
2056 strinfo si;
2058 for (i = 1;
2059 vec_safe_iterate (stridx_to_strinfo, i, &si);
2060 ++i)
2062 free_strinfo (si);
2063 (*stridx_to_strinfo)[i] = NULL;
2066 else
2067 stridx_to_strinfo = NULL;
2069 break;
2075 /* If all PHI arguments have the same string index, the PHI result
2076 has it as well. */
2077 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2079 gimple phi = gsi_stmt (gsi);
2080 tree result = gimple_phi_result (phi);
2081 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2083 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2084 if (idx != 0)
2086 unsigned int i, n = gimple_phi_num_args (phi);
2087 for (i = 1; i < n; i++)
2088 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2089 break;
2090 if (i == n)
2091 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2096 /* Attempt to optimize individual statements. */
2097 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2098 if (strlen_optimize_stmt (&gsi))
2099 gsi_next (&gsi);
2101 bb->aux = stridx_to_strinfo;
2102 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2103 (*stridx_to_strinfo)[0] = (strinfo) bb;
2106 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2107 owned by the current bb, clear bb->aux. */
2109 void
2110 strlen_dom_walker::after_dom_children (basic_block bb)
2112 if (bb->aux)
2114 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux);
2115 if (vec_safe_length (stridx_to_strinfo)
2116 && (*stridx_to_strinfo)[0] == (strinfo) bb)
2118 unsigned int i;
2119 strinfo si;
2121 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2122 free_strinfo (si);
2123 vec_free (stridx_to_strinfo);
2125 bb->aux = NULL;
2129 /* Main entry point. */
2131 namespace {
2133 const pass_data pass_data_strlen =
2135 GIMPLE_PASS, /* type */
2136 "strlen", /* name */
2137 OPTGROUP_NONE, /* optinfo_flags */
2138 TV_TREE_STRLEN, /* tv_id */
2139 ( PROP_cfg | PROP_ssa ), /* properties_required */
2140 0, /* properties_provided */
2141 0, /* properties_destroyed */
2142 0, /* todo_flags_start */
2143 0, /* todo_flags_finish */
2146 class pass_strlen : public gimple_opt_pass
2148 public:
2149 pass_strlen (gcc::context *ctxt)
2150 : gimple_opt_pass (pass_data_strlen, ctxt)
2153 /* opt_pass methods: */
2154 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2155 virtual unsigned int execute (function *);
2157 }; // class pass_strlen
2159 unsigned int
2160 pass_strlen::execute (function *fun)
2162 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2163 max_stridx = 1;
2164 strinfo_pool = create_alloc_pool ("strinfo_struct pool",
2165 sizeof (struct strinfo_struct), 64);
2167 calculate_dominance_info (CDI_DOMINATORS);
2169 /* String length optimization is implemented as a walk of the dominator
2170 tree and a forward walk of statements within each block. */
2171 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2173 ssa_ver_to_stridx.release ();
2174 free_alloc_pool (strinfo_pool);
2175 if (decl_to_stridxlist_htab)
2177 obstack_free (&stridx_obstack, NULL);
2178 delete decl_to_stridxlist_htab;
2179 decl_to_stridxlist_htab = NULL;
2181 laststmt.stmt = NULL;
2182 laststmt.len = NULL_TREE;
2183 laststmt.stridx = 0;
2185 return 0;
2188 } // anon namespace
2190 gimple_opt_pass *
2191 make_pass_strlen (gcc::context *ctxt)
2193 return new pass_strlen (ctxt);