Update ChangeLog and version files for release
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob403464db2561453f54af1448a7fcc570e9ed3e7a
1 /* String length optimization
2 Copyright (C) 2011-2016 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 "backend.h"
25 #include "rtl.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "alloc-pool.h"
29 #include "tree-pass.h"
30 #include "ssa.h"
31 #include "cgraph.h"
32 #include "gimple-pretty-print.h"
33 #include "fold-const.h"
34 #include "stor-layout.h"
35 #include "gimple-fold.h"
36 #include "tree-eh.h"
37 #include "gimplify.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
40 #include "expr.h"
41 #include "tree-dfa.h"
42 #include "domwalk.h"
43 #include "tree-ssa-propagate.h"
44 #include "params.h"
45 #include "ipa-chkp.h"
46 #include "tree-hash-traits.h"
48 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
49 is an index into strinfo vector, negative value stands for
50 string length of a string literal (~strlen). */
51 static vec<int> ssa_ver_to_stridx;
53 /* Number of currently active string indexes plus one. */
54 static int max_stridx;
56 /* String information record. */
57 struct strinfo
59 /* String length of this string. */
60 tree length;
61 /* Any of the corresponding pointers for querying alias oracle. */
62 tree ptr;
63 /* Statement for delayed length computation. */
64 gimple *stmt;
65 /* Pointer to '\0' if known, if NULL, it can be computed as
66 ptr + length. */
67 tree endptr;
68 /* Reference count. Any changes to strinfo entry possibly shared
69 with dominating basic blocks need unshare_strinfo first, except
70 for dont_invalidate which affects only the immediately next
71 maybe_invalidate. */
72 int refcount;
73 /* Copy of index. get_strinfo (si->idx) should return si; */
74 int idx;
75 /* These 3 fields are for chaining related string pointers together.
76 E.g. for
77 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
78 strcpy (c, d); e = c + dl;
79 strinfo(a) -> strinfo(c) -> strinfo(e)
80 All have ->first field equal to strinfo(a)->idx and are doubly
81 chained through prev/next fields. The later strinfos are required
82 to point into the same string with zero or more bytes after
83 the previous pointer and all bytes in between the two pointers
84 must be non-zero. Functions like strcpy or memcpy are supposed
85 to adjust all previous strinfo lengths, but not following strinfo
86 lengths (those are uncertain, usually invalidated during
87 maybe_invalidate, except when the alias oracle knows better).
88 Functions like strcat on the other side adjust the whole
89 related strinfo chain.
90 They are updated lazily, so to use the chain the same first fields
91 and si->prev->next == si->idx needs to be verified. */
92 int first;
93 int next;
94 int prev;
95 /* A flag whether the string is known to be written in the current
96 function. */
97 bool writable;
98 /* A flag for the next maybe_invalidate that this strinfo shouldn't
99 be invalidated. Always cleared by maybe_invalidate. */
100 bool dont_invalidate;
103 /* Pool for allocating strinfo_struct entries. */
104 static object_allocator<strinfo> strinfo_pool ("strinfo pool");
106 /* Vector mapping positive string indexes to strinfo, for the
107 current basic block. The first pointer in the vector is special,
108 it is either NULL, meaning the vector isn't shared, or it is
109 a basic block pointer to the owner basic_block if shared.
110 If some other bb wants to modify the vector, the vector needs
111 to be unshared first, and only the owner bb is supposed to free it. */
112 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
114 /* One OFFSET->IDX mapping. */
115 struct stridxlist
117 struct stridxlist *next;
118 HOST_WIDE_INT offset;
119 int idx;
122 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
123 struct decl_stridxlist_map
125 struct tree_map_base base;
126 struct stridxlist list;
129 /* Hash table for mapping decls to a chained list of offset -> idx
130 mappings. */
131 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
133 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
134 static struct obstack stridx_obstack;
136 /* Last memcpy statement if it could be adjusted if the trailing
137 '\0' written is immediately overwritten, or
138 *x = '\0' store that could be removed if it is immediately overwritten. */
139 struct laststmt_struct
141 gimple *stmt;
142 tree len;
143 int stridx;
144 } laststmt;
146 static int get_stridx_plus_constant (strinfo *, HOST_WIDE_INT, tree);
148 /* Return strinfo vector entry IDX. */
150 static inline strinfo *
151 get_strinfo (int idx)
153 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
154 return NULL;
155 return (*stridx_to_strinfo)[idx];
158 /* Helper function for get_stridx. */
160 static int
161 get_addr_stridx (tree exp)
163 HOST_WIDE_INT off;
164 struct stridxlist *list;
165 tree base;
167 if (!decl_to_stridxlist_htab)
168 return 0;
170 base = get_addr_base_and_unit_offset (exp, &off);
171 if (base == NULL || !DECL_P (base))
172 return 0;
174 list = decl_to_stridxlist_htab->get (base);
175 if (list == NULL)
176 return 0;
180 if (list->offset == off)
181 return list->idx;
182 list = list->next;
184 while (list);
185 return 0;
188 /* Return string index for EXP. */
190 static int
191 get_stridx (tree exp)
193 tree s, o;
195 if (TREE_CODE (exp) == SSA_NAME)
197 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
198 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
199 int i;
200 tree e = exp;
201 HOST_WIDE_INT off = 0;
202 for (i = 0; i < 5; i++)
204 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
205 if (!is_gimple_assign (def_stmt)
206 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
207 return 0;
208 tree rhs1 = gimple_assign_rhs1 (def_stmt);
209 tree rhs2 = gimple_assign_rhs2 (def_stmt);
210 if (TREE_CODE (rhs1) != SSA_NAME
211 || !tree_fits_shwi_p (rhs2))
212 return 0;
213 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
214 if (this_off < 0)
215 return 0;
216 off = (unsigned HOST_WIDE_INT) off + this_off;
217 if (off < 0)
218 return 0;
219 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
221 strinfo *si
222 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
223 if (si
224 && si->length
225 && TREE_CODE (si->length) == INTEGER_CST
226 && compare_tree_int (si->length, off) != -1)
227 return get_stridx_plus_constant (si, off, exp);
229 e = rhs1;
231 return 0;
234 if (TREE_CODE (exp) == ADDR_EXPR)
236 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
237 if (idx != 0)
238 return idx;
241 s = string_constant (exp, &o);
242 if (s != NULL_TREE
243 && (o == NULL_TREE || tree_fits_shwi_p (o))
244 && TREE_STRING_LENGTH (s) > 0)
246 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
247 const char *p = TREE_STRING_POINTER (s);
248 int max = TREE_STRING_LENGTH (s) - 1;
250 if (p[max] == '\0' && offset >= 0 && offset <= max)
251 return ~(int) strlen (p + offset);
253 return 0;
256 /* Return true if strinfo vector is shared with the immediate dominator. */
258 static inline bool
259 strinfo_shared (void)
261 return vec_safe_length (stridx_to_strinfo)
262 && (*stridx_to_strinfo)[0] != NULL;
265 /* Unshare strinfo vector that is shared with the immediate dominator. */
267 static void
268 unshare_strinfo_vec (void)
270 strinfo *si;
271 unsigned int i = 0;
273 gcc_assert (strinfo_shared ());
274 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
275 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
276 if (si != NULL)
277 si->refcount++;
278 (*stridx_to_strinfo)[0] = NULL;
281 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
282 Return a pointer to the location where the string index can
283 be stored (if 0) or is stored, or NULL if this can't be tracked. */
285 static int *
286 addr_stridxptr (tree exp)
288 HOST_WIDE_INT off;
290 tree base = get_addr_base_and_unit_offset (exp, &off);
291 if (base == NULL_TREE || !DECL_P (base))
292 return NULL;
294 if (!decl_to_stridxlist_htab)
296 decl_to_stridxlist_htab
297 = new hash_map<tree_decl_hash, stridxlist> (64);
298 gcc_obstack_init (&stridx_obstack);
301 bool existed;
302 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
303 if (existed)
305 int i;
306 for (i = 0; i < 16; i++)
308 if (list->offset == off)
309 return &list->idx;
310 if (list->next == NULL)
311 break;
313 if (i == 16)
314 return NULL;
315 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
316 list = list->next;
319 list->next = NULL;
320 list->offset = off;
321 list->idx = 0;
322 return &list->idx;
325 /* Create a new string index, or return 0 if reached limit. */
327 static int
328 new_stridx (tree exp)
330 int idx;
331 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
332 return 0;
333 if (TREE_CODE (exp) == SSA_NAME)
335 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
336 return 0;
337 idx = max_stridx++;
338 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
339 return idx;
341 if (TREE_CODE (exp) == ADDR_EXPR)
343 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
344 if (pidx != NULL)
346 gcc_assert (*pidx == 0);
347 *pidx = max_stridx++;
348 return *pidx;
351 return 0;
354 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
356 static int
357 new_addr_stridx (tree exp)
359 int *pidx;
360 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
361 return 0;
362 pidx = addr_stridxptr (exp);
363 if (pidx != NULL)
365 gcc_assert (*pidx == 0);
366 *pidx = max_stridx++;
367 return *pidx;
369 return 0;
372 /* Create a new strinfo. */
374 static strinfo *
375 new_strinfo (tree ptr, int idx, tree length)
377 strinfo *si = strinfo_pool.allocate ();
378 si->length = length;
379 si->ptr = ptr;
380 si->stmt = NULL;
381 si->endptr = NULL_TREE;
382 si->refcount = 1;
383 si->idx = idx;
384 si->first = 0;
385 si->prev = 0;
386 si->next = 0;
387 si->writable = false;
388 si->dont_invalidate = false;
389 return si;
392 /* Decrease strinfo refcount and free it if not referenced anymore. */
394 static inline void
395 free_strinfo (strinfo *si)
397 if (si && --si->refcount == 0)
398 strinfo_pool.remove (si);
401 /* Set strinfo in the vector entry IDX to SI. */
403 static inline void
404 set_strinfo (int idx, strinfo *si)
406 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
407 unshare_strinfo_vec ();
408 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
409 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
410 (*stridx_to_strinfo)[idx] = si;
413 /* Return string length, or NULL if it can't be computed. */
415 static tree
416 get_string_length (strinfo *si)
418 if (si->length)
419 return si->length;
421 if (si->stmt)
423 gimple *stmt = si->stmt, *lenstmt;
424 bool with_bounds = gimple_call_with_bounds_p (stmt);
425 tree callee, lhs, fn, tem;
426 location_t loc;
427 gimple_stmt_iterator gsi;
429 gcc_assert (is_gimple_call (stmt));
430 callee = gimple_call_fndecl (stmt);
431 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
432 lhs = gimple_call_lhs (stmt);
433 /* unshare_strinfo is intentionally not called here. The (delayed)
434 transformation of strcpy or strcat into stpcpy is done at the place
435 of the former strcpy/strcat call and so can affect all the strinfos
436 with the same stmt. If they were unshared before and transformation
437 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
438 just compute the right length. */
439 switch (DECL_FUNCTION_CODE (callee))
441 case BUILT_IN_STRCAT:
442 case BUILT_IN_STRCAT_CHK:
443 case BUILT_IN_STRCAT_CHKP:
444 case BUILT_IN_STRCAT_CHK_CHKP:
445 gsi = gsi_for_stmt (stmt);
446 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
447 gcc_assert (lhs == NULL_TREE);
448 tem = unshare_expr (gimple_call_arg (stmt, 0));
449 if (with_bounds)
451 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
452 2, tem, gimple_call_arg (stmt, 1));
453 gimple_call_set_with_bounds (lenstmt, true);
455 else
456 lenstmt = gimple_build_call (fn, 1, tem);
457 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
458 gimple_call_set_lhs (lenstmt, lhs);
459 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
460 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
461 tem = gimple_call_arg (stmt, 0);
462 if (!ptrofftype_p (TREE_TYPE (lhs)))
464 lhs = convert_to_ptrofftype (lhs);
465 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
466 true, GSI_SAME_STMT);
468 lenstmt = gimple_build_assign
469 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
470 POINTER_PLUS_EXPR,tem, lhs);
471 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
472 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
473 lhs = NULL_TREE;
474 /* FALLTHRU */
475 case BUILT_IN_STRCPY:
476 case BUILT_IN_STRCPY_CHK:
477 case BUILT_IN_STRCPY_CHKP:
478 case BUILT_IN_STRCPY_CHK_CHKP:
479 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
480 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
481 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
482 else
483 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
484 if (with_bounds)
485 fn = chkp_maybe_create_clone (fn)->decl;
486 gcc_assert (lhs == NULL_TREE);
487 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
489 fprintf (dump_file, "Optimizing: ");
490 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
492 gimple_call_set_fndecl (stmt, fn);
493 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
494 gimple_call_set_lhs (stmt, lhs);
495 update_stmt (stmt);
496 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
498 fprintf (dump_file, "into: ");
499 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
501 /* FALLTHRU */
502 case BUILT_IN_STPCPY:
503 case BUILT_IN_STPCPY_CHK:
504 case BUILT_IN_STPCPY_CHKP:
505 case BUILT_IN_STPCPY_CHK_CHKP:
506 gcc_assert (lhs != NULL_TREE);
507 loc = gimple_location (stmt);
508 si->endptr = lhs;
509 si->stmt = NULL;
510 lhs = fold_convert_loc (loc, size_type_node, lhs);
511 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
512 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
513 lhs, si->length);
514 break;
515 case BUILT_IN_MALLOC:
516 break;
517 /* BUILT_IN_CALLOC always has si->length set. */
518 default:
519 gcc_unreachable ();
520 break;
524 return si->length;
527 /* Invalidate string length information for strings whose length
528 might change due to stores in stmt. */
530 static bool
531 maybe_invalidate (gimple *stmt)
533 strinfo *si;
534 unsigned int i;
535 bool nonempty = false;
537 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
538 if (si != NULL)
540 if (!si->dont_invalidate)
542 ao_ref r;
543 /* Do not use si->length. */
544 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
545 if (stmt_may_clobber_ref_p_1 (stmt, &r))
547 set_strinfo (i, NULL);
548 free_strinfo (si);
549 continue;
552 si->dont_invalidate = false;
553 nonempty = true;
555 return nonempty;
558 /* Unshare strinfo record SI, if it has refcount > 1 or
559 if stridx_to_strinfo vector is shared with some other
560 bbs. */
562 static strinfo *
563 unshare_strinfo (strinfo *si)
565 strinfo *nsi;
567 if (si->refcount == 1 && !strinfo_shared ())
568 return si;
570 nsi = new_strinfo (si->ptr, si->idx, si->length);
571 nsi->stmt = si->stmt;
572 nsi->endptr = si->endptr;
573 nsi->first = si->first;
574 nsi->prev = si->prev;
575 nsi->next = si->next;
576 nsi->writable = si->writable;
577 set_strinfo (si->idx, nsi);
578 free_strinfo (si);
579 return nsi;
582 /* Return first strinfo in the related strinfo chain
583 if all strinfos in between belong to the chain, otherwise
584 NULL. */
586 static strinfo *
587 verify_related_strinfos (strinfo *origsi)
589 strinfo *si = origsi, *psi;
591 if (origsi->first == 0)
592 return NULL;
593 for (; si->prev; si = psi)
595 if (si->first != origsi->first)
596 return NULL;
597 psi = get_strinfo (si->prev);
598 if (psi == NULL)
599 return NULL;
600 if (psi->next != si->idx)
601 return NULL;
603 if (si->idx != si->first)
604 return NULL;
605 return si;
608 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
609 strinfo if there is any. Return it's idx, or 0 if no strinfo has
610 been created. */
612 static int
613 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
615 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
617 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
618 return 0;
620 if (basesi->length == NULL_TREE
621 || TREE_CODE (basesi->length) != INTEGER_CST
622 || compare_tree_int (basesi->length, off) == -1
623 || !tree_fits_shwi_p (basesi->length))
624 return 0;
626 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
627 strinfo *si = basesi, *chainsi;
628 if (si->first || si->prev || si->next)
629 si = verify_related_strinfos (basesi);
630 if (si == NULL
631 || si->length == NULL_TREE
632 || TREE_CODE (si->length) != INTEGER_CST)
633 return 0;
635 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
636 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
638 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
639 for (chainsi = si; chainsi->next; chainsi = si)
641 si = get_strinfo (chainsi->next);
642 if (si == NULL
643 || si->first != chainsi->first
644 || si->prev != chainsi->idx
645 || si->length == NULL_TREE
646 || TREE_CODE (si->length) != INTEGER_CST)
647 break;
648 int r = compare_tree_int (si->length, len);
649 if (r != 1)
651 if (r == 0)
653 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
654 return si->idx;
656 break;
660 int idx = new_stridx (ptr);
661 if (idx == 0)
662 return 0;
663 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
664 set_strinfo (idx, si);
665 if (chainsi->next)
667 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
668 si->next = nextsi->idx;
669 nextsi->prev = idx;
671 chainsi = unshare_strinfo (chainsi);
672 if (chainsi->first == 0)
673 chainsi->first = chainsi->idx;
674 chainsi->next = idx;
675 if (chainsi->endptr == NULL_TREE && len == 0)
676 chainsi->endptr = ptr;
677 si->endptr = chainsi->endptr;
678 si->prev = chainsi->idx;
679 si->first = chainsi->first;
680 si->writable = chainsi->writable;
681 return si->idx;
684 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
685 to a zero-length string and if possible chain it to a related strinfo
686 chain whose part is or might be CHAINSI. */
688 static strinfo *
689 zero_length_string (tree ptr, strinfo *chainsi)
691 strinfo *si;
692 int idx;
693 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
694 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
695 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
696 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
698 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
699 return NULL;
700 if (chainsi != NULL)
702 si = verify_related_strinfos (chainsi);
703 if (si)
705 chainsi = si;
706 for (; chainsi->next; chainsi = si)
708 if (chainsi->endptr == NULL_TREE)
710 chainsi = unshare_strinfo (chainsi);
711 chainsi->endptr = ptr;
713 si = get_strinfo (chainsi->next);
714 if (si == NULL
715 || si->first != chainsi->first
716 || si->prev != chainsi->idx)
717 break;
719 gcc_assert (chainsi->length || chainsi->stmt);
720 if (chainsi->endptr == NULL_TREE)
722 chainsi = unshare_strinfo (chainsi);
723 chainsi->endptr = ptr;
725 if (chainsi->length && integer_zerop (chainsi->length))
727 if (chainsi->next)
729 chainsi = unshare_strinfo (chainsi);
730 chainsi->next = 0;
732 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
733 return chainsi;
736 else if (chainsi->first || chainsi->prev || chainsi->next)
738 chainsi = unshare_strinfo (chainsi);
739 chainsi->first = 0;
740 chainsi->prev = 0;
741 chainsi->next = 0;
744 idx = new_stridx (ptr);
745 if (idx == 0)
746 return NULL;
747 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
748 set_strinfo (idx, si);
749 si->endptr = ptr;
750 if (chainsi != NULL)
752 chainsi = unshare_strinfo (chainsi);
753 if (chainsi->first == 0)
754 chainsi->first = chainsi->idx;
755 chainsi->next = idx;
756 if (chainsi->endptr == NULL_TREE)
757 chainsi->endptr = ptr;
758 si->prev = chainsi->idx;
759 si->first = chainsi->first;
760 si->writable = chainsi->writable;
762 return si;
765 /* For strinfo ORIGSI whose length has been just updated
766 update also related strinfo lengths (add ADJ to each,
767 but don't adjust ORIGSI). */
769 static void
770 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
772 strinfo *si = verify_related_strinfos (origsi);
774 if (si == NULL)
775 return;
777 while (1)
779 strinfo *nsi;
781 if (si != origsi)
783 tree tem;
785 si = unshare_strinfo (si);
786 if (si->length)
788 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
789 si->length = fold_build2_loc (loc, PLUS_EXPR,
790 TREE_TYPE (si->length), si->length,
791 tem);
793 else if (si->stmt != NULL)
794 /* Delayed length computation is unaffected. */
796 else
797 gcc_unreachable ();
799 si->endptr = NULL_TREE;
800 si->dont_invalidate = true;
802 if (si->next == 0)
803 return;
804 nsi = get_strinfo (si->next);
805 if (nsi == NULL
806 || nsi->first != si->first
807 || nsi->prev != si->idx)
808 return;
809 si = nsi;
813 /* Find if there are other SSA_NAME pointers equal to PTR
814 for which we don't track their string lengths yet. If so, use
815 IDX for them. */
817 static void
818 find_equal_ptrs (tree ptr, int idx)
820 if (TREE_CODE (ptr) != SSA_NAME)
821 return;
822 while (1)
824 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
825 if (!is_gimple_assign (stmt))
826 return;
827 ptr = gimple_assign_rhs1 (stmt);
828 switch (gimple_assign_rhs_code (stmt))
830 case SSA_NAME:
831 break;
832 CASE_CONVERT:
833 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
834 return;
835 if (TREE_CODE (ptr) == SSA_NAME)
836 break;
837 if (TREE_CODE (ptr) != ADDR_EXPR)
838 return;
839 /* FALLTHRU */
840 case ADDR_EXPR:
842 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
843 if (pidx != NULL && *pidx == 0)
844 *pidx = idx;
845 return;
847 default:
848 return;
851 /* We might find an endptr created in this pass. Grow the
852 vector in that case. */
853 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
854 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
856 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
857 return;
858 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
862 /* Return true if STMT is a call to a builtin function with the right
863 arguments and attributes that should be considered for optimization
864 by this pass. */
866 static bool
867 valid_builtin_call (gimple *stmt)
869 if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
870 return false;
872 tree callee = gimple_call_fndecl (stmt);
873 switch (DECL_FUNCTION_CODE (callee))
875 case BUILT_IN_MEMCMP:
876 case BUILT_IN_STRCHR:
877 case BUILT_IN_STRCHR_CHKP:
878 case BUILT_IN_STRLEN:
879 case BUILT_IN_STRLEN_CHKP:
880 /* The above functions should be pure. Punt if they aren't. */
881 if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
882 return false;
883 break;
885 case BUILT_IN_CALLOC:
886 case BUILT_IN_MALLOC:
887 case BUILT_IN_MEMCPY:
888 case BUILT_IN_MEMCPY_CHK:
889 case BUILT_IN_MEMCPY_CHKP:
890 case BUILT_IN_MEMCPY_CHK_CHKP:
891 case BUILT_IN_MEMPCPY:
892 case BUILT_IN_MEMPCPY_CHK:
893 case BUILT_IN_MEMPCPY_CHKP:
894 case BUILT_IN_MEMPCPY_CHK_CHKP:
895 case BUILT_IN_MEMSET:
896 case BUILT_IN_STPCPY:
897 case BUILT_IN_STPCPY_CHK:
898 case BUILT_IN_STPCPY_CHKP:
899 case BUILT_IN_STPCPY_CHK_CHKP:
900 case BUILT_IN_STRCAT:
901 case BUILT_IN_STRCAT_CHK:
902 case BUILT_IN_STRCAT_CHKP:
903 case BUILT_IN_STRCAT_CHK_CHKP:
904 case BUILT_IN_STRCPY:
905 case BUILT_IN_STRCPY_CHK:
906 case BUILT_IN_STRCPY_CHKP:
907 case BUILT_IN_STRCPY_CHK_CHKP:
908 /* The above functions should be neither const nor pure. Punt if they
909 aren't. */
910 if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
911 return false;
912 break;
914 default:
915 break;
918 return true;
921 /* If the last .MEM setter statement before STMT is
922 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
923 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
924 just memcpy (x, y, strlen (y)). SI must be the zero length
925 strinfo. */
927 static void
928 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
930 tree vuse, callee, len;
931 struct laststmt_struct last = laststmt;
932 strinfo *lastsi, *firstsi;
933 unsigned len_arg_no = 2;
935 laststmt.stmt = NULL;
936 laststmt.len = NULL_TREE;
937 laststmt.stridx = 0;
939 if (last.stmt == NULL)
940 return;
942 vuse = gimple_vuse (stmt);
943 if (vuse == NULL_TREE
944 || SSA_NAME_DEF_STMT (vuse) != last.stmt
945 || !has_single_use (vuse))
946 return;
948 gcc_assert (last.stridx > 0);
949 lastsi = get_strinfo (last.stridx);
950 if (lastsi == NULL)
951 return;
953 if (lastsi != si)
955 if (lastsi->first == 0 || lastsi->first != si->first)
956 return;
958 firstsi = verify_related_strinfos (si);
959 if (firstsi == NULL)
960 return;
961 while (firstsi != lastsi)
963 strinfo *nextsi;
964 if (firstsi->next == 0)
965 return;
966 nextsi = get_strinfo (firstsi->next);
967 if (nextsi == NULL
968 || nextsi->prev != firstsi->idx
969 || nextsi->first != si->first)
970 return;
971 firstsi = nextsi;
975 if (!is_strcat)
977 if (si->length == NULL_TREE || !integer_zerop (si->length))
978 return;
981 if (is_gimple_assign (last.stmt))
983 gimple_stmt_iterator gsi;
985 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
986 return;
987 if (stmt_could_throw_p (last.stmt))
988 return;
989 gsi = gsi_for_stmt (last.stmt);
990 unlink_stmt_vdef (last.stmt);
991 release_defs (last.stmt);
992 gsi_remove (&gsi, true);
993 return;
996 if (!valid_builtin_call (last.stmt))
997 return;
999 callee = gimple_call_fndecl (last.stmt);
1000 switch (DECL_FUNCTION_CODE (callee))
1002 case BUILT_IN_MEMCPY:
1003 case BUILT_IN_MEMCPY_CHK:
1004 break;
1005 case BUILT_IN_MEMCPY_CHKP:
1006 case BUILT_IN_MEMCPY_CHK_CHKP:
1007 len_arg_no = 4;
1008 break;
1009 default:
1010 return;
1013 len = gimple_call_arg (last.stmt, len_arg_no);
1014 if (tree_fits_uhwi_p (len))
1016 if (!tree_fits_uhwi_p (last.len)
1017 || integer_zerop (len)
1018 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1019 return;
1020 /* Don't adjust the length if it is divisible by 4, it is more efficient
1021 to store the extra '\0' in that case. */
1022 if ((tree_to_uhwi (len) & 3) == 0)
1023 return;
1025 else if (TREE_CODE (len) == SSA_NAME)
1027 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1028 if (!is_gimple_assign (def_stmt)
1029 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1030 || gimple_assign_rhs1 (def_stmt) != last.len
1031 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1032 return;
1034 else
1035 return;
1037 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1038 update_stmt (last.stmt);
1041 /* Handle a strlen call. If strlen of the argument is known, replace
1042 the strlen call with the known value, otherwise remember that strlen
1043 of the argument is stored in the lhs SSA_NAME. */
1045 static void
1046 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1048 int idx;
1049 tree src;
1050 gimple *stmt = gsi_stmt (*gsi);
1051 tree lhs = gimple_call_lhs (stmt);
1053 if (lhs == NULL_TREE)
1054 return;
1056 src = gimple_call_arg (stmt, 0);
1057 idx = get_stridx (src);
1058 if (idx)
1060 strinfo *si = NULL;
1061 tree rhs;
1063 if (idx < 0)
1064 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1065 else
1067 rhs = NULL_TREE;
1068 si = get_strinfo (idx);
1069 if (si != NULL)
1070 rhs = get_string_length (si);
1072 if (rhs != NULL_TREE)
1074 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1076 fprintf (dump_file, "Optimizing: ");
1077 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1079 rhs = unshare_expr (rhs);
1080 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1081 rhs = fold_convert_loc (gimple_location (stmt),
1082 TREE_TYPE (lhs), rhs);
1083 if (!update_call_from_tree (gsi, rhs))
1084 gimplify_and_update_call_from_tree (gsi, rhs);
1085 stmt = gsi_stmt (*gsi);
1086 update_stmt (stmt);
1087 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1089 fprintf (dump_file, "into: ");
1090 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1092 if (si != NULL
1093 && TREE_CODE (si->length) != SSA_NAME
1094 && TREE_CODE (si->length) != INTEGER_CST
1095 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1097 si = unshare_strinfo (si);
1098 si->length = lhs;
1100 return;
1103 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1104 return;
1105 if (idx == 0)
1106 idx = new_stridx (src);
1107 else if (get_strinfo (idx) != NULL)
1108 return;
1109 if (idx)
1111 strinfo *si = new_strinfo (src, idx, lhs);
1112 set_strinfo (idx, si);
1113 find_equal_ptrs (src, idx);
1117 /* Handle a strchr call. If strlen of the first argument is known, replace
1118 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1119 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1121 static void
1122 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1124 int idx;
1125 tree src;
1126 gimple *stmt = gsi_stmt (*gsi);
1127 tree lhs = gimple_call_lhs (stmt);
1128 bool with_bounds = gimple_call_with_bounds_p (stmt);
1130 if (lhs == NULL_TREE)
1131 return;
1133 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1134 return;
1136 src = gimple_call_arg (stmt, 0);
1137 idx = get_stridx (src);
1138 if (idx)
1140 strinfo *si = NULL;
1141 tree rhs;
1143 if (idx < 0)
1144 rhs = build_int_cst (size_type_node, ~idx);
1145 else
1147 rhs = NULL_TREE;
1148 si = get_strinfo (idx);
1149 if (si != NULL)
1150 rhs = get_string_length (si);
1152 if (rhs != NULL_TREE)
1154 location_t loc = gimple_location (stmt);
1156 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1158 fprintf (dump_file, "Optimizing: ");
1159 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1161 if (si != NULL && si->endptr != NULL_TREE)
1163 rhs = unshare_expr (si->endptr);
1164 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1165 TREE_TYPE (rhs)))
1166 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1168 else
1170 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1171 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1172 TREE_TYPE (src), src, rhs);
1173 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1174 TREE_TYPE (rhs)))
1175 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1177 if (!update_call_from_tree (gsi, rhs))
1178 gimplify_and_update_call_from_tree (gsi, rhs);
1179 stmt = gsi_stmt (*gsi);
1180 update_stmt (stmt);
1181 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1183 fprintf (dump_file, "into: ");
1184 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1186 if (si != NULL
1187 && si->endptr == NULL_TREE
1188 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1190 si = unshare_strinfo (si);
1191 si->endptr = lhs;
1193 zero_length_string (lhs, si);
1194 return;
1197 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1198 return;
1199 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1201 if (idx == 0)
1202 idx = new_stridx (src);
1203 else if (get_strinfo (idx) != NULL)
1205 zero_length_string (lhs, NULL);
1206 return;
1208 if (idx)
1210 location_t loc = gimple_location (stmt);
1211 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1212 tree srcu = fold_convert_loc (loc, size_type_node, src);
1213 tree length = fold_build2_loc (loc, MINUS_EXPR,
1214 size_type_node, lhsu, srcu);
1215 strinfo *si = new_strinfo (src, idx, length);
1216 si->endptr = lhs;
1217 set_strinfo (idx, si);
1218 find_equal_ptrs (src, idx);
1219 zero_length_string (lhs, si);
1222 else
1223 zero_length_string (lhs, NULL);
1226 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1227 If strlen of the second argument is known, strlen of the first argument
1228 is the same after this call. Furthermore, attempt to convert it to
1229 memcpy. */
1231 static void
1232 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1234 int idx, didx;
1235 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1236 bool success;
1237 gimple *stmt = gsi_stmt (*gsi);
1238 strinfo *si, *dsi, *olddsi, *zsi;
1239 location_t loc;
1240 bool with_bounds = gimple_call_with_bounds_p (stmt);
1242 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1243 dst = gimple_call_arg (stmt, 0);
1244 lhs = gimple_call_lhs (stmt);
1245 idx = get_stridx (src);
1246 si = NULL;
1247 if (idx > 0)
1248 si = get_strinfo (idx);
1250 didx = get_stridx (dst);
1251 olddsi = NULL;
1252 oldlen = NULL_TREE;
1253 if (didx > 0)
1254 olddsi = get_strinfo (didx);
1255 else if (didx < 0)
1256 return;
1258 if (olddsi != NULL)
1259 adjust_last_stmt (olddsi, stmt, false);
1261 srclen = NULL_TREE;
1262 if (si != NULL)
1263 srclen = get_string_length (si);
1264 else if (idx < 0)
1265 srclen = build_int_cst (size_type_node, ~idx);
1267 loc = gimple_location (stmt);
1268 if (srclen == NULL_TREE)
1269 switch (bcode)
1271 case BUILT_IN_STRCPY:
1272 case BUILT_IN_STRCPY_CHK:
1273 case BUILT_IN_STRCPY_CHKP:
1274 case BUILT_IN_STRCPY_CHK_CHKP:
1275 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1276 return;
1277 break;
1278 case BUILT_IN_STPCPY:
1279 case BUILT_IN_STPCPY_CHK:
1280 case BUILT_IN_STPCPY_CHKP:
1281 case BUILT_IN_STPCPY_CHK_CHKP:
1282 if (lhs == NULL_TREE)
1283 return;
1284 else
1286 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1287 srclen = fold_convert_loc (loc, size_type_node, dst);
1288 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1289 lhsuint, srclen);
1291 break;
1292 default:
1293 gcc_unreachable ();
1296 if (didx == 0)
1298 didx = new_stridx (dst);
1299 if (didx == 0)
1300 return;
1302 if (olddsi != NULL)
1304 oldlen = olddsi->length;
1305 dsi = unshare_strinfo (olddsi);
1306 dsi->length = srclen;
1307 /* Break the chain, so adjust_related_strinfo on later pointers in
1308 the chain won't adjust this one anymore. */
1309 dsi->next = 0;
1310 dsi->stmt = NULL;
1311 dsi->endptr = NULL_TREE;
1313 else
1315 dsi = new_strinfo (dst, didx, srclen);
1316 set_strinfo (didx, dsi);
1317 find_equal_ptrs (dst, didx);
1319 dsi->writable = true;
1320 dsi->dont_invalidate = true;
1322 if (dsi->length == NULL_TREE)
1324 strinfo *chainsi;
1326 /* If string length of src is unknown, use delayed length
1327 computation. If string lenth of dst will be needed, it
1328 can be computed by transforming this strcpy call into
1329 stpcpy and subtracting dst from the return value. */
1331 /* Look for earlier strings whose length could be determined if
1332 this strcpy is turned into an stpcpy. */
1334 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1336 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1338 /* When setting a stmt for delayed length computation
1339 prevent all strinfos through dsi from being
1340 invalidated. */
1341 chainsi = unshare_strinfo (chainsi);
1342 chainsi->stmt = stmt;
1343 chainsi->length = NULL_TREE;
1344 chainsi->endptr = NULL_TREE;
1345 chainsi->dont_invalidate = true;
1348 dsi->stmt = stmt;
1349 return;
1352 if (olddsi != NULL)
1354 tree adj = NULL_TREE;
1355 if (oldlen == NULL_TREE)
1357 else if (integer_zerop (oldlen))
1358 adj = srclen;
1359 else if (TREE_CODE (oldlen) == INTEGER_CST
1360 || TREE_CODE (srclen) == INTEGER_CST)
1361 adj = fold_build2_loc (loc, MINUS_EXPR,
1362 TREE_TYPE (srclen), srclen,
1363 fold_convert_loc (loc, TREE_TYPE (srclen),
1364 oldlen));
1365 if (adj != NULL_TREE)
1366 adjust_related_strinfos (loc, dsi, adj);
1367 else
1368 dsi->prev = 0;
1370 /* strcpy src may not overlap dst, so src doesn't need to be
1371 invalidated either. */
1372 if (si != NULL)
1373 si->dont_invalidate = true;
1375 fn = NULL_TREE;
1376 zsi = NULL;
1377 switch (bcode)
1379 case BUILT_IN_STRCPY:
1380 case BUILT_IN_STRCPY_CHKP:
1381 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1382 if (lhs)
1383 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1384 break;
1385 case BUILT_IN_STRCPY_CHK:
1386 case BUILT_IN_STRCPY_CHK_CHKP:
1387 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1388 if (lhs)
1389 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1390 break;
1391 case BUILT_IN_STPCPY:
1392 case BUILT_IN_STPCPY_CHKP:
1393 /* This would need adjustment of the lhs (subtract one),
1394 or detection that the trailing '\0' doesn't need to be
1395 written, if it will be immediately overwritten.
1396 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1397 if (lhs)
1399 dsi->endptr = lhs;
1400 zsi = zero_length_string (lhs, dsi);
1402 break;
1403 case BUILT_IN_STPCPY_CHK:
1404 case BUILT_IN_STPCPY_CHK_CHKP:
1405 /* This would need adjustment of the lhs (subtract one),
1406 or detection that the trailing '\0' doesn't need to be
1407 written, if it will be immediately overwritten.
1408 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1409 if (lhs)
1411 dsi->endptr = lhs;
1412 zsi = zero_length_string (lhs, dsi);
1414 break;
1415 default:
1416 gcc_unreachable ();
1418 if (zsi != NULL)
1419 zsi->dont_invalidate = true;
1421 if (fn == NULL_TREE)
1422 return;
1424 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1425 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1427 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1428 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1429 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1430 GSI_SAME_STMT);
1431 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1433 fprintf (dump_file, "Optimizing: ");
1434 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1436 if (with_bounds)
1438 fn = chkp_maybe_create_clone (fn)->decl;
1439 if (gimple_call_num_args (stmt) == 4)
1440 success = update_gimple_call (gsi, fn, 5, dst,
1441 gimple_call_arg (stmt, 1),
1442 src,
1443 gimple_call_arg (stmt, 3),
1444 len);
1445 else
1446 success = update_gimple_call (gsi, fn, 6, dst,
1447 gimple_call_arg (stmt, 1),
1448 src,
1449 gimple_call_arg (stmt, 3),
1450 len,
1451 gimple_call_arg (stmt, 4));
1453 else
1454 if (gimple_call_num_args (stmt) == 2)
1455 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1456 else
1457 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1458 gimple_call_arg (stmt, 2));
1459 if (success)
1461 stmt = gsi_stmt (*gsi);
1462 gimple_call_set_with_bounds (stmt, with_bounds);
1463 update_stmt (stmt);
1464 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1466 fprintf (dump_file, "into: ");
1467 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1469 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1470 laststmt.stmt = stmt;
1471 laststmt.len = srclen;
1472 laststmt.stridx = dsi->idx;
1474 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1475 fprintf (dump_file, "not possible.\n");
1478 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1479 If strlen of the second argument is known and length of the third argument
1480 is that plus one, strlen of the first argument is the same after this
1481 call. */
1483 static void
1484 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1486 int idx, didx;
1487 tree src, dst, len, lhs, oldlen, newlen;
1488 gimple *stmt = gsi_stmt (*gsi);
1489 strinfo *si, *dsi, *olddsi;
1490 bool with_bounds = gimple_call_with_bounds_p (stmt);
1492 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1493 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1494 dst = gimple_call_arg (stmt, 0);
1495 idx = get_stridx (src);
1496 if (idx == 0)
1497 return;
1499 didx = get_stridx (dst);
1500 olddsi = NULL;
1501 if (didx > 0)
1502 olddsi = get_strinfo (didx);
1503 else if (didx < 0)
1504 return;
1506 if (olddsi != NULL
1507 && tree_fits_uhwi_p (len)
1508 && !integer_zerop (len))
1509 adjust_last_stmt (olddsi, stmt, false);
1511 if (idx > 0)
1513 gimple *def_stmt;
1515 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1516 si = get_strinfo (idx);
1517 if (si == NULL || si->length == NULL_TREE)
1518 return;
1519 if (TREE_CODE (len) != SSA_NAME)
1520 return;
1521 def_stmt = SSA_NAME_DEF_STMT (len);
1522 if (!is_gimple_assign (def_stmt)
1523 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1524 || gimple_assign_rhs1 (def_stmt) != si->length
1525 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1526 return;
1528 else
1530 si = NULL;
1531 /* Handle memcpy (x, "abcd", 5) or
1532 memcpy (x, "abc\0uvw", 7). */
1533 if (!tree_fits_uhwi_p (len)
1534 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1535 return;
1538 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1539 adjust_last_stmt (olddsi, stmt, false);
1541 if (didx == 0)
1543 didx = new_stridx (dst);
1544 if (didx == 0)
1545 return;
1547 if (si != NULL)
1548 newlen = si->length;
1549 else
1550 newlen = build_int_cst (size_type_node, ~idx);
1551 oldlen = NULL_TREE;
1552 if (olddsi != NULL)
1554 dsi = unshare_strinfo (olddsi);
1555 oldlen = olddsi->length;
1556 dsi->length = newlen;
1557 /* Break the chain, so adjust_related_strinfo on later pointers in
1558 the chain won't adjust this one anymore. */
1559 dsi->next = 0;
1560 dsi->stmt = NULL;
1561 dsi->endptr = NULL_TREE;
1563 else
1565 dsi = new_strinfo (dst, didx, newlen);
1566 set_strinfo (didx, dsi);
1567 find_equal_ptrs (dst, didx);
1569 dsi->writable = true;
1570 dsi->dont_invalidate = true;
1571 if (olddsi != NULL)
1573 tree adj = NULL_TREE;
1574 location_t loc = gimple_location (stmt);
1575 if (oldlen == NULL_TREE)
1577 else if (integer_zerop (oldlen))
1578 adj = dsi->length;
1579 else if (TREE_CODE (oldlen) == INTEGER_CST
1580 || TREE_CODE (dsi->length) == INTEGER_CST)
1581 adj = fold_build2_loc (loc, MINUS_EXPR,
1582 TREE_TYPE (dsi->length), dsi->length,
1583 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1584 oldlen));
1585 if (adj != NULL_TREE)
1586 adjust_related_strinfos (loc, dsi, adj);
1587 else
1588 dsi->prev = 0;
1590 /* memcpy src may not overlap dst, so src doesn't need to be
1591 invalidated either. */
1592 if (si != NULL)
1593 si->dont_invalidate = true;
1595 lhs = gimple_call_lhs (stmt);
1596 switch (bcode)
1598 case BUILT_IN_MEMCPY:
1599 case BUILT_IN_MEMCPY_CHK:
1600 case BUILT_IN_MEMCPY_CHKP:
1601 case BUILT_IN_MEMCPY_CHK_CHKP:
1602 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1603 laststmt.stmt = stmt;
1604 laststmt.len = dsi->length;
1605 laststmt.stridx = dsi->idx;
1606 if (lhs)
1607 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1608 break;
1609 case BUILT_IN_MEMPCPY:
1610 case BUILT_IN_MEMPCPY_CHK:
1611 case BUILT_IN_MEMPCPY_CHKP:
1612 case BUILT_IN_MEMPCPY_CHK_CHKP:
1613 break;
1614 default:
1615 gcc_unreachable ();
1619 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1620 If strlen of the second argument is known, strlen of the first argument
1621 is increased by the length of the second argument. Furthermore, attempt
1622 to convert it to memcpy/strcpy if the length of the first argument
1623 is known. */
1625 static void
1626 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1628 int idx, didx;
1629 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1630 bool success;
1631 gimple *stmt = gsi_stmt (*gsi);
1632 strinfo *si, *dsi;
1633 location_t loc;
1634 bool with_bounds = gimple_call_with_bounds_p (stmt);
1636 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1637 dst = gimple_call_arg (stmt, 0);
1638 lhs = gimple_call_lhs (stmt);
1640 didx = get_stridx (dst);
1641 if (didx < 0)
1642 return;
1644 dsi = NULL;
1645 if (didx > 0)
1646 dsi = get_strinfo (didx);
1647 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1649 /* strcat (p, q) can be transformed into
1650 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1651 with length endptr - p if we need to compute the length
1652 later on. Don't do this transformation if we don't need
1653 it. */
1654 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1656 if (didx == 0)
1658 didx = new_stridx (dst);
1659 if (didx == 0)
1660 return;
1662 if (dsi == NULL)
1664 dsi = new_strinfo (dst, didx, NULL_TREE);
1665 set_strinfo (didx, dsi);
1666 find_equal_ptrs (dst, didx);
1668 else
1670 dsi = unshare_strinfo (dsi);
1671 dsi->length = NULL_TREE;
1672 dsi->next = 0;
1673 dsi->endptr = NULL_TREE;
1675 dsi->writable = true;
1676 dsi->stmt = stmt;
1677 dsi->dont_invalidate = true;
1679 return;
1682 srclen = NULL_TREE;
1683 si = NULL;
1684 idx = get_stridx (src);
1685 if (idx < 0)
1686 srclen = build_int_cst (size_type_node, ~idx);
1687 else if (idx > 0)
1689 si = get_strinfo (idx);
1690 if (si != NULL)
1691 srclen = get_string_length (si);
1694 loc = gimple_location (stmt);
1695 dstlen = dsi->length;
1696 endptr = dsi->endptr;
1698 dsi = unshare_strinfo (dsi);
1699 dsi->endptr = NULL_TREE;
1700 dsi->stmt = NULL;
1701 dsi->writable = true;
1703 if (srclen != NULL_TREE)
1705 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1706 dsi->length, srclen);
1707 adjust_related_strinfos (loc, dsi, srclen);
1708 dsi->dont_invalidate = true;
1710 else
1712 dsi->length = NULL;
1713 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1714 dsi->dont_invalidate = true;
1717 if (si != NULL)
1718 /* strcat src may not overlap dst, so src doesn't need to be
1719 invalidated either. */
1720 si->dont_invalidate = true;
1722 /* For now. Could remove the lhs from the call and add
1723 lhs = dst; afterwards. */
1724 if (lhs)
1725 return;
1727 fn = NULL_TREE;
1728 objsz = NULL_TREE;
1729 switch (bcode)
1731 case BUILT_IN_STRCAT:
1732 case BUILT_IN_STRCAT_CHKP:
1733 if (srclen != NULL_TREE)
1734 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1735 else
1736 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1737 break;
1738 case BUILT_IN_STRCAT_CHK:
1739 case BUILT_IN_STRCAT_CHK_CHKP:
1740 if (srclen != NULL_TREE)
1741 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1742 else
1743 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1744 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1745 break;
1746 default:
1747 gcc_unreachable ();
1750 if (fn == NULL_TREE)
1751 return;
1753 len = NULL_TREE;
1754 if (srclen != NULL_TREE)
1756 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1757 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1759 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1760 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1761 build_int_cst (type, 1));
1762 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1763 GSI_SAME_STMT);
1765 if (endptr)
1766 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1767 else
1768 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1769 TREE_TYPE (dst), unshare_expr (dst),
1770 fold_convert_loc (loc, sizetype,
1771 unshare_expr (dstlen)));
1772 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1773 GSI_SAME_STMT);
1774 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1776 fprintf (dump_file, "Optimizing: ");
1777 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1779 if (with_bounds)
1781 fn = chkp_maybe_create_clone (fn)->decl;
1782 if (srclen != NULL_TREE)
1783 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1784 dst,
1785 gimple_call_arg (stmt, 1),
1786 src,
1787 gimple_call_arg (stmt, 3),
1788 len, objsz);
1789 else
1790 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1791 dst,
1792 gimple_call_arg (stmt, 1),
1793 src,
1794 gimple_call_arg (stmt, 3),
1795 objsz);
1797 else
1798 if (srclen != NULL_TREE)
1799 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1800 dst, src, len, objsz);
1801 else
1802 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1803 dst, src, objsz);
1804 if (success)
1806 stmt = gsi_stmt (*gsi);
1807 gimple_call_set_with_bounds (stmt, with_bounds);
1808 update_stmt (stmt);
1809 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1811 fprintf (dump_file, "into: ");
1812 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1814 /* If srclen == NULL, note that current string length can be
1815 computed by transforming this strcpy into stpcpy. */
1816 if (srclen == NULL_TREE && dsi->dont_invalidate)
1817 dsi->stmt = stmt;
1818 adjust_last_stmt (dsi, stmt, true);
1819 if (srclen != NULL_TREE)
1821 laststmt.stmt = stmt;
1822 laststmt.len = srclen;
1823 laststmt.stridx = dsi->idx;
1826 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1827 fprintf (dump_file, "not possible.\n");
1830 /* Handle a call to malloc or calloc. */
1832 static void
1833 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1835 gimple *stmt = gsi_stmt (*gsi);
1836 tree lhs = gimple_call_lhs (stmt);
1837 gcc_assert (get_stridx (lhs) == 0);
1838 int idx = new_stridx (lhs);
1839 tree length = NULL_TREE;
1840 if (bcode == BUILT_IN_CALLOC)
1841 length = build_int_cst (size_type_node, 0);
1842 strinfo *si = new_strinfo (lhs, idx, length);
1843 if (bcode == BUILT_IN_CALLOC)
1844 si->endptr = lhs;
1845 set_strinfo (idx, si);
1846 si->writable = true;
1847 si->stmt = stmt;
1848 si->dont_invalidate = true;
1851 /* Handle a call to memset.
1852 After a call to calloc, memset(,0,) is unnecessary.
1853 memset(malloc(n),0,n) is calloc(n,1). */
1855 static bool
1856 handle_builtin_memset (gimple_stmt_iterator *gsi)
1858 gimple *stmt2 = gsi_stmt (*gsi);
1859 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1860 return true;
1861 tree ptr = gimple_call_arg (stmt2, 0);
1862 int idx1 = get_stridx (ptr);
1863 if (idx1 <= 0)
1864 return true;
1865 strinfo *si1 = get_strinfo (idx1);
1866 if (!si1)
1867 return true;
1868 gimple *stmt1 = si1->stmt;
1869 if (!stmt1 || !is_gimple_call (stmt1))
1870 return true;
1871 tree callee1 = gimple_call_fndecl (stmt1);
1872 if (!valid_builtin_call (stmt1))
1873 return true;
1874 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1875 tree size = gimple_call_arg (stmt2, 2);
1876 if (code1 == BUILT_IN_CALLOC)
1877 /* Not touching stmt1 */ ;
1878 else if (code1 == BUILT_IN_MALLOC
1879 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1881 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1882 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1883 size, build_one_cst (size_type_node));
1884 si1->length = build_int_cst (size_type_node, 0);
1885 si1->stmt = gsi_stmt (gsi1);
1887 else
1888 return true;
1889 tree lhs = gimple_call_lhs (stmt2);
1890 unlink_stmt_vdef (stmt2);
1891 if (lhs)
1893 gimple *assign = gimple_build_assign (lhs, ptr);
1894 gsi_replace (gsi, assign, false);
1896 else
1898 gsi_remove (gsi, true);
1899 release_defs (stmt2);
1902 return false;
1905 /* Handle a POINTER_PLUS_EXPR statement.
1906 For p = "abcd" + 2; compute associated length, or if
1907 p = q + off is pointing to a '\0' character of a string, call
1908 zero_length_string on it. */
1910 static void
1911 handle_pointer_plus (gimple_stmt_iterator *gsi)
1913 gimple *stmt = gsi_stmt (*gsi);
1914 tree lhs = gimple_assign_lhs (stmt), off;
1915 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1916 strinfo *si, *zsi;
1918 if (idx == 0)
1919 return;
1921 if (idx < 0)
1923 tree off = gimple_assign_rhs2 (stmt);
1924 if (tree_fits_uhwi_p (off)
1925 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1926 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1927 = ~(~idx - (int) tree_to_uhwi (off));
1928 return;
1931 si = get_strinfo (idx);
1932 if (si == NULL || si->length == NULL_TREE)
1933 return;
1935 off = gimple_assign_rhs2 (stmt);
1936 zsi = NULL;
1937 if (operand_equal_p (si->length, off, 0))
1938 zsi = zero_length_string (lhs, si);
1939 else if (TREE_CODE (off) == SSA_NAME)
1941 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
1942 if (gimple_assign_single_p (def_stmt)
1943 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1944 zsi = zero_length_string (lhs, si);
1946 if (zsi != NULL
1947 && si->endptr != NULL_TREE
1948 && si->endptr != lhs
1949 && TREE_CODE (si->endptr) == SSA_NAME)
1951 enum tree_code rhs_code
1952 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1953 ? SSA_NAME : NOP_EXPR;
1954 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
1955 gcc_assert (gsi_stmt (*gsi) == stmt);
1956 update_stmt (stmt);
1960 /* Handle a single character store. */
1962 static bool
1963 handle_char_store (gimple_stmt_iterator *gsi)
1965 int idx = -1;
1966 strinfo *si = NULL;
1967 gimple *stmt = gsi_stmt (*gsi);
1968 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1970 if (TREE_CODE (lhs) == MEM_REF
1971 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1973 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1975 ssaname = TREE_OPERAND (lhs, 0);
1976 idx = get_stridx (ssaname);
1979 else
1980 idx = get_addr_stridx (lhs);
1982 if (idx > 0)
1984 si = get_strinfo (idx);
1985 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1987 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1989 /* When storing '\0', the store can be removed
1990 if we know it has been stored in the current function. */
1991 if (!stmt_could_throw_p (stmt) && si->writable)
1993 unlink_stmt_vdef (stmt);
1994 release_defs (stmt);
1995 gsi_remove (gsi, true);
1996 return false;
1998 else
2000 si->writable = true;
2001 gsi_next (gsi);
2002 return false;
2005 else
2006 /* Otherwise this statement overwrites the '\0' with
2007 something, if the previous stmt was a memcpy,
2008 its length may be decreased. */
2009 adjust_last_stmt (si, stmt, false);
2011 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
2013 si = unshare_strinfo (si);
2014 si->length = build_int_cst (size_type_node, 0);
2015 si->endptr = NULL;
2016 si->prev = 0;
2017 si->next = 0;
2018 si->stmt = NULL;
2019 si->first = 0;
2020 si->writable = true;
2021 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2022 si->endptr = ssaname;
2023 si->dont_invalidate = true;
2025 /* If si->length is non-zero constant, we aren't overwriting '\0',
2026 and if we aren't storing '\0', we know that the length of the
2027 string and any other zero terminated string in memory remains
2028 the same. In that case we move to the next gimple statement and
2029 return to signal the caller that it shouldn't invalidate anything.
2031 This is benefical for cases like:
2033 char p[20];
2034 void foo (char *q)
2036 strcpy (p, "foobar");
2037 size_t len = strlen (p); // This can be optimized into 6
2038 size_t len2 = strlen (q); // This has to be computed
2039 p[0] = 'X';
2040 size_t len3 = strlen (p); // This can be optimized into 6
2041 size_t len4 = strlen (q); // This can be optimized into len2
2042 bar (len, len2, len3, len4);
2045 else if (si != NULL && si->length != NULL_TREE
2046 && TREE_CODE (si->length) == INTEGER_CST
2047 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2049 gsi_next (gsi);
2050 return false;
2053 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2055 if (ssaname)
2057 si = zero_length_string (ssaname, NULL);
2058 if (si != NULL)
2059 si->dont_invalidate = true;
2061 else
2063 int idx = new_addr_stridx (lhs);
2064 if (idx != 0)
2066 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2067 build_int_cst (size_type_node, 0));
2068 set_strinfo (idx, si);
2069 si->dont_invalidate = true;
2072 if (si != NULL)
2073 si->writable = true;
2075 else if (idx == 0
2076 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2077 && ssaname == NULL_TREE
2078 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2080 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2081 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2082 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2084 int idx = new_addr_stridx (lhs);
2085 if (idx != 0)
2087 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2088 build_int_cst (size_type_node, l));
2089 set_strinfo (idx, si);
2090 si->dont_invalidate = true;
2095 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2097 /* Allow adjust_last_stmt to remove it if the stored '\0'
2098 is immediately overwritten. */
2099 laststmt.stmt = stmt;
2100 laststmt.len = build_int_cst (size_type_node, 1);
2101 laststmt.stridx = si->idx;
2103 return true;
2106 /* Attempt to optimize a single statement at *GSI using string length
2107 knowledge. */
2109 static bool
2110 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2112 gimple *stmt = gsi_stmt (*gsi);
2114 if (is_gimple_call (stmt))
2116 tree callee = gimple_call_fndecl (stmt);
2117 if (valid_builtin_call (stmt))
2118 switch (DECL_FUNCTION_CODE (callee))
2120 case BUILT_IN_STRLEN:
2121 case BUILT_IN_STRLEN_CHKP:
2122 handle_builtin_strlen (gsi);
2123 break;
2124 case BUILT_IN_STRCHR:
2125 case BUILT_IN_STRCHR_CHKP:
2126 handle_builtin_strchr (gsi);
2127 break;
2128 case BUILT_IN_STRCPY:
2129 case BUILT_IN_STRCPY_CHK:
2130 case BUILT_IN_STPCPY:
2131 case BUILT_IN_STPCPY_CHK:
2132 case BUILT_IN_STRCPY_CHKP:
2133 case BUILT_IN_STRCPY_CHK_CHKP:
2134 case BUILT_IN_STPCPY_CHKP:
2135 case BUILT_IN_STPCPY_CHK_CHKP:
2136 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2137 break;
2138 case BUILT_IN_MEMCPY:
2139 case BUILT_IN_MEMCPY_CHK:
2140 case BUILT_IN_MEMPCPY:
2141 case BUILT_IN_MEMPCPY_CHK:
2142 case BUILT_IN_MEMCPY_CHKP:
2143 case BUILT_IN_MEMCPY_CHK_CHKP:
2144 case BUILT_IN_MEMPCPY_CHKP:
2145 case BUILT_IN_MEMPCPY_CHK_CHKP:
2146 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2147 break;
2148 case BUILT_IN_STRCAT:
2149 case BUILT_IN_STRCAT_CHK:
2150 case BUILT_IN_STRCAT_CHKP:
2151 case BUILT_IN_STRCAT_CHK_CHKP:
2152 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2153 break;
2154 case BUILT_IN_MALLOC:
2155 case BUILT_IN_CALLOC:
2156 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2157 break;
2158 case BUILT_IN_MEMSET:
2159 if (!handle_builtin_memset (gsi))
2160 return false;
2161 break;
2162 default:
2163 break;
2166 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2168 tree lhs = gimple_assign_lhs (stmt);
2170 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2172 if (gimple_assign_single_p (stmt)
2173 || (gimple_assign_cast_p (stmt)
2174 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2176 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2177 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2179 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2180 handle_pointer_plus (gsi);
2182 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2184 tree type = TREE_TYPE (lhs);
2185 if (TREE_CODE (type) == ARRAY_TYPE)
2186 type = TREE_TYPE (type);
2187 if (TREE_CODE (type) == INTEGER_TYPE
2188 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2189 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2191 if (! handle_char_store (gsi))
2192 return false;
2197 if (gimple_vdef (stmt))
2198 maybe_invalidate (stmt);
2199 return true;
2202 /* Recursively call maybe_invalidate on stmts that might be executed
2203 in between dombb and current bb and that contain a vdef. Stop when
2204 *count stmts are inspected, or if the whole strinfo vector has
2205 been invalidated. */
2207 static void
2208 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2210 unsigned int i, n = gimple_phi_num_args (phi);
2212 for (i = 0; i < n; i++)
2214 tree vuse = gimple_phi_arg_def (phi, i);
2215 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2216 basic_block bb = gimple_bb (stmt);
2217 if (bb == NULL
2218 || bb == dombb
2219 || !bitmap_set_bit (visited, bb->index)
2220 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2221 continue;
2222 while (1)
2224 if (gimple_code (stmt) == GIMPLE_PHI)
2226 do_invalidate (dombb, stmt, visited, count);
2227 if (*count == 0)
2228 return;
2229 break;
2231 if (--*count == 0)
2232 return;
2233 if (!maybe_invalidate (stmt))
2235 *count = 0;
2236 return;
2238 vuse = gimple_vuse (stmt);
2239 stmt = SSA_NAME_DEF_STMT (vuse);
2240 if (gimple_bb (stmt) != bb)
2242 bb = gimple_bb (stmt);
2243 if (bb == NULL
2244 || bb == dombb
2245 || !bitmap_set_bit (visited, bb->index)
2246 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2247 break;
2253 class strlen_dom_walker : public dom_walker
2255 public:
2256 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2258 virtual edge before_dom_children (basic_block);
2259 virtual void after_dom_children (basic_block);
2262 /* Callback for walk_dominator_tree. Attempt to optimize various
2263 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2265 edge
2266 strlen_dom_walker::before_dom_children (basic_block bb)
2268 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2270 if (dombb == NULL)
2271 stridx_to_strinfo = NULL;
2272 else
2274 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2275 if (stridx_to_strinfo)
2277 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2278 gsi_next (&gsi))
2280 gphi *phi = gsi.phi ();
2281 if (virtual_operand_p (gimple_phi_result (phi)))
2283 bitmap visited = BITMAP_ALLOC (NULL);
2284 int count_vdef = 100;
2285 do_invalidate (dombb, phi, visited, &count_vdef);
2286 BITMAP_FREE (visited);
2287 if (count_vdef == 0)
2289 /* If there were too many vdefs in between immediate
2290 dominator and current bb, invalidate everything.
2291 If stridx_to_strinfo has been unshared, we need
2292 to free it, otherwise just set it to NULL. */
2293 if (!strinfo_shared ())
2295 unsigned int i;
2296 strinfo *si;
2298 for (i = 1;
2299 vec_safe_iterate (stridx_to_strinfo, i, &si);
2300 ++i)
2302 free_strinfo (si);
2303 (*stridx_to_strinfo)[i] = NULL;
2306 else
2307 stridx_to_strinfo = NULL;
2309 break;
2315 /* If all PHI arguments have the same string index, the PHI result
2316 has it as well. */
2317 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2318 gsi_next (&gsi))
2320 gphi *phi = gsi.phi ();
2321 tree result = gimple_phi_result (phi);
2322 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2324 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2325 if (idx != 0)
2327 unsigned int i, n = gimple_phi_num_args (phi);
2328 for (i = 1; i < n; i++)
2329 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2330 break;
2331 if (i == n)
2332 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2337 /* Attempt to optimize individual statements. */
2338 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2339 if (strlen_optimize_stmt (&gsi))
2340 gsi_next (&gsi);
2342 bb->aux = stridx_to_strinfo;
2343 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2344 (*stridx_to_strinfo)[0] = (strinfo *) bb;
2345 return NULL;
2348 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2349 owned by the current bb, clear bb->aux. */
2351 void
2352 strlen_dom_walker::after_dom_children (basic_block bb)
2354 if (bb->aux)
2356 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2357 if (vec_safe_length (stridx_to_strinfo)
2358 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2360 unsigned int i;
2361 strinfo *si;
2363 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2364 free_strinfo (si);
2365 vec_free (stridx_to_strinfo);
2367 bb->aux = NULL;
2371 /* Main entry point. */
2373 namespace {
2375 const pass_data pass_data_strlen =
2377 GIMPLE_PASS, /* type */
2378 "strlen", /* name */
2379 OPTGROUP_NONE, /* optinfo_flags */
2380 TV_TREE_STRLEN, /* tv_id */
2381 ( PROP_cfg | PROP_ssa ), /* properties_required */
2382 0, /* properties_provided */
2383 0, /* properties_destroyed */
2384 0, /* todo_flags_start */
2385 0, /* todo_flags_finish */
2388 class pass_strlen : public gimple_opt_pass
2390 public:
2391 pass_strlen (gcc::context *ctxt)
2392 : gimple_opt_pass (pass_data_strlen, ctxt)
2395 /* opt_pass methods: */
2396 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2397 virtual unsigned int execute (function *);
2399 }; // class pass_strlen
2401 unsigned int
2402 pass_strlen::execute (function *fun)
2404 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2405 max_stridx = 1;
2407 calculate_dominance_info (CDI_DOMINATORS);
2409 /* String length optimization is implemented as a walk of the dominator
2410 tree and a forward walk of statements within each block. */
2411 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2413 ssa_ver_to_stridx.release ();
2414 strinfo_pool.release ();
2415 if (decl_to_stridxlist_htab)
2417 obstack_free (&stridx_obstack, NULL);
2418 delete decl_to_stridxlist_htab;
2419 decl_to_stridxlist_htab = NULL;
2421 laststmt.stmt = NULL;
2422 laststmt.len = NULL_TREE;
2423 laststmt.stridx = 0;
2425 return 0;
2428 } // anon namespace
2430 gimple_opt_pass *
2431 make_pass_strlen (gcc::context *ctxt)
2433 return new pass_strlen (ctxt);