2015-01-14 Sandra Loosemore <sandra@codesourcery.com>
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob11b9c7db0a3c3ba561b542c65445d74008ea96d2
1 /* String length optimization
2 Copyright (C) 2011-2015 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "hash-set.h"
25 #include "machmode.h"
26 #include "vec.h"
27 #include "double-int.h"
28 #include "input.h"
29 #include "alias.h"
30 #include "symtab.h"
31 #include "options.h"
32 #include "wide-int.h"
33 #include "inchash.h"
34 #include "tree.h"
35 #include "fold-const.h"
36 #include "stor-layout.h"
37 #include "hash-table.h"
38 #include "hash-map.h"
39 #include "bitmap.h"
40 #include "predict.h"
41 #include "tm.h"
42 #include "hard-reg-set.h"
43 #include "input.h"
44 #include "function.h"
45 #include "dominance.h"
46 #include "cfg.h"
47 #include "basic-block.h"
48 #include "tree-ssa-alias.h"
49 #include "internal-fn.h"
50 #include "gimple-fold.h"
51 #include "tree-eh.h"
52 #include "gimple-expr.h"
53 #include "is-a.h"
54 #include "gimple.h"
55 #include "gimplify.h"
56 #include "gimple-iterator.h"
57 #include "gimplify-me.h"
58 #include "gimple-ssa.h"
59 #include "tree-phinodes.h"
60 #include "ssa-iterators.h"
61 #include "stringpool.h"
62 #include "tree-ssanames.h"
63 #include "expr.h"
64 #include "tree-dfa.h"
65 #include "tree-pass.h"
66 #include "domwalk.h"
67 #include "alloc-pool.h"
68 #include "tree-ssa-propagate.h"
69 #include "gimple-pretty-print.h"
70 #include "params.h"
71 #include "expr.h"
72 #include "plugin-api.h"
73 #include "ipa-ref.h"
74 #include "cgraph.h"
75 #include "ipa-chkp.h"
77 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
78 is an index into strinfo vector, negative value stands for
79 string length of a string literal (~strlen). */
80 static vec<int> ssa_ver_to_stridx;
82 /* Number of currently active string indexes plus one. */
83 static int max_stridx;
85 /* String information record. */
86 typedef struct strinfo_struct
88 /* String length of this string. */
89 tree length;
90 /* Any of the corresponding pointers for querying alias oracle. */
91 tree ptr;
92 /* Statement for delayed length computation. */
93 gimple stmt;
94 /* Pointer to '\0' if known, if NULL, it can be computed as
95 ptr + length. */
96 tree endptr;
97 /* Reference count. Any changes to strinfo entry possibly shared
98 with dominating basic blocks need unshare_strinfo first, except
99 for dont_invalidate which affects only the immediately next
100 maybe_invalidate. */
101 int refcount;
102 /* Copy of index. get_strinfo (si->idx) should return si; */
103 int idx;
104 /* These 3 fields are for chaining related string pointers together.
105 E.g. for
106 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
107 strcpy (c, d); e = c + dl;
108 strinfo(a) -> strinfo(c) -> strinfo(e)
109 All have ->first field equal to strinfo(a)->idx and are doubly
110 chained through prev/next fields. The later strinfos are required
111 to point into the same string with zero or more bytes after
112 the previous pointer and all bytes in between the two pointers
113 must be non-zero. Functions like strcpy or memcpy are supposed
114 to adjust all previous strinfo lengths, but not following strinfo
115 lengths (those are uncertain, usually invalidated during
116 maybe_invalidate, except when the alias oracle knows better).
117 Functions like strcat on the other side adjust the whole
118 related strinfo chain.
119 They are updated lazily, so to use the chain the same first fields
120 and si->prev->next == si->idx needs to be verified. */
121 int first;
122 int next;
123 int prev;
124 /* A flag whether the string is known to be written in the current
125 function. */
126 bool writable;
127 /* A flag for the next maybe_invalidate that this strinfo shouldn't
128 be invalidated. Always cleared by maybe_invalidate. */
129 bool dont_invalidate;
130 } *strinfo;
132 /* Pool for allocating strinfo_struct entries. */
133 static alloc_pool strinfo_pool;
135 /* Vector mapping positive string indexes to strinfo, for the
136 current basic block. The first pointer in the vector is special,
137 it is either NULL, meaning the vector isn't shared, or it is
138 a basic block pointer to the owner basic_block if shared.
139 If some other bb wants to modify the vector, the vector needs
140 to be unshared first, and only the owner bb is supposed to free it. */
141 static vec<strinfo, va_heap, vl_embed> *stridx_to_strinfo;
143 /* One OFFSET->IDX mapping. */
144 struct stridxlist
146 struct stridxlist *next;
147 HOST_WIDE_INT offset;
148 int idx;
151 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
152 struct decl_stridxlist_map
154 struct tree_map_base base;
155 struct stridxlist list;
158 /* stridxlist hashtable helpers. */
160 struct stridxlist_hash_traits : default_hashmap_traits
162 static inline hashval_t hash (tree);
165 /* Hash a from tree in a decl_stridxlist_map. */
167 inline hashval_t
168 stridxlist_hash_traits::hash (tree item)
170 return DECL_UID (item);
173 /* Hash table for mapping decls to a chained list of offset -> idx
174 mappings. */
175 static hash_map<tree, stridxlist, stridxlist_hash_traits>
176 *decl_to_stridxlist_htab;
178 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
179 static struct obstack stridx_obstack;
181 /* Last memcpy statement if it could be adjusted if the trailing
182 '\0' written is immediately overwritten, or
183 *x = '\0' store that could be removed if it is immediately overwritten. */
184 struct laststmt_struct
186 gimple stmt;
187 tree len;
188 int stridx;
189 } laststmt;
191 static int get_stridx_plus_constant (strinfo, HOST_WIDE_INT, tree);
193 /* Return strinfo vector entry IDX. */
195 static inline strinfo
196 get_strinfo (int idx)
198 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
199 return NULL;
200 return (*stridx_to_strinfo)[idx];
203 /* Helper function for get_stridx. */
205 static int
206 get_addr_stridx (tree exp)
208 HOST_WIDE_INT off;
209 struct stridxlist *list;
210 tree base;
212 if (!decl_to_stridxlist_htab)
213 return 0;
215 base = get_addr_base_and_unit_offset (exp, &off);
216 if (base == NULL || !DECL_P (base))
217 return 0;
219 list = decl_to_stridxlist_htab->get (base);
220 if (list == NULL)
221 return 0;
225 if (list->offset == off)
226 return list->idx;
227 list = list->next;
229 while (list);
230 return 0;
233 /* Return string index for EXP. */
235 static int
236 get_stridx (tree exp)
238 tree s, o;
240 if (TREE_CODE (exp) == SSA_NAME)
242 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
243 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
244 int i;
245 tree e = exp;
246 HOST_WIDE_INT off = 0;
247 for (i = 0; i < 5; i++)
249 gimple def_stmt = SSA_NAME_DEF_STMT (e);
250 if (!is_gimple_assign (def_stmt)
251 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
252 return 0;
253 tree rhs1 = gimple_assign_rhs1 (def_stmt);
254 tree rhs2 = gimple_assign_rhs2 (def_stmt);
255 if (TREE_CODE (rhs1) != SSA_NAME
256 || !tree_fits_shwi_p (rhs2))
257 return 0;
258 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
259 if (this_off < 0)
260 return 0;
261 off = (unsigned HOST_WIDE_INT) off + this_off;
262 if (off < 0)
263 return 0;
264 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
266 strinfo si
267 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
268 if (si
269 && si->length
270 && TREE_CODE (si->length) == INTEGER_CST
271 && compare_tree_int (si->length, off) != -1)
272 return get_stridx_plus_constant (si, off, exp);
274 e = rhs1;
276 return 0;
279 if (TREE_CODE (exp) == ADDR_EXPR)
281 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
282 if (idx != 0)
283 return idx;
286 s = string_constant (exp, &o);
287 if (s != NULL_TREE
288 && (o == NULL_TREE || tree_fits_shwi_p (o))
289 && TREE_STRING_LENGTH (s) > 0)
291 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
292 const char *p = TREE_STRING_POINTER (s);
293 int max = TREE_STRING_LENGTH (s) - 1;
295 if (p[max] == '\0' && offset >= 0 && offset <= max)
296 return ~(int) strlen (p + offset);
298 return 0;
301 /* Return true if strinfo vector is shared with the immediate dominator. */
303 static inline bool
304 strinfo_shared (void)
306 return vec_safe_length (stridx_to_strinfo)
307 && (*stridx_to_strinfo)[0] != NULL;
310 /* Unshare strinfo vector that is shared with the immediate dominator. */
312 static void
313 unshare_strinfo_vec (void)
315 strinfo si;
316 unsigned int i = 0;
318 gcc_assert (strinfo_shared ());
319 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
320 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
321 if (si != NULL)
322 si->refcount++;
323 (*stridx_to_strinfo)[0] = NULL;
326 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
327 Return a pointer to the location where the string index can
328 be stored (if 0) or is stored, or NULL if this can't be tracked. */
330 static int *
331 addr_stridxptr (tree exp)
333 HOST_WIDE_INT off;
335 tree base = get_addr_base_and_unit_offset (exp, &off);
336 if (base == NULL_TREE || !DECL_P (base))
337 return NULL;
339 if (!decl_to_stridxlist_htab)
341 decl_to_stridxlist_htab
342 = new hash_map<tree, stridxlist, stridxlist_hash_traits> (64);
343 gcc_obstack_init (&stridx_obstack);
346 bool existed;
347 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
348 if (existed)
350 int i;
351 for (i = 0; i < 16; i++)
353 if (list->offset == off)
354 return &list->idx;
355 if (list->next == NULL)
356 break;
358 if (i == 16)
359 return NULL;
360 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
361 list = list->next;
364 list->next = NULL;
365 list->offset = off;
366 list->idx = 0;
367 return &list->idx;
370 /* Create a new string index, or return 0 if reached limit. */
372 static int
373 new_stridx (tree exp)
375 int idx;
376 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
377 return 0;
378 if (TREE_CODE (exp) == SSA_NAME)
380 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
381 return 0;
382 idx = max_stridx++;
383 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
384 return idx;
386 if (TREE_CODE (exp) == ADDR_EXPR)
388 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
389 if (pidx != NULL)
391 gcc_assert (*pidx == 0);
392 *pidx = max_stridx++;
393 return *pidx;
396 return 0;
399 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
401 static int
402 new_addr_stridx (tree exp)
404 int *pidx;
405 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
406 return 0;
407 pidx = addr_stridxptr (exp);
408 if (pidx != NULL)
410 gcc_assert (*pidx == 0);
411 *pidx = max_stridx++;
412 return *pidx;
414 return 0;
417 /* Create a new strinfo. */
419 static strinfo
420 new_strinfo (tree ptr, int idx, tree length)
422 strinfo si = (strinfo) pool_alloc (strinfo_pool);
423 si->length = length;
424 si->ptr = ptr;
425 si->stmt = NULL;
426 si->endptr = NULL_TREE;
427 si->refcount = 1;
428 si->idx = idx;
429 si->first = 0;
430 si->prev = 0;
431 si->next = 0;
432 si->writable = false;
433 si->dont_invalidate = false;
434 return si;
437 /* Decrease strinfo refcount and free it if not referenced anymore. */
439 static inline void
440 free_strinfo (strinfo si)
442 if (si && --si->refcount == 0)
443 pool_free (strinfo_pool, si);
446 /* Set strinfo in the vector entry IDX to SI. */
448 static inline void
449 set_strinfo (int idx, strinfo si)
451 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
452 unshare_strinfo_vec ();
453 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
454 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
455 (*stridx_to_strinfo)[idx] = si;
458 /* Return string length, or NULL if it can't be computed. */
460 static tree
461 get_string_length (strinfo si)
463 if (si->length)
464 return si->length;
466 if (si->stmt)
468 gimple stmt = si->stmt, lenstmt;
469 bool with_bounds = gimple_call_with_bounds_p (stmt);
470 tree callee, lhs, fn, tem;
471 location_t loc;
472 gimple_stmt_iterator gsi;
474 gcc_assert (is_gimple_call (stmt));
475 callee = gimple_call_fndecl (stmt);
476 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
477 lhs = gimple_call_lhs (stmt);
478 /* unshare_strinfo is intentionally not called here. The (delayed)
479 transformation of strcpy or strcat into stpcpy is done at the place
480 of the former strcpy/strcat call and so can affect all the strinfos
481 with the same stmt. If they were unshared before and transformation
482 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
483 just compute the right length. */
484 switch (DECL_FUNCTION_CODE (callee))
486 case BUILT_IN_STRCAT:
487 case BUILT_IN_STRCAT_CHK:
488 case BUILT_IN_STRCAT_CHKP:
489 case BUILT_IN_STRCAT_CHK_CHKP:
490 gsi = gsi_for_stmt (stmt);
491 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
492 gcc_assert (lhs == NULL_TREE);
493 tem = unshare_expr (gimple_call_arg (stmt, 0));
494 if (with_bounds)
496 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
497 2, tem, gimple_call_arg (stmt, 1));
498 gimple_call_set_with_bounds (lenstmt, true);
500 else
501 lenstmt = gimple_build_call (fn, 1, tem);
502 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
503 gimple_call_set_lhs (lenstmt, lhs);
504 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
505 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
506 tem = gimple_call_arg (stmt, 0);
507 if (!ptrofftype_p (TREE_TYPE (lhs)))
509 lhs = convert_to_ptrofftype (lhs);
510 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
511 true, GSI_SAME_STMT);
513 lenstmt = gimple_build_assign
514 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
515 POINTER_PLUS_EXPR,tem, lhs);
516 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
517 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
518 lhs = NULL_TREE;
519 /* FALLTHRU */
520 case BUILT_IN_STRCPY:
521 case BUILT_IN_STRCPY_CHK:
522 case BUILT_IN_STRCPY_CHKP:
523 case BUILT_IN_STRCPY_CHK_CHKP:
524 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
525 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
526 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
527 else
528 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
529 if (with_bounds)
530 fn = chkp_maybe_create_clone (fn)->decl;
531 gcc_assert (lhs == NULL_TREE);
532 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
534 fprintf (dump_file, "Optimizing: ");
535 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
537 gimple_call_set_fndecl (stmt, fn);
538 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
539 gimple_call_set_lhs (stmt, lhs);
540 update_stmt (stmt);
541 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
543 fprintf (dump_file, "into: ");
544 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
546 /* FALLTHRU */
547 case BUILT_IN_STPCPY:
548 case BUILT_IN_STPCPY_CHK:
549 case BUILT_IN_STPCPY_CHKP:
550 case BUILT_IN_STPCPY_CHK_CHKP:
551 gcc_assert (lhs != NULL_TREE);
552 loc = gimple_location (stmt);
553 si->endptr = lhs;
554 si->stmt = NULL;
555 lhs = fold_convert_loc (loc, size_type_node, lhs);
556 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
557 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
558 lhs, si->length);
559 break;
560 case BUILT_IN_MALLOC:
561 break;
562 /* BUILT_IN_CALLOC always has si->length set. */
563 default:
564 gcc_unreachable ();
565 break;
569 return si->length;
572 /* Invalidate string length information for strings whose length
573 might change due to stores in stmt. */
575 static bool
576 maybe_invalidate (gimple stmt)
578 strinfo si;
579 unsigned int i;
580 bool nonempty = false;
582 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
583 if (si != NULL)
585 if (!si->dont_invalidate)
587 ao_ref r;
588 /* Do not use si->length. */
589 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
590 if (stmt_may_clobber_ref_p_1 (stmt, &r))
592 set_strinfo (i, NULL);
593 free_strinfo (si);
594 continue;
597 si->dont_invalidate = false;
598 nonempty = true;
600 return nonempty;
603 /* Unshare strinfo record SI, if it has refcount > 1 or
604 if stridx_to_strinfo vector is shared with some other
605 bbs. */
607 static strinfo
608 unshare_strinfo (strinfo si)
610 strinfo nsi;
612 if (si->refcount == 1 && !strinfo_shared ())
613 return si;
615 nsi = new_strinfo (si->ptr, si->idx, si->length);
616 nsi->stmt = si->stmt;
617 nsi->endptr = si->endptr;
618 nsi->first = si->first;
619 nsi->prev = si->prev;
620 nsi->next = si->next;
621 nsi->writable = si->writable;
622 set_strinfo (si->idx, nsi);
623 free_strinfo (si);
624 return nsi;
627 /* Return first strinfo in the related strinfo chain
628 if all strinfos in between belong to the chain, otherwise
629 NULL. */
631 static strinfo
632 verify_related_strinfos (strinfo origsi)
634 strinfo si = origsi, psi;
636 if (origsi->first == 0)
637 return NULL;
638 for (; si->prev; si = psi)
640 if (si->first != origsi->first)
641 return NULL;
642 psi = get_strinfo (si->prev);
643 if (psi == NULL)
644 return NULL;
645 if (psi->next != si->idx)
646 return NULL;
648 if (si->idx != si->first)
649 return NULL;
650 return si;
653 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
654 strinfo if there is any. Return it's idx, or 0 if no strinfo has
655 been created. */
657 static int
658 get_stridx_plus_constant (strinfo basesi, HOST_WIDE_INT off, tree ptr)
660 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
662 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
663 return 0;
665 if (basesi->length == NULL_TREE
666 || TREE_CODE (basesi->length) != INTEGER_CST
667 || compare_tree_int (basesi->length, off) == -1
668 || !tree_fits_shwi_p (basesi->length))
669 return 0;
671 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
672 strinfo si = basesi, chainsi;
673 if (si->first || si->prev || si->next)
674 si = verify_related_strinfos (basesi);
675 if (si == NULL
676 || si->length == NULL_TREE
677 || TREE_CODE (si->length) != INTEGER_CST)
678 return 0;
680 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
681 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
683 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
684 for (chainsi = si; chainsi->next; chainsi = si)
686 si = get_strinfo (chainsi->next);
687 if (si == NULL
688 || si->first != chainsi->first
689 || si->prev != chainsi->idx
690 || si->length == NULL_TREE
691 || TREE_CODE (si->length) != INTEGER_CST)
692 break;
693 int r = compare_tree_int (si->length, len);
694 if (r != 1)
696 if (r == 0)
698 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
699 return si->idx;
701 break;
705 int idx = new_stridx (ptr);
706 if (idx == 0)
707 return 0;
708 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
709 set_strinfo (idx, si);
710 if (chainsi->next)
712 strinfo nextsi = unshare_strinfo (get_strinfo (chainsi->next));
713 si->next = nextsi->idx;
714 nextsi->prev = idx;
716 chainsi = unshare_strinfo (chainsi);
717 if (chainsi->first == 0)
718 chainsi->first = chainsi->idx;
719 chainsi->next = idx;
720 if (chainsi->endptr == NULL_TREE && len == 0)
721 chainsi->endptr = ptr;
722 si->endptr = chainsi->endptr;
723 si->prev = chainsi->idx;
724 si->first = chainsi->first;
725 si->writable = chainsi->writable;
726 return si->idx;
729 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
730 to a zero-length string and if possible chain it to a related strinfo
731 chain whose part is or might be CHAINSI. */
733 static strinfo
734 zero_length_string (tree ptr, strinfo chainsi)
736 strinfo si;
737 int idx;
738 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
739 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
740 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
741 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
743 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
744 return NULL;
745 if (chainsi != NULL)
747 si = verify_related_strinfos (chainsi);
748 if (si)
750 chainsi = si;
751 for (; chainsi->next; chainsi = si)
753 if (chainsi->endptr == NULL_TREE)
755 chainsi = unshare_strinfo (chainsi);
756 chainsi->endptr = ptr;
758 si = get_strinfo (chainsi->next);
759 if (si == NULL
760 || si->first != chainsi->first
761 || si->prev != chainsi->idx)
762 break;
764 gcc_assert (chainsi->length || chainsi->stmt);
765 if (chainsi->endptr == NULL_TREE)
767 chainsi = unshare_strinfo (chainsi);
768 chainsi->endptr = ptr;
770 if (chainsi->length && integer_zerop (chainsi->length))
772 if (chainsi->next)
774 chainsi = unshare_strinfo (chainsi);
775 chainsi->next = 0;
777 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
778 return chainsi;
781 else if (chainsi->first || chainsi->prev || chainsi->next)
783 chainsi = unshare_strinfo (chainsi);
784 chainsi->first = 0;
785 chainsi->prev = 0;
786 chainsi->next = 0;
789 idx = new_stridx (ptr);
790 if (idx == 0)
791 return NULL;
792 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
793 set_strinfo (idx, si);
794 si->endptr = ptr;
795 if (chainsi != NULL)
797 chainsi = unshare_strinfo (chainsi);
798 if (chainsi->first == 0)
799 chainsi->first = chainsi->idx;
800 chainsi->next = idx;
801 if (chainsi->endptr == NULL_TREE)
802 chainsi->endptr = ptr;
803 si->prev = chainsi->idx;
804 si->first = chainsi->first;
805 si->writable = chainsi->writable;
807 return si;
810 /* For strinfo ORIGSI whose length has been just updated
811 update also related strinfo lengths (add ADJ to each,
812 but don't adjust ORIGSI). */
814 static void
815 adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
817 strinfo si = verify_related_strinfos (origsi);
819 if (si == NULL)
820 return;
822 while (1)
824 strinfo nsi;
826 if (si != origsi)
828 tree tem;
830 si = unshare_strinfo (si);
831 if (si->length)
833 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
834 si->length = fold_build2_loc (loc, PLUS_EXPR,
835 TREE_TYPE (si->length), si->length,
836 tem);
838 else if (si->stmt != NULL)
839 /* Delayed length computation is unaffected. */
841 else
842 gcc_unreachable ();
844 si->endptr = NULL_TREE;
845 si->dont_invalidate = true;
847 if (si->next == 0)
848 return;
849 nsi = get_strinfo (si->next);
850 if (nsi == NULL
851 || nsi->first != si->first
852 || nsi->prev != si->idx)
853 return;
854 si = nsi;
858 /* Find if there are other SSA_NAME pointers equal to PTR
859 for which we don't track their string lengths yet. If so, use
860 IDX for them. */
862 static void
863 find_equal_ptrs (tree ptr, int idx)
865 if (TREE_CODE (ptr) != SSA_NAME)
866 return;
867 while (1)
869 gimple stmt = SSA_NAME_DEF_STMT (ptr);
870 if (!is_gimple_assign (stmt))
871 return;
872 ptr = gimple_assign_rhs1 (stmt);
873 switch (gimple_assign_rhs_code (stmt))
875 case SSA_NAME:
876 break;
877 CASE_CONVERT:
878 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
879 return;
880 if (TREE_CODE (ptr) == SSA_NAME)
881 break;
882 if (TREE_CODE (ptr) != ADDR_EXPR)
883 return;
884 /* FALLTHRU */
885 case ADDR_EXPR:
887 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
888 if (pidx != NULL && *pidx == 0)
889 *pidx = idx;
890 return;
892 default:
893 return;
896 /* We might find an endptr created in this pass. Grow the
897 vector in that case. */
898 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
899 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
901 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
902 return;
903 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
907 /* If the last .MEM setter statement before STMT is
908 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
909 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
910 just memcpy (x, y, strlen (y)). SI must be the zero length
911 strinfo. */
913 static void
914 adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
916 tree vuse, callee, len;
917 struct laststmt_struct last = laststmt;
918 strinfo lastsi, firstsi;
919 unsigned len_arg_no = 2;
921 laststmt.stmt = NULL;
922 laststmt.len = NULL_TREE;
923 laststmt.stridx = 0;
925 if (last.stmt == NULL)
926 return;
928 vuse = gimple_vuse (stmt);
929 if (vuse == NULL_TREE
930 || SSA_NAME_DEF_STMT (vuse) != last.stmt
931 || !has_single_use (vuse))
932 return;
934 gcc_assert (last.stridx > 0);
935 lastsi = get_strinfo (last.stridx);
936 if (lastsi == NULL)
937 return;
939 if (lastsi != si)
941 if (lastsi->first == 0 || lastsi->first != si->first)
942 return;
944 firstsi = verify_related_strinfos (si);
945 if (firstsi == NULL)
946 return;
947 while (firstsi != lastsi)
949 strinfo nextsi;
950 if (firstsi->next == 0)
951 return;
952 nextsi = get_strinfo (firstsi->next);
953 if (nextsi == NULL
954 || nextsi->prev != firstsi->idx
955 || nextsi->first != si->first)
956 return;
957 firstsi = nextsi;
961 if (!is_strcat)
963 if (si->length == NULL_TREE || !integer_zerop (si->length))
964 return;
967 if (is_gimple_assign (last.stmt))
969 gimple_stmt_iterator gsi;
971 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
972 return;
973 if (stmt_could_throw_p (last.stmt))
974 return;
975 gsi = gsi_for_stmt (last.stmt);
976 unlink_stmt_vdef (last.stmt);
977 release_defs (last.stmt);
978 gsi_remove (&gsi, true);
979 return;
982 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
983 return;
985 callee = gimple_call_fndecl (last.stmt);
986 switch (DECL_FUNCTION_CODE (callee))
988 case BUILT_IN_MEMCPY:
989 case BUILT_IN_MEMCPY_CHK:
990 break;
991 case BUILT_IN_MEMCPY_CHKP:
992 case BUILT_IN_MEMCPY_CHK_CHKP:
993 len_arg_no = 4;
994 break;
995 default:
996 return;
999 len = gimple_call_arg (last.stmt, len_arg_no);
1000 if (tree_fits_uhwi_p (len))
1002 if (!tree_fits_uhwi_p (last.len)
1003 || integer_zerop (len)
1004 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1005 return;
1006 /* Don't adjust the length if it is divisible by 4, it is more efficient
1007 to store the extra '\0' in that case. */
1008 if ((tree_to_uhwi (len) & 3) == 0)
1009 return;
1011 else if (TREE_CODE (len) == SSA_NAME)
1013 gimple def_stmt = SSA_NAME_DEF_STMT (len);
1014 if (!is_gimple_assign (def_stmt)
1015 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1016 || gimple_assign_rhs1 (def_stmt) != last.len
1017 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1018 return;
1020 else
1021 return;
1023 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1024 update_stmt (last.stmt);
1027 /* Handle a strlen call. If strlen of the argument is known, replace
1028 the strlen call with the known value, otherwise remember that strlen
1029 of the argument is stored in the lhs SSA_NAME. */
1031 static void
1032 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1034 int idx;
1035 tree src;
1036 gimple stmt = gsi_stmt (*gsi);
1037 tree lhs = gimple_call_lhs (stmt);
1039 if (lhs == NULL_TREE)
1040 return;
1042 src = gimple_call_arg (stmt, 0);
1043 idx = get_stridx (src);
1044 if (idx)
1046 strinfo si = NULL;
1047 tree rhs;
1049 if (idx < 0)
1050 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1051 else
1053 rhs = NULL_TREE;
1054 si = get_strinfo (idx);
1055 if (si != NULL)
1056 rhs = get_string_length (si);
1058 if (rhs != NULL_TREE)
1060 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1062 fprintf (dump_file, "Optimizing: ");
1063 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1065 rhs = unshare_expr (rhs);
1066 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1067 rhs = fold_convert_loc (gimple_location (stmt),
1068 TREE_TYPE (lhs), rhs);
1069 if (!update_call_from_tree (gsi, rhs))
1070 gimplify_and_update_call_from_tree (gsi, rhs);
1071 stmt = gsi_stmt (*gsi);
1072 update_stmt (stmt);
1073 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1075 fprintf (dump_file, "into: ");
1076 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1078 if (si != NULL
1079 && TREE_CODE (si->length) != SSA_NAME
1080 && TREE_CODE (si->length) != INTEGER_CST
1081 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1083 si = unshare_strinfo (si);
1084 si->length = lhs;
1086 return;
1089 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1090 return;
1091 if (idx == 0)
1092 idx = new_stridx (src);
1093 else if (get_strinfo (idx) != NULL)
1094 return;
1095 if (idx)
1097 strinfo si = new_strinfo (src, idx, lhs);
1098 set_strinfo (idx, si);
1099 find_equal_ptrs (src, idx);
1103 /* Handle a strchr call. If strlen of the first argument is known, replace
1104 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1105 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1107 static void
1108 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1110 int idx;
1111 tree src;
1112 gimple stmt = gsi_stmt (*gsi);
1113 tree lhs = gimple_call_lhs (stmt);
1114 bool with_bounds = gimple_call_with_bounds_p (stmt);
1116 if (lhs == NULL_TREE)
1117 return;
1119 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1120 return;
1122 src = gimple_call_arg (stmt, 0);
1123 idx = get_stridx (src);
1124 if (idx)
1126 strinfo si = NULL;
1127 tree rhs;
1129 if (idx < 0)
1130 rhs = build_int_cst (size_type_node, ~idx);
1131 else
1133 rhs = NULL_TREE;
1134 si = get_strinfo (idx);
1135 if (si != NULL)
1136 rhs = get_string_length (si);
1138 if (rhs != NULL_TREE)
1140 location_t loc = gimple_location (stmt);
1142 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1144 fprintf (dump_file, "Optimizing: ");
1145 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1147 if (si != NULL && si->endptr != NULL_TREE)
1149 rhs = unshare_expr (si->endptr);
1150 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1151 TREE_TYPE (rhs)))
1152 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1154 else
1156 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1157 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1158 TREE_TYPE (src), src, rhs);
1159 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1160 TREE_TYPE (rhs)))
1161 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1163 if (!update_call_from_tree (gsi, rhs))
1164 gimplify_and_update_call_from_tree (gsi, rhs);
1165 stmt = gsi_stmt (*gsi);
1166 update_stmt (stmt);
1167 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1169 fprintf (dump_file, "into: ");
1170 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1172 if (si != NULL
1173 && si->endptr == NULL_TREE
1174 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1176 si = unshare_strinfo (si);
1177 si->endptr = lhs;
1179 zero_length_string (lhs, si);
1180 return;
1183 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1184 return;
1185 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1187 if (idx == 0)
1188 idx = new_stridx (src);
1189 else if (get_strinfo (idx) != NULL)
1191 zero_length_string (lhs, NULL);
1192 return;
1194 if (idx)
1196 location_t loc = gimple_location (stmt);
1197 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1198 tree srcu = fold_convert_loc (loc, size_type_node, src);
1199 tree length = fold_build2_loc (loc, MINUS_EXPR,
1200 size_type_node, lhsu, srcu);
1201 strinfo si = new_strinfo (src, idx, length);
1202 si->endptr = lhs;
1203 set_strinfo (idx, si);
1204 find_equal_ptrs (src, idx);
1205 zero_length_string (lhs, si);
1208 else
1209 zero_length_string (lhs, NULL);
1212 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1213 If strlen of the second argument is known, strlen of the first argument
1214 is the same after this call. Furthermore, attempt to convert it to
1215 memcpy. */
1217 static void
1218 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1220 int idx, didx;
1221 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1222 bool success;
1223 gimple stmt = gsi_stmt (*gsi);
1224 strinfo si, dsi, olddsi, zsi;
1225 location_t loc;
1226 bool with_bounds = gimple_call_with_bounds_p (stmt);
1228 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1229 dst = gimple_call_arg (stmt, 0);
1230 lhs = gimple_call_lhs (stmt);
1231 idx = get_stridx (src);
1232 si = NULL;
1233 if (idx > 0)
1234 si = get_strinfo (idx);
1236 didx = get_stridx (dst);
1237 olddsi = NULL;
1238 oldlen = NULL_TREE;
1239 if (didx > 0)
1240 olddsi = get_strinfo (didx);
1241 else if (didx < 0)
1242 return;
1244 if (olddsi != NULL)
1245 adjust_last_stmt (olddsi, stmt, false);
1247 srclen = NULL_TREE;
1248 if (si != NULL)
1249 srclen = get_string_length (si);
1250 else if (idx < 0)
1251 srclen = build_int_cst (size_type_node, ~idx);
1253 loc = gimple_location (stmt);
1254 if (srclen == NULL_TREE)
1255 switch (bcode)
1257 case BUILT_IN_STRCPY:
1258 case BUILT_IN_STRCPY_CHK:
1259 case BUILT_IN_STRCPY_CHKP:
1260 case BUILT_IN_STRCPY_CHK_CHKP:
1261 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1262 return;
1263 break;
1264 case BUILT_IN_STPCPY:
1265 case BUILT_IN_STPCPY_CHK:
1266 case BUILT_IN_STPCPY_CHKP:
1267 case BUILT_IN_STPCPY_CHK_CHKP:
1268 if (lhs == NULL_TREE)
1269 return;
1270 else
1272 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1273 srclen = fold_convert_loc (loc, size_type_node, dst);
1274 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1275 lhsuint, srclen);
1277 break;
1278 default:
1279 gcc_unreachable ();
1282 if (didx == 0)
1284 didx = new_stridx (dst);
1285 if (didx == 0)
1286 return;
1288 if (olddsi != NULL)
1290 oldlen = olddsi->length;
1291 dsi = unshare_strinfo (olddsi);
1292 dsi->length = srclen;
1293 /* Break the chain, so adjust_related_strinfo on later pointers in
1294 the chain won't adjust this one anymore. */
1295 dsi->next = 0;
1296 dsi->stmt = NULL;
1297 dsi->endptr = NULL_TREE;
1299 else
1301 dsi = new_strinfo (dst, didx, srclen);
1302 set_strinfo (didx, dsi);
1303 find_equal_ptrs (dst, didx);
1305 dsi->writable = true;
1306 dsi->dont_invalidate = true;
1308 if (dsi->length == NULL_TREE)
1310 strinfo chainsi;
1312 /* If string length of src is unknown, use delayed length
1313 computation. If string lenth of dst will be needed, it
1314 can be computed by transforming this strcpy call into
1315 stpcpy and subtracting dst from the return value. */
1317 /* Look for earlier strings whose length could be determined if
1318 this strcpy is turned into an stpcpy. */
1320 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1322 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1324 /* When setting a stmt for delayed length computation
1325 prevent all strinfos through dsi from being
1326 invalidated. */
1327 chainsi = unshare_strinfo (chainsi);
1328 chainsi->stmt = stmt;
1329 chainsi->length = NULL_TREE;
1330 chainsi->endptr = NULL_TREE;
1331 chainsi->dont_invalidate = true;
1334 dsi->stmt = stmt;
1335 return;
1338 if (olddsi != NULL)
1340 tree adj = NULL_TREE;
1341 if (oldlen == NULL_TREE)
1343 else if (integer_zerop (oldlen))
1344 adj = srclen;
1345 else if (TREE_CODE (oldlen) == INTEGER_CST
1346 || TREE_CODE (srclen) == INTEGER_CST)
1347 adj = fold_build2_loc (loc, MINUS_EXPR,
1348 TREE_TYPE (srclen), srclen,
1349 fold_convert_loc (loc, TREE_TYPE (srclen),
1350 oldlen));
1351 if (adj != NULL_TREE)
1352 adjust_related_strinfos (loc, dsi, adj);
1353 else
1354 dsi->prev = 0;
1356 /* strcpy src may not overlap dst, so src doesn't need to be
1357 invalidated either. */
1358 if (si != NULL)
1359 si->dont_invalidate = true;
1361 fn = NULL_TREE;
1362 zsi = NULL;
1363 switch (bcode)
1365 case BUILT_IN_STRCPY:
1366 case BUILT_IN_STRCPY_CHKP:
1367 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1368 if (lhs)
1369 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1370 break;
1371 case BUILT_IN_STRCPY_CHK:
1372 case BUILT_IN_STRCPY_CHK_CHKP:
1373 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1374 if (lhs)
1375 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1376 break;
1377 case BUILT_IN_STPCPY:
1378 case BUILT_IN_STPCPY_CHKP:
1379 /* This would need adjustment of the lhs (subtract one),
1380 or detection that the trailing '\0' doesn't need to be
1381 written, if it will be immediately overwritten.
1382 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1383 if (lhs)
1385 dsi->endptr = lhs;
1386 zsi = zero_length_string (lhs, dsi);
1388 break;
1389 case BUILT_IN_STPCPY_CHK:
1390 case BUILT_IN_STPCPY_CHK_CHKP:
1391 /* This would need adjustment of the lhs (subtract one),
1392 or detection that the trailing '\0' doesn't need to be
1393 written, if it will be immediately overwritten.
1394 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1395 if (lhs)
1397 dsi->endptr = lhs;
1398 zsi = zero_length_string (lhs, dsi);
1400 break;
1401 default:
1402 gcc_unreachable ();
1404 if (zsi != NULL)
1405 zsi->dont_invalidate = true;
1407 if (fn == NULL_TREE)
1408 return;
1410 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1411 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1413 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1414 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1415 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1416 GSI_SAME_STMT);
1417 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1419 fprintf (dump_file, "Optimizing: ");
1420 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1422 if (with_bounds)
1424 fn = chkp_maybe_create_clone (fn)->decl;
1425 if (gimple_call_num_args (stmt) == 4)
1426 success = update_gimple_call (gsi, fn, 5, dst,
1427 gimple_call_arg (stmt, 1),
1428 src,
1429 gimple_call_arg (stmt, 3),
1430 len);
1431 else
1432 success = update_gimple_call (gsi, fn, 6, dst,
1433 gimple_call_arg (stmt, 1),
1434 src,
1435 gimple_call_arg (stmt, 3),
1436 len,
1437 gimple_call_arg (stmt, 4));
1439 else
1440 if (gimple_call_num_args (stmt) == 2)
1441 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1442 else
1443 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1444 gimple_call_arg (stmt, 2));
1445 if (success)
1447 stmt = gsi_stmt (*gsi);
1448 gimple_call_set_with_bounds (stmt, with_bounds);
1449 update_stmt (stmt);
1450 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1452 fprintf (dump_file, "into: ");
1453 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1455 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1456 laststmt.stmt = stmt;
1457 laststmt.len = srclen;
1458 laststmt.stridx = dsi->idx;
1460 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1461 fprintf (dump_file, "not possible.\n");
1464 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1465 If strlen of the second argument is known and length of the third argument
1466 is that plus one, strlen of the first argument is the same after this
1467 call. */
1469 static void
1470 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1472 int idx, didx;
1473 tree src, dst, len, lhs, oldlen, newlen;
1474 gimple stmt = gsi_stmt (*gsi);
1475 strinfo si, dsi, olddsi;
1476 bool with_bounds = gimple_call_with_bounds_p (stmt);
1478 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1479 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1480 dst = gimple_call_arg (stmt, 0);
1481 idx = get_stridx (src);
1482 if (idx == 0)
1483 return;
1485 didx = get_stridx (dst);
1486 olddsi = NULL;
1487 if (didx > 0)
1488 olddsi = get_strinfo (didx);
1489 else if (didx < 0)
1490 return;
1492 if (olddsi != NULL
1493 && tree_fits_uhwi_p (len)
1494 && !integer_zerop (len))
1495 adjust_last_stmt (olddsi, stmt, false);
1497 if (idx > 0)
1499 gimple def_stmt;
1501 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1502 si = get_strinfo (idx);
1503 if (si == NULL || si->length == NULL_TREE)
1504 return;
1505 if (TREE_CODE (len) != SSA_NAME)
1506 return;
1507 def_stmt = SSA_NAME_DEF_STMT (len);
1508 if (!is_gimple_assign (def_stmt)
1509 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1510 || gimple_assign_rhs1 (def_stmt) != si->length
1511 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1512 return;
1514 else
1516 si = NULL;
1517 /* Handle memcpy (x, "abcd", 5) or
1518 memcpy (x, "abc\0uvw", 7). */
1519 if (!tree_fits_uhwi_p (len)
1520 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1521 return;
1524 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1525 adjust_last_stmt (olddsi, stmt, false);
1527 if (didx == 0)
1529 didx = new_stridx (dst);
1530 if (didx == 0)
1531 return;
1533 if (si != NULL)
1534 newlen = si->length;
1535 else
1536 newlen = build_int_cst (size_type_node, ~idx);
1537 oldlen = NULL_TREE;
1538 if (olddsi != NULL)
1540 dsi = unshare_strinfo (olddsi);
1541 oldlen = olddsi->length;
1542 dsi->length = newlen;
1543 /* Break the chain, so adjust_related_strinfo on later pointers in
1544 the chain won't adjust this one anymore. */
1545 dsi->next = 0;
1546 dsi->stmt = NULL;
1547 dsi->endptr = NULL_TREE;
1549 else
1551 dsi = new_strinfo (dst, didx, newlen);
1552 set_strinfo (didx, dsi);
1553 find_equal_ptrs (dst, didx);
1555 dsi->writable = true;
1556 dsi->dont_invalidate = true;
1557 if (olddsi != NULL)
1559 tree adj = NULL_TREE;
1560 location_t loc = gimple_location (stmt);
1561 if (oldlen == NULL_TREE)
1563 else if (integer_zerop (oldlen))
1564 adj = dsi->length;
1565 else if (TREE_CODE (oldlen) == INTEGER_CST
1566 || TREE_CODE (dsi->length) == INTEGER_CST)
1567 adj = fold_build2_loc (loc, MINUS_EXPR,
1568 TREE_TYPE (dsi->length), dsi->length,
1569 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1570 oldlen));
1571 if (adj != NULL_TREE)
1572 adjust_related_strinfos (loc, dsi, adj);
1573 else
1574 dsi->prev = 0;
1576 /* memcpy src may not overlap dst, so src doesn't need to be
1577 invalidated either. */
1578 if (si != NULL)
1579 si->dont_invalidate = true;
1581 lhs = gimple_call_lhs (stmt);
1582 switch (bcode)
1584 case BUILT_IN_MEMCPY:
1585 case BUILT_IN_MEMCPY_CHK:
1586 case BUILT_IN_MEMCPY_CHKP:
1587 case BUILT_IN_MEMCPY_CHK_CHKP:
1588 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1589 laststmt.stmt = stmt;
1590 laststmt.len = dsi->length;
1591 laststmt.stridx = dsi->idx;
1592 if (lhs)
1593 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1594 break;
1595 case BUILT_IN_MEMPCPY:
1596 case BUILT_IN_MEMPCPY_CHK:
1597 case BUILT_IN_MEMPCPY_CHKP:
1598 case BUILT_IN_MEMPCPY_CHK_CHKP:
1599 break;
1600 default:
1601 gcc_unreachable ();
1605 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1606 If strlen of the second argument is known, strlen of the first argument
1607 is increased by the length of the second argument. Furthermore, attempt
1608 to convert it to memcpy/strcpy if the length of the first argument
1609 is known. */
1611 static void
1612 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1614 int idx, didx;
1615 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1616 bool success;
1617 gimple stmt = gsi_stmt (*gsi);
1618 strinfo si, dsi;
1619 location_t loc;
1620 bool with_bounds = gimple_call_with_bounds_p (stmt);
1622 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1623 dst = gimple_call_arg (stmt, 0);
1624 lhs = gimple_call_lhs (stmt);
1626 didx = get_stridx (dst);
1627 if (didx < 0)
1628 return;
1630 dsi = NULL;
1631 if (didx > 0)
1632 dsi = get_strinfo (didx);
1633 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1635 /* strcat (p, q) can be transformed into
1636 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1637 with length endptr - p if we need to compute the length
1638 later on. Don't do this transformation if we don't need
1639 it. */
1640 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1642 if (didx == 0)
1644 didx = new_stridx (dst);
1645 if (didx == 0)
1646 return;
1648 if (dsi == NULL)
1650 dsi = new_strinfo (dst, didx, NULL_TREE);
1651 set_strinfo (didx, dsi);
1652 find_equal_ptrs (dst, didx);
1654 else
1656 dsi = unshare_strinfo (dsi);
1657 dsi->length = NULL_TREE;
1658 dsi->next = 0;
1659 dsi->endptr = NULL_TREE;
1661 dsi->writable = true;
1662 dsi->stmt = stmt;
1663 dsi->dont_invalidate = true;
1665 return;
1668 srclen = NULL_TREE;
1669 si = NULL;
1670 idx = get_stridx (src);
1671 if (idx < 0)
1672 srclen = build_int_cst (size_type_node, ~idx);
1673 else if (idx > 0)
1675 si = get_strinfo (idx);
1676 if (si != NULL)
1677 srclen = get_string_length (si);
1680 loc = gimple_location (stmt);
1681 dstlen = dsi->length;
1682 endptr = dsi->endptr;
1684 dsi = unshare_strinfo (dsi);
1685 dsi->endptr = NULL_TREE;
1686 dsi->stmt = NULL;
1687 dsi->writable = true;
1689 if (srclen != NULL_TREE)
1691 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1692 dsi->length, srclen);
1693 adjust_related_strinfos (loc, dsi, srclen);
1694 dsi->dont_invalidate = true;
1696 else
1698 dsi->length = NULL;
1699 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1700 dsi->dont_invalidate = true;
1703 if (si != NULL)
1704 /* strcat src may not overlap dst, so src doesn't need to be
1705 invalidated either. */
1706 si->dont_invalidate = true;
1708 /* For now. Could remove the lhs from the call and add
1709 lhs = dst; afterwards. */
1710 if (lhs)
1711 return;
1713 fn = NULL_TREE;
1714 objsz = NULL_TREE;
1715 switch (bcode)
1717 case BUILT_IN_STRCAT:
1718 case BUILT_IN_STRCAT_CHKP:
1719 if (srclen != NULL_TREE)
1720 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1721 else
1722 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1723 break;
1724 case BUILT_IN_STRCAT_CHK:
1725 case BUILT_IN_STRCAT_CHK_CHKP:
1726 if (srclen != NULL_TREE)
1727 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1728 else
1729 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1730 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1731 break;
1732 default:
1733 gcc_unreachable ();
1736 if (fn == NULL_TREE)
1737 return;
1739 len = NULL_TREE;
1740 if (srclen != NULL_TREE)
1742 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1743 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1745 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1746 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1747 build_int_cst (type, 1));
1748 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1749 GSI_SAME_STMT);
1751 if (endptr)
1752 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1753 else
1754 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1755 TREE_TYPE (dst), unshare_expr (dst),
1756 fold_convert_loc (loc, sizetype,
1757 unshare_expr (dstlen)));
1758 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1759 GSI_SAME_STMT);
1760 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1762 fprintf (dump_file, "Optimizing: ");
1763 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1765 if (with_bounds)
1767 fn = chkp_maybe_create_clone (fn)->decl;
1768 if (srclen != NULL_TREE)
1769 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1770 dst,
1771 gimple_call_arg (stmt, 1),
1772 src,
1773 gimple_call_arg (stmt, 3),
1774 len, objsz);
1775 else
1776 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1777 dst,
1778 gimple_call_arg (stmt, 1),
1779 src,
1780 gimple_call_arg (stmt, 3),
1781 objsz);
1783 else
1784 if (srclen != NULL_TREE)
1785 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1786 dst, src, len, objsz);
1787 else
1788 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1789 dst, src, objsz);
1790 if (success)
1792 stmt = gsi_stmt (*gsi);
1793 gimple_call_set_with_bounds (stmt, with_bounds);
1794 update_stmt (stmt);
1795 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1797 fprintf (dump_file, "into: ");
1798 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1800 /* If srclen == NULL, note that current string length can be
1801 computed by transforming this strcpy into stpcpy. */
1802 if (srclen == NULL_TREE && dsi->dont_invalidate)
1803 dsi->stmt = stmt;
1804 adjust_last_stmt (dsi, stmt, true);
1805 if (srclen != NULL_TREE)
1807 laststmt.stmt = stmt;
1808 laststmt.len = srclen;
1809 laststmt.stridx = dsi->idx;
1812 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1813 fprintf (dump_file, "not possible.\n");
1816 /* Handle a call to malloc or calloc. */
1818 static void
1819 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1821 gimple stmt = gsi_stmt (*gsi);
1822 tree lhs = gimple_call_lhs (stmt);
1823 gcc_assert (get_stridx (lhs) == 0);
1824 int idx = new_stridx (lhs);
1825 tree length = NULL_TREE;
1826 if (bcode == BUILT_IN_CALLOC)
1827 length = build_int_cst (size_type_node, 0);
1828 strinfo si = new_strinfo (lhs, idx, length);
1829 if (bcode == BUILT_IN_CALLOC)
1830 si->endptr = lhs;
1831 set_strinfo (idx, si);
1832 si->writable = true;
1833 si->stmt = stmt;
1834 si->dont_invalidate = true;
1837 /* Handle a call to memset.
1838 After a call to calloc, memset(,0,) is unnecessary.
1839 memset(malloc(n),0,n) is calloc(n,1). */
1841 static bool
1842 handle_builtin_memset (gimple_stmt_iterator *gsi)
1844 gimple stmt2 = gsi_stmt (*gsi);
1845 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1846 return true;
1847 tree ptr = gimple_call_arg (stmt2, 0);
1848 int idx1 = get_stridx (ptr);
1849 if (idx1 <= 0)
1850 return true;
1851 strinfo si1 = get_strinfo (idx1);
1852 if (!si1)
1853 return true;
1854 gimple stmt1 = si1->stmt;
1855 if (!stmt1 || !is_gimple_call (stmt1))
1856 return true;
1857 tree callee1 = gimple_call_fndecl (stmt1);
1858 if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL))
1859 return true;
1860 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1861 tree size = gimple_call_arg (stmt2, 2);
1862 if (code1 == BUILT_IN_CALLOC)
1863 /* Not touching stmt1 */ ;
1864 else if (code1 == BUILT_IN_MALLOC
1865 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1867 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1868 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1869 size, build_one_cst (size_type_node));
1870 si1->length = build_int_cst (size_type_node, 0);
1871 si1->stmt = gsi_stmt (gsi1);
1873 else
1874 return true;
1875 tree lhs = gimple_call_lhs (stmt2);
1876 unlink_stmt_vdef (stmt2);
1877 if (lhs)
1879 gimple assign = gimple_build_assign (lhs, ptr);
1880 gsi_replace (gsi, assign, false);
1882 else
1884 gsi_remove (gsi, true);
1885 release_defs (stmt2);
1888 return false;
1891 /* Handle a POINTER_PLUS_EXPR statement.
1892 For p = "abcd" + 2; compute associated length, or if
1893 p = q + off is pointing to a '\0' character of a string, call
1894 zero_length_string on it. */
1896 static void
1897 handle_pointer_plus (gimple_stmt_iterator *gsi)
1899 gimple stmt = gsi_stmt (*gsi);
1900 tree lhs = gimple_assign_lhs (stmt), off;
1901 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1902 strinfo si, zsi;
1904 if (idx == 0)
1905 return;
1907 if (idx < 0)
1909 tree off = gimple_assign_rhs2 (stmt);
1910 if (tree_fits_uhwi_p (off)
1911 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1912 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1913 = ~(~idx - (int) tree_to_uhwi (off));
1914 return;
1917 si = get_strinfo (idx);
1918 if (si == NULL || si->length == NULL_TREE)
1919 return;
1921 off = gimple_assign_rhs2 (stmt);
1922 zsi = NULL;
1923 if (operand_equal_p (si->length, off, 0))
1924 zsi = zero_length_string (lhs, si);
1925 else if (TREE_CODE (off) == SSA_NAME)
1927 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1928 if (gimple_assign_single_p (def_stmt)
1929 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1930 zsi = zero_length_string (lhs, si);
1932 if (zsi != NULL
1933 && si->endptr != NULL_TREE
1934 && si->endptr != lhs
1935 && TREE_CODE (si->endptr) == SSA_NAME)
1937 enum tree_code rhs_code
1938 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1939 ? SSA_NAME : NOP_EXPR;
1940 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
1941 gcc_assert (gsi_stmt (*gsi) == stmt);
1942 update_stmt (stmt);
1946 /* Handle a single character store. */
1948 static bool
1949 handle_char_store (gimple_stmt_iterator *gsi)
1951 int idx = -1;
1952 strinfo si = NULL;
1953 gimple stmt = gsi_stmt (*gsi);
1954 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1956 if (TREE_CODE (lhs) == MEM_REF
1957 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1959 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1961 ssaname = TREE_OPERAND (lhs, 0);
1962 idx = get_stridx (ssaname);
1965 else
1966 idx = get_addr_stridx (lhs);
1968 if (idx > 0)
1970 si = get_strinfo (idx);
1971 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1973 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1975 /* When storing '\0', the store can be removed
1976 if we know it has been stored in the current function. */
1977 if (!stmt_could_throw_p (stmt) && si->writable)
1979 unlink_stmt_vdef (stmt);
1980 release_defs (stmt);
1981 gsi_remove (gsi, true);
1982 return false;
1984 else
1986 si->writable = true;
1987 gsi_next (gsi);
1988 return false;
1991 else
1992 /* Otherwise this statement overwrites the '\0' with
1993 something, if the previous stmt was a memcpy,
1994 its length may be decreased. */
1995 adjust_last_stmt (si, stmt, false);
1997 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1999 si = unshare_strinfo (si);
2000 si->length = build_int_cst (size_type_node, 0);
2001 si->endptr = NULL;
2002 si->prev = 0;
2003 si->next = 0;
2004 si->stmt = NULL;
2005 si->first = 0;
2006 si->writable = true;
2007 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2008 si->endptr = ssaname;
2009 si->dont_invalidate = true;
2011 /* If si->length is non-zero constant, we aren't overwriting '\0',
2012 and if we aren't storing '\0', we know that the length of the
2013 string and any other zero terminated string in memory remains
2014 the same. In that case we move to the next gimple statement and
2015 return to signal the caller that it shouldn't invalidate anything.
2017 This is benefical for cases like:
2019 char p[20];
2020 void foo (char *q)
2022 strcpy (p, "foobar");
2023 size_t len = strlen (p); // This can be optimized into 6
2024 size_t len2 = strlen (q); // This has to be computed
2025 p[0] = 'X';
2026 size_t len3 = strlen (p); // This can be optimized into 6
2027 size_t len4 = strlen (q); // This can be optimized into len2
2028 bar (len, len2, len3, len4);
2031 else if (si != NULL && si->length != NULL_TREE
2032 && TREE_CODE (si->length) == INTEGER_CST
2033 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2035 gsi_next (gsi);
2036 return false;
2039 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2041 if (ssaname)
2043 si = zero_length_string (ssaname, NULL);
2044 if (si != NULL)
2045 si->dont_invalidate = true;
2047 else
2049 int idx = new_addr_stridx (lhs);
2050 if (idx != 0)
2052 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2053 build_int_cst (size_type_node, 0));
2054 set_strinfo (idx, si);
2055 si->dont_invalidate = true;
2058 if (si != NULL)
2059 si->writable = true;
2061 else if (idx == 0
2062 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2063 && ssaname == NULL_TREE
2064 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2066 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2067 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2068 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2070 int idx = new_addr_stridx (lhs);
2071 if (idx != 0)
2073 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2074 build_int_cst (size_type_node, l));
2075 set_strinfo (idx, si);
2076 si->dont_invalidate = true;
2081 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2083 /* Allow adjust_last_stmt to remove it if the stored '\0'
2084 is immediately overwritten. */
2085 laststmt.stmt = stmt;
2086 laststmt.len = build_int_cst (size_type_node, 1);
2087 laststmt.stridx = si->idx;
2089 return true;
2092 /* Attempt to optimize a single statement at *GSI using string length
2093 knowledge. */
2095 static bool
2096 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2098 gimple stmt = gsi_stmt (*gsi);
2100 if (is_gimple_call (stmt))
2102 tree callee = gimple_call_fndecl (stmt);
2103 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
2104 switch (DECL_FUNCTION_CODE (callee))
2106 case BUILT_IN_STRLEN:
2107 case BUILT_IN_STRLEN_CHKP:
2108 handle_builtin_strlen (gsi);
2109 break;
2110 case BUILT_IN_STRCHR:
2111 case BUILT_IN_STRCHR_CHKP:
2112 handle_builtin_strchr (gsi);
2113 break;
2114 case BUILT_IN_STRCPY:
2115 case BUILT_IN_STRCPY_CHK:
2116 case BUILT_IN_STPCPY:
2117 case BUILT_IN_STPCPY_CHK:
2118 case BUILT_IN_STRCPY_CHKP:
2119 case BUILT_IN_STRCPY_CHK_CHKP:
2120 case BUILT_IN_STPCPY_CHKP:
2121 case BUILT_IN_STPCPY_CHK_CHKP:
2122 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2123 break;
2124 case BUILT_IN_MEMCPY:
2125 case BUILT_IN_MEMCPY_CHK:
2126 case BUILT_IN_MEMPCPY:
2127 case BUILT_IN_MEMPCPY_CHK:
2128 case BUILT_IN_MEMCPY_CHKP:
2129 case BUILT_IN_MEMCPY_CHK_CHKP:
2130 case BUILT_IN_MEMPCPY_CHKP:
2131 case BUILT_IN_MEMPCPY_CHK_CHKP:
2132 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2133 break;
2134 case BUILT_IN_STRCAT:
2135 case BUILT_IN_STRCAT_CHK:
2136 case BUILT_IN_STRCAT_CHKP:
2137 case BUILT_IN_STRCAT_CHK_CHKP:
2138 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2139 break;
2140 case BUILT_IN_MALLOC:
2141 case BUILT_IN_CALLOC:
2142 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2143 break;
2144 case BUILT_IN_MEMSET:
2145 if (!handle_builtin_memset (gsi))
2146 return false;
2147 break;
2148 default:
2149 break;
2152 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2154 tree lhs = gimple_assign_lhs (stmt);
2156 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2158 if (gimple_assign_single_p (stmt)
2159 || (gimple_assign_cast_p (stmt)
2160 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2162 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2163 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2165 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2166 handle_pointer_plus (gsi);
2168 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2170 tree type = TREE_TYPE (lhs);
2171 if (TREE_CODE (type) == ARRAY_TYPE)
2172 type = TREE_TYPE (type);
2173 if (TREE_CODE (type) == INTEGER_TYPE
2174 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2175 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2177 if (! handle_char_store (gsi))
2178 return false;
2183 if (gimple_vdef (stmt))
2184 maybe_invalidate (stmt);
2185 return true;
2188 /* Recursively call maybe_invalidate on stmts that might be executed
2189 in between dombb and current bb and that contain a vdef. Stop when
2190 *count stmts are inspected, or if the whole strinfo vector has
2191 been invalidated. */
2193 static void
2194 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
2196 unsigned int i, n = gimple_phi_num_args (phi);
2198 for (i = 0; i < n; i++)
2200 tree vuse = gimple_phi_arg_def (phi, i);
2201 gimple stmt = SSA_NAME_DEF_STMT (vuse);
2202 basic_block bb = gimple_bb (stmt);
2203 if (bb == NULL
2204 || bb == dombb
2205 || !bitmap_set_bit (visited, bb->index)
2206 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2207 continue;
2208 while (1)
2210 if (gimple_code (stmt) == GIMPLE_PHI)
2212 do_invalidate (dombb, stmt, visited, count);
2213 if (*count == 0)
2214 return;
2215 break;
2217 if (--*count == 0)
2218 return;
2219 if (!maybe_invalidate (stmt))
2221 *count = 0;
2222 return;
2224 vuse = gimple_vuse (stmt);
2225 stmt = SSA_NAME_DEF_STMT (vuse);
2226 if (gimple_bb (stmt) != bb)
2228 bb = gimple_bb (stmt);
2229 if (bb == NULL
2230 || bb == dombb
2231 || !bitmap_set_bit (visited, bb->index)
2232 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2233 break;
2239 class strlen_dom_walker : public dom_walker
2241 public:
2242 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2244 virtual void before_dom_children (basic_block);
2245 virtual void after_dom_children (basic_block);
2248 /* Callback for walk_dominator_tree. Attempt to optimize various
2249 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2251 void
2252 strlen_dom_walker::before_dom_children (basic_block bb)
2254 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2256 if (dombb == NULL)
2257 stridx_to_strinfo = NULL;
2258 else
2260 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) dombb->aux);
2261 if (stridx_to_strinfo)
2263 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2264 gsi_next (&gsi))
2266 gphi *phi = gsi.phi ();
2267 if (virtual_operand_p (gimple_phi_result (phi)))
2269 bitmap visited = BITMAP_ALLOC (NULL);
2270 int count_vdef = 100;
2271 do_invalidate (dombb, phi, visited, &count_vdef);
2272 BITMAP_FREE (visited);
2273 if (count_vdef == 0)
2275 /* If there were too many vdefs in between immediate
2276 dominator and current bb, invalidate everything.
2277 If stridx_to_strinfo has been unshared, we need
2278 to free it, otherwise just set it to NULL. */
2279 if (!strinfo_shared ())
2281 unsigned int i;
2282 strinfo si;
2284 for (i = 1;
2285 vec_safe_iterate (stridx_to_strinfo, i, &si);
2286 ++i)
2288 free_strinfo (si);
2289 (*stridx_to_strinfo)[i] = NULL;
2292 else
2293 stridx_to_strinfo = NULL;
2295 break;
2301 /* If all PHI arguments have the same string index, the PHI result
2302 has it as well. */
2303 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2304 gsi_next (&gsi))
2306 gphi *phi = gsi.phi ();
2307 tree result = gimple_phi_result (phi);
2308 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2310 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2311 if (idx != 0)
2313 unsigned int i, n = gimple_phi_num_args (phi);
2314 for (i = 1; i < n; i++)
2315 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2316 break;
2317 if (i == n)
2318 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2323 /* Attempt to optimize individual statements. */
2324 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2325 if (strlen_optimize_stmt (&gsi))
2326 gsi_next (&gsi);
2328 bb->aux = stridx_to_strinfo;
2329 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2330 (*stridx_to_strinfo)[0] = (strinfo) bb;
2333 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2334 owned by the current bb, clear bb->aux. */
2336 void
2337 strlen_dom_walker::after_dom_children (basic_block bb)
2339 if (bb->aux)
2341 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux);
2342 if (vec_safe_length (stridx_to_strinfo)
2343 && (*stridx_to_strinfo)[0] == (strinfo) bb)
2345 unsigned int i;
2346 strinfo si;
2348 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2349 free_strinfo (si);
2350 vec_free (stridx_to_strinfo);
2352 bb->aux = NULL;
2356 /* Main entry point. */
2358 namespace {
2360 const pass_data pass_data_strlen =
2362 GIMPLE_PASS, /* type */
2363 "strlen", /* name */
2364 OPTGROUP_NONE, /* optinfo_flags */
2365 TV_TREE_STRLEN, /* tv_id */
2366 ( PROP_cfg | PROP_ssa ), /* properties_required */
2367 0, /* properties_provided */
2368 0, /* properties_destroyed */
2369 0, /* todo_flags_start */
2370 0, /* todo_flags_finish */
2373 class pass_strlen : public gimple_opt_pass
2375 public:
2376 pass_strlen (gcc::context *ctxt)
2377 : gimple_opt_pass (pass_data_strlen, ctxt)
2380 /* opt_pass methods: */
2381 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2382 virtual unsigned int execute (function *);
2384 }; // class pass_strlen
2386 unsigned int
2387 pass_strlen::execute (function *fun)
2389 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2390 max_stridx = 1;
2391 strinfo_pool = create_alloc_pool ("strinfo_struct pool",
2392 sizeof (struct strinfo_struct), 64);
2394 calculate_dominance_info (CDI_DOMINATORS);
2396 /* String length optimization is implemented as a walk of the dominator
2397 tree and a forward walk of statements within each block. */
2398 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2400 ssa_ver_to_stridx.release ();
2401 free_alloc_pool (strinfo_pool);
2402 if (decl_to_stridxlist_htab)
2404 obstack_free (&stridx_obstack, NULL);
2405 delete decl_to_stridxlist_htab;
2406 decl_to_stridxlist_htab = NULL;
2408 laststmt.stmt = NULL;
2409 laststmt.len = NULL_TREE;
2410 laststmt.stridx = 0;
2412 return 0;
2415 } // anon namespace
2417 gimple_opt_pass *
2418 make_pass_strlen (gcc::context *ctxt)
2420 return new pass_strlen (ctxt);