gcc/testsuite/
[official-gcc.git] / gcc / tree-ssa-strlen.c
blobbc3d712796ab11c4649676b8022ebc3c44c159e1
1 /* String length optimization
2 Copyright (C) 2011-2014 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "stor-layout.h"
26 #include "hash-table.h"
27 #include "bitmap.h"
28 #include "basic-block.h"
29 #include "tree-ssa-alias.h"
30 #include "internal-fn.h"
31 #include "gimple-fold.h"
32 #include "tree-eh.h"
33 #include "gimple-expr.h"
34 #include "is-a.h"
35 #include "gimple.h"
36 #include "gimplify.h"
37 #include "gimple-iterator.h"
38 #include "gimplify-me.h"
39 #include "gimple-ssa.h"
40 #include "tree-phinodes.h"
41 #include "ssa-iterators.h"
42 #include "stringpool.h"
43 #include "tree-ssanames.h"
44 #include "expr.h"
45 #include "tree-dfa.h"
46 #include "tree-pass.h"
47 #include "domwalk.h"
48 #include "alloc-pool.h"
49 #include "tree-ssa-propagate.h"
50 #include "gimple-pretty-print.h"
51 #include "params.h"
52 #include "expr.h"
54 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
55 is an index into strinfo vector, negative value stands for
56 string length of a string literal (~strlen). */
57 static vec<int> ssa_ver_to_stridx;
59 /* Number of currently active string indexes plus one. */
60 static int max_stridx;
62 /* String information record. */
63 typedef struct strinfo_struct
65 /* String length of this string. */
66 tree length;
67 /* Any of the corresponding pointers for querying alias oracle. */
68 tree ptr;
69 /* Statement for delayed length computation. */
70 gimple stmt;
71 /* Pointer to '\0' if known, if NULL, it can be computed as
72 ptr + length. */
73 tree endptr;
74 /* Reference count. Any changes to strinfo entry possibly shared
75 with dominating basic blocks need unshare_strinfo first, except
76 for dont_invalidate which affects only the immediately next
77 maybe_invalidate. */
78 int refcount;
79 /* Copy of index. get_strinfo (si->idx) should return si; */
80 int idx;
81 /* These 3 fields are for chaining related string pointers together.
82 E.g. for
83 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
84 strcpy (c, d); e = c + dl;
85 strinfo(a) -> strinfo(c) -> strinfo(e)
86 All have ->first field equal to strinfo(a)->idx and are doubly
87 chained through prev/next fields. The later strinfos are required
88 to point into the same string with zero or more bytes after
89 the previous pointer and all bytes in between the two pointers
90 must be non-zero. Functions like strcpy or memcpy are supposed
91 to adjust all previous strinfo lengths, but not following strinfo
92 lengths (those are uncertain, usually invalidated during
93 maybe_invalidate, except when the alias oracle knows better).
94 Functions like strcat on the other side adjust the whole
95 related strinfo chain.
96 They are updated lazily, so to use the chain the same first fields
97 and si->prev->next == si->idx needs to be verified. */
98 int first;
99 int next;
100 int prev;
101 /* A flag whether the string is known to be written in the current
102 function. */
103 bool writable;
104 /* A flag for the next maybe_invalidate that this strinfo shouldn't
105 be invalidated. Always cleared by maybe_invalidate. */
106 bool dont_invalidate;
107 } *strinfo;
109 /* Pool for allocating strinfo_struct entries. */
110 static alloc_pool strinfo_pool;
112 /* Vector mapping positive string indexes to strinfo, for the
113 current basic block. The first pointer in the vector is special,
114 it is either NULL, meaning the vector isn't shared, or it is
115 a basic block pointer to the owner basic_block if shared.
116 If some other bb wants to modify the vector, the vector needs
117 to be unshared first, and only the owner bb is supposed to free it. */
118 static vec<strinfo, va_heap, vl_embed> *stridx_to_strinfo;
120 /* One OFFSET->IDX mapping. */
121 struct stridxlist
123 struct stridxlist *next;
124 HOST_WIDE_INT offset;
125 int idx;
128 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
129 struct decl_stridxlist_map
131 struct tree_map_base base;
132 struct stridxlist list;
135 /* stridxlist hashtable helpers. */
137 struct stridxlist_hasher : typed_noop_remove <decl_stridxlist_map>
139 typedef decl_stridxlist_map value_type;
140 typedef decl_stridxlist_map compare_type;
141 static inline hashval_t hash (const value_type *);
142 static inline bool equal (const value_type *, const compare_type *);
145 /* Hash a from tree in a decl_stridxlist_map. */
147 inline hashval_t
148 stridxlist_hasher::hash (const value_type *item)
150 return DECL_UID (item->base.from);
153 inline bool
154 stridxlist_hasher::equal (const value_type *v, const compare_type *c)
156 return tree_map_base_eq (&v->base, &c->base);
159 /* Hash table for mapping decls to a chained list of offset -> idx
160 mappings. */
161 static hash_table <stridxlist_hasher> decl_to_stridxlist_htab;
163 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
164 static struct obstack stridx_obstack;
166 /* Last memcpy statement if it could be adjusted if the trailing
167 '\0' written is immediately overwritten, or
168 *x = '\0' store that could be removed if it is immediately overwritten. */
169 struct laststmt_struct
171 gimple stmt;
172 tree len;
173 int stridx;
174 } laststmt;
176 /* Helper function for get_stridx. */
178 static int
179 get_addr_stridx (tree exp)
181 HOST_WIDE_INT off;
182 struct decl_stridxlist_map ent, *e;
183 struct stridxlist *list;
184 tree base;
186 if (!decl_to_stridxlist_htab.is_created ())
187 return 0;
189 base = get_addr_base_and_unit_offset (exp, &off);
190 if (base == NULL || !DECL_P (base))
191 return 0;
193 ent.base.from = base;
194 e = decl_to_stridxlist_htab.find_with_hash (&ent, DECL_UID (base));
195 if (e == NULL)
196 return 0;
198 list = &e->list;
201 if (list->offset == off)
202 return list->idx;
203 list = list->next;
205 while (list);
206 return 0;
209 /* Return string index for EXP. */
211 static int
212 get_stridx (tree exp)
214 tree s, o;
216 if (TREE_CODE (exp) == SSA_NAME)
217 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
219 if (TREE_CODE (exp) == ADDR_EXPR)
221 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
222 if (idx != 0)
223 return idx;
226 s = string_constant (exp, &o);
227 if (s != NULL_TREE
228 && (o == NULL_TREE || tree_fits_shwi_p (o))
229 && TREE_STRING_LENGTH (s) > 0)
231 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
232 const char *p = TREE_STRING_POINTER (s);
233 int max = TREE_STRING_LENGTH (s) - 1;
235 if (p[max] == '\0' && offset >= 0 && offset <= max)
236 return ~(int) strlen (p + offset);
238 return 0;
241 /* Return true if strinfo vector is shared with the immediate dominator. */
243 static inline bool
244 strinfo_shared (void)
246 return vec_safe_length (stridx_to_strinfo)
247 && (*stridx_to_strinfo)[0] != NULL;
250 /* Unshare strinfo vector that is shared with the immediate dominator. */
252 static void
253 unshare_strinfo_vec (void)
255 strinfo si;
256 unsigned int i = 0;
258 gcc_assert (strinfo_shared ());
259 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
260 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
261 if (si != NULL)
262 si->refcount++;
263 (*stridx_to_strinfo)[0] = NULL;
266 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
267 Return a pointer to the location where the string index can
268 be stored (if 0) or is stored, or NULL if this can't be tracked. */
270 static int *
271 addr_stridxptr (tree exp)
273 decl_stridxlist_map **slot;
274 struct decl_stridxlist_map ent;
275 struct stridxlist *list;
276 HOST_WIDE_INT off;
278 tree base = get_addr_base_and_unit_offset (exp, &off);
279 if (base == NULL_TREE || !DECL_P (base))
280 return NULL;
282 if (!decl_to_stridxlist_htab.is_created ())
284 decl_to_stridxlist_htab.create (64);
285 gcc_obstack_init (&stridx_obstack);
287 ent.base.from = base;
288 slot = decl_to_stridxlist_htab.find_slot_with_hash (&ent, DECL_UID (base),
289 INSERT);
290 if (*slot)
292 int i;
293 list = &(*slot)->list;
294 for (i = 0; i < 16; i++)
296 if (list->offset == off)
297 return &list->idx;
298 if (list->next == NULL)
299 break;
301 if (i == 16)
302 return NULL;
303 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
304 list = list->next;
306 else
308 struct decl_stridxlist_map *e
309 = XOBNEW (&stridx_obstack, struct decl_stridxlist_map);
310 e->base.from = base;
311 *slot = e;
312 list = &e->list;
314 list->next = NULL;
315 list->offset = off;
316 list->idx = 0;
317 return &list->idx;
320 /* Create a new string index, or return 0 if reached limit. */
322 static int
323 new_stridx (tree exp)
325 int idx;
326 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
327 return 0;
328 if (TREE_CODE (exp) == SSA_NAME)
330 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
331 return 0;
332 idx = max_stridx++;
333 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
334 return idx;
336 if (TREE_CODE (exp) == ADDR_EXPR)
338 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
339 if (pidx != NULL)
341 gcc_assert (*pidx == 0);
342 *pidx = max_stridx++;
343 return *pidx;
346 return 0;
349 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
351 static int
352 new_addr_stridx (tree exp)
354 int *pidx;
355 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
356 return 0;
357 pidx = addr_stridxptr (exp);
358 if (pidx != NULL)
360 gcc_assert (*pidx == 0);
361 *pidx = max_stridx++;
362 return *pidx;
364 return 0;
367 /* Create a new strinfo. */
369 static strinfo
370 new_strinfo (tree ptr, int idx, tree length)
372 strinfo si = (strinfo) pool_alloc (strinfo_pool);
373 si->length = length;
374 si->ptr = ptr;
375 si->stmt = NULL;
376 si->endptr = NULL_TREE;
377 si->refcount = 1;
378 si->idx = idx;
379 si->first = 0;
380 si->prev = 0;
381 si->next = 0;
382 si->writable = false;
383 si->dont_invalidate = false;
384 return si;
387 /* Decrease strinfo refcount and free it if not referenced anymore. */
389 static inline void
390 free_strinfo (strinfo si)
392 if (si && --si->refcount == 0)
393 pool_free (strinfo_pool, si);
396 /* Return strinfo vector entry IDX. */
398 static inline strinfo
399 get_strinfo (int idx)
401 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
402 return NULL;
403 return (*stridx_to_strinfo)[idx];
406 /* Set strinfo in the vector entry IDX to SI. */
408 static inline void
409 set_strinfo (int idx, strinfo si)
411 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
412 unshare_strinfo_vec ();
413 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
414 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
415 (*stridx_to_strinfo)[idx] = si;
418 /* Return string length, or NULL if it can't be computed. */
420 static tree
421 get_string_length (strinfo si)
423 if (si->length)
424 return si->length;
426 if (si->stmt)
428 gimple stmt = si->stmt, lenstmt;
429 tree callee, lhs, fn, tem;
430 location_t loc;
431 gimple_stmt_iterator gsi;
433 gcc_assert (is_gimple_call (stmt));
434 callee = gimple_call_fndecl (stmt);
435 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
436 lhs = gimple_call_lhs (stmt);
437 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
438 /* unshare_strinfo is intentionally not called here. The (delayed)
439 transformation of strcpy or strcat into stpcpy is done at the place
440 of the former strcpy/strcat call and so can affect all the strinfos
441 with the same stmt. If they were unshared before and transformation
442 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
443 just compute the right length. */
444 switch (DECL_FUNCTION_CODE (callee))
446 case BUILT_IN_STRCAT:
447 case BUILT_IN_STRCAT_CHK:
448 gsi = gsi_for_stmt (stmt);
449 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
450 gcc_assert (lhs == NULL_TREE);
451 tem = unshare_expr (gimple_call_arg (stmt, 0));
452 lenstmt = gimple_build_call (fn, 1, tem);
453 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
454 gimple_call_set_lhs (lenstmt, lhs);
455 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
456 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
457 tem = gimple_call_arg (stmt, 0);
458 if (!ptrofftype_p (TREE_TYPE (lhs)))
460 lhs = convert_to_ptrofftype (lhs);
461 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
462 true, GSI_SAME_STMT);
464 lenstmt
465 = gimple_build_assign_with_ops
466 (POINTER_PLUS_EXPR,
467 make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0)), NULL),
468 tem, lhs);
469 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
470 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
471 lhs = NULL_TREE;
472 /* FALLTHRU */
473 case BUILT_IN_STRCPY:
474 case BUILT_IN_STRCPY_CHK:
475 if (gimple_call_num_args (stmt) == 2)
476 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
477 else
478 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
479 gcc_assert (lhs == NULL_TREE);
480 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
482 fprintf (dump_file, "Optimizing: ");
483 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
485 gimple_call_set_fndecl (stmt, fn);
486 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
487 gimple_call_set_lhs (stmt, lhs);
488 update_stmt (stmt);
489 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
491 fprintf (dump_file, "into: ");
492 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
494 /* FALLTHRU */
495 case BUILT_IN_STPCPY:
496 case BUILT_IN_STPCPY_CHK:
497 gcc_assert (lhs != NULL_TREE);
498 loc = gimple_location (stmt);
499 si->endptr = lhs;
500 si->stmt = NULL;
501 lhs = fold_convert_loc (loc, size_type_node, lhs);
502 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
503 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
504 lhs, si->length);
505 break;
506 default:
507 gcc_unreachable ();
508 break;
512 return si->length;
515 /* Invalidate string length information for strings whose length
516 might change due to stores in stmt. */
518 static bool
519 maybe_invalidate (gimple stmt)
521 strinfo si;
522 unsigned int i;
523 bool nonempty = false;
525 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
526 if (si != NULL)
528 if (!si->dont_invalidate)
530 ao_ref r;
531 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
532 if (stmt_may_clobber_ref_p_1 (stmt, &r))
534 set_strinfo (i, NULL);
535 free_strinfo (si);
536 continue;
539 si->dont_invalidate = false;
540 nonempty = true;
542 return nonempty;
545 /* Unshare strinfo record SI, if it has recount > 1 or
546 if stridx_to_strinfo vector is shared with some other
547 bbs. */
549 static strinfo
550 unshare_strinfo (strinfo si)
552 strinfo nsi;
554 if (si->refcount == 1 && !strinfo_shared ())
555 return si;
557 nsi = new_strinfo (si->ptr, si->idx, si->length);
558 nsi->stmt = si->stmt;
559 nsi->endptr = si->endptr;
560 nsi->first = si->first;
561 nsi->prev = si->prev;
562 nsi->next = si->next;
563 nsi->writable = si->writable;
564 set_strinfo (si->idx, nsi);
565 free_strinfo (si);
566 return nsi;
569 /* Return first strinfo in the related strinfo chain
570 if all strinfos in between belong to the chain, otherwise
571 NULL. */
573 static strinfo
574 verify_related_strinfos (strinfo origsi)
576 strinfo si = origsi, psi;
578 if (origsi->first == 0)
579 return NULL;
580 for (; si->prev; si = psi)
582 if (si->first != origsi->first)
583 return NULL;
584 psi = get_strinfo (si->prev);
585 if (psi == NULL)
586 return NULL;
587 if (psi->next != si->idx)
588 return NULL;
590 if (si->idx != si->first)
591 return NULL;
592 return si;
595 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
596 to a zero-length string and if possible chain it to a related strinfo
597 chain whose part is or might be CHAINSI. */
599 static strinfo
600 zero_length_string (tree ptr, strinfo chainsi)
602 strinfo si;
603 int idx;
604 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
605 && get_stridx (ptr) == 0);
607 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
608 return NULL;
609 if (chainsi != NULL)
611 si = verify_related_strinfos (chainsi);
612 if (si)
614 chainsi = si;
615 for (; chainsi->next; chainsi = si)
617 if (chainsi->endptr == NULL_TREE)
619 chainsi = unshare_strinfo (chainsi);
620 chainsi->endptr = ptr;
622 si = get_strinfo (chainsi->next);
623 if (si == NULL
624 || si->first != chainsi->first
625 || si->prev != chainsi->idx)
626 break;
628 gcc_assert (chainsi->length || chainsi->stmt);
629 if (chainsi->endptr == NULL_TREE)
631 chainsi = unshare_strinfo (chainsi);
632 chainsi->endptr = ptr;
634 if (chainsi->length && integer_zerop (chainsi->length))
636 if (chainsi->next)
638 chainsi = unshare_strinfo (chainsi);
639 chainsi->next = 0;
641 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
642 return chainsi;
645 else if (chainsi->first || chainsi->prev || chainsi->next)
647 chainsi = unshare_strinfo (chainsi);
648 chainsi->first = 0;
649 chainsi->prev = 0;
650 chainsi->next = 0;
653 idx = new_stridx (ptr);
654 if (idx == 0)
655 return NULL;
656 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
657 set_strinfo (idx, si);
658 si->endptr = ptr;
659 if (chainsi != NULL)
661 chainsi = unshare_strinfo (chainsi);
662 if (chainsi->first == 0)
663 chainsi->first = chainsi->idx;
664 chainsi->next = idx;
665 if (chainsi->endptr == NULL_TREE)
666 chainsi->endptr = ptr;
667 si->prev = chainsi->idx;
668 si->first = chainsi->first;
669 si->writable = chainsi->writable;
671 return si;
674 /* For strinfo ORIGSI whose length has been just updated
675 update also related strinfo lengths (add ADJ to each,
676 but don't adjust ORIGSI). */
678 static void
679 adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
681 strinfo si = verify_related_strinfos (origsi);
683 if (si == NULL)
684 return;
686 while (1)
688 strinfo nsi;
690 if (si != origsi)
692 tree tem;
694 si = unshare_strinfo (si);
695 if (si->length)
697 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
698 si->length = fold_build2_loc (loc, PLUS_EXPR,
699 TREE_TYPE (si->length), si->length,
700 tem);
702 else if (si->stmt != NULL)
703 /* Delayed length computation is unaffected. */
705 else
706 gcc_unreachable ();
708 si->endptr = NULL_TREE;
709 si->dont_invalidate = true;
711 if (si->next == 0)
712 return;
713 nsi = get_strinfo (si->next);
714 if (nsi == NULL
715 || nsi->first != si->first
716 || nsi->prev != si->idx)
717 return;
718 si = nsi;
722 /* Find if there are other SSA_NAME pointers equal to PTR
723 for which we don't track their string lengths yet. If so, use
724 IDX for them. */
726 static void
727 find_equal_ptrs (tree ptr, int idx)
729 if (TREE_CODE (ptr) != SSA_NAME)
730 return;
731 while (1)
733 gimple stmt = SSA_NAME_DEF_STMT (ptr);
734 if (!is_gimple_assign (stmt))
735 return;
736 ptr = gimple_assign_rhs1 (stmt);
737 switch (gimple_assign_rhs_code (stmt))
739 case SSA_NAME:
740 break;
741 CASE_CONVERT:
742 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
743 return;
744 if (TREE_CODE (ptr) == SSA_NAME)
745 break;
746 if (TREE_CODE (ptr) != ADDR_EXPR)
747 return;
748 /* FALLTHRU */
749 case ADDR_EXPR:
751 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
752 if (pidx != NULL && *pidx == 0)
753 *pidx = idx;
754 return;
756 default:
757 return;
760 /* We might find an endptr created in this pass. Grow the
761 vector in that case. */
762 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
763 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
765 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
766 return;
767 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
771 /* If the last .MEM setter statement before STMT is
772 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
773 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
774 just memcpy (x, y, strlen (y)). SI must be the zero length
775 strinfo. */
777 static void
778 adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
780 tree vuse, callee, len;
781 struct laststmt_struct last = laststmt;
782 strinfo lastsi, firstsi;
784 laststmt.stmt = NULL;
785 laststmt.len = NULL_TREE;
786 laststmt.stridx = 0;
788 if (last.stmt == NULL)
789 return;
791 vuse = gimple_vuse (stmt);
792 if (vuse == NULL_TREE
793 || SSA_NAME_DEF_STMT (vuse) != last.stmt
794 || !has_single_use (vuse))
795 return;
797 gcc_assert (last.stridx > 0);
798 lastsi = get_strinfo (last.stridx);
799 if (lastsi == NULL)
800 return;
802 if (lastsi != si)
804 if (lastsi->first == 0 || lastsi->first != si->first)
805 return;
807 firstsi = verify_related_strinfos (si);
808 if (firstsi == NULL)
809 return;
810 while (firstsi != lastsi)
812 strinfo nextsi;
813 if (firstsi->next == 0)
814 return;
815 nextsi = get_strinfo (firstsi->next);
816 if (nextsi == NULL
817 || nextsi->prev != firstsi->idx
818 || nextsi->first != si->first)
819 return;
820 firstsi = nextsi;
824 if (!is_strcat)
826 if (si->length == NULL_TREE || !integer_zerop (si->length))
827 return;
830 if (is_gimple_assign (last.stmt))
832 gimple_stmt_iterator gsi;
834 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
835 return;
836 if (stmt_could_throw_p (last.stmt))
837 return;
838 gsi = gsi_for_stmt (last.stmt);
839 unlink_stmt_vdef (last.stmt);
840 release_defs (last.stmt);
841 gsi_remove (&gsi, true);
842 return;
845 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
846 return;
848 callee = gimple_call_fndecl (last.stmt);
849 switch (DECL_FUNCTION_CODE (callee))
851 case BUILT_IN_MEMCPY:
852 case BUILT_IN_MEMCPY_CHK:
853 break;
854 default:
855 return;
858 len = gimple_call_arg (last.stmt, 2);
859 if (tree_fits_uhwi_p (len))
861 if (!tree_fits_uhwi_p (last.len)
862 || integer_zerop (len)
863 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
864 return;
865 /* Don't adjust the length if it is divisible by 4, it is more efficient
866 to store the extra '\0' in that case. */
867 if ((tree_to_uhwi (len) & 3) == 0)
868 return;
870 else if (TREE_CODE (len) == SSA_NAME)
872 gimple def_stmt = SSA_NAME_DEF_STMT (len);
873 if (!is_gimple_assign (def_stmt)
874 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
875 || gimple_assign_rhs1 (def_stmt) != last.len
876 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
877 return;
879 else
880 return;
882 gimple_call_set_arg (last.stmt, 2, last.len);
883 update_stmt (last.stmt);
886 /* Handle a strlen call. If strlen of the argument is known, replace
887 the strlen call with the known value, otherwise remember that strlen
888 of the argument is stored in the lhs SSA_NAME. */
890 static void
891 handle_builtin_strlen (gimple_stmt_iterator *gsi)
893 int idx;
894 tree src;
895 gimple stmt = gsi_stmt (*gsi);
896 tree lhs = gimple_call_lhs (stmt);
898 if (lhs == NULL_TREE)
899 return;
901 src = gimple_call_arg (stmt, 0);
902 idx = get_stridx (src);
903 if (idx)
905 strinfo si = NULL;
906 tree rhs;
908 if (idx < 0)
909 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
910 else
912 rhs = NULL_TREE;
913 si = get_strinfo (idx);
914 if (si != NULL)
915 rhs = get_string_length (si);
917 if (rhs != NULL_TREE)
919 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
921 fprintf (dump_file, "Optimizing: ");
922 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
924 rhs = unshare_expr (rhs);
925 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
926 rhs = fold_convert_loc (gimple_location (stmt),
927 TREE_TYPE (lhs), rhs);
928 if (!update_call_from_tree (gsi, rhs))
929 gimplify_and_update_call_from_tree (gsi, rhs);
930 stmt = gsi_stmt (*gsi);
931 update_stmt (stmt);
932 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
934 fprintf (dump_file, "into: ");
935 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
937 if (si != NULL
938 && TREE_CODE (si->length) != SSA_NAME
939 && TREE_CODE (si->length) != INTEGER_CST
940 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
942 si = unshare_strinfo (si);
943 si->length = lhs;
945 return;
948 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
949 return;
950 if (idx == 0)
951 idx = new_stridx (src);
952 else if (get_strinfo (idx) != NULL)
953 return;
954 if (idx)
956 strinfo si = new_strinfo (src, idx, lhs);
957 set_strinfo (idx, si);
958 find_equal_ptrs (src, idx);
962 /* Handle a strchr call. If strlen of the first argument is known, replace
963 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
964 that lhs of the call is endptr and strlen of the argument is endptr - x. */
966 static void
967 handle_builtin_strchr (gimple_stmt_iterator *gsi)
969 int idx;
970 tree src;
971 gimple stmt = gsi_stmt (*gsi);
972 tree lhs = gimple_call_lhs (stmt);
974 if (lhs == NULL_TREE)
975 return;
977 if (!integer_zerop (gimple_call_arg (stmt, 1)))
978 return;
980 src = gimple_call_arg (stmt, 0);
981 idx = get_stridx (src);
982 if (idx)
984 strinfo si = NULL;
985 tree rhs;
987 if (idx < 0)
988 rhs = build_int_cst (size_type_node, ~idx);
989 else
991 rhs = NULL_TREE;
992 si = get_strinfo (idx);
993 if (si != NULL)
994 rhs = get_string_length (si);
996 if (rhs != NULL_TREE)
998 location_t loc = gimple_location (stmt);
1000 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1002 fprintf (dump_file, "Optimizing: ");
1003 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1005 if (si != NULL && si->endptr != NULL_TREE)
1007 rhs = unshare_expr (si->endptr);
1008 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1009 TREE_TYPE (rhs)))
1010 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1012 else
1014 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1015 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1016 TREE_TYPE (src), src, rhs);
1017 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1018 TREE_TYPE (rhs)))
1019 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1021 if (!update_call_from_tree (gsi, rhs))
1022 gimplify_and_update_call_from_tree (gsi, rhs);
1023 stmt = gsi_stmt (*gsi);
1024 update_stmt (stmt);
1025 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1027 fprintf (dump_file, "into: ");
1028 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1030 if (si != NULL
1031 && si->endptr == NULL_TREE
1032 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1034 si = unshare_strinfo (si);
1035 si->endptr = lhs;
1037 zero_length_string (lhs, si);
1038 return;
1041 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1042 return;
1043 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1045 if (idx == 0)
1046 idx = new_stridx (src);
1047 else if (get_strinfo (idx) != NULL)
1049 zero_length_string (lhs, NULL);
1050 return;
1052 if (idx)
1054 location_t loc = gimple_location (stmt);
1055 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1056 tree srcu = fold_convert_loc (loc, size_type_node, src);
1057 tree length = fold_build2_loc (loc, MINUS_EXPR,
1058 size_type_node, lhsu, srcu);
1059 strinfo si = new_strinfo (src, idx, length);
1060 si->endptr = lhs;
1061 set_strinfo (idx, si);
1062 find_equal_ptrs (src, idx);
1063 zero_length_string (lhs, si);
1066 else
1067 zero_length_string (lhs, NULL);
1070 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1071 If strlen of the second argument is known, strlen of the first argument
1072 is the same after this call. Furthermore, attempt to convert it to
1073 memcpy. */
1075 static void
1076 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1078 int idx, didx;
1079 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1080 bool success;
1081 gimple stmt = gsi_stmt (*gsi);
1082 strinfo si, dsi, olddsi, zsi;
1083 location_t loc;
1085 src = gimple_call_arg (stmt, 1);
1086 dst = gimple_call_arg (stmt, 0);
1087 lhs = gimple_call_lhs (stmt);
1088 idx = get_stridx (src);
1089 si = NULL;
1090 if (idx > 0)
1091 si = get_strinfo (idx);
1093 didx = get_stridx (dst);
1094 olddsi = NULL;
1095 oldlen = NULL_TREE;
1096 if (didx > 0)
1097 olddsi = get_strinfo (didx);
1098 else if (didx < 0)
1099 return;
1101 if (olddsi != NULL)
1102 adjust_last_stmt (olddsi, stmt, false);
1104 srclen = NULL_TREE;
1105 if (si != NULL)
1106 srclen = get_string_length (si);
1107 else if (idx < 0)
1108 srclen = build_int_cst (size_type_node, ~idx);
1110 loc = gimple_location (stmt);
1111 if (srclen == NULL_TREE)
1112 switch (bcode)
1114 case BUILT_IN_STRCPY:
1115 case BUILT_IN_STRCPY_CHK:
1116 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1117 return;
1118 break;
1119 case BUILT_IN_STPCPY:
1120 case BUILT_IN_STPCPY_CHK:
1121 if (lhs == NULL_TREE)
1122 return;
1123 else
1125 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1126 srclen = fold_convert_loc (loc, size_type_node, dst);
1127 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1128 lhsuint, srclen);
1130 break;
1131 default:
1132 gcc_unreachable ();
1135 if (didx == 0)
1137 didx = new_stridx (dst);
1138 if (didx == 0)
1139 return;
1141 if (olddsi != NULL)
1143 oldlen = olddsi->length;
1144 dsi = unshare_strinfo (olddsi);
1145 dsi->length = srclen;
1146 /* Break the chain, so adjust_related_strinfo on later pointers in
1147 the chain won't adjust this one anymore. */
1148 dsi->next = 0;
1149 dsi->stmt = NULL;
1150 dsi->endptr = NULL_TREE;
1152 else
1154 dsi = new_strinfo (dst, didx, srclen);
1155 set_strinfo (didx, dsi);
1156 find_equal_ptrs (dst, didx);
1158 dsi->writable = true;
1159 dsi->dont_invalidate = true;
1161 if (dsi->length == NULL_TREE)
1163 strinfo chainsi;
1165 /* If string length of src is unknown, use delayed length
1166 computation. If string lenth of dst will be needed, it
1167 can be computed by transforming this strcpy call into
1168 stpcpy and subtracting dst from the return value. */
1170 /* Look for earlier strings whose length could be determined if
1171 this strcpy is turned into an stpcpy. */
1173 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1175 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1177 /* When setting a stmt for delayed length computation
1178 prevent all strinfos through dsi from being
1179 invalidated. */
1180 chainsi = unshare_strinfo (chainsi);
1181 chainsi->stmt = stmt;
1182 chainsi->length = NULL_TREE;
1183 chainsi->endptr = NULL_TREE;
1184 chainsi->dont_invalidate = true;
1187 dsi->stmt = stmt;
1188 return;
1191 if (olddsi != NULL)
1193 tree adj = NULL_TREE;
1194 if (oldlen == NULL_TREE)
1196 else if (integer_zerop (oldlen))
1197 adj = srclen;
1198 else if (TREE_CODE (oldlen) == INTEGER_CST
1199 || TREE_CODE (srclen) == INTEGER_CST)
1200 adj = fold_build2_loc (loc, MINUS_EXPR,
1201 TREE_TYPE (srclen), srclen,
1202 fold_convert_loc (loc, TREE_TYPE (srclen),
1203 oldlen));
1204 if (adj != NULL_TREE)
1205 adjust_related_strinfos (loc, dsi, adj);
1206 else
1207 dsi->prev = 0;
1209 /* strcpy src may not overlap dst, so src doesn't need to be
1210 invalidated either. */
1211 if (si != NULL)
1212 si->dont_invalidate = true;
1214 fn = NULL_TREE;
1215 zsi = NULL;
1216 switch (bcode)
1218 case BUILT_IN_STRCPY:
1219 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1220 if (lhs)
1221 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1222 break;
1223 case BUILT_IN_STRCPY_CHK:
1224 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1225 if (lhs)
1226 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1227 break;
1228 case BUILT_IN_STPCPY:
1229 /* This would need adjustment of the lhs (subtract one),
1230 or detection that the trailing '\0' doesn't need to be
1231 written, if it will be immediately overwritten.
1232 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1233 if (lhs)
1235 dsi->endptr = lhs;
1236 zsi = zero_length_string (lhs, dsi);
1238 break;
1239 case BUILT_IN_STPCPY_CHK:
1240 /* This would need adjustment of the lhs (subtract one),
1241 or detection that the trailing '\0' doesn't need to be
1242 written, if it will be immediately overwritten.
1243 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1244 if (lhs)
1246 dsi->endptr = lhs;
1247 zsi = zero_length_string (lhs, dsi);
1249 break;
1250 default:
1251 gcc_unreachable ();
1253 if (zsi != NULL)
1254 zsi->dont_invalidate = true;
1256 if (fn == NULL_TREE)
1257 return;
1259 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1260 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1262 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1263 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1264 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1265 GSI_SAME_STMT);
1266 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1268 fprintf (dump_file, "Optimizing: ");
1269 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1271 if (gimple_call_num_args (stmt) == 2)
1272 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1273 else
1274 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1275 gimple_call_arg (stmt, 2));
1276 if (success)
1278 stmt = gsi_stmt (*gsi);
1279 update_stmt (stmt);
1280 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1282 fprintf (dump_file, "into: ");
1283 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1285 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1286 laststmt.stmt = stmt;
1287 laststmt.len = srclen;
1288 laststmt.stridx = dsi->idx;
1290 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1291 fprintf (dump_file, "not possible.\n");
1294 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1295 If strlen of the second argument is known and length of the third argument
1296 is that plus one, strlen of the first argument is the same after this
1297 call. */
1299 static void
1300 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1302 int idx, didx;
1303 tree src, dst, len, lhs, oldlen, newlen;
1304 gimple stmt = gsi_stmt (*gsi);
1305 strinfo si, dsi, olddsi;
1307 len = gimple_call_arg (stmt, 2);
1308 src = gimple_call_arg (stmt, 1);
1309 dst = gimple_call_arg (stmt, 0);
1310 idx = get_stridx (src);
1311 if (idx == 0)
1312 return;
1314 didx = get_stridx (dst);
1315 olddsi = NULL;
1316 if (didx > 0)
1317 olddsi = get_strinfo (didx);
1318 else if (didx < 0)
1319 return;
1321 if (olddsi != NULL
1322 && tree_fits_uhwi_p (len)
1323 && !integer_zerop (len))
1324 adjust_last_stmt (olddsi, stmt, false);
1326 if (idx > 0)
1328 gimple def_stmt;
1330 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1331 si = get_strinfo (idx);
1332 if (si == NULL || si->length == NULL_TREE)
1333 return;
1334 if (TREE_CODE (len) != SSA_NAME)
1335 return;
1336 def_stmt = SSA_NAME_DEF_STMT (len);
1337 if (!is_gimple_assign (def_stmt)
1338 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1339 || gimple_assign_rhs1 (def_stmt) != si->length
1340 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1341 return;
1343 else
1345 si = NULL;
1346 /* Handle memcpy (x, "abcd", 5) or
1347 memcpy (x, "abc\0uvw", 7). */
1348 if (!tree_fits_uhwi_p (len)
1349 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1350 return;
1353 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1354 adjust_last_stmt (olddsi, stmt, false);
1356 if (didx == 0)
1358 didx = new_stridx (dst);
1359 if (didx == 0)
1360 return;
1362 if (si != NULL)
1363 newlen = si->length;
1364 else
1365 newlen = build_int_cst (size_type_node, ~idx);
1366 oldlen = NULL_TREE;
1367 if (olddsi != NULL)
1369 dsi = unshare_strinfo (olddsi);
1370 oldlen = olddsi->length;
1371 dsi->length = newlen;
1372 /* Break the chain, so adjust_related_strinfo on later pointers in
1373 the chain won't adjust this one anymore. */
1374 dsi->next = 0;
1375 dsi->stmt = NULL;
1376 dsi->endptr = NULL_TREE;
1378 else
1380 dsi = new_strinfo (dst, didx, newlen);
1381 set_strinfo (didx, dsi);
1382 find_equal_ptrs (dst, didx);
1384 dsi->writable = true;
1385 dsi->dont_invalidate = true;
1386 if (olddsi != NULL)
1388 tree adj = NULL_TREE;
1389 location_t loc = gimple_location (stmt);
1390 if (oldlen == NULL_TREE)
1392 else if (integer_zerop (oldlen))
1393 adj = dsi->length;
1394 else if (TREE_CODE (oldlen) == INTEGER_CST
1395 || TREE_CODE (dsi->length) == INTEGER_CST)
1396 adj = fold_build2_loc (loc, MINUS_EXPR,
1397 TREE_TYPE (dsi->length), dsi->length,
1398 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1399 oldlen));
1400 if (adj != NULL_TREE)
1401 adjust_related_strinfos (loc, dsi, adj);
1402 else
1403 dsi->prev = 0;
1405 /* memcpy src may not overlap dst, so src doesn't need to be
1406 invalidated either. */
1407 if (si != NULL)
1408 si->dont_invalidate = true;
1410 lhs = gimple_call_lhs (stmt);
1411 switch (bcode)
1413 case BUILT_IN_MEMCPY:
1414 case BUILT_IN_MEMCPY_CHK:
1415 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1416 laststmt.stmt = stmt;
1417 laststmt.len = dsi->length;
1418 laststmt.stridx = dsi->idx;
1419 if (lhs)
1420 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1421 break;
1422 case BUILT_IN_MEMPCPY:
1423 case BUILT_IN_MEMPCPY_CHK:
1424 break;
1425 default:
1426 gcc_unreachable ();
1430 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1431 If strlen of the second argument is known, strlen of the first argument
1432 is increased by the length of the second argument. Furthermore, attempt
1433 to convert it to memcpy/strcpy if the length of the first argument
1434 is known. */
1436 static void
1437 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1439 int idx, didx;
1440 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1441 bool success;
1442 gimple stmt = gsi_stmt (*gsi);
1443 strinfo si, dsi;
1444 location_t loc;
1446 src = gimple_call_arg (stmt, 1);
1447 dst = gimple_call_arg (stmt, 0);
1448 lhs = gimple_call_lhs (stmt);
1450 didx = get_stridx (dst);
1451 if (didx < 0)
1452 return;
1454 dsi = NULL;
1455 if (didx > 0)
1456 dsi = get_strinfo (didx);
1457 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1459 /* strcat (p, q) can be transformed into
1460 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1461 with length endptr - p if we need to compute the length
1462 later on. Don't do this transformation if we don't need
1463 it. */
1464 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1466 if (didx == 0)
1468 didx = new_stridx (dst);
1469 if (didx == 0)
1470 return;
1472 if (dsi == NULL)
1474 dsi = new_strinfo (dst, didx, NULL_TREE);
1475 set_strinfo (didx, dsi);
1476 find_equal_ptrs (dst, didx);
1478 else
1480 dsi = unshare_strinfo (dsi);
1481 dsi->length = NULL_TREE;
1482 dsi->next = 0;
1483 dsi->endptr = NULL_TREE;
1485 dsi->writable = true;
1486 dsi->stmt = stmt;
1487 dsi->dont_invalidate = true;
1489 return;
1492 srclen = NULL_TREE;
1493 si = NULL;
1494 idx = get_stridx (src);
1495 if (idx < 0)
1496 srclen = build_int_cst (size_type_node, ~idx);
1497 else if (idx > 0)
1499 si = get_strinfo (idx);
1500 if (si != NULL)
1501 srclen = get_string_length (si);
1504 loc = gimple_location (stmt);
1505 dstlen = dsi->length;
1506 endptr = dsi->endptr;
1508 dsi = unshare_strinfo (dsi);
1509 dsi->endptr = NULL_TREE;
1510 dsi->stmt = NULL;
1511 dsi->writable = true;
1513 if (srclen != NULL_TREE)
1515 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1516 dsi->length, srclen);
1517 adjust_related_strinfos (loc, dsi, srclen);
1518 dsi->dont_invalidate = true;
1520 else
1522 dsi->length = NULL;
1523 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1524 dsi->dont_invalidate = true;
1527 if (si != NULL)
1528 /* strcat src may not overlap dst, so src doesn't need to be
1529 invalidated either. */
1530 si->dont_invalidate = true;
1532 /* For now. Could remove the lhs from the call and add
1533 lhs = dst; afterwards. */
1534 if (lhs)
1535 return;
1537 fn = NULL_TREE;
1538 objsz = NULL_TREE;
1539 switch (bcode)
1541 case BUILT_IN_STRCAT:
1542 if (srclen != NULL_TREE)
1543 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1544 else
1545 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1546 break;
1547 case BUILT_IN_STRCAT_CHK:
1548 if (srclen != NULL_TREE)
1549 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1550 else
1551 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1552 objsz = gimple_call_arg (stmt, 2);
1553 break;
1554 default:
1555 gcc_unreachable ();
1558 if (fn == NULL_TREE)
1559 return;
1561 len = NULL_TREE;
1562 if (srclen != NULL_TREE)
1564 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1565 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1567 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1568 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1569 build_int_cst (type, 1));
1570 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1571 GSI_SAME_STMT);
1573 if (endptr)
1574 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1575 else
1576 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1577 TREE_TYPE (dst), unshare_expr (dst),
1578 fold_convert_loc (loc, sizetype,
1579 unshare_expr (dstlen)));
1580 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1581 GSI_SAME_STMT);
1582 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1584 fprintf (dump_file, "Optimizing: ");
1585 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1587 if (srclen != NULL_TREE)
1588 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1589 dst, src, len, objsz);
1590 else
1591 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1592 dst, src, objsz);
1593 if (success)
1595 stmt = gsi_stmt (*gsi);
1596 update_stmt (stmt);
1597 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1599 fprintf (dump_file, "into: ");
1600 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1602 /* If srclen == NULL, note that current string length can be
1603 computed by transforming this strcpy into stpcpy. */
1604 if (srclen == NULL_TREE && dsi->dont_invalidate)
1605 dsi->stmt = stmt;
1606 adjust_last_stmt (dsi, stmt, true);
1607 if (srclen != NULL_TREE)
1609 laststmt.stmt = stmt;
1610 laststmt.len = srclen;
1611 laststmt.stridx = dsi->idx;
1614 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1615 fprintf (dump_file, "not possible.\n");
1618 /* Handle a POINTER_PLUS_EXPR statement.
1619 For p = "abcd" + 2; compute associated length, or if
1620 p = q + off is pointing to a '\0' character of a string, call
1621 zero_length_string on it. */
1623 static void
1624 handle_pointer_plus (gimple_stmt_iterator *gsi)
1626 gimple stmt = gsi_stmt (*gsi);
1627 tree lhs = gimple_assign_lhs (stmt), off;
1628 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1629 strinfo si, zsi;
1631 if (idx == 0)
1632 return;
1634 if (idx < 0)
1636 tree off = gimple_assign_rhs2 (stmt);
1637 if (tree_fits_uhwi_p (off)
1638 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1639 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1640 = ~(~idx - (int) tree_to_uhwi (off));
1641 return;
1644 si = get_strinfo (idx);
1645 if (si == NULL || si->length == NULL_TREE)
1646 return;
1648 off = gimple_assign_rhs2 (stmt);
1649 zsi = NULL;
1650 if (operand_equal_p (si->length, off, 0))
1651 zsi = zero_length_string (lhs, si);
1652 else if (TREE_CODE (off) == SSA_NAME)
1654 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1655 if (gimple_assign_single_p (def_stmt)
1656 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1657 zsi = zero_length_string (lhs, si);
1659 if (zsi != NULL
1660 && si->endptr != NULL_TREE
1661 && si->endptr != lhs
1662 && TREE_CODE (si->endptr) == SSA_NAME)
1664 enum tree_code rhs_code
1665 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1666 ? SSA_NAME : NOP_EXPR;
1667 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr, NULL_TREE);
1668 gcc_assert (gsi_stmt (*gsi) == stmt);
1669 update_stmt (stmt);
1673 /* Handle a single character store. */
1675 static bool
1676 handle_char_store (gimple_stmt_iterator *gsi)
1678 int idx = -1;
1679 strinfo si = NULL;
1680 gimple stmt = gsi_stmt (*gsi);
1681 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1683 if (TREE_CODE (lhs) == MEM_REF
1684 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1686 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1688 ssaname = TREE_OPERAND (lhs, 0);
1689 idx = get_stridx (ssaname);
1692 else
1693 idx = get_addr_stridx (lhs);
1695 if (idx > 0)
1697 si = get_strinfo (idx);
1698 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1700 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1702 /* When storing '\0', the store can be removed
1703 if we know it has been stored in the current function. */
1704 if (!stmt_could_throw_p (stmt) && si->writable)
1706 unlink_stmt_vdef (stmt);
1707 release_defs (stmt);
1708 gsi_remove (gsi, true);
1709 return false;
1711 else
1713 si->writable = true;
1714 gsi_next (gsi);
1715 return false;
1718 else
1719 /* Otherwise this statement overwrites the '\0' with
1720 something, if the previous stmt was a memcpy,
1721 its length may be decreased. */
1722 adjust_last_stmt (si, stmt, false);
1724 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1726 si = unshare_strinfo (si);
1727 si->length = build_int_cst (size_type_node, 0);
1728 si->endptr = NULL;
1729 si->prev = 0;
1730 si->next = 0;
1731 si->stmt = NULL;
1732 si->first = 0;
1733 si->writable = true;
1734 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1735 si->endptr = ssaname;
1736 si->dont_invalidate = true;
1738 /* If si->length is non-zero constant, we aren't overwriting '\0',
1739 and if we aren't storing '\0', we know that the length of the
1740 string and any other zero terminated string in memory remains
1741 the same. In that case we move to the next gimple statement and
1742 return to signal the caller that it shouldn't invalidate anything.
1744 This is benefical for cases like:
1746 char p[20];
1747 void foo (char *q)
1749 strcpy (p, "foobar");
1750 size_t len = strlen (p); // This can be optimized into 6
1751 size_t len2 = strlen (q); // This has to be computed
1752 p[0] = 'X';
1753 size_t len3 = strlen (p); // This can be optimized into 6
1754 size_t len4 = strlen (q); // This can be optimized into len2
1755 bar (len, len2, len3, len4);
1758 else if (si != NULL && si->length != NULL_TREE
1759 && TREE_CODE (si->length) == INTEGER_CST
1760 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
1762 gsi_next (gsi);
1763 return false;
1766 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
1768 if (ssaname)
1770 si = zero_length_string (ssaname, NULL);
1771 if (si != NULL)
1772 si->dont_invalidate = true;
1774 else
1776 int idx = new_addr_stridx (lhs);
1777 if (idx != 0)
1779 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1780 build_int_cst (size_type_node, 0));
1781 set_strinfo (idx, si);
1782 si->dont_invalidate = true;
1785 if (si != NULL)
1786 si->writable = true;
1788 else if (idx == 0
1789 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
1790 && ssaname == NULL_TREE
1791 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
1793 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
1794 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
1795 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
1797 int idx = new_addr_stridx (lhs);
1798 if (idx != 0)
1800 si = new_strinfo (build_fold_addr_expr (lhs), idx,
1801 build_int_cst (size_type_node, l));
1802 set_strinfo (idx, si);
1803 si->dont_invalidate = true;
1808 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
1810 /* Allow adjust_last_stmt to remove it if the stored '\0'
1811 is immediately overwritten. */
1812 laststmt.stmt = stmt;
1813 laststmt.len = build_int_cst (size_type_node, 1);
1814 laststmt.stridx = si->idx;
1816 return true;
1819 /* Attempt to optimize a single statement at *GSI using string length
1820 knowledge. */
1822 static bool
1823 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
1825 gimple stmt = gsi_stmt (*gsi);
1827 if (is_gimple_call (stmt))
1829 tree callee = gimple_call_fndecl (stmt);
1830 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
1831 switch (DECL_FUNCTION_CODE (callee))
1833 case BUILT_IN_STRLEN:
1834 handle_builtin_strlen (gsi);
1835 break;
1836 case BUILT_IN_STRCHR:
1837 handle_builtin_strchr (gsi);
1838 break;
1839 case BUILT_IN_STRCPY:
1840 case BUILT_IN_STRCPY_CHK:
1841 case BUILT_IN_STPCPY:
1842 case BUILT_IN_STPCPY_CHK:
1843 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
1844 break;
1845 case BUILT_IN_MEMCPY:
1846 case BUILT_IN_MEMCPY_CHK:
1847 case BUILT_IN_MEMPCPY:
1848 case BUILT_IN_MEMPCPY_CHK:
1849 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
1850 break;
1851 case BUILT_IN_STRCAT:
1852 case BUILT_IN_STRCAT_CHK:
1853 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
1854 break;
1855 default:
1856 break;
1859 else if (is_gimple_assign (stmt))
1861 tree lhs = gimple_assign_lhs (stmt);
1863 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
1865 if (gimple_assign_single_p (stmt)
1866 || (gimple_assign_cast_p (stmt)
1867 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
1869 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1870 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
1872 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1873 handle_pointer_plus (gsi);
1875 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
1877 tree type = TREE_TYPE (lhs);
1878 if (TREE_CODE (type) == ARRAY_TYPE)
1879 type = TREE_TYPE (type);
1880 if (TREE_CODE (type) == INTEGER_TYPE
1881 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
1882 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
1884 if (! handle_char_store (gsi))
1885 return false;
1890 if (gimple_vdef (stmt))
1891 maybe_invalidate (stmt);
1892 return true;
1895 /* Recursively call maybe_invalidate on stmts that might be executed
1896 in between dombb and current bb and that contain a vdef. Stop when
1897 *count stmts are inspected, or if the whole strinfo vector has
1898 been invalidated. */
1900 static void
1901 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
1903 unsigned int i, n = gimple_phi_num_args (phi);
1905 for (i = 0; i < n; i++)
1907 tree vuse = gimple_phi_arg_def (phi, i);
1908 gimple stmt = SSA_NAME_DEF_STMT (vuse);
1909 basic_block bb = gimple_bb (stmt);
1910 if (bb == NULL
1911 || bb == dombb
1912 || !bitmap_set_bit (visited, bb->index)
1913 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1914 continue;
1915 while (1)
1917 if (gimple_code (stmt) == GIMPLE_PHI)
1919 do_invalidate (dombb, stmt, visited, count);
1920 if (*count == 0)
1921 return;
1922 break;
1924 if (--*count == 0)
1925 return;
1926 if (!maybe_invalidate (stmt))
1928 *count = 0;
1929 return;
1931 vuse = gimple_vuse (stmt);
1932 stmt = SSA_NAME_DEF_STMT (vuse);
1933 if (gimple_bb (stmt) != bb)
1935 bb = gimple_bb (stmt);
1936 if (bb == NULL
1937 || bb == dombb
1938 || !bitmap_set_bit (visited, bb->index)
1939 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
1940 break;
1946 class strlen_dom_walker : public dom_walker
1948 public:
1949 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
1951 virtual void before_dom_children (basic_block);
1952 virtual void after_dom_children (basic_block);
1955 /* Callback for walk_dominator_tree. Attempt to optimize various
1956 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1958 void
1959 strlen_dom_walker::before_dom_children (basic_block bb)
1961 gimple_stmt_iterator gsi;
1962 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
1964 if (dombb == NULL)
1965 stridx_to_strinfo = NULL;
1966 else
1968 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) dombb->aux);
1969 if (stridx_to_strinfo)
1971 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1973 gimple phi = gsi_stmt (gsi);
1974 if (virtual_operand_p (gimple_phi_result (phi)))
1976 bitmap visited = BITMAP_ALLOC (NULL);
1977 int count_vdef = 100;
1978 do_invalidate (dombb, phi, visited, &count_vdef);
1979 BITMAP_FREE (visited);
1980 if (count_vdef == 0)
1982 /* If there were too many vdefs in between immediate
1983 dominator and current bb, invalidate everything.
1984 If stridx_to_strinfo has been unshared, we need
1985 to free it, otherwise just set it to NULL. */
1986 if (!strinfo_shared ())
1988 unsigned int i;
1989 strinfo si;
1991 for (i = 1;
1992 vec_safe_iterate (stridx_to_strinfo, i, &si);
1993 ++i)
1995 free_strinfo (si);
1996 (*stridx_to_strinfo)[i] = NULL;
1999 else
2000 stridx_to_strinfo = NULL;
2002 break;
2008 /* If all PHI arguments have the same string index, the PHI result
2009 has it as well. */
2010 for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2012 gimple phi = gsi_stmt (gsi);
2013 tree result = gimple_phi_result (phi);
2014 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2016 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2017 if (idx != 0)
2019 unsigned int i, n = gimple_phi_num_args (phi);
2020 for (i = 1; i < n; i++)
2021 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2022 break;
2023 if (i == n)
2024 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2029 /* Attempt to optimize individual statements. */
2030 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2031 if (strlen_optimize_stmt (&gsi))
2032 gsi_next (&gsi);
2034 bb->aux = stridx_to_strinfo;
2035 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2036 (*stridx_to_strinfo)[0] = (strinfo) bb;
2039 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2040 owned by the current bb, clear bb->aux. */
2042 void
2043 strlen_dom_walker::after_dom_children (basic_block bb)
2045 if (bb->aux)
2047 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux);
2048 if (vec_safe_length (stridx_to_strinfo)
2049 && (*stridx_to_strinfo)[0] == (strinfo) bb)
2051 unsigned int i;
2052 strinfo si;
2054 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2055 free_strinfo (si);
2056 vec_free (stridx_to_strinfo);
2058 bb->aux = NULL;
2062 /* Main entry point. */
2064 namespace {
2066 const pass_data pass_data_strlen =
2068 GIMPLE_PASS, /* type */
2069 "strlen", /* name */
2070 OPTGROUP_NONE, /* optinfo_flags */
2071 true, /* has_execute */
2072 TV_TREE_STRLEN, /* tv_id */
2073 ( PROP_cfg | PROP_ssa ), /* properties_required */
2074 0, /* properties_provided */
2075 0, /* properties_destroyed */
2076 0, /* todo_flags_start */
2077 0, /* todo_flags_finish */
2080 class pass_strlen : public gimple_opt_pass
2082 public:
2083 pass_strlen (gcc::context *ctxt)
2084 : gimple_opt_pass (pass_data_strlen, ctxt)
2087 /* opt_pass methods: */
2088 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2089 virtual unsigned int execute (function *);
2091 }; // class pass_strlen
2093 unsigned int
2094 pass_strlen::execute (function *fun)
2096 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2097 max_stridx = 1;
2098 strinfo_pool = create_alloc_pool ("strinfo_struct pool",
2099 sizeof (struct strinfo_struct), 64);
2101 calculate_dominance_info (CDI_DOMINATORS);
2103 /* String length optimization is implemented as a walk of the dominator
2104 tree and a forward walk of statements within each block. */
2105 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2107 ssa_ver_to_stridx.release ();
2108 free_alloc_pool (strinfo_pool);
2109 if (decl_to_stridxlist_htab.is_created ())
2111 obstack_free (&stridx_obstack, NULL);
2112 decl_to_stridxlist_htab.dispose ();
2114 laststmt.stmt = NULL;
2115 laststmt.len = NULL_TREE;
2116 laststmt.stridx = 0;
2118 return 0;
2121 } // anon namespace
2123 gimple_opt_pass *
2124 make_pass_strlen (gcc::context *ctxt)
2126 return new pass_strlen (ctxt);