2013-10-01 Saurabh Verma <saurabh.verma@codito.com>
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob5df1ddf59bd5ac077a1158822fde1df935d1229c
1 /* String length optimization
2 Copyright (C) 2011-2013 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 "hash-table.h"
25 #include "tree-ssa.h"
26 #include "tree-pass.h"
27 #include "domwalk.h"
28 #include "alloc-pool.h"
29 #include "tree-ssa-propagate.h"
30 #include "gimple-pretty-print.h"
31 #include "params.h"
32 #include "expr.h"
34 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
35 is an index into strinfo vector, negative value stands for
36 string length of a string literal (~strlen). */
37 static vec<int> ssa_ver_to_stridx;
39 /* Number of currently active string indexes plus one. */
40 static int max_stridx;
42 /* String information record. */
43 typedef struct strinfo_struct
45 /* String length of this string. */
46 tree length;
47 /* Any of the corresponding pointers for querying alias oracle. */
48 tree ptr;
49 /* Statement for delayed length computation. */
50 gimple stmt;
51 /* Pointer to '\0' if known, if NULL, it can be computed as
52 ptr + length. */
53 tree endptr;
54 /* Reference count. Any changes to strinfo entry possibly shared
55 with dominating basic blocks need unshare_strinfo first, except
56 for dont_invalidate which affects only the immediately next
57 maybe_invalidate. */
58 int refcount;
59 /* Copy of index. get_strinfo (si->idx) should return si; */
60 int idx;
61 /* These 3 fields are for chaining related string pointers together.
62 E.g. for
63 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
64 strcpy (c, d); e = c + dl;
65 strinfo(a) -> strinfo(c) -> strinfo(e)
66 All have ->first field equal to strinfo(a)->idx and are doubly
67 chained through prev/next fields. The later strinfos are required
68 to point into the same string with zero or more bytes after
69 the previous pointer and all bytes in between the two pointers
70 must be non-zero. Functions like strcpy or memcpy are supposed
71 to adjust all previous strinfo lengths, but not following strinfo
72 lengths (those are uncertain, usually invalidated during
73 maybe_invalidate, except when the alias oracle knows better).
74 Functions like strcat on the other side adjust the whole
75 related strinfo chain.
76 They are updated lazily, so to use the chain the same first fields
77 and si->prev->next == si->idx needs to be verified. */
78 int first;
79 int next;
80 int prev;
81 /* A flag whether the string is known to be written in the current
82 function. */
83 bool writable;
84 /* A flag for the next maybe_invalidate that this strinfo shouldn't
85 be invalidated. Always cleared by maybe_invalidate. */
86 bool dont_invalidate;
87 } *strinfo;
89 /* Pool for allocating strinfo_struct entries. */
90 static alloc_pool strinfo_pool;
92 /* Vector mapping positive string indexes to strinfo, for the
93 current basic block. The first pointer in the vector is special,
94 it is either NULL, meaning the vector isn't shared, or it is
95 a basic block pointer to the owner basic_block if shared.
96 If some other bb wants to modify the vector, the vector needs
97 to be unshared first, and only the owner bb is supposed to free it. */
98 static vec<strinfo, va_heap, vl_embed> *stridx_to_strinfo;
100 /* One OFFSET->IDX mapping. */
101 struct stridxlist
103 struct stridxlist *next;
104 HOST_WIDE_INT offset;
105 int idx;
108 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
109 struct decl_stridxlist_map
111 struct tree_map_base base;
112 struct stridxlist list;
115 /* stridxlist hashtable helpers. */
117 struct stridxlist_hasher : typed_noop_remove <decl_stridxlist_map>
119 typedef decl_stridxlist_map value_type;
120 typedef decl_stridxlist_map compare_type;
121 static inline hashval_t hash (const value_type *);
122 static inline bool equal (const value_type *, const compare_type *);
125 /* Hash a from tree in a decl_stridxlist_map. */
127 inline hashval_t
128 stridxlist_hasher::hash (const value_type *item)
130 return DECL_UID (item->base.from);
133 inline bool
134 stridxlist_hasher::equal (const value_type *v, const compare_type *c)
136 return tree_map_base_eq (&v->base, &c->base);
139 /* Hash table for mapping decls to a chained list of offset -> idx
140 mappings. */
141 static hash_table <stridxlist_hasher> decl_to_stridxlist_htab;
143 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
144 static struct obstack stridx_obstack;
146 /* Last memcpy statement if it could be adjusted if the trailing
147 '\0' written is immediately overwritten, or
148 *x = '\0' store that could be removed if it is immediately overwritten. */
149 struct laststmt_struct
151 gimple stmt;
152 tree len;
153 int stridx;
154 } laststmt;
156 /* Helper function for get_stridx. */
158 static int
159 get_addr_stridx (tree exp)
161 HOST_WIDE_INT off;
162 struct decl_stridxlist_map ent, *e;
163 struct stridxlist *list;
164 tree base;
166 if (!decl_to_stridxlist_htab.is_created ())
167 return 0;
169 base = get_addr_base_and_unit_offset (exp, &off);
170 if (base == NULL || !DECL_P (base))
171 return 0;
173 ent.base.from = base;
174 e = decl_to_stridxlist_htab.find_with_hash (&ent, DECL_UID (base));
175 if (e == NULL)
176 return 0;
178 list = &e->list;
181 if (list->offset == off)
182 return list->idx;
183 list = list->next;
185 while (list);
186 return 0;
189 /* Return string index for EXP. */
191 static int
192 get_stridx (tree exp)
194 tree s, o;
196 if (TREE_CODE (exp) == SSA_NAME)
197 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
199 if (TREE_CODE (exp) == ADDR_EXPR)
201 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
202 if (idx != 0)
203 return idx;
206 s = string_constant (exp, &o);
207 if (s != NULL_TREE
208 && (o == NULL_TREE || host_integerp (o, 0))
209 && TREE_STRING_LENGTH (s) > 0)
211 HOST_WIDE_INT offset = o ? tree_low_cst (o, 0) : 0;
212 const char *p = TREE_STRING_POINTER (s);
213 int max = TREE_STRING_LENGTH (s) - 1;
215 if (p[max] == '\0' && offset >= 0 && offset <= max)
216 return ~(int) strlen (p + offset);
218 return 0;
221 /* Return true if strinfo vector is shared with the immediate dominator. */
223 static inline bool
224 strinfo_shared (void)
226 return vec_safe_length (stridx_to_strinfo)
227 && (*stridx_to_strinfo)[0] != NULL;
230 /* Unshare strinfo vector that is shared with the immediate dominator. */
232 static void
233 unshare_strinfo_vec (void)
235 strinfo si;
236 unsigned int i = 0;
238 gcc_assert (strinfo_shared ());
239 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
240 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
241 if (si != NULL)
242 si->refcount++;
243 (*stridx_to_strinfo)[0] = NULL;
246 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
247 Return a pointer to the location where the string index can
248 be stored (if 0) or is stored, or NULL if this can't be tracked. */
250 static int *
251 addr_stridxptr (tree exp)
253 decl_stridxlist_map **slot;
254 struct decl_stridxlist_map ent;
255 struct stridxlist *list;
256 HOST_WIDE_INT off;
258 tree base = get_addr_base_and_unit_offset (exp, &off);
259 if (base == NULL_TREE || !DECL_P (base))
260 return NULL;
262 if (!decl_to_stridxlist_htab.is_created ())
264 decl_to_stridxlist_htab.create (64);
265 gcc_obstack_init (&stridx_obstack);
267 ent.base.from = base;
268 slot = decl_to_stridxlist_htab.find_slot_with_hash (&ent, DECL_UID (base),
269 INSERT);
270 if (*slot)
272 int i;
273 list = &(*slot)->list;
274 for (i = 0; i < 16; i++)
276 if (list->offset == off)
277 return &list->idx;
278 if (list->next == NULL)
279 break;
281 if (i == 16)
282 return NULL;
283 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
284 list = list->next;
286 else
288 struct decl_stridxlist_map *e
289 = XOBNEW (&stridx_obstack, struct decl_stridxlist_map);
290 e->base.from = base;
291 *slot = e;
292 list = &e->list;
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 default:
487 gcc_unreachable ();
488 break;
492 return si->length;
495 /* Invalidate string length information for strings whose length
496 might change due to stores in stmt. */
498 static bool
499 maybe_invalidate (gimple stmt)
501 strinfo si;
502 unsigned int i;
503 bool nonempty = false;
505 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
506 if (si != NULL)
508 if (!si->dont_invalidate)
510 ao_ref r;
511 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
512 if (stmt_may_clobber_ref_p_1 (stmt, &r))
514 set_strinfo (i, NULL);
515 free_strinfo (si);
516 continue;
519 si->dont_invalidate = false;
520 nonempty = true;
522 return nonempty;
525 /* Unshare strinfo record SI, if it has recount > 1 or
526 if stridx_to_strinfo vector is shared with some other
527 bbs. */
529 static strinfo
530 unshare_strinfo (strinfo si)
532 strinfo nsi;
534 if (si->refcount == 1 && !strinfo_shared ())
535 return si;
537 nsi = new_strinfo (si->ptr, si->idx, si->length);
538 nsi->stmt = si->stmt;
539 nsi->endptr = si->endptr;
540 nsi->first = si->first;
541 nsi->prev = si->prev;
542 nsi->next = si->next;
543 nsi->writable = si->writable;
544 set_strinfo (si->idx, nsi);
545 free_strinfo (si);
546 return nsi;
549 /* Return first strinfo in the related strinfo chain
550 if all strinfos in between belong to the chain, otherwise
551 NULL. */
553 static strinfo
554 verify_related_strinfos (strinfo origsi)
556 strinfo si = origsi, psi;
558 if (origsi->first == 0)
559 return NULL;
560 for (; si->prev; si = psi)
562 if (si->first != origsi->first)
563 return NULL;
564 psi = get_strinfo (si->prev);
565 if (psi == NULL)
566 return NULL;
567 if (psi->next != si->idx)
568 return NULL;
570 if (si->idx != si->first)
571 return NULL;
572 return si;
575 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
576 to a zero-length string and if possible chain it to a related strinfo
577 chain whose part is or might be CHAINSI. */
579 static strinfo
580 zero_length_string (tree ptr, strinfo chainsi)
582 strinfo si;
583 int idx;
584 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
585 && get_stridx (ptr) == 0);
587 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
588 return NULL;
589 if (chainsi != NULL)
591 si = verify_related_strinfos (chainsi);
592 if (si)
594 chainsi = si;
595 for (; chainsi->next; chainsi = si)
597 if (chainsi->endptr == NULL_TREE)
599 chainsi = unshare_strinfo (chainsi);
600 chainsi->endptr = ptr;
602 si = get_strinfo (chainsi->next);
603 if (si == NULL
604 || si->first != chainsi->first
605 || si->prev != chainsi->idx)
606 break;
608 gcc_assert (chainsi->length || chainsi->stmt);
609 if (chainsi->endptr == NULL_TREE)
611 chainsi = unshare_strinfo (chainsi);
612 chainsi->endptr = ptr;
614 if (chainsi->length && integer_zerop (chainsi->length))
616 if (chainsi->next)
618 chainsi = unshare_strinfo (chainsi);
619 chainsi->next = 0;
621 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
622 return chainsi;
625 else if (chainsi->first || chainsi->prev || chainsi->next)
627 chainsi = unshare_strinfo (chainsi);
628 chainsi->first = 0;
629 chainsi->prev = 0;
630 chainsi->next = 0;
633 idx = new_stridx (ptr);
634 if (idx == 0)
635 return NULL;
636 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
637 set_strinfo (idx, si);
638 si->endptr = ptr;
639 if (chainsi != NULL)
641 chainsi = unshare_strinfo (chainsi);
642 if (chainsi->first == 0)
643 chainsi->first = chainsi->idx;
644 chainsi->next = idx;
645 if (chainsi->endptr == NULL_TREE)
646 chainsi->endptr = ptr;
647 si->prev = chainsi->idx;
648 si->first = chainsi->first;
649 si->writable = chainsi->writable;
651 return si;
654 /* For strinfo ORIGSI whose length has been just updated
655 update also related strinfo lengths (add ADJ to each,
656 but don't adjust ORIGSI). */
658 static void
659 adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
661 strinfo si = verify_related_strinfos (origsi);
663 if (si == NULL)
664 return;
666 while (1)
668 strinfo nsi;
670 if (si != origsi)
672 tree tem;
674 si = unshare_strinfo (si);
675 if (si->length)
677 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
678 si->length = fold_build2_loc (loc, PLUS_EXPR,
679 TREE_TYPE (si->length), si->length,
680 tem);
682 else if (si->stmt != NULL)
683 /* Delayed length computation is unaffected. */
685 else
686 gcc_unreachable ();
688 si->endptr = NULL_TREE;
689 si->dont_invalidate = true;
691 if (si->next == 0)
692 return;
693 nsi = get_strinfo (si->next);
694 if (nsi == NULL
695 || nsi->first != si->first
696 || nsi->prev != si->idx)
697 return;
698 si = nsi;
702 /* Find if there are other SSA_NAME pointers equal to PTR
703 for which we don't track their string lengths yet. If so, use
704 IDX for them. */
706 static void
707 find_equal_ptrs (tree ptr, int idx)
709 if (TREE_CODE (ptr) != SSA_NAME)
710 return;
711 while (1)
713 gimple stmt = SSA_NAME_DEF_STMT (ptr);
714 if (!is_gimple_assign (stmt))
715 return;
716 ptr = gimple_assign_rhs1 (stmt);
717 switch (gimple_assign_rhs_code (stmt))
719 case SSA_NAME:
720 break;
721 CASE_CONVERT:
722 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
723 return;
724 if (TREE_CODE (ptr) == SSA_NAME)
725 break;
726 if (TREE_CODE (ptr) != ADDR_EXPR)
727 return;
728 /* FALLTHRU */
729 case ADDR_EXPR:
731 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
732 if (pidx != NULL && *pidx == 0)
733 *pidx = idx;
734 return;
736 default:
737 return;
740 /* We might find an endptr created in this pass. Grow the
741 vector in that case. */
742 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
743 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
745 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
746 return;
747 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
751 /* If the last .MEM setter statement before STMT is
752 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
753 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
754 just memcpy (x, y, strlen (y)). SI must be the zero length
755 strinfo. */
757 static void
758 adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
760 tree vuse, callee, len;
761 struct laststmt_struct last = laststmt;
762 strinfo lastsi, firstsi;
764 laststmt.stmt = NULL;
765 laststmt.len = NULL_TREE;
766 laststmt.stridx = 0;
768 if (last.stmt == NULL)
769 return;
771 vuse = gimple_vuse (stmt);
772 if (vuse == NULL_TREE
773 || SSA_NAME_DEF_STMT (vuse) != last.stmt
774 || !has_single_use (vuse))
775 return;
777 gcc_assert (last.stridx > 0);
778 lastsi = get_strinfo (last.stridx);
779 if (lastsi == NULL)
780 return;
782 if (lastsi != si)
784 if (lastsi->first == 0 || lastsi->first != si->first)
785 return;
787 firstsi = verify_related_strinfos (si);
788 if (firstsi == NULL)
789 return;
790 while (firstsi != lastsi)
792 strinfo nextsi;
793 if (firstsi->next == 0)
794 return;
795 nextsi = get_strinfo (firstsi->next);
796 if (nextsi == NULL
797 || nextsi->prev != firstsi->idx
798 || nextsi->first != si->first)
799 return;
800 firstsi = nextsi;
804 if (!is_strcat)
806 if (si->length == NULL_TREE || !integer_zerop (si->length))
807 return;
810 if (is_gimple_assign (last.stmt))
812 gimple_stmt_iterator gsi;
814 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
815 return;
816 if (stmt_could_throw_p (last.stmt))
817 return;
818 gsi = gsi_for_stmt (last.stmt);
819 unlink_stmt_vdef (last.stmt);
820 release_defs (last.stmt);
821 gsi_remove (&gsi, true);
822 return;
825 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
826 return;
828 callee = gimple_call_fndecl (last.stmt);
829 switch (DECL_FUNCTION_CODE (callee))
831 case BUILT_IN_MEMCPY:
832 case BUILT_IN_MEMCPY_CHK:
833 break;
834 default:
835 return;
838 len = gimple_call_arg (last.stmt, 2);
839 if (host_integerp (len, 1))
841 if (!host_integerp (last.len, 1)
842 || integer_zerop (len)
843 || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
844 != (unsigned HOST_WIDE_INT) tree_low_cst (last.len, 1) + 1)
845 return;
846 /* Don't adjust the length if it is divisible by 4, it is more efficient
847 to store the extra '\0' in that case. */
848 if ((((unsigned HOST_WIDE_INT) tree_low_cst (len, 1)) & 3) == 0)
849 return;
851 else if (TREE_CODE (len) == SSA_NAME)
853 gimple def_stmt = SSA_NAME_DEF_STMT (len);
854 if (!is_gimple_assign (def_stmt)
855 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
856 || gimple_assign_rhs1 (def_stmt) != last.len
857 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
858 return;
860 else
861 return;
863 gimple_call_set_arg (last.stmt, 2, last.len);
864 update_stmt (last.stmt);
867 /* Handle a strlen call. If strlen of the argument is known, replace
868 the strlen call with the known value, otherwise remember that strlen
869 of the argument is stored in the lhs SSA_NAME. */
871 static void
872 handle_builtin_strlen (gimple_stmt_iterator *gsi)
874 int idx;
875 tree src;
876 gimple stmt = gsi_stmt (*gsi);
877 tree lhs = gimple_call_lhs (stmt);
879 if (lhs == NULL_TREE)
880 return;
882 src = gimple_call_arg (stmt, 0);
883 idx = get_stridx (src);
884 if (idx)
886 strinfo si = NULL;
887 tree rhs;
889 if (idx < 0)
890 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
891 else
893 rhs = NULL_TREE;
894 si = get_strinfo (idx);
895 if (si != NULL)
896 rhs = get_string_length (si);
898 if (rhs != NULL_TREE)
900 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
902 fprintf (dump_file, "Optimizing: ");
903 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
905 rhs = unshare_expr (rhs);
906 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
907 rhs = fold_convert_loc (gimple_location (stmt),
908 TREE_TYPE (lhs), rhs);
909 if (!update_call_from_tree (gsi, rhs))
910 gimplify_and_update_call_from_tree (gsi, rhs);
911 stmt = gsi_stmt (*gsi);
912 update_stmt (stmt);
913 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
915 fprintf (dump_file, "into: ");
916 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
918 if (si != NULL
919 && TREE_CODE (si->length) != SSA_NAME
920 && TREE_CODE (si->length) != INTEGER_CST
921 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
923 si = unshare_strinfo (si);
924 si->length = lhs;
926 return;
929 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
930 return;
931 if (idx == 0)
932 idx = new_stridx (src);
933 else if (get_strinfo (idx) != NULL)
934 return;
935 if (idx)
937 strinfo si = new_strinfo (src, idx, lhs);
938 set_strinfo (idx, si);
939 find_equal_ptrs (src, idx);
943 /* Handle a strchr call. If strlen of the first argument is known, replace
944 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
945 that lhs of the call is endptr and strlen of the argument is endptr - x. */
947 static void
948 handle_builtin_strchr (gimple_stmt_iterator *gsi)
950 int idx;
951 tree src;
952 gimple stmt = gsi_stmt (*gsi);
953 tree lhs = gimple_call_lhs (stmt);
955 if (lhs == NULL_TREE)
956 return;
958 if (!integer_zerop (gimple_call_arg (stmt, 1)))
959 return;
961 src = gimple_call_arg (stmt, 0);
962 idx = get_stridx (src);
963 if (idx)
965 strinfo si = NULL;
966 tree rhs;
968 if (idx < 0)
969 rhs = build_int_cst (size_type_node, ~idx);
970 else
972 rhs = NULL_TREE;
973 si = get_strinfo (idx);
974 if (si != NULL)
975 rhs = get_string_length (si);
977 if (rhs != NULL_TREE)
979 location_t loc = gimple_location (stmt);
981 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
983 fprintf (dump_file, "Optimizing: ");
984 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
986 if (si != NULL && si->endptr != NULL_TREE)
988 rhs = unshare_expr (si->endptr);
989 if (!useless_type_conversion_p (TREE_TYPE (lhs),
990 TREE_TYPE (rhs)))
991 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
993 else
995 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
996 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
997 TREE_TYPE (src), src, rhs);
998 if (!useless_type_conversion_p (TREE_TYPE (lhs),
999 TREE_TYPE (rhs)))
1000 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1002 if (!update_call_from_tree (gsi, rhs))
1003 gimplify_and_update_call_from_tree (gsi, rhs);
1004 stmt = gsi_stmt (*gsi);
1005 update_stmt (stmt);
1006 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1008 fprintf (dump_file, "into: ");
1009 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1011 if (si != NULL
1012 && si->endptr == NULL_TREE
1013 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1015 si = unshare_strinfo (si);
1016 si->endptr = lhs;
1018 zero_length_string (lhs, si);
1019 return;
1022 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1023 return;
1024 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1026 if (idx == 0)
1027 idx = new_stridx (src);
1028 else if (get_strinfo (idx) != NULL)
1030 zero_length_string (lhs, NULL);
1031 return;
1033 if (idx)
1035 location_t loc = gimple_location (stmt);
1036 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1037 tree srcu = fold_convert_loc (loc, size_type_node, src);
1038 tree length = fold_build2_loc (loc, MINUS_EXPR,
1039 size_type_node, lhsu, srcu);
1040 strinfo si = new_strinfo (src, idx, length);
1041 si->endptr = lhs;
1042 set_strinfo (idx, si);
1043 find_equal_ptrs (src, idx);
1044 zero_length_string (lhs, si);
1047 else
1048 zero_length_string (lhs, NULL);
1051 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1052 If strlen of the second argument is known, strlen of the first argument
1053 is the same after this call. Furthermore, attempt to convert it to
1054 memcpy. */
1056 static void
1057 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1059 int idx, didx;
1060 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1061 bool success;
1062 gimple stmt = gsi_stmt (*gsi);
1063 strinfo si, dsi, olddsi, zsi;
1064 location_t loc;
1066 src = gimple_call_arg (stmt, 1);
1067 dst = gimple_call_arg (stmt, 0);
1068 lhs = gimple_call_lhs (stmt);
1069 idx = get_stridx (src);
1070 si = NULL;
1071 if (idx > 0)
1072 si = get_strinfo (idx);
1074 didx = get_stridx (dst);
1075 olddsi = NULL;
1076 oldlen = NULL_TREE;
1077 if (didx > 0)
1078 olddsi = get_strinfo (didx);
1079 else if (didx < 0)
1080 return;
1082 if (olddsi != NULL)
1083 adjust_last_stmt (olddsi, stmt, false);
1085 srclen = NULL_TREE;
1086 if (si != NULL)
1087 srclen = get_string_length (si);
1088 else if (idx < 0)
1089 srclen = build_int_cst (size_type_node, ~idx);
1091 loc = gimple_location (stmt);
1092 if (srclen == NULL_TREE)
1093 switch (bcode)
1095 case BUILT_IN_STRCPY:
1096 case BUILT_IN_STRCPY_CHK:
1097 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1098 return;
1099 break;
1100 case BUILT_IN_STPCPY:
1101 case BUILT_IN_STPCPY_CHK:
1102 if (lhs == NULL_TREE)
1103 return;
1104 else
1106 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1107 srclen = fold_convert_loc (loc, size_type_node, dst);
1108 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1109 lhsuint, srclen);
1111 break;
1112 default:
1113 gcc_unreachable ();
1116 if (didx == 0)
1118 didx = new_stridx (dst);
1119 if (didx == 0)
1120 return;
1122 if (olddsi != NULL)
1124 oldlen = olddsi->length;
1125 dsi = unshare_strinfo (olddsi);
1126 dsi->length = srclen;
1127 /* Break the chain, so adjust_related_strinfo on later pointers in
1128 the chain won't adjust this one anymore. */
1129 dsi->next = 0;
1130 dsi->stmt = NULL;
1131 dsi->endptr = NULL_TREE;
1133 else
1135 dsi = new_strinfo (dst, didx, srclen);
1136 set_strinfo (didx, dsi);
1137 find_equal_ptrs (dst, didx);
1139 dsi->writable = true;
1140 dsi->dont_invalidate = true;
1142 if (dsi->length == NULL_TREE)
1144 strinfo chainsi;
1146 /* If string length of src is unknown, use delayed length
1147 computation. If string lenth of dst will be needed, it
1148 can be computed by transforming this strcpy call into
1149 stpcpy and subtracting dst from the return value. */
1151 /* Look for earlier strings whose length could be determined if
1152 this strcpy is turned into an stpcpy. */
1154 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1156 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1158 /* When setting a stmt for delayed length computation
1159 prevent all strinfos through dsi from being
1160 invalidated. */
1161 chainsi = unshare_strinfo (chainsi);
1162 chainsi->stmt = stmt;
1163 chainsi->length = NULL_TREE;
1164 chainsi->endptr = NULL_TREE;
1165 chainsi->dont_invalidate = true;
1168 dsi->stmt = stmt;
1169 return;
1172 if (olddsi != NULL)
1174 tree adj = NULL_TREE;
1175 if (oldlen == NULL_TREE)
1177 else if (integer_zerop (oldlen))
1178 adj = srclen;
1179 else if (TREE_CODE (oldlen) == INTEGER_CST
1180 || TREE_CODE (srclen) == INTEGER_CST)
1181 adj = fold_build2_loc (loc, MINUS_EXPR,
1182 TREE_TYPE (srclen), srclen,
1183 fold_convert_loc (loc, TREE_TYPE (srclen),
1184 oldlen));
1185 if (adj != NULL_TREE)
1186 adjust_related_strinfos (loc, dsi, adj);
1187 else
1188 dsi->prev = 0;
1190 /* strcpy src may not overlap dst, so src doesn't need to be
1191 invalidated either. */
1192 if (si != NULL)
1193 si->dont_invalidate = true;
1195 fn = NULL_TREE;
1196 zsi = NULL;
1197 switch (bcode)
1199 case BUILT_IN_STRCPY:
1200 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1201 if (lhs)
1202 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1203 break;
1204 case BUILT_IN_STRCPY_CHK:
1205 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1206 if (lhs)
1207 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1208 break;
1209 case BUILT_IN_STPCPY:
1210 /* This would need adjustment of the lhs (subtract one),
1211 or detection that the trailing '\0' doesn't need to be
1212 written, if it will be immediately overwritten.
1213 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1214 if (lhs)
1216 dsi->endptr = lhs;
1217 zsi = zero_length_string (lhs, dsi);
1219 break;
1220 case BUILT_IN_STPCPY_CHK:
1221 /* This would need adjustment of the lhs (subtract one),
1222 or detection that the trailing '\0' doesn't need to be
1223 written, if it will be immediately overwritten.
1224 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1225 if (lhs)
1227 dsi->endptr = lhs;
1228 zsi = zero_length_string (lhs, dsi);
1230 break;
1231 default:
1232 gcc_unreachable ();
1234 if (zsi != NULL)
1235 zsi->dont_invalidate = true;
1237 if (fn == NULL_TREE)
1238 return;
1240 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1241 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1243 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1244 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1245 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1246 GSI_SAME_STMT);
1247 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1249 fprintf (dump_file, "Optimizing: ");
1250 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1252 if (gimple_call_num_args (stmt) == 2)
1253 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1254 else
1255 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1256 gimple_call_arg (stmt, 2));
1257 if (success)
1259 stmt = gsi_stmt (*gsi);
1260 update_stmt (stmt);
1261 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1263 fprintf (dump_file, "into: ");
1264 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1266 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1267 laststmt.stmt = stmt;
1268 laststmt.len = srclen;
1269 laststmt.stridx = dsi->idx;
1271 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1272 fprintf (dump_file, "not possible.\n");
1275 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1276 If strlen of the second argument is known and length of the third argument
1277 is that plus one, strlen of the first argument is the same after this
1278 call. */
1280 static void
1281 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1283 int idx, didx;
1284 tree src, dst, len, lhs, oldlen, newlen;
1285 gimple stmt = gsi_stmt (*gsi);
1286 strinfo si, dsi, olddsi;
1288 len = gimple_call_arg (stmt, 2);
1289 src = gimple_call_arg (stmt, 1);
1290 dst = gimple_call_arg (stmt, 0);
1291 idx = get_stridx (src);
1292 if (idx == 0)
1293 return;
1295 didx = get_stridx (dst);
1296 olddsi = NULL;
1297 if (didx > 0)
1298 olddsi = get_strinfo (didx);
1299 else if (didx < 0)
1300 return;
1302 if (olddsi != NULL
1303 && host_integerp (len, 1)
1304 && !integer_zerop (len))
1305 adjust_last_stmt (olddsi, stmt, false);
1307 if (idx > 0)
1309 gimple def_stmt;
1311 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1312 si = get_strinfo (idx);
1313 if (si == NULL || si->length == NULL_TREE)
1314 return;
1315 if (TREE_CODE (len) != SSA_NAME)
1316 return;
1317 def_stmt = SSA_NAME_DEF_STMT (len);
1318 if (!is_gimple_assign (def_stmt)
1319 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1320 || gimple_assign_rhs1 (def_stmt) != si->length
1321 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1322 return;
1324 else
1326 si = NULL;
1327 /* Handle memcpy (x, "abcd", 5) or
1328 memcpy (x, "abc\0uvw", 7). */
1329 if (!host_integerp (len, 1)
1330 || (unsigned HOST_WIDE_INT) tree_low_cst (len, 1)
1331 <= (unsigned HOST_WIDE_INT) ~idx)
1332 return;
1335 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1336 adjust_last_stmt (olddsi, stmt, false);
1338 if (didx == 0)
1340 didx = new_stridx (dst);
1341 if (didx == 0)
1342 return;
1344 if (si != NULL)
1345 newlen = si->length;
1346 else
1347 newlen = build_int_cst (size_type_node, ~idx);
1348 oldlen = NULL_TREE;
1349 if (olddsi != NULL)
1351 dsi = unshare_strinfo (olddsi);
1352 oldlen = olddsi->length;
1353 dsi->length = newlen;
1354 /* Break the chain, so adjust_related_strinfo on later pointers in
1355 the chain won't adjust this one anymore. */
1356 dsi->next = 0;
1357 dsi->stmt = NULL;
1358 dsi->endptr = NULL_TREE;
1360 else
1362 dsi = new_strinfo (dst, didx, newlen);
1363 set_strinfo (didx, dsi);
1364 find_equal_ptrs (dst, didx);
1366 dsi->writable = true;
1367 dsi->dont_invalidate = true;
1368 if (olddsi != NULL)
1370 tree adj = NULL_TREE;
1371 location_t loc = gimple_location (stmt);
1372 if (oldlen == NULL_TREE)
1374 else if (integer_zerop (oldlen))
1375 adj = dsi->length;
1376 else if (TREE_CODE (oldlen) == INTEGER_CST
1377 || TREE_CODE (dsi->length) == INTEGER_CST)
1378 adj = fold_build2_loc (loc, MINUS_EXPR,
1379 TREE_TYPE (dsi->length), dsi->length,
1380 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1381 oldlen));
1382 if (adj != NULL_TREE)
1383 adjust_related_strinfos (loc, dsi, adj);
1384 else
1385 dsi->prev = 0;
1387 /* memcpy src may not overlap dst, so src doesn't need to be
1388 invalidated either. */
1389 if (si != NULL)
1390 si->dont_invalidate = true;
1392 lhs = gimple_call_lhs (stmt);
1393 switch (bcode)
1395 case BUILT_IN_MEMCPY:
1396 case BUILT_IN_MEMCPY_CHK:
1397 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1398 laststmt.stmt = stmt;
1399 laststmt.len = dsi->length;
1400 laststmt.stridx = dsi->idx;
1401 if (lhs)
1402 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1403 break;
1404 case BUILT_IN_MEMPCPY:
1405 case BUILT_IN_MEMPCPY_CHK:
1406 break;
1407 default:
1408 gcc_unreachable ();
1412 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1413 If strlen of the second argument is known, strlen of the first argument
1414 is increased by the length of the second argument. Furthermore, attempt
1415 to convert it to memcpy/strcpy if the length of the first argument
1416 is known. */
1418 static void
1419 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1421 int idx, didx;
1422 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1423 bool success;
1424 gimple stmt = gsi_stmt (*gsi);
1425 strinfo si, dsi;
1426 location_t loc;
1428 src = gimple_call_arg (stmt, 1);
1429 dst = gimple_call_arg (stmt, 0);
1430 lhs = gimple_call_lhs (stmt);
1432 didx = get_stridx (dst);
1433 if (didx < 0)
1434 return;
1436 dsi = NULL;
1437 if (didx > 0)
1438 dsi = get_strinfo (didx);
1439 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1441 /* strcat (p, q) can be transformed into
1442 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1443 with length endptr - p if we need to compute the length
1444 later on. Don't do this transformation if we don't need
1445 it. */
1446 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1448 if (didx == 0)
1450 didx = new_stridx (dst);
1451 if (didx == 0)
1452 return;
1454 if (dsi == NULL)
1456 dsi = new_strinfo (dst, didx, NULL_TREE);
1457 set_strinfo (didx, dsi);
1458 find_equal_ptrs (dst, didx);
1460 else
1462 dsi = unshare_strinfo (dsi);
1463 dsi->length = NULL_TREE;
1464 dsi->next = 0;
1465 dsi->endptr = NULL_TREE;
1467 dsi->writable = true;
1468 dsi->stmt = stmt;
1469 dsi->dont_invalidate = true;
1471 return;
1474 srclen = NULL_TREE;
1475 si = NULL;
1476 idx = get_stridx (src);
1477 if (idx < 0)
1478 srclen = build_int_cst (size_type_node, ~idx);
1479 else if (idx > 0)
1481 si = get_strinfo (idx);
1482 if (si != NULL)
1483 srclen = get_string_length (si);
1486 loc = gimple_location (stmt);
1487 dstlen = dsi->length;
1488 endptr = dsi->endptr;
1490 dsi = unshare_strinfo (dsi);
1491 dsi->endptr = NULL_TREE;
1492 dsi->stmt = NULL;
1493 dsi->writable = true;
1495 if (srclen != NULL_TREE)
1497 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1498 dsi->length, srclen);
1499 adjust_related_strinfos (loc, dsi, srclen);
1500 dsi->dont_invalidate = true;
1502 else
1504 dsi->length = NULL;
1505 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1506 dsi->dont_invalidate = true;
1509 if (si != NULL)
1510 /* strcat src may not overlap dst, so src doesn't need to be
1511 invalidated either. */
1512 si->dont_invalidate = true;
1514 /* For now. Could remove the lhs from the call and add
1515 lhs = dst; afterwards. */
1516 if (lhs)
1517 return;
1519 fn = NULL_TREE;
1520 objsz = NULL_TREE;
1521 switch (bcode)
1523 case BUILT_IN_STRCAT:
1524 if (srclen != NULL_TREE)
1525 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1526 else
1527 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1528 break;
1529 case BUILT_IN_STRCAT_CHK:
1530 if (srclen != NULL_TREE)
1531 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1532 else
1533 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1534 objsz = gimple_call_arg (stmt, 2);
1535 break;
1536 default:
1537 gcc_unreachable ();
1540 if (fn == NULL_TREE)
1541 return;
1543 len = NULL_TREE;
1544 if (srclen != NULL_TREE)
1546 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1547 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1549 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1550 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1551 build_int_cst (type, 1));
1552 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1553 GSI_SAME_STMT);
1555 if (endptr)
1556 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1557 else
1558 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1559 TREE_TYPE (dst), unshare_expr (dst),
1560 fold_convert_loc (loc, sizetype,
1561 unshare_expr (dstlen)));
1562 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1563 GSI_SAME_STMT);
1564 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1566 fprintf (dump_file, "Optimizing: ");
1567 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1569 if (srclen != NULL_TREE)
1570 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1571 dst, src, len, objsz);
1572 else
1573 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1574 dst, src, objsz);
1575 if (success)
1577 stmt = gsi_stmt (*gsi);
1578 update_stmt (stmt);
1579 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1581 fprintf (dump_file, "into: ");
1582 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1584 /* If srclen == NULL, note that current string length can be
1585 computed by transforming this strcpy into stpcpy. */
1586 if (srclen == NULL_TREE && dsi->dont_invalidate)
1587 dsi->stmt = stmt;
1588 adjust_last_stmt (dsi, stmt, true);
1589 if (srclen != NULL_TREE)
1591 laststmt.stmt = stmt;
1592 laststmt.len = srclen;
1593 laststmt.stridx = dsi->idx;
1596 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1597 fprintf (dump_file, "not possible.\n");
1600 /* Handle a POINTER_PLUS_EXPR statement.
1601 For p = "abcd" + 2; compute associated length, or if
1602 p = q + off is pointing to a '\0' character of a string, call
1603 zero_length_string on it. */
1605 static void
1606 handle_pointer_plus (gimple_stmt_iterator *gsi)
1608 gimple stmt = gsi_stmt (*gsi);
1609 tree lhs = gimple_assign_lhs (stmt), off;
1610 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1611 strinfo si, zsi;
1613 if (idx == 0)
1614 return;
1616 if (idx < 0)
1618 tree off = gimple_assign_rhs2 (stmt);
1619 if (host_integerp (off, 1)
1620 && (unsigned HOST_WIDE_INT) tree_low_cst (off, 1)
1621 <= (unsigned HOST_WIDE_INT) ~idx)
1622 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1623 = ~(~idx - (int) tree_low_cst (off, 1));
1624 return;
1627 si = get_strinfo (idx);
1628 if (si == NULL || si->length == NULL_TREE)
1629 return;
1631 off = gimple_assign_rhs2 (stmt);
1632 zsi = NULL;
1633 if (operand_equal_p (si->length, off, 0))
1634 zsi = zero_length_string (lhs, si);
1635 else if (TREE_CODE (off) == SSA_NAME)
1637 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1638 if (gimple_assign_single_p (def_stmt)
1639 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1640 zsi = zero_length_string (lhs, si);
1642 if (zsi != NULL
1643 && si->endptr != NULL_TREE
1644 && si->endptr != lhs
1645 && TREE_CODE (si->endptr) == SSA_NAME)
1647 enum tree_code rhs_code
1648 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1649 ? SSA_NAME : NOP_EXPR;
1650 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr, NULL_TREE);
1651 gcc_assert (gsi_stmt (*gsi) == stmt);
1652 update_stmt (stmt);
1656 /* Handle a single character store. */
1658 static bool
1659 handle_char_store (gimple_stmt_iterator *gsi)
1661 int idx = -1;
1662 strinfo si = NULL;
1663 gimple stmt = gsi_stmt (*gsi);
1664 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1666 if (TREE_CODE (lhs) == MEM_REF
1667 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1669 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1671 ssaname = TREE_OPERAND (lhs, 0);
1672 idx = get_stridx (ssaname);
1675 else
1676 idx = get_addr_stridx (lhs);
1678 if (idx > 0)
1680 si = get_strinfo (idx);
1681 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1683 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1685 /* When storing '\0', the store can be removed
1686 if we know it has been stored in the current function. */
1687 if (!stmt_could_throw_p (stmt) && si->writable)
1689 unlink_stmt_vdef (stmt);
1690 release_defs (stmt);
1691 gsi_remove (gsi, true);
1692 return false;
1694 else
1696 si->writable = true;
1697 gsi_next (gsi);
1698 return false;
1701 else
1702 /* Otherwise this statement overwrites the '\0' with
1703 something, if the previous stmt was a memcpy,
1704 its length may be decreased. */
1705 adjust_last_stmt (si, stmt, false);
1707 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1709 si = unshare_strinfo (si);
1710 si->length = build_int_cst (size_type_node, 0);
1711 si->endptr = NULL;
1712 si->prev = 0;
1713 si->next = 0;
1714 si->stmt = NULL;
1715 si->first = 0;
1716 si->writable = true;
1717 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1718 si->endptr = ssaname;
1719 si->dont_invalidate = true;
1721 /* If si->length is non-zero constant, we aren't overwriting '\0',
1722 and if we aren't storing '\0', we know that the length of the
1723 string and any other zero terminated string in memory remains
1724 the same. In that case we move to the next gimple statement and
1725 return to signal the caller that it shouldn't invalidate anything.
1727 This is benefical for cases like:
1729 char p[20];
1730 void foo (char *q)
1732 strcpy (p, "foobar");
1733 size_t len = strlen (p); // This can be optimized into 6
1734 size_t len2 = strlen (q); // This has to be computed
1735 p[0] = 'X';
1736 size_t len3 = strlen (p); // This can be optimized into 6
1737 size_t len4 = strlen (q); // This can be optimized into len2
1738 bar (len, len2, len3, len4);
1741 else if (si != NULL && si->length != NULL_TREE
1742 && TREE_CODE (si->length) == INTEGER_CST
1743 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
1745 gsi_next (gsi);
1746 return false;
1749 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1751 if (ssaname)
1753 si = zero_length_string (ssaname, NULL);
1754 if (si != NULL)
1755 si->dont_invalidate = true;
1757 else
1759 int idx = new_addr_stridx (lhs);
1760 if (idx != 0)
1762 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1763 build_int_cst (size_type_node, 0));
1764 set_strinfo (idx, si);
1765 si->dont_invalidate = true;
1768 if (si != NULL)
1769 si->writable = true;
1771 else if (idx == 0
1772 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
1773 && ssaname == NULL_TREE
1774 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
1776 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
1777 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
1778 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
1780 int idx = new_addr_stridx (lhs);
1781 if (idx != 0)
1783 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1784 build_int_cst (size_type_node, l));
1785 set_strinfo (idx, si);
1786 si->dont_invalidate = true;
1791 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
1793 /* Allow adjust_last_stmt to remove it if the stored '\0'
1794 is immediately overwritten. */
1795 laststmt.stmt = stmt;
1796 laststmt.len = build_int_cst (size_type_node, 1);
1797 laststmt.stridx = si->idx;
1799 return true;
1802 /* Attempt to optimize a single statement at *GSI using string length
1803 knowledge. */
1805 static bool
1806 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
1808 gimple stmt = gsi_stmt (*gsi);
1810 if (is_gimple_call (stmt))
1812 tree callee = gimple_call_fndecl (stmt);
1813 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
1814 switch (DECL_FUNCTION_CODE (callee))
1816 case BUILT_IN_STRLEN:
1817 handle_builtin_strlen (gsi);
1818 break;
1819 case BUILT_IN_STRCHR:
1820 handle_builtin_strchr (gsi);
1821 break;
1822 case BUILT_IN_STRCPY:
1823 case BUILT_IN_STRCPY_CHK:
1824 case BUILT_IN_STPCPY:
1825 case BUILT_IN_STPCPY_CHK:
1826 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
1827 break;
1828 case BUILT_IN_MEMCPY:
1829 case BUILT_IN_MEMCPY_CHK:
1830 case BUILT_IN_MEMPCPY:
1831 case BUILT_IN_MEMPCPY_CHK:
1832 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
1833 break;
1834 case BUILT_IN_STRCAT:
1835 case BUILT_IN_STRCAT_CHK:
1836 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
1837 break;
1838 default:
1839 break;
1842 else if (is_gimple_assign (stmt))
1844 tree lhs = gimple_assign_lhs (stmt);
1846 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
1848 if (gimple_assign_single_p (stmt)
1849 || (gimple_assign_cast_p (stmt)
1850 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
1852 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1853 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
1855 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1856 handle_pointer_plus (gsi);
1858 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
1860 tree type = TREE_TYPE (lhs);
1861 if (TREE_CODE (type) == ARRAY_TYPE)
1862 type = TREE_TYPE (type);
1863 if (TREE_CODE (type) == INTEGER_TYPE
1864 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
1865 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
1867 if (! handle_char_store (gsi))
1868 return false;
1873 if (gimple_vdef (stmt))
1874 maybe_invalidate (stmt);
1875 return true;
1878 /* Recursively call maybe_invalidate on stmts that might be executed
1879 in between dombb and current bb and that contain a vdef. Stop when
1880 *count stmts are inspected, or if the whole strinfo vector has
1881 been invalidated. */
1883 static void
1884 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
1886 unsigned int i, n = gimple_phi_num_args (phi);
1888 for (i = 0; i < n; i++)
1890 tree vuse = gimple_phi_arg_def (phi, i);
1891 gimple stmt = SSA_NAME_DEF_STMT (vuse);
1892 basic_block bb = gimple_bb (stmt);
1893 if (bb == NULL
1894 || bb == dombb
1895 || !bitmap_set_bit (visited, bb->index)
1896 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1897 continue;
1898 while (1)
1900 if (gimple_code (stmt) == GIMPLE_PHI)
1902 do_invalidate (dombb, stmt, visited, count);
1903 if (*count == 0)
1904 return;
1905 break;
1907 if (--*count == 0)
1908 return;
1909 if (!maybe_invalidate (stmt))
1911 *count = 0;
1912 return;
1914 vuse = gimple_vuse (stmt);
1915 stmt = SSA_NAME_DEF_STMT (vuse);
1916 if (gimple_bb (stmt) != bb)
1918 bb = gimple_bb (stmt);
1919 if (bb == NULL
1920 || bb == dombb
1921 || !bitmap_set_bit (visited, bb->index)
1922 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1923 break;
1929 class strlen_dom_walker : public dom_walker
1931 public:
1932 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
1934 virtual void before_dom_children (basic_block);
1935 virtual void after_dom_children (basic_block);
1938 /* Callback for walk_dominator_tree. Attempt to optimize various
1939 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1941 void
1942 strlen_dom_walker::before_dom_children (basic_block bb)
1944 gimple_stmt_iterator gsi;
1945 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
1947 if (dombb == NULL)
1948 stridx_to_strinfo = NULL;
1949 else
1951 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) dombb->aux);
1952 if (stridx_to_strinfo)
1954 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1956 gimple phi = gsi_stmt (gsi);
1957 if (virtual_operand_p (gimple_phi_result (phi)))
1959 bitmap visited = BITMAP_ALLOC (NULL);
1960 int count_vdef = 100;
1961 do_invalidate (dombb, phi, visited, &count_vdef);
1962 BITMAP_FREE (visited);
1963 if (count_vdef == 0)
1965 /* If there were too many vdefs in between immediate
1966 dominator and current bb, invalidate everything.
1967 If stridx_to_strinfo has been unshared, we need
1968 to free it, otherwise just set it to NULL. */
1969 if (!strinfo_shared ())
1971 unsigned int i;
1972 strinfo si;
1974 for (i = 1;
1975 vec_safe_iterate (stridx_to_strinfo, i, &si);
1976 ++i)
1978 free_strinfo (si);
1979 (*stridx_to_strinfo)[i] = NULL;
1982 else
1983 stridx_to_strinfo = NULL;
1985 break;
1991 /* If all PHI arguments have the same string index, the PHI result
1992 has it as well. */
1993 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1995 gimple phi = gsi_stmt (gsi);
1996 tree result = gimple_phi_result (phi);
1997 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
1999 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2000 if (idx != 0)
2002 unsigned int i, n = gimple_phi_num_args (phi);
2003 for (i = 1; i < n; i++)
2004 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2005 break;
2006 if (i == n)
2007 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2012 /* Attempt to optimize individual statements. */
2013 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2014 if (strlen_optimize_stmt (&gsi))
2015 gsi_next (&gsi);
2017 bb->aux = stridx_to_strinfo;
2018 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2019 (*stridx_to_strinfo)[0] = (strinfo) bb;
2022 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2023 owned by the current bb, clear bb->aux. */
2025 void
2026 strlen_dom_walker::after_dom_children (basic_block bb)
2028 if (bb->aux)
2030 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux);
2031 if (vec_safe_length (stridx_to_strinfo)
2032 && (*stridx_to_strinfo)[0] == (strinfo) bb)
2034 unsigned int i;
2035 strinfo si;
2037 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2038 free_strinfo (si);
2039 vec_free (stridx_to_strinfo);
2041 bb->aux = NULL;
2045 /* Main entry point. */
2047 static unsigned int
2048 tree_ssa_strlen (void)
2050 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2051 max_stridx = 1;
2052 strinfo_pool = create_alloc_pool ("strinfo_struct pool",
2053 sizeof (struct strinfo_struct), 64);
2055 calculate_dominance_info (CDI_DOMINATORS);
2057 /* String length optimization is implemented as a walk of the dominator
2058 tree and a forward walk of statements within each block. */
2059 strlen_dom_walker (CDI_DOMINATORS).walk (cfun->cfg->x_entry_block_ptr);
2061 ssa_ver_to_stridx.release ();
2062 free_alloc_pool (strinfo_pool);
2063 if (decl_to_stridxlist_htab.is_created ())
2065 obstack_free (&stridx_obstack, NULL);
2066 decl_to_stridxlist_htab.dispose ();
2068 laststmt.stmt = NULL;
2069 laststmt.len = NULL_TREE;
2070 laststmt.stridx = 0;
2072 return 0;
2075 static bool
2076 gate_strlen (void)
2078 return flag_optimize_strlen != 0;
2081 namespace {
2083 const pass_data pass_data_strlen =
2085 GIMPLE_PASS, /* type */
2086 "strlen", /* name */
2087 OPTGROUP_NONE, /* optinfo_flags */
2088 true, /* has_gate */
2089 true, /* has_execute */
2090 TV_TREE_STRLEN, /* tv_id */
2091 ( PROP_cfg | PROP_ssa ), /* properties_required */
2092 0, /* properties_provided */
2093 0, /* properties_destroyed */
2094 0, /* todo_flags_start */
2095 TODO_verify_ssa, /* todo_flags_finish */
2098 class pass_strlen : public gimple_opt_pass
2100 public:
2101 pass_strlen (gcc::context *ctxt)
2102 : gimple_opt_pass (pass_data_strlen, ctxt)
2105 /* opt_pass methods: */
2106 bool gate () { return gate_strlen (); }
2107 unsigned int execute () { return tree_ssa_strlen (); }
2109 }; // class pass_strlen
2111 } // anon namespace
2113 gimple_opt_pass *
2114 make_pass_strlen (gcc::context *ctxt)
2116 return new pass_strlen (ctxt);