2011-11-04 Tom de Vries <tom@codesourcery.com>
[official-gcc.git] / gcc / tree-ssa-strlen.c
bloba37633a920f227406df372484eabdfd312253065
1 /* String length optimization
2 Copyright (C) 2011 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-flow.h"
25 #include "tree-pass.h"
26 #include "domwalk.h"
27 #include "alloc-pool.h"
28 #include "tree-ssa-propagate.h"
29 #include "gimple-pretty-print.h"
30 #include "params.h"
31 #include "expr.h"
33 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
34 is an index into strinfo vector, negative value stands for
35 string length of a string literal (~strlen). */
36 static VEC (int, heap) *ssa_ver_to_stridx;
38 /* Number of currently active string indexes plus one. */
39 static int max_stridx;
41 /* String information record. */
42 typedef struct strinfo_struct
44 /* String length of this string. */
45 tree length;
46 /* Any of the corresponding pointers for querying alias oracle. */
47 tree ptr;
48 /* Statement for delayed length computation. */
49 gimple stmt;
50 /* Pointer to '\0' if known, if NULL, it can be computed as
51 ptr + length. */
52 tree endptr;
53 /* Reference count. Any changes to strinfo entry possibly shared
54 with dominating basic blocks need unshare_strinfo first, except
55 for dont_invalidate which affects only the immediately next
56 maybe_invalidate. */
57 int refcount;
58 /* Copy of index. get_strinfo (si->idx) should return si; */
59 int idx;
60 /* These 3 fields are for chaining related string pointers together.
61 E.g. for
62 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
63 strcpy (c, d); e = c + dl;
64 strinfo(a) -> strinfo(c) -> strinfo(e)
65 All have ->first field equal to strinfo(a)->idx and are doubly
66 chained through prev/next fields. The later strinfos are required
67 to point into the same string with zero or more bytes after
68 the previous pointer and all bytes in between the two pointers
69 must be non-zero. Functions like strcpy or memcpy are supposed
70 to adjust all previous strinfo lengths, but not following strinfo
71 lengths (those are uncertain, usually invalidated during
72 maybe_invalidate, except when the alias oracle knows better).
73 Functions like strcat on the other side adjust the whole
74 related strinfo chain.
75 They are updated lazily, so to use the chain the same first fields
76 and si->prev->next == si->idx needs to be verified. */
77 int first;
78 int next;
79 int prev;
80 /* A flag whether the string is known to be written in the current
81 function. */
82 bool writable;
83 /* A flag for the next maybe_invalidate that this strinfo shouldn't
84 be invalidated. Always cleared by maybe_invalidate. */
85 bool dont_invalidate;
86 } *strinfo;
87 DEF_VEC_P(strinfo);
88 DEF_VEC_ALLOC_P(strinfo,heap);
90 /* Pool for allocating strinfo_struct entries. */
91 static alloc_pool strinfo_pool;
93 /* Vector mapping positive string indexes to strinfo, for the
94 current basic block. The first pointer in the vector is special,
95 it is either NULL, meaning the vector isn't shared, or it is
96 a basic block pointer to the owner basic_block if shared.
97 If some other bb wants to modify the vector, the vector needs
98 to be unshared first, and only the owner bb is supposed to free it. */
99 static VEC(strinfo, heap) *stridx_to_strinfo;
101 /* One OFFSET->IDX mapping. */
102 struct stridxlist
104 struct stridxlist *next;
105 HOST_WIDE_INT offset;
106 int idx;
109 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
110 struct decl_stridxlist_map
112 struct tree_map_base base;
113 struct stridxlist list;
116 /* Hash table for mapping decls to a chained list of offset -> idx
117 mappings. */
118 static htab_t decl_to_stridxlist_htab;
120 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
121 static struct obstack stridx_obstack;
123 /* Last memcpy statement if it could be adjusted if the trailing
124 '\0' written is immediately overwritten, or
125 *x = '\0' store that could be removed if it is immediately overwritten. */
126 struct laststmt_struct
128 gimple stmt;
129 tree len;
130 int stridx;
131 } laststmt;
133 /* Hash a from tree in a decl_stridxlist_map. */
135 static unsigned int
136 decl_to_stridxlist_hash (const void *item)
138 return DECL_UID (((const struct decl_stridxlist_map *) item)->base.from);
141 /* Helper function for get_stridx. */
143 static int
144 get_addr_stridx (tree exp)
146 HOST_WIDE_INT off;
147 struct decl_stridxlist_map ent, *e;
148 struct stridxlist *list;
149 tree base;
151 if (decl_to_stridxlist_htab == NULL)
152 return 0;
154 base = get_addr_base_and_unit_offset (exp, &off);
155 if (base == NULL || !DECL_P (base))
156 return 0;
158 ent.base.from = base;
159 e = (struct decl_stridxlist_map *)
160 htab_find_with_hash (decl_to_stridxlist_htab, &ent, DECL_UID (base));
161 if (e == NULL)
162 return 0;
164 list = &e->list;
167 if (list->offset == off)
168 return list->idx;
169 list = list->next;
171 while (list);
172 return 0;
175 /* Return string index for EXP. */
177 static int
178 get_stridx (tree exp)
180 tree s, o;
182 if (TREE_CODE (exp) == SSA_NAME)
183 return VEC_index (int, ssa_ver_to_stridx, SSA_NAME_VERSION (exp));
185 if (TREE_CODE (exp) == ADDR_EXPR)
187 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
188 if (idx != 0)
189 return idx;
192 s = string_constant (exp, &o);
193 if (s != NULL_TREE
194 && (o == NULL_TREE || host_integerp (o, 0))
195 && TREE_STRING_LENGTH (s) > 0)
197 HOST_WIDE_INT offset = o ? tree_low_cst (o, 0) : 0;
198 const char *p = TREE_STRING_POINTER (s);
199 int max = TREE_STRING_LENGTH (s) - 1;
201 if (p[max] == '\0' && offset >= 0 && offset <= max)
202 return ~(int) strlen (p + offset);
204 return 0;
207 /* Return true if strinfo vector is shared with the immediate dominator. */
209 static inline bool
210 strinfo_shared (void)
212 return VEC_length (strinfo, stridx_to_strinfo)
213 && VEC_index (strinfo, stridx_to_strinfo, 0) != NULL;
216 /* Unshare strinfo vector that is shared with the immediate dominator. */
218 static void
219 unshare_strinfo_vec (void)
221 strinfo si;
222 unsigned int i = 0;
224 gcc_assert (strinfo_shared ());
225 stridx_to_strinfo = VEC_copy (strinfo, heap, stridx_to_strinfo);
226 for (i = 1; VEC_iterate (strinfo, stridx_to_strinfo, i, si); ++i)
227 if (si != NULL)
228 si->refcount++;
229 VEC_replace (strinfo, stridx_to_strinfo, 0, NULL);
232 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
233 Return a pointer to the location where the string index can
234 be stored (if 0) or is stored, or NULL if this can't be tracked. */
236 static int *
237 addr_stridxptr (tree exp)
239 void **slot;
240 struct decl_stridxlist_map ent;
241 struct stridxlist *list;
242 HOST_WIDE_INT off;
244 tree base = get_addr_base_and_unit_offset (exp, &off);
245 if (base == NULL_TREE || !DECL_P (base))
246 return NULL;
248 if (decl_to_stridxlist_htab == NULL)
250 decl_to_stridxlist_htab
251 = htab_create (64, decl_to_stridxlist_hash, tree_map_base_eq, NULL);
252 gcc_obstack_init (&stridx_obstack);
254 ent.base.from = base;
255 slot = htab_find_slot_with_hash (decl_to_stridxlist_htab, &ent,
256 DECL_UID (base), INSERT);
257 if (*slot)
259 int i;
260 list = &((struct decl_stridxlist_map *)*slot)->list;
261 for (i = 0; i < 16; i++)
263 if (list->offset == off)
264 return &list->idx;
265 if (list->next == NULL)
266 break;
268 if (i == 16)
269 return NULL;
270 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
271 list = list->next;
273 else
275 struct decl_stridxlist_map *e
276 = XOBNEW (&stridx_obstack, struct decl_stridxlist_map);
277 e->base.from = base;
278 *slot = (void *) e;
279 list = &e->list;
281 list->next = NULL;
282 list->offset = off;
283 list->idx = 0;
284 return &list->idx;
287 /* Create a new string index, or return 0 if reached limit. */
289 static int
290 new_stridx (tree exp)
292 int idx;
293 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
294 return 0;
295 if (TREE_CODE (exp) == SSA_NAME)
297 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
298 return 0;
299 idx = max_stridx++;
300 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (exp), idx);
301 return idx;
303 if (TREE_CODE (exp) == ADDR_EXPR)
305 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
306 if (pidx != NULL)
308 gcc_assert (*pidx == 0);
309 *pidx = max_stridx++;
310 return *pidx;
313 return 0;
316 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
318 static int
319 new_addr_stridx (tree exp)
321 int *pidx;
322 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
323 return 0;
324 pidx = addr_stridxptr (exp);
325 if (pidx != NULL)
327 gcc_assert (*pidx == 0);
328 *pidx = max_stridx++;
329 return *pidx;
331 return 0;
334 /* Create a new strinfo. */
336 static strinfo
337 new_strinfo (tree ptr, int idx, tree length)
339 strinfo si = (strinfo) pool_alloc (strinfo_pool);
340 si->length = length;
341 si->ptr = ptr;
342 si->stmt = NULL;
343 si->endptr = NULL_TREE;
344 si->refcount = 1;
345 si->idx = idx;
346 si->first = 0;
347 si->prev = 0;
348 si->next = 0;
349 si->writable = false;
350 si->dont_invalidate = false;
351 return si;
354 /* Decrease strinfo refcount and free it if not referenced anymore. */
356 static inline void
357 free_strinfo (strinfo si)
359 if (si && --si->refcount == 0)
360 pool_free (strinfo_pool, si);
363 /* Return strinfo vector entry IDX. */
365 static inline strinfo
366 get_strinfo (int idx)
368 if (VEC_length (strinfo, stridx_to_strinfo) <= (unsigned int) idx)
369 return NULL;
370 return VEC_index (strinfo, stridx_to_strinfo, idx);
373 /* Set strinfo in the vector entry IDX to SI. */
375 static inline void
376 set_strinfo (int idx, strinfo si)
378 if (VEC_length (strinfo, stridx_to_strinfo) && VEC_index (strinfo, stridx_to_strinfo, 0))
379 unshare_strinfo_vec ();
380 if (VEC_length (strinfo, stridx_to_strinfo) <= (unsigned int) idx)
381 VEC_safe_grow_cleared (strinfo, heap, stridx_to_strinfo, idx + 1);
382 VEC_replace (strinfo, stridx_to_strinfo, idx, si);
385 /* Return string length, or NULL if it can't be computed. */
387 static tree
388 get_string_length (strinfo si)
390 if (si->length)
391 return si->length;
393 if (si->stmt)
395 gimple stmt = si->stmt, lenstmt;
396 tree callee, lhs, lhs_var, fn, tem;
397 location_t loc;
398 gimple_stmt_iterator gsi;
400 gcc_assert (is_gimple_call (stmt));
401 callee = gimple_call_fndecl (stmt);
402 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
403 lhs = gimple_call_lhs (stmt);
404 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
405 /* unshare_strinfo is intentionally not called here. The (delayed)
406 transformation of strcpy or strcat into stpcpy is done at the place
407 of the former strcpy/strcat call and so can affect all the strinfos
408 with the same stmt. If they were unshared before and transformation
409 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
410 just compute the right length. */
411 switch (DECL_FUNCTION_CODE (callee))
413 case BUILT_IN_STRCAT:
414 case BUILT_IN_STRCAT_CHK:
415 gsi = gsi_for_stmt (stmt);
416 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
417 gcc_assert (lhs == NULL_TREE);
418 lhs_var = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
419 add_referenced_var (lhs_var);
420 tem = unshare_expr (gimple_call_arg (stmt, 0));
421 lenstmt = gimple_build_call (fn, 1, tem);
422 lhs = make_ssa_name (lhs_var, lenstmt);
423 gimple_call_set_lhs (lenstmt, lhs);
424 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
425 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
426 lhs_var = create_tmp_var (TREE_TYPE (gimple_call_arg (stmt, 0)),
427 NULL);
428 add_referenced_var (lhs_var);
429 tem = gimple_call_arg (stmt, 0);
430 lenstmt
431 = gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
432 make_ssa_name (lhs_var, NULL),
433 tem, lhs);
434 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
435 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
436 lhs = NULL_TREE;
437 /* FALLTHRU */
438 case BUILT_IN_STRCPY:
439 case BUILT_IN_STRCPY_CHK:
440 if (gimple_call_num_args (stmt) == 2)
441 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
442 else
443 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
444 gcc_assert (lhs == NULL_TREE);
445 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
447 fprintf (dump_file, "Optimizing: ");
448 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
450 gimple_call_set_fndecl (stmt, fn);
451 lhs_var = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
452 add_referenced_var (lhs_var);
453 lhs = make_ssa_name (lhs_var, stmt);
454 gimple_call_set_lhs (stmt, lhs);
455 update_stmt (stmt);
456 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
458 fprintf (dump_file, "into: ");
459 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
461 /* FALLTHRU */
462 case BUILT_IN_STPCPY:
463 case BUILT_IN_STPCPY_CHK:
464 gcc_assert (lhs != NULL_TREE);
465 loc = gimple_location (stmt);
466 si->endptr = lhs;
467 si->stmt = NULL;
468 lhs = fold_convert_loc (loc, size_type_node, lhs);
469 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
470 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
471 lhs, si->length);
472 break;
473 default:
474 gcc_unreachable ();
475 break;
479 return si->length;
482 /* Invalidate string length information for strings whose length
483 might change due to stores in stmt. */
485 static bool
486 maybe_invalidate (gimple stmt)
488 strinfo si;
489 unsigned int i;
490 bool nonempty = false;
492 for (i = 1; VEC_iterate (strinfo, stridx_to_strinfo, i, si); ++i)
493 if (si != NULL)
495 if (!si->dont_invalidate)
497 ao_ref r;
498 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
499 if (stmt_may_clobber_ref_p_1 (stmt, &r))
501 set_strinfo (i, NULL);
502 free_strinfo (si);
503 continue;
506 si->dont_invalidate = false;
507 nonempty = true;
509 return nonempty;
512 /* Unshare strinfo record SI, if it has recount > 1 or
513 if stridx_to_strinfo vector is shared with some other
514 bbs. */
516 static strinfo
517 unshare_strinfo (strinfo si)
519 strinfo nsi;
521 if (si->refcount == 1 && !strinfo_shared ())
522 return si;
524 nsi = new_strinfo (si->ptr, si->idx, si->length);
525 nsi->stmt = si->stmt;
526 nsi->endptr = si->endptr;
527 nsi->first = si->first;
528 nsi->prev = si->prev;
529 nsi->next = si->next;
530 nsi->writable = si->writable;
531 set_strinfo (si->idx, nsi);
532 free_strinfo (si);
533 return nsi;
536 /* Return first strinfo in the related strinfo chain
537 if all strinfos in between belong to the chain, otherwise
538 NULL. */
540 static strinfo
541 verify_related_strinfos (strinfo origsi)
543 strinfo si = origsi, psi;
545 if (origsi->first == 0)
546 return NULL;
547 for (; si->prev; si = psi)
549 if (si->first != origsi->first)
550 return NULL;
551 psi = get_strinfo (si->prev);
552 if (psi == NULL)
553 return NULL;
554 if (psi->next != si->idx)
555 return NULL;
557 if (si->idx != si->first)
558 return NULL;
559 return si;
562 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
563 to a zero-length string and if possible chain it to a related strinfo
564 chain whose part is or might be CHAINSI. */
566 static strinfo
567 zero_length_string (tree ptr, strinfo chainsi)
569 strinfo si;
570 int idx;
571 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
572 && get_stridx (ptr) == 0);
574 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
575 return NULL;
576 if (chainsi != NULL)
578 si = verify_related_strinfos (chainsi);
579 if (si)
581 chainsi = si;
582 for (; chainsi->next; chainsi = si)
584 if (chainsi->endptr == NULL_TREE)
586 chainsi = unshare_strinfo (chainsi);
587 chainsi->endptr = ptr;
589 si = get_strinfo (chainsi->next);
590 if (si == NULL
591 || si->first != chainsi->first
592 || si->prev != chainsi->idx)
593 break;
595 gcc_assert (chainsi->length || chainsi->stmt);
596 if (chainsi->endptr == NULL_TREE)
598 chainsi = unshare_strinfo (chainsi);
599 chainsi->endptr = ptr;
601 if (chainsi->length && integer_zerop (chainsi->length))
603 if (chainsi->next)
605 chainsi = unshare_strinfo (chainsi);
606 chainsi->next = 0;
608 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (ptr),
609 chainsi->idx);
610 return chainsi;
613 else if (chainsi->first || chainsi->prev || chainsi->next)
615 chainsi = unshare_strinfo (chainsi);
616 chainsi->first = 0;
617 chainsi->prev = 0;
618 chainsi->next = 0;
621 idx = new_stridx (ptr);
622 if (idx == 0)
623 return NULL;
624 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
625 set_strinfo (idx, si);
626 si->endptr = ptr;
627 if (chainsi != NULL)
629 chainsi = unshare_strinfo (chainsi);
630 if (chainsi->first == 0)
631 chainsi->first = chainsi->idx;
632 chainsi->next = idx;
633 if (chainsi->endptr == NULL_TREE)
634 chainsi->endptr = ptr;
635 si->prev = chainsi->idx;
636 si->first = chainsi->first;
637 si->writable = chainsi->writable;
639 return si;
642 /* For strinfo ORIGSI whose length has been just updated
643 update also related strinfo lengths (add ADJ to each,
644 but don't adjust ORIGSI). */
646 static void
647 adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
649 strinfo si = verify_related_strinfos (origsi);
651 if (si == NULL)
652 return;
654 while (1)
656 strinfo nsi;
658 if (si != origsi)
660 tree tem;
662 si = unshare_strinfo (si);
663 if (si->length)
665 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
666 si->length = fold_build2_loc (loc, PLUS_EXPR,
667 TREE_TYPE (si->length), si->length,
668 tem);
670 else if (si->stmt != NULL)
671 /* Delayed length computation is unaffected. */
673 else
674 gcc_unreachable ();
676 si->endptr = NULL_TREE;
677 si->dont_invalidate = true;
679 if (si->next == 0)
680 return;
681 nsi = get_strinfo (si->next);
682 if (nsi == NULL
683 || nsi->first != si->first
684 || nsi->prev != si->idx)
685 return;
686 si = nsi;
690 /* Find if there are other SSA_NAME pointers equal to PTR
691 for which we don't track their string lengths yet. If so, use
692 IDX for them. */
694 static void
695 find_equal_ptrs (tree ptr, int idx)
697 if (TREE_CODE (ptr) != SSA_NAME)
698 return;
699 while (1)
701 gimple stmt = SSA_NAME_DEF_STMT (ptr);
702 if (!is_gimple_assign (stmt))
703 return;
704 ptr = gimple_assign_rhs1 (stmt);
705 switch (gimple_assign_rhs_code (stmt))
707 case SSA_NAME:
708 break;
709 CASE_CONVERT:
710 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
711 return;
712 if (TREE_CODE (ptr) == SSA_NAME)
713 break;
714 if (TREE_CODE (ptr) != ADDR_EXPR)
715 return;
716 /* FALLTHRU */
717 case ADDR_EXPR:
719 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
720 if (pidx != NULL && *pidx == 0)
721 *pidx = idx;
722 return;
724 default:
725 return;
728 /* We might find an endptr created in this pass. Grow the
729 vector in that case. */
730 if (VEC_length (int, ssa_ver_to_stridx) <= SSA_NAME_VERSION (ptr))
731 VEC_safe_grow_cleared (int, heap, ssa_ver_to_stridx, num_ssa_names);
733 if (VEC_index (int, ssa_ver_to_stridx, SSA_NAME_VERSION (ptr)) != 0)
734 return;
735 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (ptr), idx);
739 /* If the last .MEM setter statement before STMT is
740 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
741 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
742 just memcpy (x, y, strlen (y)). SI must be the zero length
743 strinfo. */
745 static void
746 adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
748 tree vuse, callee, len;
749 struct laststmt_struct last = laststmt;
750 strinfo lastsi, firstsi;
752 laststmt.stmt = NULL;
753 laststmt.len = NULL_TREE;
754 laststmt.stridx = 0;
756 if (last.stmt == NULL)
757 return;
759 vuse = gimple_vuse (stmt);
760 if (vuse == NULL_TREE
761 || SSA_NAME_DEF_STMT (vuse) != last.stmt
762 || !has_single_use (vuse))
763 return;
765 gcc_assert (last.stridx > 0);
766 lastsi = get_strinfo (last.stridx);
767 if (lastsi == NULL)
768 return;
770 if (lastsi != si)
772 if (lastsi->first == 0 || lastsi->first != si->first)
773 return;
775 firstsi = verify_related_strinfos (si);
776 if (firstsi == NULL)
777 return;
778 while (firstsi != lastsi)
780 strinfo nextsi;
781 if (firstsi->next == 0)
782 return;
783 nextsi = get_strinfo (firstsi->next);
784 if (nextsi == NULL
785 || nextsi->prev != firstsi->idx
786 || nextsi->first != si->first)
787 return;
788 firstsi = nextsi;
792 if (!is_strcat)
794 if (si->length == NULL_TREE || !integer_zerop (si->length))
795 return;
798 if (is_gimple_assign (last.stmt))
800 gimple_stmt_iterator gsi;
802 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
803 return;
804 if (stmt_could_throw_p (last.stmt))
805 return;
806 gsi = gsi_for_stmt (last.stmt);
807 unlink_stmt_vdef (last.stmt);
808 release_defs (last.stmt);
809 gsi_remove (&gsi, true);
810 return;
813 if (!is_gimple_call (last.stmt))
814 return;
815 callee = gimple_call_fndecl (last.stmt);
816 if (callee == NULL_TREE || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
817 return;
819 switch (DECL_FUNCTION_CODE (callee))
821 case BUILT_IN_MEMCPY:
822 case BUILT_IN_MEMCPY_CHK:
823 break;
824 default:
825 return;
828 len = gimple_call_arg (last.stmt, 2);
829 if (host_integerp (len, 1))
831 if (!host_integerp (last.len, 1)
832 || integer_zerop (len)
833 || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
834 != (unsigned HOST_WIDE_INT) tree_low_cst (last.len, 1) + 1)
835 return;
836 /* Don't adjust the length if it is divisible by 4, it is more efficient
837 to store the extra '\0' in that case. */
838 if ((((unsigned HOST_WIDE_INT) tree_low_cst (len, 1)) & 3) == 0)
839 return;
841 else if (TREE_CODE (len) == SSA_NAME)
843 gimple def_stmt = SSA_NAME_DEF_STMT (len);
844 if (!is_gimple_assign (def_stmt)
845 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
846 || gimple_assign_rhs1 (def_stmt) != last.len
847 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
848 return;
850 else
851 return;
853 gimple_call_set_arg (last.stmt, 2, last.len);
854 update_stmt (last.stmt);
857 /* Handle a strlen call. If strlen of the argument is known, replace
858 the strlen call with the known value, otherwise remember that strlen
859 of the argument is stored in the lhs SSA_NAME. */
861 static void
862 handle_builtin_strlen (gimple_stmt_iterator *gsi)
864 int idx;
865 tree src;
866 gimple stmt = gsi_stmt (*gsi);
867 tree lhs = gimple_call_lhs (stmt);
869 if (lhs == NULL_TREE)
870 return;
872 src = gimple_call_arg (stmt, 0);
873 idx = get_stridx (src);
874 if (idx)
876 strinfo si = NULL;
877 tree rhs;
879 if (idx < 0)
880 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
881 else
883 rhs = NULL_TREE;
884 si = get_strinfo (idx);
885 if (si != NULL)
886 rhs = get_string_length (si);
888 if (rhs != NULL_TREE)
890 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
892 fprintf (dump_file, "Optimizing: ");
893 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
895 rhs = unshare_expr (rhs);
896 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
897 rhs = fold_convert_loc (gimple_location (stmt),
898 TREE_TYPE (lhs), rhs);
899 if (!update_call_from_tree (gsi, rhs))
900 gimplify_and_update_call_from_tree (gsi, rhs);
901 stmt = gsi_stmt (*gsi);
902 update_stmt (stmt);
903 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
905 fprintf (dump_file, "into: ");
906 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
908 if (si != NULL
909 && TREE_CODE (si->length) != SSA_NAME
910 && TREE_CODE (si->length) != INTEGER_CST
911 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
913 si = unshare_strinfo (si);
914 si->length = lhs;
916 return;
919 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
920 return;
921 if (idx == 0)
922 idx = new_stridx (src);
923 else if (get_strinfo (idx) != NULL)
924 return;
925 if (idx)
927 strinfo si = new_strinfo (src, idx, lhs);
928 set_strinfo (idx, si);
929 find_equal_ptrs (src, idx);
933 /* Handle a strchr call. If strlen of the first argument is known, replace
934 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
935 that lhs of the call is endptr and strlen of the argument is endptr - x. */
937 static void
938 handle_builtin_strchr (gimple_stmt_iterator *gsi)
940 int idx;
941 tree src;
942 gimple stmt = gsi_stmt (*gsi);
943 tree lhs = gimple_call_lhs (stmt);
945 if (lhs == NULL_TREE)
946 return;
948 if (!integer_zerop (gimple_call_arg (stmt, 1)))
949 return;
951 src = gimple_call_arg (stmt, 0);
952 idx = get_stridx (src);
953 if (idx)
955 strinfo si = NULL;
956 tree rhs;
958 if (idx < 0)
959 rhs = build_int_cst (size_type_node, ~idx);
960 else
962 rhs = NULL_TREE;
963 si = get_strinfo (idx);
964 if (si != NULL)
965 rhs = get_string_length (si);
967 if (rhs != NULL_TREE)
969 location_t loc = gimple_location (stmt);
971 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
973 fprintf (dump_file, "Optimizing: ");
974 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
976 if (si != NULL && si->endptr != NULL_TREE)
978 rhs = unshare_expr (si->endptr);
979 if (!useless_type_conversion_p (TREE_TYPE (lhs),
980 TREE_TYPE (rhs)))
981 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
983 else
985 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
986 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
987 TREE_TYPE (src), src, rhs);
988 if (!useless_type_conversion_p (TREE_TYPE (lhs),
989 TREE_TYPE (rhs)))
990 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
992 if (!update_call_from_tree (gsi, rhs))
993 gimplify_and_update_call_from_tree (gsi, rhs);
994 stmt = gsi_stmt (*gsi);
995 update_stmt (stmt);
996 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
998 fprintf (dump_file, "into: ");
999 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1001 if (si != NULL
1002 && si->endptr == NULL_TREE
1003 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1005 si = unshare_strinfo (si);
1006 si->endptr = lhs;
1008 zero_length_string (lhs, si);
1009 return;
1012 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1013 return;
1014 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1016 if (idx == 0)
1017 idx = new_stridx (src);
1018 else if (get_strinfo (idx) != NULL)
1020 zero_length_string (lhs, NULL);
1021 return;
1023 if (idx)
1025 location_t loc = gimple_location (stmt);
1026 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1027 tree srcu = fold_convert_loc (loc, size_type_node, src);
1028 tree length = fold_build2_loc (loc, MINUS_EXPR,
1029 size_type_node, lhsu, srcu);
1030 strinfo si = new_strinfo (src, idx, length);
1031 si->endptr = lhs;
1032 set_strinfo (idx, si);
1033 find_equal_ptrs (src, idx);
1034 zero_length_string (lhs, si);
1037 else
1038 zero_length_string (lhs, NULL);
1041 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1042 If strlen of the second argument is known, strlen of the first argument
1043 is the same after this call. Furthermore, attempt to convert it to
1044 memcpy. */
1046 static void
1047 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1049 int idx, didx;
1050 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1051 bool success;
1052 gimple stmt = gsi_stmt (*gsi);
1053 strinfo si, dsi, olddsi, zsi;
1054 location_t loc;
1056 src = gimple_call_arg (stmt, 1);
1057 dst = gimple_call_arg (stmt, 0);
1058 lhs = gimple_call_lhs (stmt);
1059 idx = get_stridx (src);
1060 si = NULL;
1061 if (idx > 0)
1062 si = get_strinfo (idx);
1064 didx = get_stridx (dst);
1065 olddsi = NULL;
1066 oldlen = NULL_TREE;
1067 if (didx > 0)
1068 olddsi = get_strinfo (didx);
1069 else if (didx < 0)
1070 return;
1072 if (olddsi != NULL)
1073 adjust_last_stmt (olddsi, stmt, false);
1075 srclen = NULL_TREE;
1076 if (si != NULL)
1077 srclen = get_string_length (si);
1078 else if (idx < 0)
1079 srclen = build_int_cst (size_type_node, ~idx);
1081 loc = gimple_location (stmt);
1082 if (srclen == NULL_TREE)
1083 switch (bcode)
1085 case BUILT_IN_STRCPY:
1086 case BUILT_IN_STRCPY_CHK:
1087 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1088 return;
1089 break;
1090 case BUILT_IN_STPCPY:
1091 case BUILT_IN_STPCPY_CHK:
1092 if (lhs == NULL_TREE)
1093 return;
1094 else
1096 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1097 srclen = fold_convert_loc (loc, size_type_node, dst);
1098 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1099 lhsuint, srclen);
1101 break;
1102 default:
1103 gcc_unreachable ();
1106 if (didx == 0)
1108 didx = new_stridx (dst);
1109 if (didx == 0)
1110 return;
1112 if (olddsi != NULL)
1114 oldlen = olddsi->length;
1115 dsi = unshare_strinfo (olddsi);
1116 dsi->length = srclen;
1117 /* Break the chain, so adjust_related_strinfo on later pointers in
1118 the chain won't adjust this one anymore. */
1119 dsi->next = 0;
1120 dsi->stmt = NULL;
1121 dsi->endptr = NULL_TREE;
1123 else
1125 dsi = new_strinfo (dst, didx, srclen);
1126 set_strinfo (didx, dsi);
1127 find_equal_ptrs (dst, didx);
1129 dsi->writable = true;
1130 dsi->dont_invalidate = true;
1132 if (dsi->length == NULL_TREE)
1134 strinfo chainsi;
1136 /* If string length of src is unknown, use delayed length
1137 computation. If string lenth of dst will be needed, it
1138 can be computed by transforming this strcpy call into
1139 stpcpy and subtracting dst from the return value. */
1141 /* Look for earlier strings whose length could be determined if
1142 this strcpy is turned into an stpcpy. */
1144 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1146 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1148 /* When setting a stmt for delayed length computation
1149 prevent all strinfos through dsi from being
1150 invalidated. */
1151 chainsi = unshare_strinfo (chainsi);
1152 chainsi->stmt = stmt;
1153 chainsi->length = NULL_TREE;
1154 chainsi->endptr = NULL_TREE;
1155 chainsi->dont_invalidate = true;
1158 dsi->stmt = stmt;
1159 return;
1162 if (olddsi != NULL)
1164 tree adj = NULL_TREE;
1165 if (oldlen == NULL_TREE)
1167 else if (integer_zerop (oldlen))
1168 adj = srclen;
1169 else if (TREE_CODE (oldlen) == INTEGER_CST
1170 || TREE_CODE (srclen) == INTEGER_CST)
1171 adj = fold_build2_loc (loc, MINUS_EXPR,
1172 TREE_TYPE (srclen), srclen,
1173 fold_convert_loc (loc, TREE_TYPE (srclen),
1174 oldlen));
1175 if (adj != NULL_TREE)
1176 adjust_related_strinfos (loc, dsi, adj);
1177 else
1178 dsi->prev = 0;
1180 /* strcpy src may not overlap dst, so src doesn't need to be
1181 invalidated either. */
1182 if (si != NULL)
1183 si->dont_invalidate = true;
1185 fn = NULL_TREE;
1186 zsi = NULL;
1187 switch (bcode)
1189 case BUILT_IN_STRCPY:
1190 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1191 if (lhs)
1192 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
1193 break;
1194 case BUILT_IN_STRCPY_CHK:
1195 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1196 if (lhs)
1197 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
1198 break;
1199 case BUILT_IN_STPCPY:
1200 /* This would need adjustment of the lhs (subtract one),
1201 or detection that the trailing '\0' doesn't need to be
1202 written, if it will be immediately overwritten.
1203 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1204 if (lhs)
1206 dsi->endptr = lhs;
1207 zsi = zero_length_string (lhs, dsi);
1209 break;
1210 case BUILT_IN_STPCPY_CHK:
1211 /* This would need adjustment of the lhs (subtract one),
1212 or detection that the trailing '\0' doesn't need to be
1213 written, if it will be immediately overwritten.
1214 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1215 if (lhs)
1217 dsi->endptr = lhs;
1218 zsi = zero_length_string (lhs, dsi);
1220 break;
1221 default:
1222 gcc_unreachable ();
1224 if (zsi != NULL)
1225 zsi->dont_invalidate = true;
1227 if (fn == NULL_TREE)
1228 return;
1230 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1231 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1233 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1234 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1235 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1236 GSI_SAME_STMT);
1237 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1239 fprintf (dump_file, "Optimizing: ");
1240 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1242 if (gimple_call_num_args (stmt) == 2)
1243 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1244 else
1245 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1246 gimple_call_arg (stmt, 2));
1247 if (success)
1249 stmt = gsi_stmt (*gsi);
1250 update_stmt (stmt);
1251 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1253 fprintf (dump_file, "into: ");
1254 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1256 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1257 laststmt.stmt = stmt;
1258 laststmt.len = srclen;
1259 laststmt.stridx = dsi->idx;
1261 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1262 fprintf (dump_file, "not possible.\n");
1265 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1266 If strlen of the second argument is known and length of the third argument
1267 is that plus one, strlen of the first argument is the same after this
1268 call. */
1270 static void
1271 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1273 int idx, didx;
1274 tree src, dst, len, lhs, oldlen, newlen;
1275 gimple stmt = gsi_stmt (*gsi);
1276 strinfo si, dsi, olddsi;
1278 len = gimple_call_arg (stmt, 2);
1279 src = gimple_call_arg (stmt, 1);
1280 dst = gimple_call_arg (stmt, 0);
1281 idx = get_stridx (src);
1282 if (idx == 0)
1283 return;
1285 didx = get_stridx (dst);
1286 olddsi = NULL;
1287 if (didx > 0)
1288 olddsi = get_strinfo (didx);
1289 else if (didx < 0)
1290 return;
1292 if (olddsi != NULL
1293 && host_integerp (len, 1)
1294 && !integer_zerop (len))
1295 adjust_last_stmt (olddsi, stmt, false);
1297 if (idx > 0)
1299 gimple def_stmt;
1301 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1302 si = get_strinfo (idx);
1303 if (si == NULL || si->length == NULL_TREE)
1304 return;
1305 if (TREE_CODE (len) != SSA_NAME)
1306 return;
1307 def_stmt = SSA_NAME_DEF_STMT (len);
1308 if (!is_gimple_assign (def_stmt)
1309 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1310 || gimple_assign_rhs1 (def_stmt) != si->length
1311 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1312 return;
1314 else
1316 si = NULL;
1317 /* Handle memcpy (x, "abcd", 5) or
1318 memcpy (x, "abc\0uvw", 7). */
1319 if (!host_integerp (len, 1)
1320 || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
1321 <= (unsigned HOST_WIDE_INT) ~idx)
1322 return;
1325 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1326 adjust_last_stmt (olddsi, stmt, false);
1328 if (didx == 0)
1330 didx = new_stridx (dst);
1331 if (didx == 0)
1332 return;
1334 if (si != NULL)
1335 newlen = si->length;
1336 else
1337 newlen = build_int_cst (size_type_node, ~idx);
1338 oldlen = NULL_TREE;
1339 if (olddsi != NULL)
1341 dsi = unshare_strinfo (olddsi);
1342 oldlen = olddsi->length;
1343 dsi->length = newlen;
1344 /* Break the chain, so adjust_related_strinfo on later pointers in
1345 the chain won't adjust this one anymore. */
1346 dsi->next = 0;
1347 dsi->stmt = NULL;
1348 dsi->endptr = NULL_TREE;
1350 else
1352 dsi = new_strinfo (dst, didx, newlen);
1353 set_strinfo (didx, dsi);
1354 find_equal_ptrs (dst, didx);
1356 dsi->writable = true;
1357 dsi->dont_invalidate = true;
1358 if (olddsi != NULL)
1360 tree adj = NULL_TREE;
1361 location_t loc = gimple_location (stmt);
1362 if (oldlen == NULL_TREE)
1364 else if (integer_zerop (oldlen))
1365 adj = dsi->length;
1366 else if (TREE_CODE (oldlen) == INTEGER_CST
1367 || TREE_CODE (dsi->length) == INTEGER_CST)
1368 adj = fold_build2_loc (loc, MINUS_EXPR,
1369 TREE_TYPE (dsi->length), dsi->length,
1370 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1371 oldlen));
1372 if (adj != NULL_TREE)
1373 adjust_related_strinfos (loc, dsi, adj);
1374 else
1375 dsi->prev = 0;
1377 /* memcpy src may not overlap dst, so src doesn't need to be
1378 invalidated either. */
1379 if (si != NULL)
1380 si->dont_invalidate = true;
1382 lhs = gimple_call_lhs (stmt);
1383 switch (bcode)
1385 case BUILT_IN_MEMCPY:
1386 case BUILT_IN_MEMCPY_CHK:
1387 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1388 laststmt.stmt = stmt;
1389 laststmt.len = dsi->length;
1390 laststmt.stridx = dsi->idx;
1391 if (lhs)
1392 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
1393 break;
1394 case BUILT_IN_MEMPCPY:
1395 case BUILT_IN_MEMPCPY_CHK:
1396 break;
1397 default:
1398 gcc_unreachable ();
1402 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1403 If strlen of the second argument is known, strlen of the first argument
1404 is increased by the length of the second argument. Furthermore, attempt
1405 to convert it to memcpy/strcpy if the length of the first argument
1406 is known. */
1408 static void
1409 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1411 int idx, didx;
1412 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1413 bool success;
1414 gimple stmt = gsi_stmt (*gsi);
1415 strinfo si, dsi;
1416 location_t loc;
1418 src = gimple_call_arg (stmt, 1);
1419 dst = gimple_call_arg (stmt, 0);
1420 lhs = gimple_call_lhs (stmt);
1422 didx = get_stridx (dst);
1423 if (didx < 0)
1424 return;
1426 dsi = NULL;
1427 if (didx > 0)
1428 dsi = get_strinfo (didx);
1429 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1431 /* strcat (p, q) can be transformed into
1432 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1433 with length endptr - p if we need to compute the length
1434 later on. Don't do this transformation if we don't need
1435 it. */
1436 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1438 if (didx == 0)
1440 didx = new_stridx (dst);
1441 if (didx == 0)
1442 return;
1444 if (dsi == NULL)
1446 dsi = new_strinfo (dst, didx, NULL_TREE);
1447 set_strinfo (didx, dsi);
1448 find_equal_ptrs (dst, didx);
1450 else
1452 dsi = unshare_strinfo (dsi);
1453 dsi->length = NULL_TREE;
1454 dsi->next = 0;
1455 dsi->endptr = NULL_TREE;
1457 dsi->writable = true;
1458 dsi->stmt = stmt;
1459 dsi->dont_invalidate = true;
1461 return;
1464 srclen = NULL_TREE;
1465 si = NULL;
1466 idx = get_stridx (src);
1467 if (idx < 0)
1468 srclen = build_int_cst (size_type_node, ~idx);
1469 else if (idx > 0)
1471 si = get_strinfo (idx);
1472 if (si != NULL)
1473 srclen = get_string_length (si);
1476 loc = gimple_location (stmt);
1477 dstlen = dsi->length;
1478 endptr = dsi->endptr;
1480 dsi = unshare_strinfo (dsi);
1481 dsi->endptr = NULL_TREE;
1482 dsi->stmt = NULL;
1483 dsi->writable = true;
1485 if (srclen != NULL_TREE)
1487 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1488 dsi->length, srclen);
1489 adjust_related_strinfos (loc, dsi, srclen);
1490 dsi->dont_invalidate = true;
1492 else
1494 dsi->length = NULL;
1495 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1496 dsi->dont_invalidate = true;
1499 if (si != NULL)
1500 /* strcat src may not overlap dst, so src doesn't need to be
1501 invalidated either. */
1502 si->dont_invalidate = true;
1504 /* For now. Could remove the lhs from the call and add
1505 lhs = dst; afterwards. */
1506 if (lhs)
1507 return;
1509 fn = NULL_TREE;
1510 objsz = NULL_TREE;
1511 switch (bcode)
1513 case BUILT_IN_STRCAT:
1514 if (srclen != NULL_TREE)
1515 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1516 else
1517 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1518 break;
1519 case BUILT_IN_STRCAT_CHK:
1520 if (srclen != NULL_TREE)
1521 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1522 else
1523 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1524 objsz = gimple_call_arg (stmt, 2);
1525 break;
1526 default:
1527 gcc_unreachable ();
1530 if (fn == NULL_TREE)
1531 return;
1533 len = NULL_TREE;
1534 if (srclen != NULL_TREE)
1536 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1537 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1539 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1540 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1541 build_int_cst (type, 1));
1542 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1543 GSI_SAME_STMT);
1545 if (endptr)
1546 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1547 else
1548 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1549 TREE_TYPE (dst), unshare_expr (dst),
1550 fold_convert_loc (loc, sizetype,
1551 unshare_expr (dstlen)));
1552 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1553 GSI_SAME_STMT);
1554 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1556 fprintf (dump_file, "Optimizing: ");
1557 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1559 if (srclen != NULL_TREE)
1560 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1561 dst, src, len, objsz);
1562 else
1563 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1564 dst, src, objsz);
1565 if (success)
1567 stmt = gsi_stmt (*gsi);
1568 update_stmt (stmt);
1569 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1571 fprintf (dump_file, "into: ");
1572 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1574 /* If srclen == NULL, note that current string length can be
1575 computed by transforming this strcpy into stpcpy. */
1576 if (srclen == NULL_TREE && dsi->dont_invalidate)
1577 dsi->stmt = stmt;
1578 adjust_last_stmt (dsi, stmt, true);
1579 if (srclen != NULL_TREE)
1581 laststmt.stmt = stmt;
1582 laststmt.len = srclen;
1583 laststmt.stridx = dsi->idx;
1586 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1587 fprintf (dump_file, "not possible.\n");
1590 /* Handle a POINTER_PLUS_EXPR statement.
1591 For p = "abcd" + 2; compute associated length, or if
1592 p = q + off is pointing to a '\0' character of a string, call
1593 zero_length_string on it. */
1595 static void
1596 handle_pointer_plus (gimple_stmt_iterator *gsi)
1598 gimple stmt = gsi_stmt (*gsi);
1599 tree lhs = gimple_assign_lhs (stmt), off;
1600 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1601 strinfo si, zsi;
1603 if (idx == 0)
1604 return;
1606 if (idx < 0)
1608 tree off = gimple_assign_rhs2 (stmt);
1609 if (host_integerp (off, 1)
1610 && (unsigned HOST_WIDE_INT) tree_low_cst (off, 1)
1611 <= (unsigned HOST_WIDE_INT) ~idx)
1612 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs),
1613 ~(~idx - (int) tree_low_cst (off, 1)));
1614 return;
1617 si = get_strinfo (idx);
1618 if (si == NULL || si->length == NULL_TREE)
1619 return;
1621 off = gimple_assign_rhs2 (stmt);
1622 zsi = NULL;
1623 if (operand_equal_p (si->length, off, 0))
1624 zsi = zero_length_string (lhs, si);
1625 else if (TREE_CODE (off) == SSA_NAME)
1627 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1628 if (gimple_assign_single_p (def_stmt)
1629 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1630 zsi = zero_length_string (lhs, si);
1632 if (zsi != NULL
1633 && si->endptr != NULL_TREE
1634 && si->endptr != lhs
1635 && TREE_CODE (si->endptr) == SSA_NAME)
1637 enum tree_code rhs_code
1638 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1639 ? SSA_NAME : NOP_EXPR;
1640 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr, NULL_TREE);
1641 gcc_assert (gsi_stmt (*gsi) == stmt);
1642 update_stmt (stmt);
1646 /* Handle a single character store. */
1648 static bool
1649 handle_char_store (gimple_stmt_iterator *gsi)
1651 int idx = -1;
1652 strinfo si = NULL;
1653 gimple stmt = gsi_stmt (*gsi);
1654 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1656 if (TREE_CODE (lhs) == MEM_REF
1657 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1659 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1661 ssaname = TREE_OPERAND (lhs, 0);
1662 idx = get_stridx (ssaname);
1665 else
1666 idx = get_addr_stridx (lhs);
1668 if (idx > 0)
1670 si = get_strinfo (idx);
1671 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1673 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1675 /* When storing '\0', the store can be removed
1676 if we know it has been stored in the current function. */
1677 if (!stmt_could_throw_p (stmt) && si->writable)
1679 unlink_stmt_vdef (stmt);
1680 release_defs (stmt);
1681 gsi_remove (gsi, true);
1682 return false;
1684 else
1686 si->writable = true;
1687 si->dont_invalidate = true;
1690 else
1691 /* Otherwise this statement overwrites the '\0' with
1692 something, if the previous stmt was a memcpy,
1693 its length may be decreased. */
1694 adjust_last_stmt (si, stmt, false);
1696 else if (si != NULL)
1698 si = unshare_strinfo (si);
1699 si->length = build_int_cst (size_type_node, 0);
1700 si->endptr = NULL;
1701 si->prev = 0;
1702 si->next = 0;
1703 si->stmt = NULL;
1704 si->first = 0;
1705 si->writable = true;
1706 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1707 si->endptr = ssaname;
1708 si->dont_invalidate = true;
1711 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1713 if (ssaname)
1715 si = zero_length_string (ssaname, NULL);
1716 if (si != NULL)
1717 si->dont_invalidate = true;
1719 else
1721 int idx = new_addr_stridx (lhs);
1722 if (idx != 0)
1724 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1725 build_int_cst (size_type_node, 0));
1726 set_strinfo (idx, si);
1727 si->dont_invalidate = true;
1730 if (si != NULL)
1731 si->writable = true;
1734 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
1736 /* Allow adjust_last_stmt to remove it if the stored '\0'
1737 is immediately overwritten. */
1738 laststmt.stmt = stmt;
1739 laststmt.len = build_int_cst (size_type_node, 1);
1740 laststmt.stridx = si->idx;
1742 return true;
1745 /* Attempt to optimize a single statement at *GSI using string length
1746 knowledge. */
1748 static bool
1749 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
1751 gimple stmt = gsi_stmt (*gsi);
1753 if (is_gimple_call (stmt))
1755 tree callee = gimple_call_fndecl (stmt);
1756 if (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
1757 switch (DECL_FUNCTION_CODE (callee))
1759 case BUILT_IN_STRLEN:
1760 handle_builtin_strlen (gsi);
1761 break;
1762 case BUILT_IN_STRCHR:
1763 handle_builtin_strchr (gsi);
1764 break;
1765 case BUILT_IN_STRCPY:
1766 case BUILT_IN_STRCPY_CHK:
1767 case BUILT_IN_STPCPY:
1768 case BUILT_IN_STPCPY_CHK:
1769 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
1770 break;
1771 case BUILT_IN_MEMCPY:
1772 case BUILT_IN_MEMCPY_CHK:
1773 case BUILT_IN_MEMPCPY:
1774 case BUILT_IN_MEMPCPY_CHK:
1775 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
1776 break;
1777 case BUILT_IN_STRCAT:
1778 case BUILT_IN_STRCAT_CHK:
1779 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
1780 break;
1781 default:
1782 break;
1785 else if (is_gimple_assign (stmt))
1787 tree lhs = gimple_assign_lhs (stmt);
1789 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
1791 if (gimple_assign_single_p (stmt)
1792 || (gimple_assign_cast_p (stmt)
1793 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
1795 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1796 VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs),
1797 idx);
1799 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1800 handle_pointer_plus (gsi);
1802 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
1804 tree type = TREE_TYPE (lhs);
1805 if (TREE_CODE (type) == ARRAY_TYPE)
1806 type = TREE_TYPE (type);
1807 if (TREE_CODE (type) == INTEGER_TYPE
1808 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
1809 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
1811 if (! handle_char_store (gsi))
1812 return false;
1817 if (gimple_vdef (stmt))
1818 maybe_invalidate (stmt);
1819 return true;
1822 /* Recursively call maybe_invalidate on stmts that might be executed
1823 in between dombb and current bb and that contain a vdef. Stop when
1824 *count stmts are inspected, or if the whole strinfo vector has
1825 been invalidated. */
1827 static void
1828 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
1830 unsigned int i, n = gimple_phi_num_args (phi);
1832 for (i = 0; i < n; i++)
1834 tree vuse = gimple_phi_arg_def (phi, i);
1835 gimple stmt = SSA_NAME_DEF_STMT (vuse);
1836 basic_block bb = gimple_bb (stmt);
1837 if (bb == NULL
1838 || bb == dombb
1839 || !bitmap_set_bit (visited, bb->index)
1840 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1841 continue;
1842 while (1)
1844 if (gimple_code (stmt) == GIMPLE_PHI)
1846 do_invalidate (dombb, stmt, visited, count);
1847 if (*count == 0)
1848 return;
1849 break;
1851 if (--*count == 0)
1852 return;
1853 if (!maybe_invalidate (stmt))
1855 *count = 0;
1856 return;
1858 vuse = gimple_vuse (stmt);
1859 stmt = SSA_NAME_DEF_STMT (vuse);
1860 if (gimple_bb (stmt) != bb)
1862 bb = gimple_bb (stmt);
1863 if (bb == NULL
1864 || bb == dombb
1865 || !bitmap_set_bit (visited, bb->index)
1866 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1867 break;
1873 /* Callback for walk_dominator_tree. Attempt to optimize various
1874 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1876 static void
1877 strlen_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
1878 basic_block bb)
1880 gimple_stmt_iterator gsi;
1881 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
1883 if (dombb == NULL)
1884 stridx_to_strinfo = NULL;
1885 else
1887 stridx_to_strinfo = (VEC(strinfo, heap) *) dombb->aux;
1888 if (stridx_to_strinfo)
1890 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1892 gimple phi = gsi_stmt (gsi);
1893 if (!is_gimple_reg (gimple_phi_result (phi)))
1895 bitmap visited = BITMAP_ALLOC (NULL);
1896 int count_vdef = 100;
1897 do_invalidate (dombb, phi, visited, &count_vdef);
1898 BITMAP_FREE (visited);
1899 break;
1905 /* If all PHI arguments have the same string index, the PHI result
1906 has it as well. */
1907 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1909 gimple phi = gsi_stmt (gsi);
1910 tree result = gimple_phi_result (phi);
1911 if (is_gimple_reg (result) && POINTER_TYPE_P (TREE_TYPE (result)))
1913 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
1914 if (idx != 0)
1916 unsigned int i, n = gimple_phi_num_args (phi);
1917 for (i = 1; i < n; i++)
1918 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
1919 break;
1920 if (i == n)
1921 VEC_replace (int, ssa_ver_to_stridx,
1922 SSA_NAME_VERSION (result), idx);
1927 /* Attempt to optimize individual statements. */
1928 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
1929 if (strlen_optimize_stmt (&gsi))
1930 gsi_next (&gsi);
1932 bb->aux = stridx_to_strinfo;
1933 if (VEC_length (strinfo, stridx_to_strinfo) && !strinfo_shared ())
1934 VEC_replace (strinfo, stridx_to_strinfo, 0, (strinfo) bb);
1937 /* Callback for walk_dominator_tree. Free strinfo vector if it is
1938 owned by the current bb, clear bb->aux. */
1940 static void
1941 strlen_leave_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
1942 basic_block bb)
1944 if (bb->aux)
1946 stridx_to_strinfo = (VEC(strinfo, heap) *) bb->aux;
1947 if (VEC_length (strinfo, stridx_to_strinfo)
1948 && VEC_index (strinfo, stridx_to_strinfo, 0) == (strinfo) bb)
1950 unsigned int i;
1951 strinfo si;
1953 for (i = 1; VEC_iterate (strinfo, stridx_to_strinfo, i, si); ++i)
1954 free_strinfo (si);
1955 VEC_free (strinfo, heap, stridx_to_strinfo);
1957 bb->aux = NULL;
1961 /* Main entry point. */
1963 static unsigned int
1964 tree_ssa_strlen (void)
1966 struct dom_walk_data walk_data;
1968 VEC_safe_grow_cleared (int, heap, ssa_ver_to_stridx, num_ssa_names);
1969 max_stridx = 1;
1970 strinfo_pool = create_alloc_pool ("strinfo_struct pool",
1971 sizeof (struct strinfo_struct), 64);
1973 calculate_dominance_info (CDI_DOMINATORS);
1975 /* String length optimization is implemented as a walk of the dominator
1976 tree and a forward walk of statements within each block. */
1977 walk_data.dom_direction = CDI_DOMINATORS;
1978 walk_data.initialize_block_local_data = NULL;
1979 walk_data.before_dom_children = strlen_enter_block;
1980 walk_data.after_dom_children = strlen_leave_block;
1981 walk_data.block_local_data_size = 0;
1982 walk_data.global_data = NULL;
1984 /* Initialize the dominator walker. */
1985 init_walk_dominator_tree (&walk_data);
1987 /* Recursively walk the dominator tree. */
1988 walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
1990 /* Finalize the dominator walker. */
1991 fini_walk_dominator_tree (&walk_data);
1993 VEC_free (int, heap, ssa_ver_to_stridx);
1994 free_alloc_pool (strinfo_pool);
1995 if (decl_to_stridxlist_htab)
1997 obstack_free (&stridx_obstack, NULL);
1998 htab_delete (decl_to_stridxlist_htab);
1999 decl_to_stridxlist_htab = NULL;
2001 laststmt.stmt = NULL;
2002 laststmt.len = NULL_TREE;
2003 laststmt.stridx = 0;
2005 return 0;
2008 static bool
2009 gate_strlen (void)
2011 return flag_optimize_strlen != 0;
2014 struct gimple_opt_pass pass_strlen =
2017 GIMPLE_PASS,
2018 "strlen", /* name */
2019 gate_strlen, /* gate */
2020 tree_ssa_strlen, /* execute */
2021 NULL, /* sub */
2022 NULL, /* next */
2023 0, /* static_pass_number */
2024 TV_TREE_STRLEN, /* tv_id */
2025 PROP_cfg | PROP_ssa, /* properties_required */
2026 0, /* properties_provided */
2027 0, /* properties_destroyed */
2028 0, /* todo_flags_start */
2029 TODO_ggc_collect
2030 | TODO_verify_ssa /* todo_flags_finish */