Daily bump.
[official-gcc.git] / gcc / tree-ssa-strlen.c
blobcfe4dd9b31b01b373c6acd7bd76ad97fdec633bb
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 typedef struct strinfo_struct
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;
113 } *strinfo;
115 /* Pool for allocating strinfo_struct entries. */
116 static object_allocator<strinfo_struct> strinfo_pool ("strinfo_struct pool",
117 64);
119 /* Vector mapping positive string indexes to strinfo, for the
120 current basic block. The first pointer in the vector is special,
121 it is either NULL, meaning the vector isn't shared, or it is
122 a basic block pointer to the owner basic_block if shared.
123 If some other bb wants to modify the vector, the vector needs
124 to be unshared first, and only the owner bb is supposed to free it. */
125 static vec<strinfo, va_heap, vl_embed> *stridx_to_strinfo;
127 /* One OFFSET->IDX mapping. */
128 struct stridxlist
130 struct stridxlist *next;
131 HOST_WIDE_INT offset;
132 int idx;
135 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
136 struct decl_stridxlist_map
138 struct tree_map_base base;
139 struct stridxlist list;
142 /* Hash table for mapping decls to a chained list of offset -> idx
143 mappings. */
144 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
146 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
147 static struct obstack stridx_obstack;
149 /* Last memcpy statement if it could be adjusted if the trailing
150 '\0' written is immediately overwritten, or
151 *x = '\0' store that could be removed if it is immediately overwritten. */
152 struct laststmt_struct
154 gimple stmt;
155 tree len;
156 int stridx;
157 } laststmt;
159 static int get_stridx_plus_constant (strinfo, HOST_WIDE_INT, tree);
161 /* Return strinfo vector entry IDX. */
163 static inline strinfo
164 get_strinfo (int idx)
166 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
167 return NULL;
168 return (*stridx_to_strinfo)[idx];
171 /* Helper function for get_stridx. */
173 static int
174 get_addr_stridx (tree exp)
176 HOST_WIDE_INT off;
177 struct stridxlist *list;
178 tree base;
180 if (!decl_to_stridxlist_htab)
181 return 0;
183 base = get_addr_base_and_unit_offset (exp, &off);
184 if (base == NULL || !DECL_P (base))
185 return 0;
187 list = decl_to_stridxlist_htab->get (base);
188 if (list == NULL)
189 return 0;
193 if (list->offset == off)
194 return list->idx;
195 list = list->next;
197 while (list);
198 return 0;
201 /* Return string index for EXP. */
203 static int
204 get_stridx (tree exp)
206 tree s, o;
208 if (TREE_CODE (exp) == SSA_NAME)
210 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
211 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
212 int i;
213 tree e = exp;
214 HOST_WIDE_INT off = 0;
215 for (i = 0; i < 5; i++)
217 gimple def_stmt = SSA_NAME_DEF_STMT (e);
218 if (!is_gimple_assign (def_stmt)
219 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
220 return 0;
221 tree rhs1 = gimple_assign_rhs1 (def_stmt);
222 tree rhs2 = gimple_assign_rhs2 (def_stmt);
223 if (TREE_CODE (rhs1) != SSA_NAME
224 || !tree_fits_shwi_p (rhs2))
225 return 0;
226 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
227 if (this_off < 0)
228 return 0;
229 off = (unsigned HOST_WIDE_INT) off + this_off;
230 if (off < 0)
231 return 0;
232 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
234 strinfo si
235 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
236 if (si
237 && si->length
238 && TREE_CODE (si->length) == INTEGER_CST
239 && compare_tree_int (si->length, off) != -1)
240 return get_stridx_plus_constant (si, off, exp);
242 e = rhs1;
244 return 0;
247 if (TREE_CODE (exp) == ADDR_EXPR)
249 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
250 if (idx != 0)
251 return idx;
254 s = string_constant (exp, &o);
255 if (s != NULL_TREE
256 && (o == NULL_TREE || tree_fits_shwi_p (o))
257 && TREE_STRING_LENGTH (s) > 0)
259 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
260 const char *p = TREE_STRING_POINTER (s);
261 int max = TREE_STRING_LENGTH (s) - 1;
263 if (p[max] == '\0' && offset >= 0 && offset <= max)
264 return ~(int) strlen (p + offset);
266 return 0;
269 /* Return true if strinfo vector is shared with the immediate dominator. */
271 static inline bool
272 strinfo_shared (void)
274 return vec_safe_length (stridx_to_strinfo)
275 && (*stridx_to_strinfo)[0] != NULL;
278 /* Unshare strinfo vector that is shared with the immediate dominator. */
280 static void
281 unshare_strinfo_vec (void)
283 strinfo si;
284 unsigned int i = 0;
286 gcc_assert (strinfo_shared ());
287 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
288 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
289 if (si != NULL)
290 si->refcount++;
291 (*stridx_to_strinfo)[0] = NULL;
294 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
295 Return a pointer to the location where the string index can
296 be stored (if 0) or is stored, or NULL if this can't be tracked. */
298 static int *
299 addr_stridxptr (tree exp)
301 HOST_WIDE_INT off;
303 tree base = get_addr_base_and_unit_offset (exp, &off);
304 if (base == NULL_TREE || !DECL_P (base))
305 return NULL;
307 if (!decl_to_stridxlist_htab)
309 decl_to_stridxlist_htab
310 = new hash_map<tree_decl_hash, stridxlist> (64);
311 gcc_obstack_init (&stridx_obstack);
314 bool existed;
315 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
316 if (existed)
318 int i;
319 for (i = 0; i < 16; i++)
321 if (list->offset == off)
322 return &list->idx;
323 if (list->next == NULL)
324 break;
326 if (i == 16)
327 return NULL;
328 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
329 list = list->next;
332 list->next = NULL;
333 list->offset = off;
334 list->idx = 0;
335 return &list->idx;
338 /* Create a new string index, or return 0 if reached limit. */
340 static int
341 new_stridx (tree exp)
343 int idx;
344 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
345 return 0;
346 if (TREE_CODE (exp) == SSA_NAME)
348 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
349 return 0;
350 idx = max_stridx++;
351 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
352 return idx;
354 if (TREE_CODE (exp) == ADDR_EXPR)
356 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
357 if (pidx != NULL)
359 gcc_assert (*pidx == 0);
360 *pidx = max_stridx++;
361 return *pidx;
364 return 0;
367 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
369 static int
370 new_addr_stridx (tree exp)
372 int *pidx;
373 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
374 return 0;
375 pidx = addr_stridxptr (exp);
376 if (pidx != NULL)
378 gcc_assert (*pidx == 0);
379 *pidx = max_stridx++;
380 return *pidx;
382 return 0;
385 /* Create a new strinfo. */
387 static strinfo
388 new_strinfo (tree ptr, int idx, tree length)
390 strinfo si = strinfo_pool.allocate ();
391 si->length = length;
392 si->ptr = ptr;
393 si->stmt = NULL;
394 si->endptr = NULL_TREE;
395 si->refcount = 1;
396 si->idx = idx;
397 si->first = 0;
398 si->prev = 0;
399 si->next = 0;
400 si->writable = false;
401 si->dont_invalidate = false;
402 return si;
405 /* Decrease strinfo refcount and free it if not referenced anymore. */
407 static inline void
408 free_strinfo (strinfo si)
410 if (si && --si->refcount == 0)
411 strinfo_pool.remove (si);
414 /* Set strinfo in the vector entry IDX to SI. */
416 static inline void
417 set_strinfo (int idx, strinfo si)
419 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
420 unshare_strinfo_vec ();
421 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
422 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
423 (*stridx_to_strinfo)[idx] = si;
426 /* Return string length, or NULL if it can't be computed. */
428 static tree
429 get_string_length (strinfo si)
431 if (si->length)
432 return si->length;
434 if (si->stmt)
436 gimple stmt = si->stmt, lenstmt;
437 bool with_bounds = gimple_call_with_bounds_p (stmt);
438 tree callee, lhs, fn, tem;
439 location_t loc;
440 gimple_stmt_iterator gsi;
442 gcc_assert (is_gimple_call (stmt));
443 callee = gimple_call_fndecl (stmt);
444 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
445 lhs = gimple_call_lhs (stmt);
446 /* unshare_strinfo is intentionally not called here. The (delayed)
447 transformation of strcpy or strcat into stpcpy is done at the place
448 of the former strcpy/strcat call and so can affect all the strinfos
449 with the same stmt. If they were unshared before and transformation
450 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
451 just compute the right length. */
452 switch (DECL_FUNCTION_CODE (callee))
454 case BUILT_IN_STRCAT:
455 case BUILT_IN_STRCAT_CHK:
456 case BUILT_IN_STRCAT_CHKP:
457 case BUILT_IN_STRCAT_CHK_CHKP:
458 gsi = gsi_for_stmt (stmt);
459 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
460 gcc_assert (lhs == NULL_TREE);
461 tem = unshare_expr (gimple_call_arg (stmt, 0));
462 if (with_bounds)
464 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
465 2, tem, gimple_call_arg (stmt, 1));
466 gimple_call_set_with_bounds (lenstmt, true);
468 else
469 lenstmt = gimple_build_call (fn, 1, tem);
470 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
471 gimple_call_set_lhs (lenstmt, lhs);
472 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
473 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
474 tem = gimple_call_arg (stmt, 0);
475 if (!ptrofftype_p (TREE_TYPE (lhs)))
477 lhs = convert_to_ptrofftype (lhs);
478 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
479 true, GSI_SAME_STMT);
481 lenstmt = gimple_build_assign
482 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
483 POINTER_PLUS_EXPR,tem, lhs);
484 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
485 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
486 lhs = NULL_TREE;
487 /* FALLTHRU */
488 case BUILT_IN_STRCPY:
489 case BUILT_IN_STRCPY_CHK:
490 case BUILT_IN_STRCPY_CHKP:
491 case BUILT_IN_STRCPY_CHK_CHKP:
492 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
493 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
494 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
495 else
496 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
497 if (with_bounds)
498 fn = chkp_maybe_create_clone (fn)->decl;
499 gcc_assert (lhs == NULL_TREE);
500 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
502 fprintf (dump_file, "Optimizing: ");
503 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
505 gimple_call_set_fndecl (stmt, fn);
506 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
507 gimple_call_set_lhs (stmt, lhs);
508 update_stmt (stmt);
509 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
511 fprintf (dump_file, "into: ");
512 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
514 /* FALLTHRU */
515 case BUILT_IN_STPCPY:
516 case BUILT_IN_STPCPY_CHK:
517 case BUILT_IN_STPCPY_CHKP:
518 case BUILT_IN_STPCPY_CHK_CHKP:
519 gcc_assert (lhs != NULL_TREE);
520 loc = gimple_location (stmt);
521 si->endptr = lhs;
522 si->stmt = NULL;
523 lhs = fold_convert_loc (loc, size_type_node, lhs);
524 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
525 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
526 lhs, si->length);
527 break;
528 case BUILT_IN_MALLOC:
529 break;
530 /* BUILT_IN_CALLOC always has si->length set. */
531 default:
532 gcc_unreachable ();
533 break;
537 return si->length;
540 /* Invalidate string length information for strings whose length
541 might change due to stores in stmt. */
543 static bool
544 maybe_invalidate (gimple stmt)
546 strinfo si;
547 unsigned int i;
548 bool nonempty = false;
550 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
551 if (si != NULL)
553 if (!si->dont_invalidate)
555 ao_ref r;
556 /* Do not use si->length. */
557 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
558 if (stmt_may_clobber_ref_p_1 (stmt, &r))
560 set_strinfo (i, NULL);
561 free_strinfo (si);
562 continue;
565 si->dont_invalidate = false;
566 nonempty = true;
568 return nonempty;
571 /* Unshare strinfo record SI, if it has refcount > 1 or
572 if stridx_to_strinfo vector is shared with some other
573 bbs. */
575 static strinfo
576 unshare_strinfo (strinfo si)
578 strinfo nsi;
580 if (si->refcount == 1 && !strinfo_shared ())
581 return si;
583 nsi = new_strinfo (si->ptr, si->idx, si->length);
584 nsi->stmt = si->stmt;
585 nsi->endptr = si->endptr;
586 nsi->first = si->first;
587 nsi->prev = si->prev;
588 nsi->next = si->next;
589 nsi->writable = si->writable;
590 set_strinfo (si->idx, nsi);
591 free_strinfo (si);
592 return nsi;
595 /* Return first strinfo in the related strinfo chain
596 if all strinfos in between belong to the chain, otherwise
597 NULL. */
599 static strinfo
600 verify_related_strinfos (strinfo origsi)
602 strinfo si = origsi, psi;
604 if (origsi->first == 0)
605 return NULL;
606 for (; si->prev; si = psi)
608 if (si->first != origsi->first)
609 return NULL;
610 psi = get_strinfo (si->prev);
611 if (psi == NULL)
612 return NULL;
613 if (psi->next != si->idx)
614 return NULL;
616 if (si->idx != si->first)
617 return NULL;
618 return si;
621 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
622 strinfo if there is any. Return it's idx, or 0 if no strinfo has
623 been created. */
625 static int
626 get_stridx_plus_constant (strinfo basesi, HOST_WIDE_INT off, tree ptr)
628 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
630 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
631 return 0;
633 if (basesi->length == NULL_TREE
634 || TREE_CODE (basesi->length) != INTEGER_CST
635 || compare_tree_int (basesi->length, off) == -1
636 || !tree_fits_shwi_p (basesi->length))
637 return 0;
639 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
640 strinfo si = basesi, chainsi;
641 if (si->first || si->prev || si->next)
642 si = verify_related_strinfos (basesi);
643 if (si == NULL
644 || si->length == NULL_TREE
645 || TREE_CODE (si->length) != INTEGER_CST)
646 return 0;
648 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
649 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
651 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
652 for (chainsi = si; chainsi->next; chainsi = si)
654 si = get_strinfo (chainsi->next);
655 if (si == NULL
656 || si->first != chainsi->first
657 || si->prev != chainsi->idx
658 || si->length == NULL_TREE
659 || TREE_CODE (si->length) != INTEGER_CST)
660 break;
661 int r = compare_tree_int (si->length, len);
662 if (r != 1)
664 if (r == 0)
666 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
667 return si->idx;
669 break;
673 int idx = new_stridx (ptr);
674 if (idx == 0)
675 return 0;
676 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
677 set_strinfo (idx, si);
678 if (chainsi->next)
680 strinfo nextsi = unshare_strinfo (get_strinfo (chainsi->next));
681 si->next = nextsi->idx;
682 nextsi->prev = idx;
684 chainsi = unshare_strinfo (chainsi);
685 if (chainsi->first == 0)
686 chainsi->first = chainsi->idx;
687 chainsi->next = idx;
688 if (chainsi->endptr == NULL_TREE && len == 0)
689 chainsi->endptr = ptr;
690 si->endptr = chainsi->endptr;
691 si->prev = chainsi->idx;
692 si->first = chainsi->first;
693 si->writable = chainsi->writable;
694 return si->idx;
697 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
698 to a zero-length string and if possible chain it to a related strinfo
699 chain whose part is or might be CHAINSI. */
701 static strinfo
702 zero_length_string (tree ptr, strinfo chainsi)
704 strinfo si;
705 int idx;
706 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
707 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
708 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
709 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
711 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
712 return NULL;
713 if (chainsi != NULL)
715 si = verify_related_strinfos (chainsi);
716 if (si)
718 chainsi = si;
719 for (; chainsi->next; chainsi = si)
721 if (chainsi->endptr == NULL_TREE)
723 chainsi = unshare_strinfo (chainsi);
724 chainsi->endptr = ptr;
726 si = get_strinfo (chainsi->next);
727 if (si == NULL
728 || si->first != chainsi->first
729 || si->prev != chainsi->idx)
730 break;
732 gcc_assert (chainsi->length || chainsi->stmt);
733 if (chainsi->endptr == NULL_TREE)
735 chainsi = unshare_strinfo (chainsi);
736 chainsi->endptr = ptr;
738 if (chainsi->length && integer_zerop (chainsi->length))
740 if (chainsi->next)
742 chainsi = unshare_strinfo (chainsi);
743 chainsi->next = 0;
745 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
746 return chainsi;
749 else if (chainsi->first || chainsi->prev || chainsi->next)
751 chainsi = unshare_strinfo (chainsi);
752 chainsi->first = 0;
753 chainsi->prev = 0;
754 chainsi->next = 0;
757 idx = new_stridx (ptr);
758 if (idx == 0)
759 return NULL;
760 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
761 set_strinfo (idx, si);
762 si->endptr = ptr;
763 if (chainsi != NULL)
765 chainsi = unshare_strinfo (chainsi);
766 if (chainsi->first == 0)
767 chainsi->first = chainsi->idx;
768 chainsi->next = idx;
769 if (chainsi->endptr == NULL_TREE)
770 chainsi->endptr = ptr;
771 si->prev = chainsi->idx;
772 si->first = chainsi->first;
773 si->writable = chainsi->writable;
775 return si;
778 /* For strinfo ORIGSI whose length has been just updated
779 update also related strinfo lengths (add ADJ to each,
780 but don't adjust ORIGSI). */
782 static void
783 adjust_related_strinfos (location_t loc, strinfo origsi, tree adj)
785 strinfo si = verify_related_strinfos (origsi);
787 if (si == NULL)
788 return;
790 while (1)
792 strinfo nsi;
794 if (si != origsi)
796 tree tem;
798 si = unshare_strinfo (si);
799 if (si->length)
801 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
802 si->length = fold_build2_loc (loc, PLUS_EXPR,
803 TREE_TYPE (si->length), si->length,
804 tem);
806 else if (si->stmt != NULL)
807 /* Delayed length computation is unaffected. */
809 else
810 gcc_unreachable ();
812 si->endptr = NULL_TREE;
813 si->dont_invalidate = true;
815 if (si->next == 0)
816 return;
817 nsi = get_strinfo (si->next);
818 if (nsi == NULL
819 || nsi->first != si->first
820 || nsi->prev != si->idx)
821 return;
822 si = nsi;
826 /* Find if there are other SSA_NAME pointers equal to PTR
827 for which we don't track their string lengths yet. If so, use
828 IDX for them. */
830 static void
831 find_equal_ptrs (tree ptr, int idx)
833 if (TREE_CODE (ptr) != SSA_NAME)
834 return;
835 while (1)
837 gimple stmt = SSA_NAME_DEF_STMT (ptr);
838 if (!is_gimple_assign (stmt))
839 return;
840 ptr = gimple_assign_rhs1 (stmt);
841 switch (gimple_assign_rhs_code (stmt))
843 case SSA_NAME:
844 break;
845 CASE_CONVERT:
846 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
847 return;
848 if (TREE_CODE (ptr) == SSA_NAME)
849 break;
850 if (TREE_CODE (ptr) != ADDR_EXPR)
851 return;
852 /* FALLTHRU */
853 case ADDR_EXPR:
855 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
856 if (pidx != NULL && *pidx == 0)
857 *pidx = idx;
858 return;
860 default:
861 return;
864 /* We might find an endptr created in this pass. Grow the
865 vector in that case. */
866 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
867 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
869 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
870 return;
871 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
875 /* If the last .MEM setter statement before STMT is
876 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
877 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
878 just memcpy (x, y, strlen (y)). SI must be the zero length
879 strinfo. */
881 static void
882 adjust_last_stmt (strinfo si, gimple stmt, bool is_strcat)
884 tree vuse, callee, len;
885 struct laststmt_struct last = laststmt;
886 strinfo lastsi, firstsi;
887 unsigned len_arg_no = 2;
889 laststmt.stmt = NULL;
890 laststmt.len = NULL_TREE;
891 laststmt.stridx = 0;
893 if (last.stmt == NULL)
894 return;
896 vuse = gimple_vuse (stmt);
897 if (vuse == NULL_TREE
898 || SSA_NAME_DEF_STMT (vuse) != last.stmt
899 || !has_single_use (vuse))
900 return;
902 gcc_assert (last.stridx > 0);
903 lastsi = get_strinfo (last.stridx);
904 if (lastsi == NULL)
905 return;
907 if (lastsi != si)
909 if (lastsi->first == 0 || lastsi->first != si->first)
910 return;
912 firstsi = verify_related_strinfos (si);
913 if (firstsi == NULL)
914 return;
915 while (firstsi != lastsi)
917 strinfo nextsi;
918 if (firstsi->next == 0)
919 return;
920 nextsi = get_strinfo (firstsi->next);
921 if (nextsi == NULL
922 || nextsi->prev != firstsi->idx
923 || nextsi->first != si->first)
924 return;
925 firstsi = nextsi;
929 if (!is_strcat)
931 if (si->length == NULL_TREE || !integer_zerop (si->length))
932 return;
935 if (is_gimple_assign (last.stmt))
937 gimple_stmt_iterator gsi;
939 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
940 return;
941 if (stmt_could_throw_p (last.stmt))
942 return;
943 gsi = gsi_for_stmt (last.stmt);
944 unlink_stmt_vdef (last.stmt);
945 release_defs (last.stmt);
946 gsi_remove (&gsi, true);
947 return;
950 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
951 return;
953 callee = gimple_call_fndecl (last.stmt);
954 switch (DECL_FUNCTION_CODE (callee))
956 case BUILT_IN_MEMCPY:
957 case BUILT_IN_MEMCPY_CHK:
958 break;
959 case BUILT_IN_MEMCPY_CHKP:
960 case BUILT_IN_MEMCPY_CHK_CHKP:
961 len_arg_no = 4;
962 break;
963 default:
964 return;
967 len = gimple_call_arg (last.stmt, len_arg_no);
968 if (tree_fits_uhwi_p (len))
970 if (!tree_fits_uhwi_p (last.len)
971 || integer_zerop (len)
972 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
973 return;
974 /* Don't adjust the length if it is divisible by 4, it is more efficient
975 to store the extra '\0' in that case. */
976 if ((tree_to_uhwi (len) & 3) == 0)
977 return;
979 else if (TREE_CODE (len) == SSA_NAME)
981 gimple def_stmt = SSA_NAME_DEF_STMT (len);
982 if (!is_gimple_assign (def_stmt)
983 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
984 || gimple_assign_rhs1 (def_stmt) != last.len
985 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
986 return;
988 else
989 return;
991 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
992 update_stmt (last.stmt);
995 /* Handle a strlen call. If strlen of the argument is known, replace
996 the strlen call with the known value, otherwise remember that strlen
997 of the argument is stored in the lhs SSA_NAME. */
999 static void
1000 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1002 int idx;
1003 tree src;
1004 gimple stmt = gsi_stmt (*gsi);
1005 tree lhs = gimple_call_lhs (stmt);
1007 if (lhs == NULL_TREE)
1008 return;
1010 src = gimple_call_arg (stmt, 0);
1011 idx = get_stridx (src);
1012 if (idx)
1014 strinfo si = NULL;
1015 tree rhs;
1017 if (idx < 0)
1018 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1019 else
1021 rhs = NULL_TREE;
1022 si = get_strinfo (idx);
1023 if (si != NULL)
1024 rhs = get_string_length (si);
1026 if (rhs != NULL_TREE)
1028 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1030 fprintf (dump_file, "Optimizing: ");
1031 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1033 rhs = unshare_expr (rhs);
1034 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1035 rhs = fold_convert_loc (gimple_location (stmt),
1036 TREE_TYPE (lhs), rhs);
1037 if (!update_call_from_tree (gsi, rhs))
1038 gimplify_and_update_call_from_tree (gsi, rhs);
1039 stmt = gsi_stmt (*gsi);
1040 update_stmt (stmt);
1041 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1043 fprintf (dump_file, "into: ");
1044 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1046 if (si != NULL
1047 && TREE_CODE (si->length) != SSA_NAME
1048 && TREE_CODE (si->length) != INTEGER_CST
1049 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1051 si = unshare_strinfo (si);
1052 si->length = lhs;
1054 return;
1057 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1058 return;
1059 if (idx == 0)
1060 idx = new_stridx (src);
1061 else if (get_strinfo (idx) != NULL)
1062 return;
1063 if (idx)
1065 strinfo si = new_strinfo (src, idx, lhs);
1066 set_strinfo (idx, si);
1067 find_equal_ptrs (src, idx);
1071 /* Handle a strchr call. If strlen of the first argument is known, replace
1072 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1073 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1075 static void
1076 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1078 int idx;
1079 tree src;
1080 gimple stmt = gsi_stmt (*gsi);
1081 tree lhs = gimple_call_lhs (stmt);
1082 bool with_bounds = gimple_call_with_bounds_p (stmt);
1084 if (lhs == NULL_TREE)
1085 return;
1087 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1088 return;
1090 src = gimple_call_arg (stmt, 0);
1091 idx = get_stridx (src);
1092 if (idx)
1094 strinfo si = NULL;
1095 tree rhs;
1097 if (idx < 0)
1098 rhs = build_int_cst (size_type_node, ~idx);
1099 else
1101 rhs = NULL_TREE;
1102 si = get_strinfo (idx);
1103 if (si != NULL)
1104 rhs = get_string_length (si);
1106 if (rhs != NULL_TREE)
1108 location_t loc = gimple_location (stmt);
1110 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1112 fprintf (dump_file, "Optimizing: ");
1113 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1115 if (si != NULL && si->endptr != NULL_TREE)
1117 rhs = unshare_expr (si->endptr);
1118 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1119 TREE_TYPE (rhs)))
1120 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1122 else
1124 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1125 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1126 TREE_TYPE (src), src, rhs);
1127 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1128 TREE_TYPE (rhs)))
1129 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1131 if (!update_call_from_tree (gsi, rhs))
1132 gimplify_and_update_call_from_tree (gsi, rhs);
1133 stmt = gsi_stmt (*gsi);
1134 update_stmt (stmt);
1135 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1137 fprintf (dump_file, "into: ");
1138 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1140 if (si != NULL
1141 && si->endptr == NULL_TREE
1142 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1144 si = unshare_strinfo (si);
1145 si->endptr = lhs;
1147 zero_length_string (lhs, si);
1148 return;
1151 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1152 return;
1153 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1155 if (idx == 0)
1156 idx = new_stridx (src);
1157 else if (get_strinfo (idx) != NULL)
1159 zero_length_string (lhs, NULL);
1160 return;
1162 if (idx)
1164 location_t loc = gimple_location (stmt);
1165 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1166 tree srcu = fold_convert_loc (loc, size_type_node, src);
1167 tree length = fold_build2_loc (loc, MINUS_EXPR,
1168 size_type_node, lhsu, srcu);
1169 strinfo si = new_strinfo (src, idx, length);
1170 si->endptr = lhs;
1171 set_strinfo (idx, si);
1172 find_equal_ptrs (src, idx);
1173 zero_length_string (lhs, si);
1176 else
1177 zero_length_string (lhs, NULL);
1180 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1181 If strlen of the second argument is known, strlen of the first argument
1182 is the same after this call. Furthermore, attempt to convert it to
1183 memcpy. */
1185 static void
1186 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1188 int idx, didx;
1189 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1190 bool success;
1191 gimple stmt = gsi_stmt (*gsi);
1192 strinfo si, dsi, olddsi, zsi;
1193 location_t loc;
1194 bool with_bounds = gimple_call_with_bounds_p (stmt);
1196 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1197 dst = gimple_call_arg (stmt, 0);
1198 lhs = gimple_call_lhs (stmt);
1199 idx = get_stridx (src);
1200 si = NULL;
1201 if (idx > 0)
1202 si = get_strinfo (idx);
1204 didx = get_stridx (dst);
1205 olddsi = NULL;
1206 oldlen = NULL_TREE;
1207 if (didx > 0)
1208 olddsi = get_strinfo (didx);
1209 else if (didx < 0)
1210 return;
1212 if (olddsi != NULL)
1213 adjust_last_stmt (olddsi, stmt, false);
1215 srclen = NULL_TREE;
1216 if (si != NULL)
1217 srclen = get_string_length (si);
1218 else if (idx < 0)
1219 srclen = build_int_cst (size_type_node, ~idx);
1221 loc = gimple_location (stmt);
1222 if (srclen == NULL_TREE)
1223 switch (bcode)
1225 case BUILT_IN_STRCPY:
1226 case BUILT_IN_STRCPY_CHK:
1227 case BUILT_IN_STRCPY_CHKP:
1228 case BUILT_IN_STRCPY_CHK_CHKP:
1229 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1230 return;
1231 break;
1232 case BUILT_IN_STPCPY:
1233 case BUILT_IN_STPCPY_CHK:
1234 case BUILT_IN_STPCPY_CHKP:
1235 case BUILT_IN_STPCPY_CHK_CHKP:
1236 if (lhs == NULL_TREE)
1237 return;
1238 else
1240 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1241 srclen = fold_convert_loc (loc, size_type_node, dst);
1242 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1243 lhsuint, srclen);
1245 break;
1246 default:
1247 gcc_unreachable ();
1250 if (didx == 0)
1252 didx = new_stridx (dst);
1253 if (didx == 0)
1254 return;
1256 if (olddsi != NULL)
1258 oldlen = olddsi->length;
1259 dsi = unshare_strinfo (olddsi);
1260 dsi->length = srclen;
1261 /* Break the chain, so adjust_related_strinfo on later pointers in
1262 the chain won't adjust this one anymore. */
1263 dsi->next = 0;
1264 dsi->stmt = NULL;
1265 dsi->endptr = NULL_TREE;
1267 else
1269 dsi = new_strinfo (dst, didx, srclen);
1270 set_strinfo (didx, dsi);
1271 find_equal_ptrs (dst, didx);
1273 dsi->writable = true;
1274 dsi->dont_invalidate = true;
1276 if (dsi->length == NULL_TREE)
1278 strinfo chainsi;
1280 /* If string length of src is unknown, use delayed length
1281 computation. If string lenth of dst will be needed, it
1282 can be computed by transforming this strcpy call into
1283 stpcpy and subtracting dst from the return value. */
1285 /* Look for earlier strings whose length could be determined if
1286 this strcpy is turned into an stpcpy. */
1288 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1290 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1292 /* When setting a stmt for delayed length computation
1293 prevent all strinfos through dsi from being
1294 invalidated. */
1295 chainsi = unshare_strinfo (chainsi);
1296 chainsi->stmt = stmt;
1297 chainsi->length = NULL_TREE;
1298 chainsi->endptr = NULL_TREE;
1299 chainsi->dont_invalidate = true;
1302 dsi->stmt = stmt;
1303 return;
1306 if (olddsi != NULL)
1308 tree adj = NULL_TREE;
1309 if (oldlen == NULL_TREE)
1311 else if (integer_zerop (oldlen))
1312 adj = srclen;
1313 else if (TREE_CODE (oldlen) == INTEGER_CST
1314 || TREE_CODE (srclen) == INTEGER_CST)
1315 adj = fold_build2_loc (loc, MINUS_EXPR,
1316 TREE_TYPE (srclen), srclen,
1317 fold_convert_loc (loc, TREE_TYPE (srclen),
1318 oldlen));
1319 if (adj != NULL_TREE)
1320 adjust_related_strinfos (loc, dsi, adj);
1321 else
1322 dsi->prev = 0;
1324 /* strcpy src may not overlap dst, so src doesn't need to be
1325 invalidated either. */
1326 if (si != NULL)
1327 si->dont_invalidate = true;
1329 fn = NULL_TREE;
1330 zsi = NULL;
1331 switch (bcode)
1333 case BUILT_IN_STRCPY:
1334 case BUILT_IN_STRCPY_CHKP:
1335 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1336 if (lhs)
1337 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1338 break;
1339 case BUILT_IN_STRCPY_CHK:
1340 case BUILT_IN_STRCPY_CHK_CHKP:
1341 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1342 if (lhs)
1343 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1344 break;
1345 case BUILT_IN_STPCPY:
1346 case BUILT_IN_STPCPY_CHKP:
1347 /* This would need adjustment of the lhs (subtract one),
1348 or detection that the trailing '\0' doesn't need to be
1349 written, if it will be immediately overwritten.
1350 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1351 if (lhs)
1353 dsi->endptr = lhs;
1354 zsi = zero_length_string (lhs, dsi);
1356 break;
1357 case BUILT_IN_STPCPY_CHK:
1358 case BUILT_IN_STPCPY_CHK_CHKP:
1359 /* This would need adjustment of the lhs (subtract one),
1360 or detection that the trailing '\0' doesn't need to be
1361 written, if it will be immediately overwritten.
1362 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1363 if (lhs)
1365 dsi->endptr = lhs;
1366 zsi = zero_length_string (lhs, dsi);
1368 break;
1369 default:
1370 gcc_unreachable ();
1372 if (zsi != NULL)
1373 zsi->dont_invalidate = true;
1375 if (fn == NULL_TREE)
1376 return;
1378 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1379 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1381 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1382 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1383 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1384 GSI_SAME_STMT);
1385 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1387 fprintf (dump_file, "Optimizing: ");
1388 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1390 if (with_bounds)
1392 fn = chkp_maybe_create_clone (fn)->decl;
1393 if (gimple_call_num_args (stmt) == 4)
1394 success = update_gimple_call (gsi, fn, 5, dst,
1395 gimple_call_arg (stmt, 1),
1396 src,
1397 gimple_call_arg (stmt, 3),
1398 len);
1399 else
1400 success = update_gimple_call (gsi, fn, 6, dst,
1401 gimple_call_arg (stmt, 1),
1402 src,
1403 gimple_call_arg (stmt, 3),
1404 len,
1405 gimple_call_arg (stmt, 4));
1407 else
1408 if (gimple_call_num_args (stmt) == 2)
1409 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1410 else
1411 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1412 gimple_call_arg (stmt, 2));
1413 if (success)
1415 stmt = gsi_stmt (*gsi);
1416 gimple_call_set_with_bounds (stmt, with_bounds);
1417 update_stmt (stmt);
1418 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1420 fprintf (dump_file, "into: ");
1421 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1423 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1424 laststmt.stmt = stmt;
1425 laststmt.len = srclen;
1426 laststmt.stridx = dsi->idx;
1428 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1429 fprintf (dump_file, "not possible.\n");
1432 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1433 If strlen of the second argument is known and length of the third argument
1434 is that plus one, strlen of the first argument is the same after this
1435 call. */
1437 static void
1438 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1440 int idx, didx;
1441 tree src, dst, len, lhs, oldlen, newlen;
1442 gimple stmt = gsi_stmt (*gsi);
1443 strinfo si, dsi, olddsi;
1444 bool with_bounds = gimple_call_with_bounds_p (stmt);
1446 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1447 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1448 dst = gimple_call_arg (stmt, 0);
1449 idx = get_stridx (src);
1450 if (idx == 0)
1451 return;
1453 didx = get_stridx (dst);
1454 olddsi = NULL;
1455 if (didx > 0)
1456 olddsi = get_strinfo (didx);
1457 else if (didx < 0)
1458 return;
1460 if (olddsi != NULL
1461 && tree_fits_uhwi_p (len)
1462 && !integer_zerop (len))
1463 adjust_last_stmt (olddsi, stmt, false);
1465 if (idx > 0)
1467 gimple def_stmt;
1469 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1470 si = get_strinfo (idx);
1471 if (si == NULL || si->length == NULL_TREE)
1472 return;
1473 if (TREE_CODE (len) != SSA_NAME)
1474 return;
1475 def_stmt = SSA_NAME_DEF_STMT (len);
1476 if (!is_gimple_assign (def_stmt)
1477 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1478 || gimple_assign_rhs1 (def_stmt) != si->length
1479 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1480 return;
1482 else
1484 si = NULL;
1485 /* Handle memcpy (x, "abcd", 5) or
1486 memcpy (x, "abc\0uvw", 7). */
1487 if (!tree_fits_uhwi_p (len)
1488 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1489 return;
1492 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1493 adjust_last_stmt (olddsi, stmt, false);
1495 if (didx == 0)
1497 didx = new_stridx (dst);
1498 if (didx == 0)
1499 return;
1501 if (si != NULL)
1502 newlen = si->length;
1503 else
1504 newlen = build_int_cst (size_type_node, ~idx);
1505 oldlen = NULL_TREE;
1506 if (olddsi != NULL)
1508 dsi = unshare_strinfo (olddsi);
1509 oldlen = olddsi->length;
1510 dsi->length = newlen;
1511 /* Break the chain, so adjust_related_strinfo on later pointers in
1512 the chain won't adjust this one anymore. */
1513 dsi->next = 0;
1514 dsi->stmt = NULL;
1515 dsi->endptr = NULL_TREE;
1517 else
1519 dsi = new_strinfo (dst, didx, newlen);
1520 set_strinfo (didx, dsi);
1521 find_equal_ptrs (dst, didx);
1523 dsi->writable = true;
1524 dsi->dont_invalidate = true;
1525 if (olddsi != NULL)
1527 tree adj = NULL_TREE;
1528 location_t loc = gimple_location (stmt);
1529 if (oldlen == NULL_TREE)
1531 else if (integer_zerop (oldlen))
1532 adj = dsi->length;
1533 else if (TREE_CODE (oldlen) == INTEGER_CST
1534 || TREE_CODE (dsi->length) == INTEGER_CST)
1535 adj = fold_build2_loc (loc, MINUS_EXPR,
1536 TREE_TYPE (dsi->length), dsi->length,
1537 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1538 oldlen));
1539 if (adj != NULL_TREE)
1540 adjust_related_strinfos (loc, dsi, adj);
1541 else
1542 dsi->prev = 0;
1544 /* memcpy src may not overlap dst, so src doesn't need to be
1545 invalidated either. */
1546 if (si != NULL)
1547 si->dont_invalidate = true;
1549 lhs = gimple_call_lhs (stmt);
1550 switch (bcode)
1552 case BUILT_IN_MEMCPY:
1553 case BUILT_IN_MEMCPY_CHK:
1554 case BUILT_IN_MEMCPY_CHKP:
1555 case BUILT_IN_MEMCPY_CHK_CHKP:
1556 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1557 laststmt.stmt = stmt;
1558 laststmt.len = dsi->length;
1559 laststmt.stridx = dsi->idx;
1560 if (lhs)
1561 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1562 break;
1563 case BUILT_IN_MEMPCPY:
1564 case BUILT_IN_MEMPCPY_CHK:
1565 case BUILT_IN_MEMPCPY_CHKP:
1566 case BUILT_IN_MEMPCPY_CHK_CHKP:
1567 break;
1568 default:
1569 gcc_unreachable ();
1573 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1574 If strlen of the second argument is known, strlen of the first argument
1575 is increased by the length of the second argument. Furthermore, attempt
1576 to convert it to memcpy/strcpy if the length of the first argument
1577 is known. */
1579 static void
1580 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1582 int idx, didx;
1583 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1584 bool success;
1585 gimple stmt = gsi_stmt (*gsi);
1586 strinfo si, dsi;
1587 location_t loc;
1588 bool with_bounds = gimple_call_with_bounds_p (stmt);
1590 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1591 dst = gimple_call_arg (stmt, 0);
1592 lhs = gimple_call_lhs (stmt);
1594 didx = get_stridx (dst);
1595 if (didx < 0)
1596 return;
1598 dsi = NULL;
1599 if (didx > 0)
1600 dsi = get_strinfo (didx);
1601 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1603 /* strcat (p, q) can be transformed into
1604 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1605 with length endptr - p if we need to compute the length
1606 later on. Don't do this transformation if we don't need
1607 it. */
1608 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1610 if (didx == 0)
1612 didx = new_stridx (dst);
1613 if (didx == 0)
1614 return;
1616 if (dsi == NULL)
1618 dsi = new_strinfo (dst, didx, NULL_TREE);
1619 set_strinfo (didx, dsi);
1620 find_equal_ptrs (dst, didx);
1622 else
1624 dsi = unshare_strinfo (dsi);
1625 dsi->length = NULL_TREE;
1626 dsi->next = 0;
1627 dsi->endptr = NULL_TREE;
1629 dsi->writable = true;
1630 dsi->stmt = stmt;
1631 dsi->dont_invalidate = true;
1633 return;
1636 srclen = NULL_TREE;
1637 si = NULL;
1638 idx = get_stridx (src);
1639 if (idx < 0)
1640 srclen = build_int_cst (size_type_node, ~idx);
1641 else if (idx > 0)
1643 si = get_strinfo (idx);
1644 if (si != NULL)
1645 srclen = get_string_length (si);
1648 loc = gimple_location (stmt);
1649 dstlen = dsi->length;
1650 endptr = dsi->endptr;
1652 dsi = unshare_strinfo (dsi);
1653 dsi->endptr = NULL_TREE;
1654 dsi->stmt = NULL;
1655 dsi->writable = true;
1657 if (srclen != NULL_TREE)
1659 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1660 dsi->length, srclen);
1661 adjust_related_strinfos (loc, dsi, srclen);
1662 dsi->dont_invalidate = true;
1664 else
1666 dsi->length = NULL;
1667 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1668 dsi->dont_invalidate = true;
1671 if (si != NULL)
1672 /* strcat src may not overlap dst, so src doesn't need to be
1673 invalidated either. */
1674 si->dont_invalidate = true;
1676 /* For now. Could remove the lhs from the call and add
1677 lhs = dst; afterwards. */
1678 if (lhs)
1679 return;
1681 fn = NULL_TREE;
1682 objsz = NULL_TREE;
1683 switch (bcode)
1685 case BUILT_IN_STRCAT:
1686 case BUILT_IN_STRCAT_CHKP:
1687 if (srclen != NULL_TREE)
1688 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1689 else
1690 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1691 break;
1692 case BUILT_IN_STRCAT_CHK:
1693 case BUILT_IN_STRCAT_CHK_CHKP:
1694 if (srclen != NULL_TREE)
1695 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1696 else
1697 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1698 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1699 break;
1700 default:
1701 gcc_unreachable ();
1704 if (fn == NULL_TREE)
1705 return;
1707 len = NULL_TREE;
1708 if (srclen != NULL_TREE)
1710 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1711 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1713 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1714 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1715 build_int_cst (type, 1));
1716 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1717 GSI_SAME_STMT);
1719 if (endptr)
1720 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1721 else
1722 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1723 TREE_TYPE (dst), unshare_expr (dst),
1724 fold_convert_loc (loc, sizetype,
1725 unshare_expr (dstlen)));
1726 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1727 GSI_SAME_STMT);
1728 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1730 fprintf (dump_file, "Optimizing: ");
1731 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1733 if (with_bounds)
1735 fn = chkp_maybe_create_clone (fn)->decl;
1736 if (srclen != NULL_TREE)
1737 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1738 dst,
1739 gimple_call_arg (stmt, 1),
1740 src,
1741 gimple_call_arg (stmt, 3),
1742 len, objsz);
1743 else
1744 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1745 dst,
1746 gimple_call_arg (stmt, 1),
1747 src,
1748 gimple_call_arg (stmt, 3),
1749 objsz);
1751 else
1752 if (srclen != NULL_TREE)
1753 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1754 dst, src, len, objsz);
1755 else
1756 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1757 dst, src, objsz);
1758 if (success)
1760 stmt = gsi_stmt (*gsi);
1761 gimple_call_set_with_bounds (stmt, with_bounds);
1762 update_stmt (stmt);
1763 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1765 fprintf (dump_file, "into: ");
1766 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1768 /* If srclen == NULL, note that current string length can be
1769 computed by transforming this strcpy into stpcpy. */
1770 if (srclen == NULL_TREE && dsi->dont_invalidate)
1771 dsi->stmt = stmt;
1772 adjust_last_stmt (dsi, stmt, true);
1773 if (srclen != NULL_TREE)
1775 laststmt.stmt = stmt;
1776 laststmt.len = srclen;
1777 laststmt.stridx = dsi->idx;
1780 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1781 fprintf (dump_file, "not possible.\n");
1784 /* Handle a call to malloc or calloc. */
1786 static void
1787 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1789 gimple stmt = gsi_stmt (*gsi);
1790 tree lhs = gimple_call_lhs (stmt);
1791 gcc_assert (get_stridx (lhs) == 0);
1792 int idx = new_stridx (lhs);
1793 tree length = NULL_TREE;
1794 if (bcode == BUILT_IN_CALLOC)
1795 length = build_int_cst (size_type_node, 0);
1796 strinfo si = new_strinfo (lhs, idx, length);
1797 if (bcode == BUILT_IN_CALLOC)
1798 si->endptr = lhs;
1799 set_strinfo (idx, si);
1800 si->writable = true;
1801 si->stmt = stmt;
1802 si->dont_invalidate = true;
1805 /* Handle a call to memset.
1806 After a call to calloc, memset(,0,) is unnecessary.
1807 memset(malloc(n),0,n) is calloc(n,1). */
1809 static bool
1810 handle_builtin_memset (gimple_stmt_iterator *gsi)
1812 gimple stmt2 = gsi_stmt (*gsi);
1813 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1814 return true;
1815 tree ptr = gimple_call_arg (stmt2, 0);
1816 int idx1 = get_stridx (ptr);
1817 if (idx1 <= 0)
1818 return true;
1819 strinfo si1 = get_strinfo (idx1);
1820 if (!si1)
1821 return true;
1822 gimple stmt1 = si1->stmt;
1823 if (!stmt1 || !is_gimple_call (stmt1))
1824 return true;
1825 tree callee1 = gimple_call_fndecl (stmt1);
1826 if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL))
1827 return true;
1828 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1829 tree size = gimple_call_arg (stmt2, 2);
1830 if (code1 == BUILT_IN_CALLOC)
1831 /* Not touching stmt1 */ ;
1832 else if (code1 == BUILT_IN_MALLOC
1833 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1835 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1836 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1837 size, build_one_cst (size_type_node));
1838 si1->length = build_int_cst (size_type_node, 0);
1839 si1->stmt = gsi_stmt (gsi1);
1841 else
1842 return true;
1843 tree lhs = gimple_call_lhs (stmt2);
1844 unlink_stmt_vdef (stmt2);
1845 if (lhs)
1847 gimple assign = gimple_build_assign (lhs, ptr);
1848 gsi_replace (gsi, assign, false);
1850 else
1852 gsi_remove (gsi, true);
1853 release_defs (stmt2);
1856 return false;
1859 /* Handle a POINTER_PLUS_EXPR statement.
1860 For p = "abcd" + 2; compute associated length, or if
1861 p = q + off is pointing to a '\0' character of a string, call
1862 zero_length_string on it. */
1864 static void
1865 handle_pointer_plus (gimple_stmt_iterator *gsi)
1867 gimple stmt = gsi_stmt (*gsi);
1868 tree lhs = gimple_assign_lhs (stmt), off;
1869 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1870 strinfo si, zsi;
1872 if (idx == 0)
1873 return;
1875 if (idx < 0)
1877 tree off = gimple_assign_rhs2 (stmt);
1878 if (tree_fits_uhwi_p (off)
1879 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1880 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1881 = ~(~idx - (int) tree_to_uhwi (off));
1882 return;
1885 si = get_strinfo (idx);
1886 if (si == NULL || si->length == NULL_TREE)
1887 return;
1889 off = gimple_assign_rhs2 (stmt);
1890 zsi = NULL;
1891 if (operand_equal_p (si->length, off, 0))
1892 zsi = zero_length_string (lhs, si);
1893 else if (TREE_CODE (off) == SSA_NAME)
1895 gimple def_stmt = SSA_NAME_DEF_STMT (off);
1896 if (gimple_assign_single_p (def_stmt)
1897 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1898 zsi = zero_length_string (lhs, si);
1900 if (zsi != NULL
1901 && si->endptr != NULL_TREE
1902 && si->endptr != lhs
1903 && TREE_CODE (si->endptr) == SSA_NAME)
1905 enum tree_code rhs_code
1906 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1907 ? SSA_NAME : NOP_EXPR;
1908 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
1909 gcc_assert (gsi_stmt (*gsi) == stmt);
1910 update_stmt (stmt);
1914 /* Handle a single character store. */
1916 static bool
1917 handle_char_store (gimple_stmt_iterator *gsi)
1919 int idx = -1;
1920 strinfo si = NULL;
1921 gimple stmt = gsi_stmt (*gsi);
1922 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1924 if (TREE_CODE (lhs) == MEM_REF
1925 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1927 if (integer_zerop (TREE_OPERAND (lhs, 1)))
1929 ssaname = TREE_OPERAND (lhs, 0);
1930 idx = get_stridx (ssaname);
1933 else
1934 idx = get_addr_stridx (lhs);
1936 if (idx > 0)
1938 si = get_strinfo (idx);
1939 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
1941 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
1943 /* When storing '\0', the store can be removed
1944 if we know it has been stored in the current function. */
1945 if (!stmt_could_throw_p (stmt) && si->writable)
1947 unlink_stmt_vdef (stmt);
1948 release_defs (stmt);
1949 gsi_remove (gsi, true);
1950 return false;
1952 else
1954 si->writable = true;
1955 gsi_next (gsi);
1956 return false;
1959 else
1960 /* Otherwise this statement overwrites the '\0' with
1961 something, if the previous stmt was a memcpy,
1962 its length may be decreased. */
1963 adjust_last_stmt (si, stmt, false);
1965 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
1967 si = unshare_strinfo (si);
1968 si->length = build_int_cst (size_type_node, 0);
1969 si->endptr = NULL;
1970 si->prev = 0;
1971 si->next = 0;
1972 si->stmt = NULL;
1973 si->first = 0;
1974 si->writable = true;
1975 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
1976 si->endptr = ssaname;
1977 si->dont_invalidate = true;
1979 /* If si->length is non-zero constant, we aren't overwriting '\0',
1980 and if we aren't storing '\0', we know that the length of the
1981 string and any other zero terminated string in memory remains
1982 the same. In that case we move to the next gimple statement and
1983 return to signal the caller that it shouldn't invalidate anything.
1985 This is benefical for cases like:
1987 char p[20];
1988 void foo (char *q)
1990 strcpy (p, "foobar");
1991 size_t len = strlen (p); // This can be optimized into 6
1992 size_t len2 = strlen (q); // This has to be computed
1993 p[0] = 'X';
1994 size_t len3 = strlen (p); // This can be optimized into 6
1995 size_t len4 = strlen (q); // This can be optimized into len2
1996 bar (len, len2, len3, len4);
1999 else if (si != NULL && si->length != NULL_TREE
2000 && TREE_CODE (si->length) == INTEGER_CST
2001 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2003 gsi_next (gsi);
2004 return false;
2007 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2009 if (ssaname)
2011 si = zero_length_string (ssaname, NULL);
2012 if (si != NULL)
2013 si->dont_invalidate = true;
2015 else
2017 int idx = new_addr_stridx (lhs);
2018 if (idx != 0)
2020 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2021 build_int_cst (size_type_node, 0));
2022 set_strinfo (idx, si);
2023 si->dont_invalidate = true;
2026 if (si != NULL)
2027 si->writable = true;
2029 else if (idx == 0
2030 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2031 && ssaname == NULL_TREE
2032 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2034 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2035 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2036 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2038 int idx = new_addr_stridx (lhs);
2039 if (idx != 0)
2041 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2042 build_int_cst (size_type_node, l));
2043 set_strinfo (idx, si);
2044 si->dont_invalidate = true;
2049 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2051 /* Allow adjust_last_stmt to remove it if the stored '\0'
2052 is immediately overwritten. */
2053 laststmt.stmt = stmt;
2054 laststmt.len = build_int_cst (size_type_node, 1);
2055 laststmt.stridx = si->idx;
2057 return true;
2060 /* Attempt to optimize a single statement at *GSI using string length
2061 knowledge. */
2063 static bool
2064 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2066 gimple stmt = gsi_stmt (*gsi);
2068 if (is_gimple_call (stmt))
2070 tree callee = gimple_call_fndecl (stmt);
2071 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
2072 switch (DECL_FUNCTION_CODE (callee))
2074 case BUILT_IN_STRLEN:
2075 case BUILT_IN_STRLEN_CHKP:
2076 handle_builtin_strlen (gsi);
2077 break;
2078 case BUILT_IN_STRCHR:
2079 case BUILT_IN_STRCHR_CHKP:
2080 handle_builtin_strchr (gsi);
2081 break;
2082 case BUILT_IN_STRCPY:
2083 case BUILT_IN_STRCPY_CHK:
2084 case BUILT_IN_STPCPY:
2085 case BUILT_IN_STPCPY_CHK:
2086 case BUILT_IN_STRCPY_CHKP:
2087 case BUILT_IN_STRCPY_CHK_CHKP:
2088 case BUILT_IN_STPCPY_CHKP:
2089 case BUILT_IN_STPCPY_CHK_CHKP:
2090 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2091 break;
2092 case BUILT_IN_MEMCPY:
2093 case BUILT_IN_MEMCPY_CHK:
2094 case BUILT_IN_MEMPCPY:
2095 case BUILT_IN_MEMPCPY_CHK:
2096 case BUILT_IN_MEMCPY_CHKP:
2097 case BUILT_IN_MEMCPY_CHK_CHKP:
2098 case BUILT_IN_MEMPCPY_CHKP:
2099 case BUILT_IN_MEMPCPY_CHK_CHKP:
2100 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2101 break;
2102 case BUILT_IN_STRCAT:
2103 case BUILT_IN_STRCAT_CHK:
2104 case BUILT_IN_STRCAT_CHKP:
2105 case BUILT_IN_STRCAT_CHK_CHKP:
2106 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2107 break;
2108 case BUILT_IN_MALLOC:
2109 case BUILT_IN_CALLOC:
2110 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2111 break;
2112 case BUILT_IN_MEMSET:
2113 if (!handle_builtin_memset (gsi))
2114 return false;
2115 break;
2116 default:
2117 break;
2120 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2122 tree lhs = gimple_assign_lhs (stmt);
2124 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2126 if (gimple_assign_single_p (stmt)
2127 || (gimple_assign_cast_p (stmt)
2128 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2130 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2131 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2133 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2134 handle_pointer_plus (gsi);
2136 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2138 tree type = TREE_TYPE (lhs);
2139 if (TREE_CODE (type) == ARRAY_TYPE)
2140 type = TREE_TYPE (type);
2141 if (TREE_CODE (type) == INTEGER_TYPE
2142 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2143 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2145 if (! handle_char_store (gsi))
2146 return false;
2151 if (gimple_vdef (stmt))
2152 maybe_invalidate (stmt);
2153 return true;
2156 /* Recursively call maybe_invalidate on stmts that might be executed
2157 in between dombb and current bb and that contain a vdef. Stop when
2158 *count stmts are inspected, or if the whole strinfo vector has
2159 been invalidated. */
2161 static void
2162 do_invalidate (basic_block dombb, gimple phi, bitmap visited, int *count)
2164 unsigned int i, n = gimple_phi_num_args (phi);
2166 for (i = 0; i < n; i++)
2168 tree vuse = gimple_phi_arg_def (phi, i);
2169 gimple stmt = SSA_NAME_DEF_STMT (vuse);
2170 basic_block bb = gimple_bb (stmt);
2171 if (bb == NULL
2172 || bb == dombb
2173 || !bitmap_set_bit (visited, bb->index)
2174 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2175 continue;
2176 while (1)
2178 if (gimple_code (stmt) == GIMPLE_PHI)
2180 do_invalidate (dombb, stmt, visited, count);
2181 if (*count == 0)
2182 return;
2183 break;
2185 if (--*count == 0)
2186 return;
2187 if (!maybe_invalidate (stmt))
2189 *count = 0;
2190 return;
2192 vuse = gimple_vuse (stmt);
2193 stmt = SSA_NAME_DEF_STMT (vuse);
2194 if (gimple_bb (stmt) != bb)
2196 bb = gimple_bb (stmt);
2197 if (bb == NULL
2198 || bb == dombb
2199 || !bitmap_set_bit (visited, bb->index)
2200 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2201 break;
2207 class strlen_dom_walker : public dom_walker
2209 public:
2210 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2212 virtual void before_dom_children (basic_block);
2213 virtual void after_dom_children (basic_block);
2216 /* Callback for walk_dominator_tree. Attempt to optimize various
2217 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2219 void
2220 strlen_dom_walker::before_dom_children (basic_block bb)
2222 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2224 if (dombb == NULL)
2225 stridx_to_strinfo = NULL;
2226 else
2228 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) dombb->aux);
2229 if (stridx_to_strinfo)
2231 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2232 gsi_next (&gsi))
2234 gphi *phi = gsi.phi ();
2235 if (virtual_operand_p (gimple_phi_result (phi)))
2237 bitmap visited = BITMAP_ALLOC (NULL);
2238 int count_vdef = 100;
2239 do_invalidate (dombb, phi, visited, &count_vdef);
2240 BITMAP_FREE (visited);
2241 if (count_vdef == 0)
2243 /* If there were too many vdefs in between immediate
2244 dominator and current bb, invalidate everything.
2245 If stridx_to_strinfo has been unshared, we need
2246 to free it, otherwise just set it to NULL. */
2247 if (!strinfo_shared ())
2249 unsigned int i;
2250 strinfo si;
2252 for (i = 1;
2253 vec_safe_iterate (stridx_to_strinfo, i, &si);
2254 ++i)
2256 free_strinfo (si);
2257 (*stridx_to_strinfo)[i] = NULL;
2260 else
2261 stridx_to_strinfo = NULL;
2263 break;
2269 /* If all PHI arguments have the same string index, the PHI result
2270 has it as well. */
2271 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2272 gsi_next (&gsi))
2274 gphi *phi = gsi.phi ();
2275 tree result = gimple_phi_result (phi);
2276 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2278 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2279 if (idx != 0)
2281 unsigned int i, n = gimple_phi_num_args (phi);
2282 for (i = 1; i < n; i++)
2283 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2284 break;
2285 if (i == n)
2286 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2291 /* Attempt to optimize individual statements. */
2292 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2293 if (strlen_optimize_stmt (&gsi))
2294 gsi_next (&gsi);
2296 bb->aux = stridx_to_strinfo;
2297 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2298 (*stridx_to_strinfo)[0] = (strinfo) bb;
2301 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2302 owned by the current bb, clear bb->aux. */
2304 void
2305 strlen_dom_walker::after_dom_children (basic_block bb)
2307 if (bb->aux)
2309 stridx_to_strinfo = ((vec<strinfo, va_heap, vl_embed> *) bb->aux);
2310 if (vec_safe_length (stridx_to_strinfo)
2311 && (*stridx_to_strinfo)[0] == (strinfo) bb)
2313 unsigned int i;
2314 strinfo si;
2316 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2317 free_strinfo (si);
2318 vec_free (stridx_to_strinfo);
2320 bb->aux = NULL;
2324 /* Main entry point. */
2326 namespace {
2328 const pass_data pass_data_strlen =
2330 GIMPLE_PASS, /* type */
2331 "strlen", /* name */
2332 OPTGROUP_NONE, /* optinfo_flags */
2333 TV_TREE_STRLEN, /* tv_id */
2334 ( PROP_cfg | PROP_ssa ), /* properties_required */
2335 0, /* properties_provided */
2336 0, /* properties_destroyed */
2337 0, /* todo_flags_start */
2338 0, /* todo_flags_finish */
2341 class pass_strlen : public gimple_opt_pass
2343 public:
2344 pass_strlen (gcc::context *ctxt)
2345 : gimple_opt_pass (pass_data_strlen, ctxt)
2348 /* opt_pass methods: */
2349 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2350 virtual unsigned int execute (function *);
2352 }; // class pass_strlen
2354 unsigned int
2355 pass_strlen::execute (function *fun)
2357 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2358 max_stridx = 1;
2360 calculate_dominance_info (CDI_DOMINATORS);
2362 /* String length optimization is implemented as a walk of the dominator
2363 tree and a forward walk of statements within each block. */
2364 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2366 ssa_ver_to_stridx.release ();
2367 strinfo_pool.release ();
2368 if (decl_to_stridxlist_htab)
2370 obstack_free (&stridx_obstack, NULL);
2371 delete decl_to_stridxlist_htab;
2372 decl_to_stridxlist_htab = NULL;
2374 laststmt.stmt = NULL;
2375 laststmt.len = NULL_TREE;
2376 laststmt.stridx = 0;
2378 return 0;
2381 } // anon namespace
2383 gimple_opt_pass *
2384 make_pass_strlen (gcc::context *ctxt)
2386 return new pass_strlen (ctxt);