* testsuite/17_intro/static.cc: Ignore AIX TOC reload warnings.
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob514b1b829e26c152f8bddef5737897167eeb5d73
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 "tree.h"
25 #include "stor-layout.h"
26 #include "hash-table.h"
27 #include "bitmap.h"
28 #include "gimple.h"
29 #include "gimplify.h"
30 #include "gimple-iterator.h"
31 #include "gimplify-me.h"
32 #include "gimple-ssa.h"
33 #include "tree-phinodes.h"
34 #include "ssa-iterators.h"
35 #include "stringpool.h"
36 #include "tree-ssanames.h"
37 #include "expr.h"
38 #include "tree-dfa.h"
39 #include "tree-pass.h"
40 #include "domwalk.h"
41 #include "alloc-pool.h"
42 #include "tree-ssa-propagate.h"
43 #include "gimple-pretty-print.h"
44 #include "params.h"
45 #include "expr.h"
47 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
48 is an index into strinfo vector, negative value stands for
49 string length of a string literal (~strlen). */
50 static vec<int> ssa_ver_to_stridx;
52 /* Number of currently active string indexes plus one. */
53 static int max_stridx;
55 /* String information record. */
56 typedef struct strinfo_struct
58 /* String length of this string. */
59 tree length;
60 /* Any of the corresponding pointers for querying alias oracle. */
61 tree ptr;
62 /* Statement for delayed length computation. */
63 gimple stmt;
64 /* Pointer to '\0' if known, if NULL, it can be computed as
65 ptr + length. */
66 tree endptr;
67 /* Reference count. Any changes to strinfo entry possibly shared
68 with dominating basic blocks need unshare_strinfo first, except
69 for dont_invalidate which affects only the immediately next
70 maybe_invalidate. */
71 int refcount;
72 /* Copy of index. get_strinfo (si->idx) should return si; */
73 int idx;
74 /* These 3 fields are for chaining related string pointers together.
75 E.g. for
76 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
77 strcpy (c, d); e = c + dl;
78 strinfo(a) -> strinfo(c) -> strinfo(e)
79 All have ->first field equal to strinfo(a)->idx and are doubly
80 chained through prev/next fields. The later strinfos are required
81 to point into the same string with zero or more bytes after
82 the previous pointer and all bytes in between the two pointers
83 must be non-zero. Functions like strcpy or memcpy are supposed
84 to adjust all previous strinfo lengths, but not following strinfo
85 lengths (those are uncertain, usually invalidated during
86 maybe_invalidate, except when the alias oracle knows better).
87 Functions like strcat on the other side adjust the whole
88 related strinfo chain.
89 They are updated lazily, so to use the chain the same first fields
90 and si->prev->next == si->idx needs to be verified. */
91 int first;
92 int next;
93 int prev;
94 /* A flag whether the string is known to be written in the current
95 function. */
96 bool writable;
97 /* A flag for the next maybe_invalidate that this strinfo shouldn't
98 be invalidated. Always cleared by maybe_invalidate. */
99 bool dont_invalidate;
100 } *strinfo;
102 /* Pool for allocating strinfo_struct entries. */
103 static alloc_pool strinfo_pool;
105 /* Vector mapping positive string indexes to strinfo, for the
106 current basic block. The first pointer in the vector is special,
107 it is either NULL, meaning the vector isn't shared, or it is
108 a basic block pointer to the owner basic_block if shared.
109 If some other bb wants to modify the vector, the vector needs
110 to be unshared first, and only the owner bb is supposed to free it. */
111 static vec<strinfo, va_heap, vl_embed> *stridx_to_strinfo;
113 /* One OFFSET->IDX mapping. */
114 struct stridxlist
116 struct stridxlist *next;
117 HOST_WIDE_INT offset;
118 int idx;
121 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
122 struct decl_stridxlist_map
124 struct tree_map_base base;
125 struct stridxlist list;
128 /* stridxlist hashtable helpers. */
130 struct stridxlist_hasher : typed_noop_remove <decl_stridxlist_map>
132 typedef decl_stridxlist_map value_type;
133 typedef decl_stridxlist_map compare_type;
134 static inline hashval_t hash (const value_type *);
135 static inline bool equal (const value_type *, const compare_type *);
138 /* Hash a from tree in a decl_stridxlist_map. */
140 inline hashval_t
141 stridxlist_hasher::hash (const value_type *item)
143 return DECL_UID (item->base.from);
146 inline bool
147 stridxlist_hasher::equal (const value_type *v, const compare_type *c)
149 return tree_map_base_eq (&v->base, &c->base);
152 /* Hash table for mapping decls to a chained list of offset -> idx
153 mappings. */
154 static hash_table <stridxlist_hasher> decl_to_stridxlist_htab;
156 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
157 static struct obstack stridx_obstack;
159 /* Last memcpy statement if it could be adjusted if the trailing
160 '\0' written is immediately overwritten, or
161 *x = '\0' store that could be removed if it is immediately overwritten. */
162 struct laststmt_struct
164 gimple stmt;
165 tree len;
166 int stridx;
167 } laststmt;
169 /* Helper function for get_stridx. */
171 static int
172 get_addr_stridx (tree exp)
174 HOST_WIDE_INT off;
175 struct decl_stridxlist_map ent, *e;
176 struct stridxlist *list;
177 tree base;
179 if (!decl_to_stridxlist_htab.is_created ())
180 return 0;
182 base = get_addr_base_and_unit_offset (exp, &off);
183 if (base == NULL || !DECL_P (base))
184 return 0;
186 ent.base.from = base;
187 e = decl_to_stridxlist_htab.find_with_hash (&ent, DECL_UID (base));
188 if (e == NULL)
189 return 0;
191 list = &e->list;
194 if (list->offset == off)
195 return list->idx;
196 list = list->next;
198 while (list);
199 return 0;
202 /* Return string index for EXP. */
204 static int
205 get_stridx (tree exp)
207 tree s, o;
209 if (TREE_CODE (exp) == SSA_NAME)
210 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
212 if (TREE_CODE (exp) == ADDR_EXPR)
214 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
215 if (idx != 0)
216 return idx;
219 s = string_constant (exp, &o);
220 if (s != NULL_TREE
221 && (o == NULL_TREE || tree_fits_shwi_p (o))
222 && TREE_STRING_LENGTH (s) > 0)
224 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
225 const char *p = TREE_STRING_POINTER (s);
226 int max = TREE_STRING_LENGTH (s) - 1;
228 if (p[max] == '\0' && offset >= 0 && offset <= max)
229 return ~(int) strlen (p + offset);
231 return 0;
234 /* Return true if strinfo vector is shared with the immediate dominator. */
236 static inline bool
237 strinfo_shared (void)
239 return vec_safe_length (stridx_to_strinfo)
240 && (*stridx_to_strinfo)[0] != NULL;
243 /* Unshare strinfo vector that is shared with the immediate dominator. */
245 static void
246 unshare_strinfo_vec (void)
248 strinfo si;
249 unsigned int i = 0;
251 gcc_assert (strinfo_shared ());
252 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
253 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
254 if (si != NULL)
255 si->refcount++;
256 (*stridx_to_strinfo)[0] = NULL;
259 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
260 Return a pointer to the location where the string index can
261 be stored (if 0) or is stored, or NULL if this can't be tracked. */
263 static int *
264 addr_stridxptr (tree exp)
266 decl_stridxlist_map **slot;
267 struct decl_stridxlist_map ent;
268 struct stridxlist *list;
269 HOST_WIDE_INT off;
271 tree base = get_addr_base_and_unit_offset (exp, &off);
272 if (base == NULL_TREE || !DECL_P (base))
273 return NULL;
275 if (!decl_to_stridxlist_htab.is_created ())
277 decl_to_stridxlist_htab.create (64);
278 gcc_obstack_init (&stridx_obstack);
280 ent.base.from = base;
281 slot = decl_to_stridxlist_htab.find_slot_with_hash (&ent, DECL_UID (base),
282 INSERT);
283 if (*slot)
285 int i;
286 list = &(*slot)->list;
287 for (i = 0; i < 16; i++)
289 if (list->offset == off)
290 return &list->idx;
291 if (list->next == NULL)
292 break;
294 if (i == 16)
295 return NULL;
296 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
297 list = list->next;
299 else
301 struct decl_stridxlist_map *e
302 = XOBNEW (&stridx_obstack, struct decl_stridxlist_map);
303 e->base.from = base;
304 *slot = e;
305 list = &e->list;
307 list->next = NULL;
308 list->offset = off;
309 list->idx = 0;
310 return &list->idx;
313 /* Create a new string index, or return 0 if reached limit. */
315 static int
316 new_stridx (tree exp)
318 int idx;
319 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
320 return 0;
321 if (TREE_CODE (exp) == SSA_NAME)
323 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
324 return 0;
325 idx = max_stridx++;
326 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
327 return idx;
329 if (TREE_CODE (exp) == ADDR_EXPR)
331 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
332 if (pidx != NULL)
334 gcc_assert (*pidx == 0);
335 *pidx = max_stridx++;
336 return *pidx;
339 return 0;
342 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
344 static int
345 new_addr_stridx (tree exp)
347 int *pidx;
348 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
349 return 0;
350 pidx = addr_stridxptr (exp);
351 if (pidx != NULL)
353 gcc_assert (*pidx == 0);
354 *pidx = max_stridx++;
355 return *pidx;
357 return 0;
360 /* Create a new strinfo. */
362 static strinfo
363 new_strinfo (tree ptr, int idx, tree length)
365 strinfo si = (strinfo) pool_alloc (strinfo_pool);
366 si->length = length;
367 si->ptr = ptr;
368 si->stmt = NULL;
369 si->endptr = NULL_TREE;
370 si->refcount = 1;
371 si->idx = idx;
372 si->first = 0;
373 si->prev = 0;
374 si->next = 0;
375 si->writable = false;
376 si->dont_invalidate = false;
377 return si;
380 /* Decrease strinfo refcount and free it if not referenced anymore. */
382 static inline void
383 free_strinfo (strinfo si)
385 if (si && --si->refcount == 0)
386 pool_free (strinfo_pool, si);
389 /* Return strinfo vector entry IDX. */
391 static inline strinfo
392 get_strinfo (int idx)
394 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
395 return NULL;
396 return (*stridx_to_strinfo)[idx];
399 /* Set strinfo in the vector entry IDX to SI. */
401 static inline void
402 set_strinfo (int idx, strinfo si)
404 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
405 unshare_strinfo_vec ();
406 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
407 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
408 (*stridx_to_strinfo)[idx] = si;
411 /* Return string length, or NULL if it can't be computed. */
413 static tree
414 get_string_length (strinfo si)
416 if (si->length)
417 return si->length;
419 if (si->stmt)
421 gimple stmt = si->stmt, lenstmt;
422 tree callee, lhs, fn, tem;
423 location_t loc;
424 gimple_stmt_iterator gsi;
426 gcc_assert (is_gimple_call (stmt));
427 callee = gimple_call_fndecl (stmt);
428 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
429 lhs = gimple_call_lhs (stmt);
430 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
431 /* unshare_strinfo is intentionally not called here. The (delayed)
432 transformation of strcpy or strcat into stpcpy is done at the place
433 of the former strcpy/strcat call and so can affect all the strinfos
434 with the same stmt. If they were unshared before and transformation
435 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
436 just compute the right length. */
437 switch (DECL_FUNCTION_CODE (callee))
439 case BUILT_IN_STRCAT:
440 case BUILT_IN_STRCAT_CHK:
441 gsi = gsi_for_stmt (stmt);
442 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
443 gcc_assert (lhs == NULL_TREE);
444 tem = unshare_expr (gimple_call_arg (stmt, 0));
445 lenstmt = gimple_build_call (fn, 1, tem);
446 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
447 gimple_call_set_lhs (lenstmt, lhs);
448 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
449 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
450 tem = gimple_call_arg (stmt, 0);
451 if (!ptrofftype_p (TREE_TYPE (lhs)))
453 lhs = convert_to_ptrofftype (lhs);
454 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
455 true, GSI_SAME_STMT);
457 lenstmt
458 = gimple_build_assign_with_ops
459 (POINTER_PLUS_EXPR,
460 make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0)), NULL),
461 tem, lhs);
462 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
463 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
464 lhs = NULL_TREE;
465 /* FALLTHRU */
466 case BUILT_IN_STRCPY:
467 case BUILT_IN_STRCPY_CHK:
468 if (gimple_call_num_args (stmt) == 2)
469 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
470 else
471 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
472 gcc_assert (lhs == NULL_TREE);
473 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
475 fprintf (dump_file, "Optimizing: ");
476 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
478 gimple_call_set_fndecl (stmt, fn);
479 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
480 gimple_call_set_lhs (stmt, lhs);
481 update_stmt (stmt);
482 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
484 fprintf (dump_file, "into: ");
485 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
487 /* FALLTHRU */
488 case BUILT_IN_STPCPY:
489 case BUILT_IN_STPCPY_CHK:
490 gcc_assert (lhs != NULL_TREE);
491 loc = gimple_location (stmt);
492 si->endptr = lhs;
493 si->stmt = NULL;
494 lhs = fold_convert_loc (loc, size_type_node, lhs);
495 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
496 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
497 lhs, si->length);
498 break;
499 default:
500 gcc_unreachable ();
501 break;
505 return si->length;
508 /* Invalidate string length information for strings whose length
509 might change due to stores in stmt. */
511 static bool
512 maybe_invalidate (gimple stmt)
514 strinfo si;
515 unsigned int i;
516 bool nonempty = false;
518 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
519 if (si != NULL)
521 if (!si->dont_invalidate)
523 ao_ref r;
524 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
525 if (stmt_may_clobber_ref_p_1 (stmt, &r))
527 set_strinfo (i, NULL);
528 free_strinfo (si);
529 continue;
532 si->dont_invalidate = false;
533 nonempty = true;
535 return nonempty;
538 /* Unshare strinfo record SI, if it has recount > 1 or
539 if stridx_to_strinfo vector is shared with some other
540 bbs. */
542 static strinfo
543 unshare_strinfo (strinfo si)
545 strinfo nsi;
547 if (si->refcount == 1 && !strinfo_shared ())
548 return si;
550 nsi = new_strinfo (si->ptr, si->idx, si->length);
551 nsi->stmt = si->stmt;
552 nsi->endptr = si->endptr;
553 nsi->first = si->first;
554 nsi->prev = si->prev;
555 nsi->next = si->next;
556 nsi->writable = si->writable;
557 set_strinfo (si->idx, nsi);
558 free_strinfo (si);
559 return nsi;
562 /* Return first strinfo in the related strinfo chain
563 if all strinfos in between belong to the chain, otherwise
564 NULL. */
566 static strinfo
567 verify_related_strinfos (strinfo origsi)
569 strinfo si = origsi, psi;
571 if (origsi->first == 0)
572 return NULL;
573 for (; si->prev; si = psi)
575 if (si->first != origsi->first)
576 return NULL;
577 psi = get_strinfo (si->prev);
578 if (psi == NULL)
579 return NULL;
580 if (psi->next != si->idx)
581 return NULL;
583 if (si->idx != si->first)
584 return NULL;
585 return si;
588 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
589 to a zero-length string and if possible chain it to a related strinfo
590 chain whose part is or might be CHAINSI. */
592 static strinfo
593 zero_length_string (tree ptr, strinfo chainsi)
595 strinfo si;
596 int idx;
597 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
598 && get_stridx (ptr) == 0);
600 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
601 return NULL;
602 if (chainsi != NULL)
604 si = verify_related_strinfos (chainsi);
605 if (si)
607 chainsi = si;
608 for (; chainsi->next; chainsi = si)
610 if (chainsi->endptr == NULL_TREE)
612 chainsi = unshare_strinfo (chainsi);
613 chainsi->endptr = ptr;
615 si = get_strinfo (chainsi->next);
616 if (si == NULL
617 || si->first != chainsi->first
618 || si->prev != chainsi->idx)
619 break;
621 gcc_assert (chainsi->length || chainsi->stmt);
622 if (chainsi->endptr == NULL_TREE)
624 chainsi = unshare_strinfo (chainsi);
625 chainsi->endptr = ptr;
627 if (chainsi->length && integer_zerop (chainsi->length))
629 if (chainsi->next)
631 chainsi = unshare_strinfo (chainsi);
632 chainsi->next = 0;
634 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
635 return chainsi;
638 else if (chainsi->first || chainsi->prev || chainsi->next)
640 chainsi = unshare_strinfo (chainsi);
641 chainsi->first = 0;
642 chainsi->prev = 0;
643 chainsi->next = 0;
646 idx = new_stridx (ptr);
647 if (idx == 0)
648 return NULL;
649 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
650 set_strinfo (idx, si);
651 si->endptr = ptr;
652 if (chainsi != NULL)
654 chainsi = unshare_strinfo (chainsi);
655 if (chainsi->first == 0)
656 chainsi->first = chainsi->idx;
657 chainsi->next = idx;
658 if (chainsi->endptr == NULL_TREE)
659 chainsi->endptr = ptr;
660 si->prev = chainsi->idx;
661 si->first = chainsi->first;
662 si->writable = chainsi->writable;
664 return si;
667 /* For strinfo ORIGSI whose length has been just updated
668 update also related strinfo lengths (add ADJ to each,
669 but don't adjust ORIGSI). */
671 static void
672 adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
674 strinfo si = verify_related_strinfos (origsi);
676 if (si == NULL)
677 return;
679 while (1)
681 strinfo nsi;
683 if (si != origsi)
685 tree tem;
687 si = unshare_strinfo (si);
688 if (si->length)
690 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
691 si->length = fold_build2_loc (loc, PLUS_EXPR,
692 TREE_TYPE (si->length), si->length,
693 tem);
695 else if (si->stmt != NULL)
696 /* Delayed length computation is unaffected. */
698 else
699 gcc_unreachable ();
701 si->endptr = NULL_TREE;
702 si->dont_invalidate = true;
704 if (si->next == 0)
705 return;
706 nsi = get_strinfo (si->next);
707 if (nsi == NULL
708 || nsi->first != si->first
709 || nsi->prev != si->idx)
710 return;
711 si = nsi;
715 /* Find if there are other SSA_NAME pointers equal to PTR
716 for which we don't track their string lengths yet. If so, use
717 IDX for them. */
719 static void
720 find_equal_ptrs (tree ptr, int idx)
722 if (TREE_CODE (ptr) != SSA_NAME)
723 return;
724 while (1)
726 gimple stmt = SSA_NAME_DEF_STMT (ptr);
727 if (!is_gimple_assign (stmt))
728 return;
729 ptr = gimple_assign_rhs1 (stmt);
730 switch (gimple_assign_rhs_code (stmt))
732 case SSA_NAME:
733 break;
734 CASE_CONVERT:
735 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
736 return;
737 if (TREE_CODE (ptr) == SSA_NAME)
738 break;
739 if (TREE_CODE (ptr) != ADDR_EXPR)
740 return;
741 /* FALLTHRU */
742 case ADDR_EXPR:
744 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
745 if (pidx != NULL && *pidx == 0)
746 *pidx = idx;
747 return;
749 default:
750 return;
753 /* We might find an endptr created in this pass. Grow the
754 vector in that case. */
755 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
756 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
758 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
759 return;
760 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
764 /* If the last .MEM setter statement before STMT is
765 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
766 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
767 just memcpy (x, y, strlen (y)). SI must be the zero length
768 strinfo. */
770 static void
771 adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
773 tree vuse, callee, len;
774 struct laststmt_struct last = laststmt;
775 strinfo lastsi, firstsi;
777 laststmt.stmt = NULL;
778 laststmt.len = NULL_TREE;
779 laststmt.stridx = 0;
781 if (last.stmt == NULL)
782 return;
784 vuse = gimple_vuse (stmt);
785 if (vuse == NULL_TREE
786 || SSA_NAME_DEF_STMT (vuse) != last.stmt
787 || !has_single_use (vuse))
788 return;
790 gcc_assert (last.stridx > 0);
791 lastsi = get_strinfo (last.stridx);
792 if (lastsi == NULL)
793 return;
795 if (lastsi != si)
797 if (lastsi->first == 0 || lastsi->first != si->first)
798 return;
800 firstsi = verify_related_strinfos (si);
801 if (firstsi == NULL)
802 return;
803 while (firstsi != lastsi)
805 strinfo nextsi;
806 if (firstsi->next == 0)
807 return;
808 nextsi = get_strinfo (firstsi->next);
809 if (nextsi == NULL
810 || nextsi->prev != firstsi->idx
811 || nextsi->first != si->first)
812 return;
813 firstsi = nextsi;
817 if (!is_strcat)
819 if (si->length == NULL_TREE || !integer_zerop (si->length))
820 return;
823 if (is_gimple_assign (last.stmt))
825 gimple_stmt_iterator gsi;
827 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
828 return;
829 if (stmt_could_throw_p (last.stmt))
830 return;
831 gsi = gsi_for_stmt (last.stmt);
832 unlink_stmt_vdef (last.stmt);
833 release_defs (last.stmt);
834 gsi_remove (&gsi, true);
835 return;
838 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
839 return;
841 callee = gimple_call_fndecl (last.stmt);
842 switch (DECL_FUNCTION_CODE (callee))
844 case BUILT_IN_MEMCPY:
845 case BUILT_IN_MEMCPY_CHK:
846 break;
847 default:
848 return;
851 len = gimple_call_arg (last.stmt, 2);
852 if (tree_fits_uhwi_p (len))
854 if (!tree_fits_uhwi_p (last.len)
855 || integer_zerop (len)
856 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
857 return;
858 /* Don't adjust the length if it is divisible by 4, it is more efficient
859 to store the extra '\0' in that case. */
860 if ((tree_to_uhwi (len) & 3) == 0)
861 return;
863 else if (TREE_CODE (len) == SSA_NAME)
865 gimple def_stmt = SSA_NAME_DEF_STMT (len);
866 if (!is_gimple_assign (def_stmt)
867 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
868 || gimple_assign_rhs1 (def_stmt) != last.len
869 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
870 return;
872 else
873 return;
875 gimple_call_set_arg (last.stmt, 2, last.len);
876 update_stmt (last.stmt);
879 /* Handle a strlen call. If strlen of the argument is known, replace
880 the strlen call with the known value, otherwise remember that strlen
881 of the argument is stored in the lhs SSA_NAME. */
883 static void
884 handle_builtin_strlen (gimple_stmt_iterator *gsi)
886 int idx;
887 tree src;
888 gimple stmt = gsi_stmt (*gsi);
889 tree lhs = gimple_call_lhs (stmt);
891 if (lhs == NULL_TREE)
892 return;
894 src = gimple_call_arg (stmt, 0);
895 idx = get_stridx (src);
896 if (idx)
898 strinfo si = NULL;
899 tree rhs;
901 if (idx < 0)
902 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
903 else
905 rhs = NULL_TREE;
906 si = get_strinfo (idx);
907 if (si != NULL)
908 rhs = get_string_length (si);
910 if (rhs != NULL_TREE)
912 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
914 fprintf (dump_file, "Optimizing: ");
915 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
917 rhs = unshare_expr (rhs);
918 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
919 rhs = fold_convert_loc (gimple_location (stmt),
920 TREE_TYPE (lhs), rhs);
921 if (!update_call_from_tree (gsi, rhs))
922 gimplify_and_update_call_from_tree (gsi, rhs);
923 stmt = gsi_stmt (*gsi);
924 update_stmt (stmt);
925 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
927 fprintf (dump_file, "into: ");
928 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
930 if (si != NULL
931 && TREE_CODE (si->length) != SSA_NAME
932 && TREE_CODE (si->length) != INTEGER_CST
933 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
935 si = unshare_strinfo (si);
936 si->length = lhs;
938 return;
941 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
942 return;
943 if (idx == 0)
944 idx = new_stridx (src);
945 else if (get_strinfo (idx) != NULL)
946 return;
947 if (idx)
949 strinfo si = new_strinfo (src, idx, lhs);
950 set_strinfo (idx, si);
951 find_equal_ptrs (src, idx);
955 /* Handle a strchr call. If strlen of the first argument is known, replace
956 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
957 that lhs of the call is endptr and strlen of the argument is endptr - x. */
959 static void
960 handle_builtin_strchr (gimple_stmt_iterator *gsi)
962 int idx;
963 tree src;
964 gimple stmt = gsi_stmt (*gsi);
965 tree lhs = gimple_call_lhs (stmt);
967 if (lhs == NULL_TREE)
968 return;
970 if (!integer_zerop (gimple_call_arg (stmt, 1)))
971 return;
973 src = gimple_call_arg (stmt, 0);
974 idx = get_stridx (src);
975 if (idx)
977 strinfo si = NULL;
978 tree rhs;
980 if (idx < 0)
981 rhs = build_int_cst (size_type_node, ~idx);
982 else
984 rhs = NULL_TREE;
985 si = get_strinfo (idx);
986 if (si != NULL)
987 rhs = get_string_length (si);
989 if (rhs != NULL_TREE)
991 location_t loc = gimple_location (stmt);
993 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
995 fprintf (dump_file, "Optimizing: ");
996 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
998 if (si != NULL && si->endptr != NULL_TREE)
1000 rhs = unshare_expr (si->endptr);
1001 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1002 TREE_TYPE (rhs)))
1003 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1005 else
1007 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1008 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1009 TREE_TYPE (src), src, rhs);
1010 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1011 TREE_TYPE (rhs)))
1012 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1014 if (!update_call_from_tree (gsi, rhs))
1015 gimplify_and_update_call_from_tree (gsi, rhs);
1016 stmt = gsi_stmt (*gsi);
1017 update_stmt (stmt);
1018 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1020 fprintf (dump_file, "into: ");
1021 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1023 if (si != NULL
1024 && si->endptr == NULL_TREE
1025 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1027 si = unshare_strinfo (si);
1028 si->endptr = lhs;
1030 zero_length_string (lhs, si);
1031 return;
1034 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1035 return;
1036 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1038 if (idx == 0)
1039 idx = new_stridx (src);
1040 else if (get_strinfo (idx) != NULL)
1042 zero_length_string (lhs, NULL);
1043 return;
1045 if (idx)
1047 location_t loc = gimple_location (stmt);
1048 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1049 tree srcu = fold_convert_loc (loc, size_type_node, src);
1050 tree length = fold_build2_loc (loc, MINUS_EXPR,
1051 size_type_node, lhsu, srcu);
1052 strinfo si = new_strinfo (src, idx, length);
1053 si->endptr = lhs;
1054 set_strinfo (idx, si);
1055 find_equal_ptrs (src, idx);
1056 zero_length_string (lhs, si);
1059 else
1060 zero_length_string (lhs, NULL);
1063 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1064 If strlen of the second argument is known, strlen of the first argument
1065 is the same after this call. Furthermore, attempt to convert it to
1066 memcpy. */
1068 static void
1069 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1071 int idx, didx;
1072 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1073 bool success;
1074 gimple stmt = gsi_stmt (*gsi);
1075 strinfo si, dsi, olddsi, zsi;
1076 location_t loc;
1078 src = gimple_call_arg (stmt, 1);
1079 dst = gimple_call_arg (stmt, 0);
1080 lhs = gimple_call_lhs (stmt);
1081 idx = get_stridx (src);
1082 si = NULL;
1083 if (idx > 0)
1084 si = get_strinfo (idx);
1086 didx = get_stridx (dst);
1087 olddsi = NULL;
1088 oldlen = NULL_TREE;
1089 if (didx > 0)
1090 olddsi = get_strinfo (didx);
1091 else if (didx < 0)
1092 return;
1094 if (olddsi != NULL)
1095 adjust_last_stmt (olddsi, stmt, false);
1097 srclen = NULL_TREE;
1098 if (si != NULL)
1099 srclen = get_string_length (si);
1100 else if (idx < 0)
1101 srclen = build_int_cst (size_type_node, ~idx);
1103 loc = gimple_location (stmt);
1104 if (srclen == NULL_TREE)
1105 switch (bcode)
1107 case BUILT_IN_STRCPY:
1108 case BUILT_IN_STRCPY_CHK:
1109 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1110 return;
1111 break;
1112 case BUILT_IN_STPCPY:
1113 case BUILT_IN_STPCPY_CHK:
1114 if (lhs == NULL_TREE)
1115 return;
1116 else
1118 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1119 srclen = fold_convert_loc (loc, size_type_node, dst);
1120 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1121 lhsuint, srclen);
1123 break;
1124 default:
1125 gcc_unreachable ();
1128 if (didx == 0)
1130 didx = new_stridx (dst);
1131 if (didx == 0)
1132 return;
1134 if (olddsi != NULL)
1136 oldlen = olddsi->length;
1137 dsi = unshare_strinfo (olddsi);
1138 dsi->length = srclen;
1139 /* Break the chain, so adjust_related_strinfo on later pointers in
1140 the chain won't adjust this one anymore. */
1141 dsi->next = 0;
1142 dsi->stmt = NULL;
1143 dsi->endptr = NULL_TREE;
1145 else
1147 dsi = new_strinfo (dst, didx, srclen);
1148 set_strinfo (didx, dsi);
1149 find_equal_ptrs (dst, didx);
1151 dsi->writable = true;
1152 dsi->dont_invalidate = true;
1154 if (dsi->length == NULL_TREE)
1156 strinfo chainsi;
1158 /* If string length of src is unknown, use delayed length
1159 computation. If string lenth of dst will be needed, it
1160 can be computed by transforming this strcpy call into
1161 stpcpy and subtracting dst from the return value. */
1163 /* Look for earlier strings whose length could be determined if
1164 this strcpy is turned into an stpcpy. */
1166 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1168 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1170 /* When setting a stmt for delayed length computation
1171 prevent all strinfos through dsi from being
1172 invalidated. */
1173 chainsi = unshare_strinfo (chainsi);
1174 chainsi->stmt = stmt;
1175 chainsi->length = NULL_TREE;
1176 chainsi->endptr = NULL_TREE;
1177 chainsi->dont_invalidate = true;
1180 dsi->stmt = stmt;
1181 return;
1184 if (olddsi != NULL)
1186 tree adj = NULL_TREE;
1187 if (oldlen == NULL_TREE)
1189 else if (integer_zerop (oldlen))
1190 adj = srclen;
1191 else if (TREE_CODE (oldlen) == INTEGER_CST
1192 || TREE_CODE (srclen) == INTEGER_CST)
1193 adj = fold_build2_loc (loc, MINUS_EXPR,
1194 TREE_TYPE (srclen), srclen,
1195 fold_convert_loc (loc, TREE_TYPE (srclen),
1196 oldlen));
1197 if (adj != NULL_TREE)
1198 adjust_related_strinfos (loc, dsi, adj);
1199 else
1200 dsi->prev = 0;
1202 /* strcpy src may not overlap dst, so src doesn't need to be
1203 invalidated either. */
1204 if (si != NULL)
1205 si->dont_invalidate = true;
1207 fn = NULL_TREE;
1208 zsi = NULL;
1209 switch (bcode)
1211 case BUILT_IN_STRCPY:
1212 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1213 if (lhs)
1214 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1215 break;
1216 case BUILT_IN_STRCPY_CHK:
1217 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1218 if (lhs)
1219 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1220 break;
1221 case BUILT_IN_STPCPY:
1222 /* This would need adjustment of the lhs (subtract one),
1223 or detection that the trailing '\0' doesn't need to be
1224 written, if it will be immediately overwritten.
1225 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1226 if (lhs)
1228 dsi->endptr = lhs;
1229 zsi = zero_length_string (lhs, dsi);
1231 break;
1232 case BUILT_IN_STPCPY_CHK:
1233 /* This would need adjustment of the lhs (subtract one),
1234 or detection that the trailing '\0' doesn't need to be
1235 written, if it will be immediately overwritten.
1236 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1237 if (lhs)
1239 dsi->endptr = lhs;
1240 zsi = zero_length_string (lhs, dsi);
1242 break;
1243 default:
1244 gcc_unreachable ();
1246 if (zsi != NULL)
1247 zsi->dont_invalidate = true;
1249 if (fn == NULL_TREE)
1250 return;
1252 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1253 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1255 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1256 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1257 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1258 GSI_SAME_STMT);
1259 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1261 fprintf (dump_file, "Optimizing: ");
1262 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1264 if (gimple_call_num_args (stmt) == 2)
1265 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1266 else
1267 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1268 gimple_call_arg (stmt, 2));
1269 if (success)
1271 stmt = gsi_stmt (*gsi);
1272 update_stmt (stmt);
1273 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1275 fprintf (dump_file, "into: ");
1276 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1278 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1279 laststmt.stmt = stmt;
1280 laststmt.len = srclen;
1281 laststmt.stridx = dsi->idx;
1283 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1284 fprintf (dump_file, "not possible.\n");
1287 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1288 If strlen of the second argument is known and length of the third argument
1289 is that plus one, strlen of the first argument is the same after this
1290 call. */
1292 static void
1293 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1295 int idx, didx;
1296 tree src, dst, len, lhs, oldlen, newlen;
1297 gimple stmt = gsi_stmt (*gsi);
1298 strinfo si, dsi, olddsi;
1300 len = gimple_call_arg (stmt, 2);
1301 src = gimple_call_arg (stmt, 1);
1302 dst = gimple_call_arg (stmt, 0);
1303 idx = get_stridx (src);
1304 if (idx == 0)
1305 return;
1307 didx = get_stridx (dst);
1308 olddsi = NULL;
1309 if (didx > 0)
1310 olddsi = get_strinfo (didx);
1311 else if (didx < 0)
1312 return;
1314 if (olddsi != NULL
1315 && tree_fits_uhwi_p (len)
1316 && !integer_zerop (len))
1317 adjust_last_stmt (olddsi, stmt, false);
1319 if (idx > 0)
1321 gimple def_stmt;
1323 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1324 si = get_strinfo (idx);
1325 if (si == NULL || si->length == NULL_TREE)
1326 return;
1327 if (TREE_CODE (len) != SSA_NAME)
1328 return;
1329 def_stmt = SSA_NAME_DEF_STMT (len);
1330 if (!is_gimple_assign (def_stmt)
1331 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1332 || gimple_assign_rhs1 (def_stmt) != si->length
1333 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1334 return;
1336 else
1338 si = NULL;
1339 /* Handle memcpy (x, "abcd", 5) or
1340 memcpy (x, "abc\0uvw", 7). */
1341 if (!tree_fits_uhwi_p (len)
1342 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1343 return;
1346 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1347 adjust_last_stmt (olddsi, stmt, false);
1349 if (didx == 0)
1351 didx = new_stridx (dst);
1352 if (didx == 0)
1353 return;
1355 if (si != NULL)
1356 newlen = si->length;
1357 else
1358 newlen = build_int_cst (size_type_node, ~idx);
1359 oldlen = NULL_TREE;
1360 if (olddsi != NULL)
1362 dsi = unshare_strinfo (olddsi);
1363 oldlen = olddsi->length;
1364 dsi->length = newlen;
1365 /* Break the chain, so adjust_related_strinfo on later pointers in
1366 the chain won't adjust this one anymore. */
1367 dsi->next = 0;
1368 dsi->stmt = NULL;
1369 dsi->endptr = NULL_TREE;
1371 else
1373 dsi = new_strinfo (dst, didx, newlen);
1374 set_strinfo (didx, dsi);
1375 find_equal_ptrs (dst, didx);
1377 dsi->writable = true;
1378 dsi->dont_invalidate = true;
1379 if (olddsi != NULL)
1381 tree adj = NULL_TREE;
1382 location_t loc = gimple_location (stmt);
1383 if (oldlen == NULL_TREE)
1385 else if (integer_zerop (oldlen))
1386 adj = dsi->length;
1387 else if (TREE_CODE (oldlen) == INTEGER_CST
1388 || TREE_CODE (dsi->length) == INTEGER_CST)
1389 adj = fold_build2_loc (loc, MINUS_EXPR,
1390 TREE_TYPE (dsi->length), dsi->length,
1391 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1392 oldlen));
1393 if (adj != NULL_TREE)
1394 adjust_related_strinfos (loc, dsi, adj);
1395 else
1396 dsi->prev = 0;
1398 /* memcpy src may not overlap dst, so src doesn't need to be
1399 invalidated either. */
1400 if (si != NULL)
1401 si->dont_invalidate = true;
1403 lhs = gimple_call_lhs (stmt);
1404 switch (bcode)
1406 case BUILT_IN_MEMCPY:
1407 case BUILT_IN_MEMCPY_CHK:
1408 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1409 laststmt.stmt = stmt;
1410 laststmt.len = dsi->length;
1411 laststmt.stridx = dsi->idx;
1412 if (lhs)
1413 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1414 break;
1415 case BUILT_IN_MEMPCPY:
1416 case BUILT_IN_MEMPCPY_CHK:
1417 break;
1418 default:
1419 gcc_unreachable ();
1423 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1424 If strlen of the second argument is known, strlen of the first argument
1425 is increased by the length of the second argument. Furthermore, attempt
1426 to convert it to memcpy/strcpy if the length of the first argument
1427 is known. */
1429 static void
1430 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1432 int idx, didx;
1433 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1434 bool success;
1435 gimple stmt = gsi_stmt (*gsi);
1436 strinfo si, dsi;
1437 location_t loc;
1439 src = gimple_call_arg (stmt, 1);
1440 dst = gimple_call_arg (stmt, 0);
1441 lhs = gimple_call_lhs (stmt);
1443 didx = get_stridx (dst);
1444 if (didx < 0)
1445 return;
1447 dsi = NULL;
1448 if (didx > 0)
1449 dsi = get_strinfo (didx);
1450 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1452 /* strcat (p, q) can be transformed into
1453 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1454 with length endptr - p if we need to compute the length
1455 later on. Don't do this transformation if we don't need
1456 it. */
1457 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1459 if (didx == 0)
1461 didx = new_stridx (dst);
1462 if (didx == 0)
1463 return;
1465 if (dsi == NULL)
1467 dsi = new_strinfo (dst, didx, NULL_TREE);
1468 set_strinfo (didx, dsi);
1469 find_equal_ptrs (dst, didx);
1471 else
1473 dsi = unshare_strinfo (dsi);
1474 dsi->length = NULL_TREE;
1475 dsi->next = 0;
1476 dsi->endptr = NULL_TREE;
1478 dsi->writable = true;
1479 dsi->stmt = stmt;
1480 dsi->dont_invalidate = true;
1482 return;
1485 srclen = NULL_TREE;
1486 si = NULL;
1487 idx = get_stridx (src);
1488 if (idx < 0)
1489 srclen = build_int_cst (size_type_node, ~idx);
1490 else if (idx > 0)
1492 si = get_strinfo (idx);
1493 if (si != NULL)
1494 srclen = get_string_length (si);
1497 loc = gimple_location (stmt);
1498 dstlen = dsi->length;
1499 endptr = dsi->endptr;
1501 dsi = unshare_strinfo (dsi);
1502 dsi->endptr = NULL_TREE;
1503 dsi->stmt = NULL;
1504 dsi->writable = true;
1506 if (srclen != NULL_TREE)
1508 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1509 dsi->length, srclen);
1510 adjust_related_strinfos (loc, dsi, srclen);
1511 dsi->dont_invalidate = true;
1513 else
1515 dsi->length = NULL;
1516 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1517 dsi->dont_invalidate = true;
1520 if (si != NULL)
1521 /* strcat src may not overlap dst, so src doesn't need to be
1522 invalidated either. */
1523 si->dont_invalidate = true;
1525 /* For now. Could remove the lhs from the call and add
1526 lhs = dst; afterwards. */
1527 if (lhs)
1528 return;
1530 fn = NULL_TREE;
1531 objsz = NULL_TREE;
1532 switch (bcode)
1534 case BUILT_IN_STRCAT:
1535 if (srclen != NULL_TREE)
1536 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1537 else
1538 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1539 break;
1540 case BUILT_IN_STRCAT_CHK:
1541 if (srclen != NULL_TREE)
1542 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1543 else
1544 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1545 objsz = gimple_call_arg (stmt, 2);
1546 break;
1547 default:
1548 gcc_unreachable ();
1551 if (fn == NULL_TREE)
1552 return;
1554 len = NULL_TREE;
1555 if (srclen != NULL_TREE)
1557 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1558 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1560 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1561 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1562 build_int_cst (type, 1));
1563 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1564 GSI_SAME_STMT);
1566 if (endptr)
1567 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1568 else
1569 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1570 TREE_TYPE (dst), unshare_expr (dst),
1571 fold_convert_loc (loc, sizetype,
1572 unshare_expr (dstlen)));
1573 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1574 GSI_SAME_STMT);
1575 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1577 fprintf (dump_file, "Optimizing: ");
1578 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1580 if (srclen != NULL_TREE)
1581 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1582 dst, src, len, objsz);
1583 else
1584 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1585 dst, src, objsz);
1586 if (success)
1588 stmt = gsi_stmt (*gsi);
1589 update_stmt (stmt);
1590 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1592 fprintf (dump_file, "into: ");
1593 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1595 /* If srclen == NULL, note that current string length can be
1596 computed by transforming this strcpy into stpcpy. */
1597 if (srclen == NULL_TREE && dsi->dont_invalidate)
1598 dsi->stmt = stmt;
1599 adjust_last_stmt (dsi, stmt, true);
1600 if (srclen != NULL_TREE)
1602 laststmt.stmt = stmt;
1603 laststmt.len = srclen;
1604 laststmt.stridx = dsi->idx;
1607 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1608 fprintf (dump_file, "not possible.\n");
1611 /* Handle a POINTER_PLUS_EXPR statement.
1612 For p = "abcd" + 2; compute associated length, or if
1613 p = q + off is pointing to a '\0' character of a string, call
1614 zero_length_string on it. */
1616 static void
1617 handle_pointer_plus (gimple_stmt_iterator *gsi)
1619 gimple stmt = gsi_stmt (*gsi);
1620 tree lhs = gimple_assign_lhs (stmt), off;
1621 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1622 strinfo si, zsi;
1624 if (idx == 0)
1625 return;
1627 if (idx < 0)
1629 tree off = gimple_assign_rhs2 (stmt);
1630 if (tree_fits_uhwi_p (off)
1631 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1632 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1633 = ~(~idx - (int) tree_to_uhwi (off));
1634 return;
1637 si = get_strinfo (idx);
1638 if (si == NULL || si->length == NULL_TREE)
1639 return;
1641 off = gimple_assign_rhs2 (stmt);
1642 zsi = NULL;
1643 if (operand_equal_p (si->length, off, 0))
1644 zsi = zero_length_string (lhs, si);
1645 else if (TREE_CODE (off) == SSA_NAME)
1647 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1648 if (gimple_assign_single_p (def_stmt)
1649 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1650 zsi = zero_length_string (lhs, si);
1652 if (zsi != NULL
1653 && si->endptr != NULL_TREE
1654 && si->endptr != lhs
1655 && TREE_CODE (si->endptr) == SSA_NAME)
1657 enum tree_code rhs_code
1658 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1659 ? SSA_NAME : NOP_EXPR;
1660 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr, NULL_TREE);
1661 gcc_assert (gsi_stmt (*gsi) == stmt);
1662 update_stmt (stmt);
1666 /* Handle a single character store. */
1668 static bool
1669 handle_char_store (gimple_stmt_iterator *gsi)
1671 int idx = -1;
1672 strinfo si = NULL;
1673 gimple stmt = gsi_stmt (*gsi);
1674 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1676 if (TREE_CODE (lhs) == MEM_REF
1677 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1679 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1681 ssaname = TREE_OPERAND (lhs, 0);
1682 idx = get_stridx (ssaname);
1685 else
1686 idx = get_addr_stridx (lhs);
1688 if (idx > 0)
1690 si = get_strinfo (idx);
1691 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1693 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1695 /* When storing '\0', the store can be removed
1696 if we know it has been stored in the current function. */
1697 if (!stmt_could_throw_p (stmt) && si->writable)
1699 unlink_stmt_vdef (stmt);
1700 release_defs (stmt);
1701 gsi_remove (gsi, true);
1702 return false;
1704 else
1706 si->writable = true;
1707 gsi_next (gsi);
1708 return false;
1711 else
1712 /* Otherwise this statement overwrites the '\0' with
1713 something, if the previous stmt was a memcpy,
1714 its length may be decreased. */
1715 adjust_last_stmt (si, stmt, false);
1717 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1719 si = unshare_strinfo (si);
1720 si->length = build_int_cst (size_type_node, 0);
1721 si->endptr = NULL;
1722 si->prev = 0;
1723 si->next = 0;
1724 si->stmt = NULL;
1725 si->first = 0;
1726 si->writable = true;
1727 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1728 si->endptr = ssaname;
1729 si->dont_invalidate = true;
1731 /* If si->length is non-zero constant, we aren't overwriting '\0',
1732 and if we aren't storing '\0', we know that the length of the
1733 string and any other zero terminated string in memory remains
1734 the same. In that case we move to the next gimple statement and
1735 return to signal the caller that it shouldn't invalidate anything.
1737 This is benefical for cases like:
1739 char p[20];
1740 void foo (char *q)
1742 strcpy (p, "foobar");
1743 size_t len = strlen (p); // This can be optimized into 6
1744 size_t len2 = strlen (q); // This has to be computed
1745 p[0] = 'X';
1746 size_t len3 = strlen (p); // This can be optimized into 6
1747 size_t len4 = strlen (q); // This can be optimized into len2
1748 bar (len, len2, len3, len4);
1751 else if (si != NULL && si->length != NULL_TREE
1752 && TREE_CODE (si->length) == INTEGER_CST
1753 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
1755 gsi_next (gsi);
1756 return false;
1759 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1761 if (ssaname)
1763 si = zero_length_string (ssaname, NULL);
1764 if (si != NULL)
1765 si->dont_invalidate = true;
1767 else
1769 int idx = new_addr_stridx (lhs);
1770 if (idx != 0)
1772 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1773 build_int_cst (size_type_node, 0));
1774 set_strinfo (idx, si);
1775 si->dont_invalidate = true;
1778 if (si != NULL)
1779 si->writable = true;
1781 else if (idx == 0
1782 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
1783 && ssaname == NULL_TREE
1784 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
1786 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
1787 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
1788 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
1790 int idx = new_addr_stridx (lhs);
1791 if (idx != 0)
1793 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1794 build_int_cst (size_type_node, l));
1795 set_strinfo (idx, si);
1796 si->dont_invalidate = true;
1801 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
1803 /* Allow adjust_last_stmt to remove it if the stored '\0'
1804 is immediately overwritten. */
1805 laststmt.stmt = stmt;
1806 laststmt.len = build_int_cst (size_type_node, 1);
1807 laststmt.stridx = si->idx;
1809 return true;
1812 /* Attempt to optimize a single statement at *GSI using string length
1813 knowledge. */
1815 static bool
1816 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
1818 gimple stmt = gsi_stmt (*gsi);
1820 if (is_gimple_call (stmt))
1822 tree callee = gimple_call_fndecl (stmt);
1823 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
1824 switch (DECL_FUNCTION_CODE (callee))
1826 case BUILT_IN_STRLEN:
1827 handle_builtin_strlen (gsi);
1828 break;
1829 case BUILT_IN_STRCHR:
1830 handle_builtin_strchr (gsi);
1831 break;
1832 case BUILT_IN_STRCPY:
1833 case BUILT_IN_STRCPY_CHK:
1834 case BUILT_IN_STPCPY:
1835 case BUILT_IN_STPCPY_CHK:
1836 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
1837 break;
1838 case BUILT_IN_MEMCPY:
1839 case BUILT_IN_MEMCPY_CHK:
1840 case BUILT_IN_MEMPCPY:
1841 case BUILT_IN_MEMPCPY_CHK:
1842 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
1843 break;
1844 case BUILT_IN_STRCAT:
1845 case BUILT_IN_STRCAT_CHK:
1846 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
1847 break;
1848 default:
1849 break;
1852 else if (is_gimple_assign (stmt))
1854 tree lhs = gimple_assign_lhs (stmt);
1856 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
1858 if (gimple_assign_single_p (stmt)
1859 || (gimple_assign_cast_p (stmt)
1860 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
1862 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1863 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
1865 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1866 handle_pointer_plus (gsi);
1868 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
1870 tree type = TREE_TYPE (lhs);
1871 if (TREE_CODE (type) == ARRAY_TYPE)
1872 type = TREE_TYPE (type);
1873 if (TREE_CODE (type) == INTEGER_TYPE
1874 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
1875 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
1877 if (! handle_char_store (gsi))
1878 return false;
1883 if (gimple_vdef (stmt))
1884 maybe_invalidate (stmt);
1885 return true;
1888 /* Recursively call maybe_invalidate on stmts that might be executed
1889 in between dombb and current bb and that contain a vdef. Stop when
1890 *count stmts are inspected, or if the whole strinfo vector has
1891 been invalidated. */
1893 static void
1894 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
1896 unsigned int i, n = gimple_phi_num_args (phi);
1898 for (i = 0; i < n; i++)
1900 tree vuse = gimple_phi_arg_def (phi, i);
1901 gimple stmt = SSA_NAME_DEF_STMT (vuse);
1902 basic_block bb = gimple_bb (stmt);
1903 if (bb == NULL
1904 || bb == dombb
1905 || !bitmap_set_bit (visited, bb->index)
1906 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1907 continue;
1908 while (1)
1910 if (gimple_code (stmt) == GIMPLE_PHI)
1912 do_invalidate (dombb, stmt, visited, count);
1913 if (*count == 0)
1914 return;
1915 break;
1917 if (--*count == 0)
1918 return;
1919 if (!maybe_invalidate (stmt))
1921 *count = 0;
1922 return;
1924 vuse = gimple_vuse (stmt);
1925 stmt = SSA_NAME_DEF_STMT (vuse);
1926 if (gimple_bb (stmt) != bb)
1928 bb = gimple_bb (stmt);
1929 if (bb == NULL
1930 || bb == dombb
1931 || !bitmap_set_bit (visited, bb->index)
1932 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1933 break;
1939 class strlen_dom_walker : public dom_walker
1941 public:
1942 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
1944 virtual void before_dom_children (basic_block);
1945 virtual void after_dom_children (basic_block);
1948 /* Callback for walk_dominator_tree. Attempt to optimize various
1949 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1951 void
1952 strlen_dom_walker::before_dom_children (basic_block bb)
1954 gimple_stmt_iterator gsi;
1955 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
1957 if (dombb == NULL)
1958 stridx_to_strinfo = NULL;
1959 else
1961 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) dombb->aux);
1962 if (stridx_to_strinfo)
1964 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1966 gimple phi = gsi_stmt (gsi);
1967 if (virtual_operand_p (gimple_phi_result (phi)))
1969 bitmap visited = BITMAP_ALLOC (NULL);
1970 int count_vdef = 100;
1971 do_invalidate (dombb, phi, visited, &count_vdef);
1972 BITMAP_FREE (visited);
1973 if (count_vdef == 0)
1975 /* If there were too many vdefs in between immediate
1976 dominator and current bb, invalidate everything.
1977 If stridx_to_strinfo has been unshared, we need
1978 to free it, otherwise just set it to NULL. */
1979 if (!strinfo_shared ())
1981 unsigned int i;
1982 strinfo si;
1984 for (i = 1;
1985 vec_safe_iterate (stridx_to_strinfo, i, &si);
1986 ++i)
1988 free_strinfo (si);
1989 (*stridx_to_strinfo)[i] = NULL;
1992 else
1993 stridx_to_strinfo = NULL;
1995 break;
2001 /* If all PHI arguments have the same string index, the PHI result
2002 has it as well. */
2003 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2005 gimple phi = gsi_stmt (gsi);
2006 tree result = gimple_phi_result (phi);
2007 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2009 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2010 if (idx != 0)
2012 unsigned int i, n = gimple_phi_num_args (phi);
2013 for (i = 1; i < n; i++)
2014 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2015 break;
2016 if (i == n)
2017 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2022 /* Attempt to optimize individual statements. */
2023 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2024 if (strlen_optimize_stmt (&gsi))
2025 gsi_next (&gsi);
2027 bb->aux = stridx_to_strinfo;
2028 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2029 (*stridx_to_strinfo)[0] = (strinfo) bb;
2032 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2033 owned by the current bb, clear bb->aux. */
2035 void
2036 strlen_dom_walker::after_dom_children (basic_block bb)
2038 if (bb->aux)
2040 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux);
2041 if (vec_safe_length (stridx_to_strinfo)
2042 && (*stridx_to_strinfo)[0] == (strinfo) bb)
2044 unsigned int i;
2045 strinfo si;
2047 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2048 free_strinfo (si);
2049 vec_free (stridx_to_strinfo);
2051 bb->aux = NULL;
2055 /* Main entry point. */
2057 static unsigned int
2058 tree_ssa_strlen (void)
2060 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2061 max_stridx = 1;
2062 strinfo_pool = create_alloc_pool ("strinfo_struct pool",
2063 sizeof (struct strinfo_struct), 64);
2065 calculate_dominance_info (CDI_DOMINATORS);
2067 /* String length optimization is implemented as a walk of the dominator
2068 tree and a forward walk of statements within each block. */
2069 strlen_dom_walker (CDI_DOMINATORS).walk (cfun->cfg->x_entry_block_ptr);
2071 ssa_ver_to_stridx.release ();
2072 free_alloc_pool (strinfo_pool);
2073 if (decl_to_stridxlist_htab.is_created ())
2075 obstack_free (&stridx_obstack, NULL);
2076 decl_to_stridxlist_htab.dispose ();
2078 laststmt.stmt = NULL;
2079 laststmt.len = NULL_TREE;
2080 laststmt.stridx = 0;
2082 return 0;
2085 static bool
2086 gate_strlen (void)
2088 return flag_optimize_strlen != 0;
2091 namespace {
2093 const pass_data pass_data_strlen =
2095 GIMPLE_PASS, /* type */
2096 "strlen", /* name */
2097 OPTGROUP_NONE, /* optinfo_flags */
2098 true, /* has_gate */
2099 true, /* has_execute */
2100 TV_TREE_STRLEN, /* tv_id */
2101 ( PROP_cfg | PROP_ssa ), /* properties_required */
2102 0, /* properties_provided */
2103 0, /* properties_destroyed */
2104 0, /* todo_flags_start */
2105 TODO_verify_ssa, /* todo_flags_finish */
2108 class pass_strlen : public gimple_opt_pass
2110 public:
2111 pass_strlen (gcc::context *ctxt)
2112 : gimple_opt_pass (pass_data_strlen, ctxt)
2115 /* opt_pass methods: */
2116 bool gate () { return gate_strlen (); }
2117 unsigned int execute () { return tree_ssa_strlen (); }
2119 }; // class pass_strlen
2121 } // anon namespace
2123 gimple_opt_pass *
2124 make_pass_strlen (gcc::context *ctxt)
2126 return new pass_strlen (ctxt);