revert:
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob9430fac3f30b3822ecc04151798eb99099ff302f
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 "alias.h"
25 #include "backend.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "rtl.h"
29 #include "ssa.h"
30 #include "options.h"
31 #include "fold-const.h"
32 #include "stor-layout.h"
33 #include "internal-fn.h"
34 #include "gimple-fold.h"
35 #include "tree-eh.h"
36 #include "gimplify.h"
37 #include "gimple-iterator.h"
38 #include "gimplify-me.h"
39 #include "flags.h"
40 #include "insn-config.h"
41 #include "expmed.h"
42 #include "dojump.h"
43 #include "explow.h"
44 #include "calls.h"
45 #include "emit-rtl.h"
46 #include "varasm.h"
47 #include "stmt.h"
48 #include "expr.h"
49 #include "tree-dfa.h"
50 #include "tree-pass.h"
51 #include "domwalk.h"
52 #include "alloc-pool.h"
53 #include "tree-ssa-propagate.h"
54 #include "gimple-pretty-print.h"
55 #include "params.h"
56 #include "cgraph.h"
57 #include "ipa-chkp.h"
58 #include "tree-hash-traits.h"
60 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
61 is an index into strinfo vector, negative value stands for
62 string length of a string literal (~strlen). */
63 static vec<int> ssa_ver_to_stridx;
65 /* Number of currently active string indexes plus one. */
66 static int max_stridx;
68 /* String information record. */
69 struct strinfo
71 /* String length of this string. */
72 tree length;
73 /* Any of the corresponding pointers for querying alias oracle. */
74 tree ptr;
75 /* Statement for delayed length computation. */
76 gimple *stmt;
77 /* Pointer to '\0' if known, if NULL, it can be computed as
78 ptr + length. */
79 tree endptr;
80 /* Reference count. Any changes to strinfo entry possibly shared
81 with dominating basic blocks need unshare_strinfo first, except
82 for dont_invalidate which affects only the immediately next
83 maybe_invalidate. */
84 int refcount;
85 /* Copy of index. get_strinfo (si->idx) should return si; */
86 int idx;
87 /* These 3 fields are for chaining related string pointers together.
88 E.g. for
89 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
90 strcpy (c, d); e = c + dl;
91 strinfo(a) -> strinfo(c) -> strinfo(e)
92 All have ->first field equal to strinfo(a)->idx and are doubly
93 chained through prev/next fields. The later strinfos are required
94 to point into the same string with zero or more bytes after
95 the previous pointer and all bytes in between the two pointers
96 must be non-zero. Functions like strcpy or memcpy are supposed
97 to adjust all previous strinfo lengths, but not following strinfo
98 lengths (those are uncertain, usually invalidated during
99 maybe_invalidate, except when the alias oracle knows better).
100 Functions like strcat on the other side adjust the whole
101 related strinfo chain.
102 They are updated lazily, so to use the chain the same first fields
103 and si->prev->next == si->idx needs to be verified. */
104 int first;
105 int next;
106 int prev;
107 /* A flag whether the string is known to be written in the current
108 function. */
109 bool writable;
110 /* A flag for the next maybe_invalidate that this strinfo shouldn't
111 be invalidated. Always cleared by maybe_invalidate. */
112 bool dont_invalidate;
115 /* Pool for allocating strinfo_struct entries. */
116 static object_allocator<strinfo> strinfo_pool ("strinfo pool");
118 /* Vector mapping positive string indexes to strinfo, for the
119 current basic block. The first pointer in the vector is special,
120 it is either NULL, meaning the vector isn't shared, or it is
121 a basic block pointer to the owner basic_block if shared.
122 If some other bb wants to modify the vector, the vector needs
123 to be unshared first, and only the owner bb is supposed to free it. */
124 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
126 /* One OFFSET->IDX mapping. */
127 struct stridxlist
129 struct stridxlist *next;
130 HOST_WIDE_INT offset;
131 int idx;
134 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
135 struct decl_stridxlist_map
137 struct tree_map_base base;
138 struct stridxlist list;
141 /* Hash table for mapping decls to a chained list of offset -> idx
142 mappings. */
143 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
145 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
146 static struct obstack stridx_obstack;
148 /* Last memcpy statement if it could be adjusted if the trailing
149 '\0' written is immediately overwritten, or
150 *x = '\0' store that could be removed if it is immediately overwritten. */
151 struct laststmt_struct
153 gimple *stmt;
154 tree len;
155 int stridx;
156 } laststmt;
158 static int get_stridx_plus_constant (strinfo *, HOST_WIDE_INT, tree);
160 /* Return strinfo vector entry IDX. */
162 static inline strinfo *
163 get_strinfo (int idx)
165 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
166 return NULL;
167 return (*stridx_to_strinfo)[idx];
170 /* Helper function for get_stridx. */
172 static int
173 get_addr_stridx (tree exp)
175 HOST_WIDE_INT off;
176 struct stridxlist *list;
177 tree base;
179 if (!decl_to_stridxlist_htab)
180 return 0;
182 base = get_addr_base_and_unit_offset (exp, &off);
183 if (base == NULL || !DECL_P (base))
184 return 0;
186 list = decl_to_stridxlist_htab->get (base);
187 if (list == NULL)
188 return 0;
192 if (list->offset == off)
193 return list->idx;
194 list = list->next;
196 while (list);
197 return 0;
200 /* Return string index for EXP. */
202 static int
203 get_stridx (tree exp)
205 tree s, o;
207 if (TREE_CODE (exp) == SSA_NAME)
209 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
210 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
211 int i;
212 tree e = exp;
213 HOST_WIDE_INT off = 0;
214 for (i = 0; i < 5; i++)
216 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
217 if (!is_gimple_assign (def_stmt)
218 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
219 return 0;
220 tree rhs1 = gimple_assign_rhs1 (def_stmt);
221 tree rhs2 = gimple_assign_rhs2 (def_stmt);
222 if (TREE_CODE (rhs1) != SSA_NAME
223 || !tree_fits_shwi_p (rhs2))
224 return 0;
225 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
226 if (this_off < 0)
227 return 0;
228 off = (unsigned HOST_WIDE_INT) off + this_off;
229 if (off < 0)
230 return 0;
231 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
233 strinfo *si
234 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
235 if (si
236 && si->length
237 && TREE_CODE (si->length) == INTEGER_CST
238 && compare_tree_int (si->length, off) != -1)
239 return get_stridx_plus_constant (si, off, exp);
241 e = rhs1;
243 return 0;
246 if (TREE_CODE (exp) == ADDR_EXPR)
248 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
249 if (idx != 0)
250 return idx;
253 s = string_constant (exp, &o);
254 if (s != NULL_TREE
255 && (o == NULL_TREE || tree_fits_shwi_p (o))
256 && TREE_STRING_LENGTH (s) > 0)
258 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
259 const char *p = TREE_STRING_POINTER (s);
260 int max = TREE_STRING_LENGTH (s) - 1;
262 if (p[max] == '\0' && offset >= 0 && offset <= max)
263 return ~(int) strlen (p + offset);
265 return 0;
268 /* Return true if strinfo vector is shared with the immediate dominator. */
270 static inline bool
271 strinfo_shared (void)
273 return vec_safe_length (stridx_to_strinfo)
274 && (*stridx_to_strinfo)[0] != NULL;
277 /* Unshare strinfo vector that is shared with the immediate dominator. */
279 static void
280 unshare_strinfo_vec (void)
282 strinfo *si;
283 unsigned int i = 0;
285 gcc_assert (strinfo_shared ());
286 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
287 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
288 if (si != NULL)
289 si->refcount++;
290 (*stridx_to_strinfo)[0] = NULL;
293 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
294 Return a pointer to the location where the string index can
295 be stored (if 0) or is stored, or NULL if this can't be tracked. */
297 static int *
298 addr_stridxptr (tree exp)
300 HOST_WIDE_INT off;
302 tree base = get_addr_base_and_unit_offset (exp, &off);
303 if (base == NULL_TREE || !DECL_P (base))
304 return NULL;
306 if (!decl_to_stridxlist_htab)
308 decl_to_stridxlist_htab
309 = new hash_map<tree_decl_hash, stridxlist> (64);
310 gcc_obstack_init (&stridx_obstack);
313 bool existed;
314 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
315 if (existed)
317 int i;
318 for (i = 0; i < 16; i++)
320 if (list->offset == off)
321 return &list->idx;
322 if (list->next == NULL)
323 break;
325 if (i == 16)
326 return NULL;
327 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
328 list = list->next;
331 list->next = NULL;
332 list->offset = off;
333 list->idx = 0;
334 return &list->idx;
337 /* Create a new string index, or return 0 if reached limit. */
339 static int
340 new_stridx (tree exp)
342 int idx;
343 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
344 return 0;
345 if (TREE_CODE (exp) == SSA_NAME)
347 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
348 return 0;
349 idx = max_stridx++;
350 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
351 return idx;
353 if (TREE_CODE (exp) == ADDR_EXPR)
355 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
356 if (pidx != NULL)
358 gcc_assert (*pidx == 0);
359 *pidx = max_stridx++;
360 return *pidx;
363 return 0;
366 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
368 static int
369 new_addr_stridx (tree exp)
371 int *pidx;
372 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
373 return 0;
374 pidx = addr_stridxptr (exp);
375 if (pidx != NULL)
377 gcc_assert (*pidx == 0);
378 *pidx = max_stridx++;
379 return *pidx;
381 return 0;
384 /* Create a new strinfo. */
386 static strinfo *
387 new_strinfo (tree ptr, int idx, tree length)
389 strinfo *si = strinfo_pool.allocate ();
390 si->length = length;
391 si->ptr = ptr;
392 si->stmt = NULL;
393 si->endptr = NULL_TREE;
394 si->refcount = 1;
395 si->idx = idx;
396 si->first = 0;
397 si->prev = 0;
398 si->next = 0;
399 si->writable = false;
400 si->dont_invalidate = false;
401 return si;
404 /* Decrease strinfo refcount and free it if not referenced anymore. */
406 static inline void
407 free_strinfo (strinfo *si)
409 if (si && --si->refcount == 0)
410 strinfo_pool.remove (si);
413 /* Set strinfo in the vector entry IDX to SI. */
415 static inline void
416 set_strinfo (int idx, strinfo *si)
418 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
419 unshare_strinfo_vec ();
420 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
421 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
422 (*stridx_to_strinfo)[idx] = si;
425 /* Return string length, or NULL if it can't be computed. */
427 static tree
428 get_string_length (strinfo *si)
430 if (si->length)
431 return si->length;
433 if (si->stmt)
435 gimple *stmt = si->stmt, *lenstmt;
436 bool with_bounds = gimple_call_with_bounds_p (stmt);
437 tree callee, lhs, fn, tem;
438 location_t loc;
439 gimple_stmt_iterator gsi;
441 gcc_assert (is_gimple_call (stmt));
442 callee = gimple_call_fndecl (stmt);
443 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
444 lhs = gimple_call_lhs (stmt);
445 /* unshare_strinfo is intentionally not called here. The (delayed)
446 transformation of strcpy or strcat into stpcpy is done at the place
447 of the former strcpy/strcat call and so can affect all the strinfos
448 with the same stmt. If they were unshared before and transformation
449 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
450 just compute the right length. */
451 switch (DECL_FUNCTION_CODE (callee))
453 case BUILT_IN_STRCAT:
454 case BUILT_IN_STRCAT_CHK:
455 case BUILT_IN_STRCAT_CHKP:
456 case BUILT_IN_STRCAT_CHK_CHKP:
457 gsi = gsi_for_stmt (stmt);
458 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
459 gcc_assert (lhs == NULL_TREE);
460 tem = unshare_expr (gimple_call_arg (stmt, 0));
461 if (with_bounds)
463 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
464 2, tem, gimple_call_arg (stmt, 1));
465 gimple_call_set_with_bounds (lenstmt, true);
467 else
468 lenstmt = gimple_build_call (fn, 1, tem);
469 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
470 gimple_call_set_lhs (lenstmt, lhs);
471 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
472 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
473 tem = gimple_call_arg (stmt, 0);
474 if (!ptrofftype_p (TREE_TYPE (lhs)))
476 lhs = convert_to_ptrofftype (lhs);
477 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
478 true, GSI_SAME_STMT);
480 lenstmt = gimple_build_assign
481 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
482 POINTER_PLUS_EXPR,tem, lhs);
483 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
484 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
485 lhs = NULL_TREE;
486 /* FALLTHRU */
487 case BUILT_IN_STRCPY:
488 case BUILT_IN_STRCPY_CHK:
489 case BUILT_IN_STRCPY_CHKP:
490 case BUILT_IN_STRCPY_CHK_CHKP:
491 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
492 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
493 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
494 else
495 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
496 if (with_bounds)
497 fn = chkp_maybe_create_clone (fn)->decl;
498 gcc_assert (lhs == NULL_TREE);
499 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
501 fprintf (dump_file, "Optimizing: ");
502 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
504 gimple_call_set_fndecl (stmt, fn);
505 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
506 gimple_call_set_lhs (stmt, lhs);
507 update_stmt (stmt);
508 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
510 fprintf (dump_file, "into: ");
511 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
513 /* FALLTHRU */
514 case BUILT_IN_STPCPY:
515 case BUILT_IN_STPCPY_CHK:
516 case BUILT_IN_STPCPY_CHKP:
517 case BUILT_IN_STPCPY_CHK_CHKP:
518 gcc_assert (lhs != NULL_TREE);
519 loc = gimple_location (stmt);
520 si->endptr = lhs;
521 si->stmt = NULL;
522 lhs = fold_convert_loc (loc, size_type_node, lhs);
523 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
524 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
525 lhs, si->length);
526 break;
527 case BUILT_IN_MALLOC:
528 break;
529 /* BUILT_IN_CALLOC always has si->length set. */
530 default:
531 gcc_unreachable ();
532 break;
536 return si->length;
539 /* Invalidate string length information for strings whose length
540 might change due to stores in stmt. */
542 static bool
543 maybe_invalidate (gimple *stmt)
545 strinfo *si;
546 unsigned int i;
547 bool nonempty = false;
549 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
550 if (si != NULL)
552 if (!si->dont_invalidate)
554 ao_ref r;
555 /* Do not use si->length. */
556 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
557 if (stmt_may_clobber_ref_p_1 (stmt, &r))
559 set_strinfo (i, NULL);
560 free_strinfo (si);
561 continue;
564 si->dont_invalidate = false;
565 nonempty = true;
567 return nonempty;
570 /* Unshare strinfo record SI, if it has refcount > 1 or
571 if stridx_to_strinfo vector is shared with some other
572 bbs. */
574 static strinfo *
575 unshare_strinfo (strinfo *si)
577 strinfo *nsi;
579 if (si->refcount == 1 && !strinfo_shared ())
580 return si;
582 nsi = new_strinfo (si->ptr, si->idx, si->length);
583 nsi->stmt = si->stmt;
584 nsi->endptr = si->endptr;
585 nsi->first = si->first;
586 nsi->prev = si->prev;
587 nsi->next = si->next;
588 nsi->writable = si->writable;
589 set_strinfo (si->idx, nsi);
590 free_strinfo (si);
591 return nsi;
594 /* Return first strinfo in the related strinfo chain
595 if all strinfos in between belong to the chain, otherwise
596 NULL. */
598 static strinfo *
599 verify_related_strinfos (strinfo *origsi)
601 strinfo *si = origsi, *psi;
603 if (origsi->first == 0)
604 return NULL;
605 for (; si->prev; si = psi)
607 if (si->first != origsi->first)
608 return NULL;
609 psi = get_strinfo (si->prev);
610 if (psi == NULL)
611 return NULL;
612 if (psi->next != si->idx)
613 return NULL;
615 if (si->idx != si->first)
616 return NULL;
617 return si;
620 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
621 strinfo if there is any. Return it's idx, or 0 if no strinfo has
622 been created. */
624 static int
625 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
627 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
629 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
630 return 0;
632 if (basesi->length == NULL_TREE
633 || TREE_CODE (basesi->length) != INTEGER_CST
634 || compare_tree_int (basesi->length, off) == -1
635 || !tree_fits_shwi_p (basesi->length))
636 return 0;
638 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
639 strinfo *si = basesi, *chainsi;
640 if (si->first || si->prev || si->next)
641 si = verify_related_strinfos (basesi);
642 if (si == NULL
643 || si->length == NULL_TREE
644 || TREE_CODE (si->length) != INTEGER_CST)
645 return 0;
647 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
648 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
650 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
651 for (chainsi = si; chainsi->next; chainsi = si)
653 si = get_strinfo (chainsi->next);
654 if (si == NULL
655 || si->first != chainsi->first
656 || si->prev != chainsi->idx
657 || si->length == NULL_TREE
658 || TREE_CODE (si->length) != INTEGER_CST)
659 break;
660 int r = compare_tree_int (si->length, len);
661 if (r != 1)
663 if (r == 0)
665 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
666 return si->idx;
668 break;
672 int idx = new_stridx (ptr);
673 if (idx == 0)
674 return 0;
675 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
676 set_strinfo (idx, si);
677 if (chainsi->next)
679 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
680 si->next = nextsi->idx;
681 nextsi->prev = idx;
683 chainsi = unshare_strinfo (chainsi);
684 if (chainsi->first == 0)
685 chainsi->first = chainsi->idx;
686 chainsi->next = idx;
687 if (chainsi->endptr == NULL_TREE && len == 0)
688 chainsi->endptr = ptr;
689 si->endptr = chainsi->endptr;
690 si->prev = chainsi->idx;
691 si->first = chainsi->first;
692 si->writable = chainsi->writable;
693 return si->idx;
696 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
697 to a zero-length string and if possible chain it to a related strinfo
698 chain whose part is or might be CHAINSI. */
700 static strinfo *
701 zero_length_string (tree ptr, strinfo *chainsi)
703 strinfo *si;
704 int idx;
705 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
706 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
707 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
708 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
710 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
711 return NULL;
712 if (chainsi != NULL)
714 si = verify_related_strinfos (chainsi);
715 if (si)
717 chainsi = si;
718 for (; chainsi->next; chainsi = si)
720 if (chainsi->endptr == NULL_TREE)
722 chainsi = unshare_strinfo (chainsi);
723 chainsi->endptr = ptr;
725 si = get_strinfo (chainsi->next);
726 if (si == NULL
727 || si->first != chainsi->first
728 || si->prev != chainsi->idx)
729 break;
731 gcc_assert (chainsi->length || chainsi->stmt);
732 if (chainsi->endptr == NULL_TREE)
734 chainsi = unshare_strinfo (chainsi);
735 chainsi->endptr = ptr;
737 if (chainsi->length && integer_zerop (chainsi->length))
739 if (chainsi->next)
741 chainsi = unshare_strinfo (chainsi);
742 chainsi->next = 0;
744 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
745 return chainsi;
748 else if (chainsi->first || chainsi->prev || chainsi->next)
750 chainsi = unshare_strinfo (chainsi);
751 chainsi->first = 0;
752 chainsi->prev = 0;
753 chainsi->next = 0;
756 idx = new_stridx (ptr);
757 if (idx == 0)
758 return NULL;
759 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
760 set_strinfo (idx, si);
761 si->endptr = ptr;
762 if (chainsi != NULL)
764 chainsi = unshare_strinfo (chainsi);
765 if (chainsi->first == 0)
766 chainsi->first = chainsi->idx;
767 chainsi->next = idx;
768 if (chainsi->endptr == NULL_TREE)
769 chainsi->endptr = ptr;
770 si->prev = chainsi->idx;
771 si->first = chainsi->first;
772 si->writable = chainsi->writable;
774 return si;
777 /* For strinfo ORIGSI whose length has been just updated
778 update also related strinfo lengths (add ADJ to each,
779 but don't adjust ORIGSI). */
781 static void
782 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
784 strinfo *si = verify_related_strinfos (origsi);
786 if (si == NULL)
787 return;
789 while (1)
791 strinfo *nsi;
793 if (si != origsi)
795 tree tem;
797 si = unshare_strinfo (si);
798 if (si->length)
800 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
801 si->length = fold_build2_loc (loc, PLUS_EXPR,
802 TREE_TYPE (si->length), si->length,
803 tem);
805 else if (si->stmt != NULL)
806 /* Delayed length computation is unaffected. */
808 else
809 gcc_unreachable ();
811 si->endptr = NULL_TREE;
812 si->dont_invalidate = true;
814 if (si->next == 0)
815 return;
816 nsi = get_strinfo (si->next);
817 if (nsi == NULL
818 || nsi->first != si->first
819 || nsi->prev != si->idx)
820 return;
821 si = nsi;
825 /* Find if there are other SSA_NAME pointers equal to PTR
826 for which we don't track their string lengths yet. If so, use
827 IDX for them. */
829 static void
830 find_equal_ptrs (tree ptr, int idx)
832 if (TREE_CODE (ptr) != SSA_NAME)
833 return;
834 while (1)
836 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
837 if (!is_gimple_assign (stmt))
838 return;
839 ptr = gimple_assign_rhs1 (stmt);
840 switch (gimple_assign_rhs_code (stmt))
842 case SSA_NAME:
843 break;
844 CASE_CONVERT:
845 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
846 return;
847 if (TREE_CODE (ptr) == SSA_NAME)
848 break;
849 if (TREE_CODE (ptr) != ADDR_EXPR)
850 return;
851 /* FALLTHRU */
852 case ADDR_EXPR:
854 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
855 if (pidx != NULL && *pidx == 0)
856 *pidx = idx;
857 return;
859 default:
860 return;
863 /* We might find an endptr created in this pass. Grow the
864 vector in that case. */
865 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
866 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
868 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
869 return;
870 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
874 /* If the last .MEM setter statement before STMT is
875 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
876 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
877 just memcpy (x, y, strlen (y)). SI must be the zero length
878 strinfo. */
880 static void
881 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
883 tree vuse, callee, len;
884 struct laststmt_struct last = laststmt;
885 strinfo *lastsi, *firstsi;
886 unsigned len_arg_no = 2;
888 laststmt.stmt = NULL;
889 laststmt.len = NULL_TREE;
890 laststmt.stridx = 0;
892 if (last.stmt == NULL)
893 return;
895 vuse = gimple_vuse (stmt);
896 if (vuse == NULL_TREE
897 || SSA_NAME_DEF_STMT (vuse) != last.stmt
898 || !has_single_use (vuse))
899 return;
901 gcc_assert (last.stridx > 0);
902 lastsi = get_strinfo (last.stridx);
903 if (lastsi == NULL)
904 return;
906 if (lastsi != si)
908 if (lastsi->first == 0 || lastsi->first != si->first)
909 return;
911 firstsi = verify_related_strinfos (si);
912 if (firstsi == NULL)
913 return;
914 while (firstsi != lastsi)
916 strinfo *nextsi;
917 if (firstsi->next == 0)
918 return;
919 nextsi = get_strinfo (firstsi->next);
920 if (nextsi == NULL
921 || nextsi->prev != firstsi->idx
922 || nextsi->first != si->first)
923 return;
924 firstsi = nextsi;
928 if (!is_strcat)
930 if (si->length == NULL_TREE || !integer_zerop (si->length))
931 return;
934 if (is_gimple_assign (last.stmt))
936 gimple_stmt_iterator gsi;
938 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
939 return;
940 if (stmt_could_throw_p (last.stmt))
941 return;
942 gsi = gsi_for_stmt (last.stmt);
943 unlink_stmt_vdef (last.stmt);
944 release_defs (last.stmt);
945 gsi_remove (&gsi, true);
946 return;
949 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
950 return;
952 callee = gimple_call_fndecl (last.stmt);
953 switch (DECL_FUNCTION_CODE (callee))
955 case BUILT_IN_MEMCPY:
956 case BUILT_IN_MEMCPY_CHK:
957 break;
958 case BUILT_IN_MEMCPY_CHKP:
959 case BUILT_IN_MEMCPY_CHK_CHKP:
960 len_arg_no = 4;
961 break;
962 default:
963 return;
966 len = gimple_call_arg (last.stmt, len_arg_no);
967 if (tree_fits_uhwi_p (len))
969 if (!tree_fits_uhwi_p (last.len)
970 || integer_zerop (len)
971 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
972 return;
973 /* Don't adjust the length if it is divisible by 4, it is more efficient
974 to store the extra '\0' in that case. */
975 if ((tree_to_uhwi (len) & 3) == 0)
976 return;
978 else if (TREE_CODE (len) == SSA_NAME)
980 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
981 if (!is_gimple_assign (def_stmt)
982 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
983 || gimple_assign_rhs1 (def_stmt) != last.len
984 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
985 return;
987 else
988 return;
990 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
991 update_stmt (last.stmt);
994 /* Handle a strlen call. If strlen of the argument is known, replace
995 the strlen call with the known value, otherwise remember that strlen
996 of the argument is stored in the lhs SSA_NAME. */
998 static void
999 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1001 int idx;
1002 tree src;
1003 gimple *stmt = gsi_stmt (*gsi);
1004 tree lhs = gimple_call_lhs (stmt);
1006 if (lhs == NULL_TREE)
1007 return;
1009 src = gimple_call_arg (stmt, 0);
1010 idx = get_stridx (src);
1011 if (idx)
1013 strinfo *si = NULL;
1014 tree rhs;
1016 if (idx < 0)
1017 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1018 else
1020 rhs = NULL_TREE;
1021 si = get_strinfo (idx);
1022 if (si != NULL)
1023 rhs = get_string_length (si);
1025 if (rhs != NULL_TREE)
1027 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1029 fprintf (dump_file, "Optimizing: ");
1030 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1032 rhs = unshare_expr (rhs);
1033 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1034 rhs = fold_convert_loc (gimple_location (stmt),
1035 TREE_TYPE (lhs), rhs);
1036 if (!update_call_from_tree (gsi, rhs))
1037 gimplify_and_update_call_from_tree (gsi, rhs);
1038 stmt = gsi_stmt (*gsi);
1039 update_stmt (stmt);
1040 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1042 fprintf (dump_file, "into: ");
1043 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1045 if (si != NULL
1046 && TREE_CODE (si->length) != SSA_NAME
1047 && TREE_CODE (si->length) != INTEGER_CST
1048 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1050 si = unshare_strinfo (si);
1051 si->length = lhs;
1053 return;
1056 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1057 return;
1058 if (idx == 0)
1059 idx = new_stridx (src);
1060 else if (get_strinfo (idx) != NULL)
1061 return;
1062 if (idx)
1064 strinfo *si = new_strinfo (src, idx, lhs);
1065 set_strinfo (idx, si);
1066 find_equal_ptrs (src, idx);
1070 /* Handle a strchr call. If strlen of the first argument is known, replace
1071 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1072 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1074 static void
1075 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1077 int idx;
1078 tree src;
1079 gimple *stmt = gsi_stmt (*gsi);
1080 tree lhs = gimple_call_lhs (stmt);
1081 bool with_bounds = gimple_call_with_bounds_p (stmt);
1083 if (lhs == NULL_TREE)
1084 return;
1086 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1087 return;
1089 src = gimple_call_arg (stmt, 0);
1090 idx = get_stridx (src);
1091 if (idx)
1093 strinfo *si = NULL;
1094 tree rhs;
1096 if (idx < 0)
1097 rhs = build_int_cst (size_type_node, ~idx);
1098 else
1100 rhs = NULL_TREE;
1101 si = get_strinfo (idx);
1102 if (si != NULL)
1103 rhs = get_string_length (si);
1105 if (rhs != NULL_TREE)
1107 location_t loc = gimple_location (stmt);
1109 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1111 fprintf (dump_file, "Optimizing: ");
1112 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1114 if (si != NULL && si->endptr != NULL_TREE)
1116 rhs = unshare_expr (si->endptr);
1117 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1118 TREE_TYPE (rhs)))
1119 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1121 else
1123 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1124 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1125 TREE_TYPE (src), src, rhs);
1126 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1127 TREE_TYPE (rhs)))
1128 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1130 if (!update_call_from_tree (gsi, rhs))
1131 gimplify_and_update_call_from_tree (gsi, rhs);
1132 stmt = gsi_stmt (*gsi);
1133 update_stmt (stmt);
1134 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1136 fprintf (dump_file, "into: ");
1137 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1139 if (si != NULL
1140 && si->endptr == NULL_TREE
1141 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1143 si = unshare_strinfo (si);
1144 si->endptr = lhs;
1146 zero_length_string (lhs, si);
1147 return;
1150 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1151 return;
1152 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1154 if (idx == 0)
1155 idx = new_stridx (src);
1156 else if (get_strinfo (idx) != NULL)
1158 zero_length_string (lhs, NULL);
1159 return;
1161 if (idx)
1163 location_t loc = gimple_location (stmt);
1164 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1165 tree srcu = fold_convert_loc (loc, size_type_node, src);
1166 tree length = fold_build2_loc (loc, MINUS_EXPR,
1167 size_type_node, lhsu, srcu);
1168 strinfo *si = new_strinfo (src, idx, length);
1169 si->endptr = lhs;
1170 set_strinfo (idx, si);
1171 find_equal_ptrs (src, idx);
1172 zero_length_string (lhs, si);
1175 else
1176 zero_length_string (lhs, NULL);
1179 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1180 If strlen of the second argument is known, strlen of the first argument
1181 is the same after this call. Furthermore, attempt to convert it to
1182 memcpy. */
1184 static void
1185 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1187 int idx, didx;
1188 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1189 bool success;
1190 gimple *stmt = gsi_stmt (*gsi);
1191 strinfo *si, *dsi, *olddsi, *zsi;
1192 location_t loc;
1193 bool with_bounds = gimple_call_with_bounds_p (stmt);
1195 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1196 dst = gimple_call_arg (stmt, 0);
1197 lhs = gimple_call_lhs (stmt);
1198 idx = get_stridx (src);
1199 si = NULL;
1200 if (idx > 0)
1201 si = get_strinfo (idx);
1203 didx = get_stridx (dst);
1204 olddsi = NULL;
1205 oldlen = NULL_TREE;
1206 if (didx > 0)
1207 olddsi = get_strinfo (didx);
1208 else if (didx < 0)
1209 return;
1211 if (olddsi != NULL)
1212 adjust_last_stmt (olddsi, stmt, false);
1214 srclen = NULL_TREE;
1215 if (si != NULL)
1216 srclen = get_string_length (si);
1217 else if (idx < 0)
1218 srclen = build_int_cst (size_type_node, ~idx);
1220 loc = gimple_location (stmt);
1221 if (srclen == NULL_TREE)
1222 switch (bcode)
1224 case BUILT_IN_STRCPY:
1225 case BUILT_IN_STRCPY_CHK:
1226 case BUILT_IN_STRCPY_CHKP:
1227 case BUILT_IN_STRCPY_CHK_CHKP:
1228 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1229 return;
1230 break;
1231 case BUILT_IN_STPCPY:
1232 case BUILT_IN_STPCPY_CHK:
1233 case BUILT_IN_STPCPY_CHKP:
1234 case BUILT_IN_STPCPY_CHK_CHKP:
1235 if (lhs == NULL_TREE)
1236 return;
1237 else
1239 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1240 srclen = fold_convert_loc (loc, size_type_node, dst);
1241 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1242 lhsuint, srclen);
1244 break;
1245 default:
1246 gcc_unreachable ();
1249 if (didx == 0)
1251 didx = new_stridx (dst);
1252 if (didx == 0)
1253 return;
1255 if (olddsi != NULL)
1257 oldlen = olddsi->length;
1258 dsi = unshare_strinfo (olddsi);
1259 dsi->length = srclen;
1260 /* Break the chain, so adjust_related_strinfo on later pointers in
1261 the chain won't adjust this one anymore. */
1262 dsi->next = 0;
1263 dsi->stmt = NULL;
1264 dsi->endptr = NULL_TREE;
1266 else
1268 dsi = new_strinfo (dst, didx, srclen);
1269 set_strinfo (didx, dsi);
1270 find_equal_ptrs (dst, didx);
1272 dsi->writable = true;
1273 dsi->dont_invalidate = true;
1275 if (dsi->length == NULL_TREE)
1277 strinfo *chainsi;
1279 /* If string length of src is unknown, use delayed length
1280 computation. If string lenth of dst will be needed, it
1281 can be computed by transforming this strcpy call into
1282 stpcpy and subtracting dst from the return value. */
1284 /* Look for earlier strings whose length could be determined if
1285 this strcpy is turned into an stpcpy. */
1287 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1289 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1291 /* When setting a stmt for delayed length computation
1292 prevent all strinfos through dsi from being
1293 invalidated. */
1294 chainsi = unshare_strinfo (chainsi);
1295 chainsi->stmt = stmt;
1296 chainsi->length = NULL_TREE;
1297 chainsi->endptr = NULL_TREE;
1298 chainsi->dont_invalidate = true;
1301 dsi->stmt = stmt;
1302 return;
1305 if (olddsi != NULL)
1307 tree adj = NULL_TREE;
1308 if (oldlen == NULL_TREE)
1310 else if (integer_zerop (oldlen))
1311 adj = srclen;
1312 else if (TREE_CODE (oldlen) == INTEGER_CST
1313 || TREE_CODE (srclen) == INTEGER_CST)
1314 adj = fold_build2_loc (loc, MINUS_EXPR,
1315 TREE_TYPE (srclen), srclen,
1316 fold_convert_loc (loc, TREE_TYPE (srclen),
1317 oldlen));
1318 if (adj != NULL_TREE)
1319 adjust_related_strinfos (loc, dsi, adj);
1320 else
1321 dsi->prev = 0;
1323 /* strcpy src may not overlap dst, so src doesn't need to be
1324 invalidated either. */
1325 if (si != NULL)
1326 si->dont_invalidate = true;
1328 fn = NULL_TREE;
1329 zsi = NULL;
1330 switch (bcode)
1332 case BUILT_IN_STRCPY:
1333 case BUILT_IN_STRCPY_CHKP:
1334 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1335 if (lhs)
1336 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1337 break;
1338 case BUILT_IN_STRCPY_CHK:
1339 case BUILT_IN_STRCPY_CHK_CHKP:
1340 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1341 if (lhs)
1342 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1343 break;
1344 case BUILT_IN_STPCPY:
1345 case BUILT_IN_STPCPY_CHKP:
1346 /* This would need adjustment of the lhs (subtract one),
1347 or detection that the trailing '\0' doesn't need to be
1348 written, if it will be immediately overwritten.
1349 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1350 if (lhs)
1352 dsi->endptr = lhs;
1353 zsi = zero_length_string (lhs, dsi);
1355 break;
1356 case BUILT_IN_STPCPY_CHK:
1357 case BUILT_IN_STPCPY_CHK_CHKP:
1358 /* This would need adjustment of the lhs (subtract one),
1359 or detection that the trailing '\0' doesn't need to be
1360 written, if it will be immediately overwritten.
1361 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1362 if (lhs)
1364 dsi->endptr = lhs;
1365 zsi = zero_length_string (lhs, dsi);
1367 break;
1368 default:
1369 gcc_unreachable ();
1371 if (zsi != NULL)
1372 zsi->dont_invalidate = true;
1374 if (fn == NULL_TREE)
1375 return;
1377 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1378 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1380 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1381 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1382 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1383 GSI_SAME_STMT);
1384 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1386 fprintf (dump_file, "Optimizing: ");
1387 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1389 if (with_bounds)
1391 fn = chkp_maybe_create_clone (fn)->decl;
1392 if (gimple_call_num_args (stmt) == 4)
1393 success = update_gimple_call (gsi, fn, 5, dst,
1394 gimple_call_arg (stmt, 1),
1395 src,
1396 gimple_call_arg (stmt, 3),
1397 len);
1398 else
1399 success = update_gimple_call (gsi, fn, 6, dst,
1400 gimple_call_arg (stmt, 1),
1401 src,
1402 gimple_call_arg (stmt, 3),
1403 len,
1404 gimple_call_arg (stmt, 4));
1406 else
1407 if (gimple_call_num_args (stmt) == 2)
1408 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1409 else
1410 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1411 gimple_call_arg (stmt, 2));
1412 if (success)
1414 stmt = gsi_stmt (*gsi);
1415 gimple_call_set_with_bounds (stmt, with_bounds);
1416 update_stmt (stmt);
1417 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1419 fprintf (dump_file, "into: ");
1420 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1422 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1423 laststmt.stmt = stmt;
1424 laststmt.len = srclen;
1425 laststmt.stridx = dsi->idx;
1427 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1428 fprintf (dump_file, "not possible.\n");
1431 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1432 If strlen of the second argument is known and length of the third argument
1433 is that plus one, strlen of the first argument is the same after this
1434 call. */
1436 static void
1437 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1439 int idx, didx;
1440 tree src, dst, len, lhs, oldlen, newlen;
1441 gimple *stmt = gsi_stmt (*gsi);
1442 strinfo *si, *dsi, *olddsi;
1443 bool with_bounds = gimple_call_with_bounds_p (stmt);
1445 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1446 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1447 dst = gimple_call_arg (stmt, 0);
1448 idx = get_stridx (src);
1449 if (idx == 0)
1450 return;
1452 didx = get_stridx (dst);
1453 olddsi = NULL;
1454 if (didx > 0)
1455 olddsi = get_strinfo (didx);
1456 else if (didx < 0)
1457 return;
1459 if (olddsi != NULL
1460 && tree_fits_uhwi_p (len)
1461 && !integer_zerop (len))
1462 adjust_last_stmt (olddsi, stmt, false);
1464 if (idx > 0)
1466 gimple *def_stmt;
1468 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1469 si = get_strinfo (idx);
1470 if (si == NULL || si->length == NULL_TREE)
1471 return;
1472 if (TREE_CODE (len) != SSA_NAME)
1473 return;
1474 def_stmt = SSA_NAME_DEF_STMT (len);
1475 if (!is_gimple_assign (def_stmt)
1476 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1477 || gimple_assign_rhs1 (def_stmt) != si->length
1478 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1479 return;
1481 else
1483 si = NULL;
1484 /* Handle memcpy (x, "abcd", 5) or
1485 memcpy (x, "abc\0uvw", 7). */
1486 if (!tree_fits_uhwi_p (len)
1487 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1488 return;
1491 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1492 adjust_last_stmt (olddsi, stmt, false);
1494 if (didx == 0)
1496 didx = new_stridx (dst);
1497 if (didx == 0)
1498 return;
1500 if (si != NULL)
1501 newlen = si->length;
1502 else
1503 newlen = build_int_cst (size_type_node, ~idx);
1504 oldlen = NULL_TREE;
1505 if (olddsi != NULL)
1507 dsi = unshare_strinfo (olddsi);
1508 oldlen = olddsi->length;
1509 dsi->length = newlen;
1510 /* Break the chain, so adjust_related_strinfo on later pointers in
1511 the chain won't adjust this one anymore. */
1512 dsi->next = 0;
1513 dsi->stmt = NULL;
1514 dsi->endptr = NULL_TREE;
1516 else
1518 dsi = new_strinfo (dst, didx, newlen);
1519 set_strinfo (didx, dsi);
1520 find_equal_ptrs (dst, didx);
1522 dsi->writable = true;
1523 dsi->dont_invalidate = true;
1524 if (olddsi != NULL)
1526 tree adj = NULL_TREE;
1527 location_t loc = gimple_location (stmt);
1528 if (oldlen == NULL_TREE)
1530 else if (integer_zerop (oldlen))
1531 adj = dsi->length;
1532 else if (TREE_CODE (oldlen) == INTEGER_CST
1533 || TREE_CODE (dsi->length) == INTEGER_CST)
1534 adj = fold_build2_loc (loc, MINUS_EXPR,
1535 TREE_TYPE (dsi->length), dsi->length,
1536 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1537 oldlen));
1538 if (adj != NULL_TREE)
1539 adjust_related_strinfos (loc, dsi, adj);
1540 else
1541 dsi->prev = 0;
1543 /* memcpy src may not overlap dst, so src doesn't need to be
1544 invalidated either. */
1545 if (si != NULL)
1546 si->dont_invalidate = true;
1548 lhs = gimple_call_lhs (stmt);
1549 switch (bcode)
1551 case BUILT_IN_MEMCPY:
1552 case BUILT_IN_MEMCPY_CHK:
1553 case BUILT_IN_MEMCPY_CHKP:
1554 case BUILT_IN_MEMCPY_CHK_CHKP:
1555 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1556 laststmt.stmt = stmt;
1557 laststmt.len = dsi->length;
1558 laststmt.stridx = dsi->idx;
1559 if (lhs)
1560 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1561 break;
1562 case BUILT_IN_MEMPCPY:
1563 case BUILT_IN_MEMPCPY_CHK:
1564 case BUILT_IN_MEMPCPY_CHKP:
1565 case BUILT_IN_MEMPCPY_CHK_CHKP:
1566 break;
1567 default:
1568 gcc_unreachable ();
1572 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1573 If strlen of the second argument is known, strlen of the first argument
1574 is increased by the length of the second argument. Furthermore, attempt
1575 to convert it to memcpy/strcpy if the length of the first argument
1576 is known. */
1578 static void
1579 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1581 int idx, didx;
1582 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1583 bool success;
1584 gimple *stmt = gsi_stmt (*gsi);
1585 strinfo *si, *dsi;
1586 location_t loc;
1587 bool with_bounds = gimple_call_with_bounds_p (stmt);
1589 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1590 dst = gimple_call_arg (stmt, 0);
1591 lhs = gimple_call_lhs (stmt);
1593 didx = get_stridx (dst);
1594 if (didx < 0)
1595 return;
1597 dsi = NULL;
1598 if (didx > 0)
1599 dsi = get_strinfo (didx);
1600 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1602 /* strcat (p, q) can be transformed into
1603 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1604 with length endptr - p if we need to compute the length
1605 later on. Don't do this transformation if we don't need
1606 it. */
1607 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1609 if (didx == 0)
1611 didx = new_stridx (dst);
1612 if (didx == 0)
1613 return;
1615 if (dsi == NULL)
1617 dsi = new_strinfo (dst, didx, NULL_TREE);
1618 set_strinfo (didx, dsi);
1619 find_equal_ptrs (dst, didx);
1621 else
1623 dsi = unshare_strinfo (dsi);
1624 dsi->length = NULL_TREE;
1625 dsi->next = 0;
1626 dsi->endptr = NULL_TREE;
1628 dsi->writable = true;
1629 dsi->stmt = stmt;
1630 dsi->dont_invalidate = true;
1632 return;
1635 srclen = NULL_TREE;
1636 si = NULL;
1637 idx = get_stridx (src);
1638 if (idx < 0)
1639 srclen = build_int_cst (size_type_node, ~idx);
1640 else if (idx > 0)
1642 si = get_strinfo (idx);
1643 if (si != NULL)
1644 srclen = get_string_length (si);
1647 loc = gimple_location (stmt);
1648 dstlen = dsi->length;
1649 endptr = dsi->endptr;
1651 dsi = unshare_strinfo (dsi);
1652 dsi->endptr = NULL_TREE;
1653 dsi->stmt = NULL;
1654 dsi->writable = true;
1656 if (srclen != NULL_TREE)
1658 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1659 dsi->length, srclen);
1660 adjust_related_strinfos (loc, dsi, srclen);
1661 dsi->dont_invalidate = true;
1663 else
1665 dsi->length = NULL;
1666 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1667 dsi->dont_invalidate = true;
1670 if (si != NULL)
1671 /* strcat src may not overlap dst, so src doesn't need to be
1672 invalidated either. */
1673 si->dont_invalidate = true;
1675 /* For now. Could remove the lhs from the call and add
1676 lhs = dst; afterwards. */
1677 if (lhs)
1678 return;
1680 fn = NULL_TREE;
1681 objsz = NULL_TREE;
1682 switch (bcode)
1684 case BUILT_IN_STRCAT:
1685 case BUILT_IN_STRCAT_CHKP:
1686 if (srclen != NULL_TREE)
1687 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1688 else
1689 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1690 break;
1691 case BUILT_IN_STRCAT_CHK:
1692 case BUILT_IN_STRCAT_CHK_CHKP:
1693 if (srclen != NULL_TREE)
1694 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1695 else
1696 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1697 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1698 break;
1699 default:
1700 gcc_unreachable ();
1703 if (fn == NULL_TREE)
1704 return;
1706 len = NULL_TREE;
1707 if (srclen != NULL_TREE)
1709 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1710 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1712 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1713 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1714 build_int_cst (type, 1));
1715 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1716 GSI_SAME_STMT);
1718 if (endptr)
1719 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1720 else
1721 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1722 TREE_TYPE (dst), unshare_expr (dst),
1723 fold_convert_loc (loc, sizetype,
1724 unshare_expr (dstlen)));
1725 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1726 GSI_SAME_STMT);
1727 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1729 fprintf (dump_file, "Optimizing: ");
1730 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1732 if (with_bounds)
1734 fn = chkp_maybe_create_clone (fn)->decl;
1735 if (srclen != NULL_TREE)
1736 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1737 dst,
1738 gimple_call_arg (stmt, 1),
1739 src,
1740 gimple_call_arg (stmt, 3),
1741 len, objsz);
1742 else
1743 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1744 dst,
1745 gimple_call_arg (stmt, 1),
1746 src,
1747 gimple_call_arg (stmt, 3),
1748 objsz);
1750 else
1751 if (srclen != NULL_TREE)
1752 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1753 dst, src, len, objsz);
1754 else
1755 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1756 dst, src, objsz);
1757 if (success)
1759 stmt = gsi_stmt (*gsi);
1760 gimple_call_set_with_bounds (stmt, with_bounds);
1761 update_stmt (stmt);
1762 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1764 fprintf (dump_file, "into: ");
1765 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1767 /* If srclen == NULL, note that current string length can be
1768 computed by transforming this strcpy into stpcpy. */
1769 if (srclen == NULL_TREE && dsi->dont_invalidate)
1770 dsi->stmt = stmt;
1771 adjust_last_stmt (dsi, stmt, true);
1772 if (srclen != NULL_TREE)
1774 laststmt.stmt = stmt;
1775 laststmt.len = srclen;
1776 laststmt.stridx = dsi->idx;
1779 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1780 fprintf (dump_file, "not possible.\n");
1783 /* Handle a call to malloc or calloc. */
1785 static void
1786 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1788 gimple *stmt = gsi_stmt (*gsi);
1789 tree lhs = gimple_call_lhs (stmt);
1790 gcc_assert (get_stridx (lhs) == 0);
1791 int idx = new_stridx (lhs);
1792 tree length = NULL_TREE;
1793 if (bcode == BUILT_IN_CALLOC)
1794 length = build_int_cst (size_type_node, 0);
1795 strinfo *si = new_strinfo (lhs, idx, length);
1796 if (bcode == BUILT_IN_CALLOC)
1797 si->endptr = lhs;
1798 set_strinfo (idx, si);
1799 si->writable = true;
1800 si->stmt = stmt;
1801 si->dont_invalidate = true;
1804 /* Handle a call to memset.
1805 After a call to calloc, memset(,0,) is unnecessary.
1806 memset(malloc(n),0,n) is calloc(n,1). */
1808 static bool
1809 handle_builtin_memset (gimple_stmt_iterator *gsi)
1811 gimple *stmt2 = gsi_stmt (*gsi);
1812 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1813 return true;
1814 tree ptr = gimple_call_arg (stmt2, 0);
1815 int idx1 = get_stridx (ptr);
1816 if (idx1 <= 0)
1817 return true;
1818 strinfo *si1 = get_strinfo (idx1);
1819 if (!si1)
1820 return true;
1821 gimple *stmt1 = si1->stmt;
1822 if (!stmt1 || !is_gimple_call (stmt1))
1823 return true;
1824 tree callee1 = gimple_call_fndecl (stmt1);
1825 if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL))
1826 return true;
1827 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1828 tree size = gimple_call_arg (stmt2, 2);
1829 if (code1 == BUILT_IN_CALLOC)
1830 /* Not touching stmt1 */ ;
1831 else if (code1 == BUILT_IN_MALLOC
1832 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1834 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1835 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1836 size, build_one_cst (size_type_node));
1837 si1->length = build_int_cst (size_type_node, 0);
1838 si1->stmt = gsi_stmt (gsi1);
1840 else
1841 return true;
1842 tree lhs = gimple_call_lhs (stmt2);
1843 unlink_stmt_vdef (stmt2);
1844 if (lhs)
1846 gimple *assign = gimple_build_assign (lhs, ptr);
1847 gsi_replace (gsi, assign, false);
1849 else
1851 gsi_remove (gsi, true);
1852 release_defs (stmt2);
1855 return false;
1858 /* Handle a POINTER_PLUS_EXPR statement.
1859 For p = "abcd" + 2; compute associated length, or if
1860 p = q + off is pointing to a '\0' character of a string, call
1861 zero_length_string on it. */
1863 static void
1864 handle_pointer_plus (gimple_stmt_iterator *gsi)
1866 gimple *stmt = gsi_stmt (*gsi);
1867 tree lhs = gimple_assign_lhs (stmt), off;
1868 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1869 strinfo *si, *zsi;
1871 if (idx == 0)
1872 return;
1874 if (idx < 0)
1876 tree off = gimple_assign_rhs2 (stmt);
1877 if (tree_fits_uhwi_p (off)
1878 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1879 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1880 = ~(~idx - (int) tree_to_uhwi (off));
1881 return;
1884 si = get_strinfo (idx);
1885 if (si == NULL || si->length == NULL_TREE)
1886 return;
1888 off = gimple_assign_rhs2 (stmt);
1889 zsi = NULL;
1890 if (operand_equal_p (si->length, off, 0))
1891 zsi = zero_length_string (lhs, si);
1892 else if (TREE_CODE (off) == SSA_NAME)
1894 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
1895 if (gimple_assign_single_p (def_stmt)
1896 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1897 zsi = zero_length_string (lhs, si);
1899 if (zsi != NULL
1900 && si->endptr != NULL_TREE
1901 && si->endptr != lhs
1902 && TREE_CODE (si->endptr) == SSA_NAME)
1904 enum tree_code rhs_code
1905 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1906 ? SSA_NAME : NOP_EXPR;
1907 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
1908 gcc_assert (gsi_stmt (*gsi) == stmt);
1909 update_stmt (stmt);
1913 /* Handle a single character store. */
1915 static bool
1916 handle_char_store (gimple_stmt_iterator *gsi)
1918 int idx = -1;
1919 strinfo *si = NULL;
1920 gimple *stmt = gsi_stmt (*gsi);
1921 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1923 if (TREE_CODE (lhs) == MEM_REF
1924 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1926 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1928 ssaname = TREE_OPERAND (lhs, 0);
1929 idx = get_stridx (ssaname);
1932 else
1933 idx = get_addr_stridx (lhs);
1935 if (idx > 0)
1937 si = get_strinfo (idx);
1938 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1940 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1942 /* When storing '\0', the store can be removed
1943 if we know it has been stored in the current function. */
1944 if (!stmt_could_throw_p (stmt) && si->writable)
1946 unlink_stmt_vdef (stmt);
1947 release_defs (stmt);
1948 gsi_remove (gsi, true);
1949 return false;
1951 else
1953 si->writable = true;
1954 gsi_next (gsi);
1955 return false;
1958 else
1959 /* Otherwise this statement overwrites the '\0' with
1960 something, if the previous stmt was a memcpy,
1961 its length may be decreased. */
1962 adjust_last_stmt (si, stmt, false);
1964 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1966 si = unshare_strinfo (si);
1967 si->length = build_int_cst (size_type_node, 0);
1968 si->endptr = NULL;
1969 si->prev = 0;
1970 si->next = 0;
1971 si->stmt = NULL;
1972 si->first = 0;
1973 si->writable = true;
1974 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1975 si->endptr = ssaname;
1976 si->dont_invalidate = true;
1978 /* If si->length is non-zero constant, we aren't overwriting '\0',
1979 and if we aren't storing '\0', we know that the length of the
1980 string and any other zero terminated string in memory remains
1981 the same. In that case we move to the next gimple statement and
1982 return to signal the caller that it shouldn't invalidate anything.
1984 This is benefical for cases like:
1986 char p[20];
1987 void foo (char *q)
1989 strcpy (p, "foobar");
1990 size_t len = strlen (p); // This can be optimized into 6
1991 size_t len2 = strlen (q); // This has to be computed
1992 p[0] = 'X';
1993 size_t len3 = strlen (p); // This can be optimized into 6
1994 size_t len4 = strlen (q); // This can be optimized into len2
1995 bar (len, len2, len3, len4);
1998 else if (si != NULL && si->length != NULL_TREE
1999 && TREE_CODE (si->length) == INTEGER_CST
2000 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2002 gsi_next (gsi);
2003 return false;
2006 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2008 if (ssaname)
2010 si = zero_length_string (ssaname, NULL);
2011 if (si != NULL)
2012 si->dont_invalidate = true;
2014 else
2016 int idx = new_addr_stridx (lhs);
2017 if (idx != 0)
2019 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2020 build_int_cst (size_type_node, 0));
2021 set_strinfo (idx, si);
2022 si->dont_invalidate = true;
2025 if (si != NULL)
2026 si->writable = true;
2028 else if (idx == 0
2029 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2030 && ssaname == NULL_TREE
2031 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2033 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2034 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2035 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2037 int idx = new_addr_stridx (lhs);
2038 if (idx != 0)
2040 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2041 build_int_cst (size_type_node, l));
2042 set_strinfo (idx, si);
2043 si->dont_invalidate = true;
2048 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2050 /* Allow adjust_last_stmt to remove it if the stored '\0'
2051 is immediately overwritten. */
2052 laststmt.stmt = stmt;
2053 laststmt.len = build_int_cst (size_type_node, 1);
2054 laststmt.stridx = si->idx;
2056 return true;
2059 /* Attempt to optimize a single statement at *GSI using string length
2060 knowledge. */
2062 static bool
2063 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2065 gimple *stmt = gsi_stmt (*gsi);
2067 if (is_gimple_call (stmt))
2069 tree callee = gimple_call_fndecl (stmt);
2070 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
2071 switch (DECL_FUNCTION_CODE (callee))
2073 case BUILT_IN_STRLEN:
2074 case BUILT_IN_STRLEN_CHKP:
2075 handle_builtin_strlen (gsi);
2076 break;
2077 case BUILT_IN_STRCHR:
2078 case BUILT_IN_STRCHR_CHKP:
2079 handle_builtin_strchr (gsi);
2080 break;
2081 case BUILT_IN_STRCPY:
2082 case BUILT_IN_STRCPY_CHK:
2083 case BUILT_IN_STPCPY:
2084 case BUILT_IN_STPCPY_CHK:
2085 case BUILT_IN_STRCPY_CHKP:
2086 case BUILT_IN_STRCPY_CHK_CHKP:
2087 case BUILT_IN_STPCPY_CHKP:
2088 case BUILT_IN_STPCPY_CHK_CHKP:
2089 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2090 break;
2091 case BUILT_IN_MEMCPY:
2092 case BUILT_IN_MEMCPY_CHK:
2093 case BUILT_IN_MEMPCPY:
2094 case BUILT_IN_MEMPCPY_CHK:
2095 case BUILT_IN_MEMCPY_CHKP:
2096 case BUILT_IN_MEMCPY_CHK_CHKP:
2097 case BUILT_IN_MEMPCPY_CHKP:
2098 case BUILT_IN_MEMPCPY_CHK_CHKP:
2099 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2100 break;
2101 case BUILT_IN_STRCAT:
2102 case BUILT_IN_STRCAT_CHK:
2103 case BUILT_IN_STRCAT_CHKP:
2104 case BUILT_IN_STRCAT_CHK_CHKP:
2105 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2106 break;
2107 case BUILT_IN_MALLOC:
2108 case BUILT_IN_CALLOC:
2109 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2110 break;
2111 case BUILT_IN_MEMSET:
2112 if (!handle_builtin_memset (gsi))
2113 return false;
2114 break;
2115 default:
2116 break;
2119 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2121 tree lhs = gimple_assign_lhs (stmt);
2123 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2125 if (gimple_assign_single_p (stmt)
2126 || (gimple_assign_cast_p (stmt)
2127 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2129 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2130 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2132 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2133 handle_pointer_plus (gsi);
2135 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2137 tree type = TREE_TYPE (lhs);
2138 if (TREE_CODE (type) == ARRAY_TYPE)
2139 type = TREE_TYPE (type);
2140 if (TREE_CODE (type) == INTEGER_TYPE
2141 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2142 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2144 if (! handle_char_store (gsi))
2145 return false;
2150 if (gimple_vdef (stmt))
2151 maybe_invalidate (stmt);
2152 return true;
2155 /* Recursively call maybe_invalidate on stmts that might be executed
2156 in between dombb and current bb and that contain a vdef. Stop when
2157 *count stmts are inspected, or if the whole strinfo vector has
2158 been invalidated. */
2160 static void
2161 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2163 unsigned int i, n = gimple_phi_num_args (phi);
2165 for (i = 0; i < n; i++)
2167 tree vuse = gimple_phi_arg_def (phi, i);
2168 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2169 basic_block bb = gimple_bb (stmt);
2170 if (bb == NULL
2171 || bb == dombb
2172 || !bitmap_set_bit (visited, bb->index)
2173 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2174 continue;
2175 while (1)
2177 if (gimple_code (stmt) == GIMPLE_PHI)
2179 do_invalidate (dombb, stmt, visited, count);
2180 if (*count == 0)
2181 return;
2182 break;
2184 if (--*count == 0)
2185 return;
2186 if (!maybe_invalidate (stmt))
2188 *count = 0;
2189 return;
2191 vuse = gimple_vuse (stmt);
2192 stmt = SSA_NAME_DEF_STMT (vuse);
2193 if (gimple_bb (stmt) != bb)
2195 bb = gimple_bb (stmt);
2196 if (bb == NULL
2197 || bb == dombb
2198 || !bitmap_set_bit (visited, bb->index)
2199 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2200 break;
2206 class strlen_dom_walker : public dom_walker
2208 public:
2209 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2211 virtual void before_dom_children (basic_block);
2212 virtual void after_dom_children (basic_block);
2215 /* Callback for walk_dominator_tree. Attempt to optimize various
2216 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2218 void
2219 strlen_dom_walker::before_dom_children (basic_block bb)
2221 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2223 if (dombb == NULL)
2224 stridx_to_strinfo = NULL;
2225 else
2227 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2228 if (stridx_to_strinfo)
2230 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2231 gsi_next (&gsi))
2233 gphi *phi = gsi.phi ();
2234 if (virtual_operand_p (gimple_phi_result (phi)))
2236 bitmap visited = BITMAP_ALLOC (NULL);
2237 int count_vdef = 100;
2238 do_invalidate (dombb, phi, visited, &count_vdef);
2239 BITMAP_FREE (visited);
2240 if (count_vdef == 0)
2242 /* If there were too many vdefs in between immediate
2243 dominator and current bb, invalidate everything.
2244 If stridx_to_strinfo has been unshared, we need
2245 to free it, otherwise just set it to NULL. */
2246 if (!strinfo_shared ())
2248 unsigned int i;
2249 strinfo *si;
2251 for (i = 1;
2252 vec_safe_iterate (stridx_to_strinfo, i, &si);
2253 ++i)
2255 free_strinfo (si);
2256 (*stridx_to_strinfo)[i] = NULL;
2259 else
2260 stridx_to_strinfo = NULL;
2262 break;
2268 /* If all PHI arguments have the same string index, the PHI result
2269 has it as well. */
2270 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2271 gsi_next (&gsi))
2273 gphi *phi = gsi.phi ();
2274 tree result = gimple_phi_result (phi);
2275 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2277 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2278 if (idx != 0)
2280 unsigned int i, n = gimple_phi_num_args (phi);
2281 for (i = 1; i < n; i++)
2282 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2283 break;
2284 if (i == n)
2285 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2290 /* Attempt to optimize individual statements. */
2291 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2292 if (strlen_optimize_stmt (&gsi))
2293 gsi_next (&gsi);
2295 bb->aux = stridx_to_strinfo;
2296 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2297 (*stridx_to_strinfo)[0] = (strinfo *) bb;
2300 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2301 owned by the current bb, clear bb->aux. */
2303 void
2304 strlen_dom_walker::after_dom_children (basic_block bb)
2306 if (bb->aux)
2308 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2309 if (vec_safe_length (stridx_to_strinfo)
2310 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2312 unsigned int i;
2313 strinfo *si;
2315 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2316 free_strinfo (si);
2317 vec_free (stridx_to_strinfo);
2319 bb->aux = NULL;
2323 /* Main entry point. */
2325 namespace {
2327 const pass_data pass_data_strlen =
2329 GIMPLE_PASS, /* type */
2330 "strlen", /* name */
2331 OPTGROUP_NONE, /* optinfo_flags */
2332 TV_TREE_STRLEN, /* tv_id */
2333 ( PROP_cfg | PROP_ssa ), /* properties_required */
2334 0, /* properties_provided */
2335 0, /* properties_destroyed */
2336 0, /* todo_flags_start */
2337 0, /* todo_flags_finish */
2340 class pass_strlen : public gimple_opt_pass
2342 public:
2343 pass_strlen (gcc::context *ctxt)
2344 : gimple_opt_pass (pass_data_strlen, ctxt)
2347 /* opt_pass methods: */
2348 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2349 virtual unsigned int execute (function *);
2351 }; // class pass_strlen
2353 unsigned int
2354 pass_strlen::execute (function *fun)
2356 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2357 max_stridx = 1;
2359 calculate_dominance_info (CDI_DOMINATORS);
2361 /* String length optimization is implemented as a walk of the dominator
2362 tree and a forward walk of statements within each block. */
2363 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2365 ssa_ver_to_stridx.release ();
2366 strinfo_pool.release ();
2367 if (decl_to_stridxlist_htab)
2369 obstack_free (&stridx_obstack, NULL);
2370 delete decl_to_stridxlist_htab;
2371 decl_to_stridxlist_htab = NULL;
2373 laststmt.stmt = NULL;
2374 laststmt.len = NULL_TREE;
2375 laststmt.stridx = 0;
2377 return 0;
2380 } // anon namespace
2382 gimple_opt_pass *
2383 make_pass_strlen (gcc::context *ctxt)
2385 return new pass_strlen (ctxt);