2016-06-16 Ed Schonberg <schonberg@adacore.com>
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob700d6ce2bdbf24698b774b2df4a046019c87ea07
1 /* String length optimization
2 Copyright (C) 2011-2016 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "rtl.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "alloc-pool.h"
29 #include "tree-pass.h"
30 #include "ssa.h"
31 #include "cgraph.h"
32 #include "gimple-pretty-print.h"
33 #include "fold-const.h"
34 #include "stor-layout.h"
35 #include "gimple-fold.h"
36 #include "tree-eh.h"
37 #include "gimplify.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
40 #include "expr.h"
41 #include "tree-dfa.h"
42 #include "domwalk.h"
43 #include "tree-ssa-propagate.h"
44 #include "params.h"
45 #include "ipa-chkp.h"
46 #include "tree-hash-traits.h"
47 #include "builtins.h"
49 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
50 is an index into strinfo vector, negative value stands for
51 string length of a string literal (~strlen). */
52 static vec<int> ssa_ver_to_stridx;
54 /* Number of currently active string indexes plus one. */
55 static int max_stridx;
57 /* String information record. */
58 struct strinfo
60 /* String length of this string. */
61 tree length;
62 /* Any of the corresponding pointers for querying alias oracle. */
63 tree ptr;
64 /* Statement for delayed length computation. */
65 gimple *stmt;
66 /* Pointer to '\0' if known, if NULL, it can be computed as
67 ptr + length. */
68 tree endptr;
69 /* Reference count. Any changes to strinfo entry possibly shared
70 with dominating basic blocks need unshare_strinfo first, except
71 for dont_invalidate which affects only the immediately next
72 maybe_invalidate. */
73 int refcount;
74 /* Copy of index. get_strinfo (si->idx) should return si; */
75 int idx;
76 /* These 3 fields are for chaining related string pointers together.
77 E.g. for
78 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
79 strcpy (c, d); e = c + dl;
80 strinfo(a) -> strinfo(c) -> strinfo(e)
81 All have ->first field equal to strinfo(a)->idx and are doubly
82 chained through prev/next fields. The later strinfos are required
83 to point into the same string with zero or more bytes after
84 the previous pointer and all bytes in between the two pointers
85 must be non-zero. Functions like strcpy or memcpy are supposed
86 to adjust all previous strinfo lengths, but not following strinfo
87 lengths (those are uncertain, usually invalidated during
88 maybe_invalidate, except when the alias oracle knows better).
89 Functions like strcat on the other side adjust the whole
90 related strinfo chain.
91 They are updated lazily, so to use the chain the same first fields
92 and si->prev->next == si->idx needs to be verified. */
93 int first;
94 int next;
95 int prev;
96 /* A flag whether the string is known to be written in the current
97 function. */
98 bool writable;
99 /* A flag for the next maybe_invalidate that this strinfo shouldn't
100 be invalidated. Always cleared by maybe_invalidate. */
101 bool dont_invalidate;
104 /* Pool for allocating strinfo_struct entries. */
105 static object_allocator<strinfo> strinfo_pool ("strinfo pool");
107 /* Vector mapping positive string indexes to strinfo, for the
108 current basic block. The first pointer in the vector is special,
109 it is either NULL, meaning the vector isn't shared, or it is
110 a basic block pointer to the owner basic_block if shared.
111 If some other bb wants to modify the vector, the vector needs
112 to be unshared first, and only the owner bb is supposed to free it. */
113 static vec<strinfo *, va_heap, vl_embed> *stridx_to_strinfo;
115 /* One OFFSET->IDX mapping. */
116 struct stridxlist
118 struct stridxlist *next;
119 HOST_WIDE_INT offset;
120 int idx;
123 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
124 struct decl_stridxlist_map
126 struct tree_map_base base;
127 struct stridxlist list;
130 /* Hash table for mapping decls to a chained list of offset -> idx
131 mappings. */
132 static hash_map<tree_decl_hash, stridxlist> *decl_to_stridxlist_htab;
134 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
135 static struct obstack stridx_obstack;
137 /* Last memcpy statement if it could be adjusted if the trailing
138 '\0' written is immediately overwritten, or
139 *x = '\0' store that could be removed if it is immediately overwritten. */
140 struct laststmt_struct
142 gimple *stmt;
143 tree len;
144 int stridx;
145 } laststmt;
147 static int get_stridx_plus_constant (strinfo *, HOST_WIDE_INT, tree);
149 /* Return strinfo vector entry IDX. */
151 static inline strinfo *
152 get_strinfo (int idx)
154 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
155 return NULL;
156 return (*stridx_to_strinfo)[idx];
159 /* Helper function for get_stridx. */
161 static int
162 get_addr_stridx (tree exp)
164 HOST_WIDE_INT off;
165 struct stridxlist *list;
166 tree base;
168 if (!decl_to_stridxlist_htab)
169 return 0;
171 base = get_addr_base_and_unit_offset (exp, &off);
172 if (base == NULL || !DECL_P (base))
173 return 0;
175 list = decl_to_stridxlist_htab->get (base);
176 if (list == NULL)
177 return 0;
181 if (list->offset == off)
182 return list->idx;
183 list = list->next;
185 while (list);
186 return 0;
189 /* Return string index for EXP. */
191 static int
192 get_stridx (tree exp)
194 tree s, o;
196 if (TREE_CODE (exp) == SSA_NAME)
198 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
199 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
200 int i;
201 tree e = exp;
202 HOST_WIDE_INT off = 0;
203 for (i = 0; i < 5; i++)
205 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
206 if (!is_gimple_assign (def_stmt)
207 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
208 return 0;
209 tree rhs1 = gimple_assign_rhs1 (def_stmt);
210 tree rhs2 = gimple_assign_rhs2 (def_stmt);
211 if (TREE_CODE (rhs1) != SSA_NAME
212 || !tree_fits_shwi_p (rhs2))
213 return 0;
214 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
215 if (this_off < 0)
216 return 0;
217 off = (unsigned HOST_WIDE_INT) off + this_off;
218 if (off < 0)
219 return 0;
220 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
222 strinfo *si
223 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
224 if (si
225 && si->length
226 && TREE_CODE (si->length) == INTEGER_CST
227 && compare_tree_int (si->length, off) != -1)
228 return get_stridx_plus_constant (si, off, exp);
230 e = rhs1;
232 return 0;
235 if (TREE_CODE (exp) == ADDR_EXPR)
237 int idx = get_addr_stridx (TREE_OPERAND (exp, 0));
238 if (idx != 0)
239 return idx;
242 s = string_constant (exp, &o);
243 if (s != NULL_TREE
244 && (o == NULL_TREE || tree_fits_shwi_p (o))
245 && TREE_STRING_LENGTH (s) > 0)
247 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
248 const char *p = TREE_STRING_POINTER (s);
249 int max = TREE_STRING_LENGTH (s) - 1;
251 if (p[max] == '\0' && offset >= 0 && offset <= max)
252 return ~(int) strlen (p + offset);
254 return 0;
257 /* Return true if strinfo vector is shared with the immediate dominator. */
259 static inline bool
260 strinfo_shared (void)
262 return vec_safe_length (stridx_to_strinfo)
263 && (*stridx_to_strinfo)[0] != NULL;
266 /* Unshare strinfo vector that is shared with the immediate dominator. */
268 static void
269 unshare_strinfo_vec (void)
271 strinfo *si;
272 unsigned int i = 0;
274 gcc_assert (strinfo_shared ());
275 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
276 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
277 if (si != NULL)
278 si->refcount++;
279 (*stridx_to_strinfo)[0] = NULL;
282 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
283 Return a pointer to the location where the string index can
284 be stored (if 0) or is stored, or NULL if this can't be tracked. */
286 static int *
287 addr_stridxptr (tree exp)
289 HOST_WIDE_INT off;
291 tree base = get_addr_base_and_unit_offset (exp, &off);
292 if (base == NULL_TREE || !DECL_P (base))
293 return NULL;
295 if (!decl_to_stridxlist_htab)
297 decl_to_stridxlist_htab
298 = new hash_map<tree_decl_hash, stridxlist> (64);
299 gcc_obstack_init (&stridx_obstack);
302 bool existed;
303 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
304 if (existed)
306 int i;
307 for (i = 0; i < 16; i++)
309 if (list->offset == off)
310 return &list->idx;
311 if (list->next == NULL)
312 break;
314 if (i == 16)
315 return NULL;
316 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
317 list = list->next;
320 list->next = NULL;
321 list->offset = off;
322 list->idx = 0;
323 return &list->idx;
326 /* Create a new string index, or return 0 if reached limit. */
328 static int
329 new_stridx (tree exp)
331 int idx;
332 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
333 return 0;
334 if (TREE_CODE (exp) == SSA_NAME)
336 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
337 return 0;
338 idx = max_stridx++;
339 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
340 return idx;
342 if (TREE_CODE (exp) == ADDR_EXPR)
344 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
345 if (pidx != NULL)
347 gcc_assert (*pidx == 0);
348 *pidx = max_stridx++;
349 return *pidx;
352 return 0;
355 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
357 static int
358 new_addr_stridx (tree exp)
360 int *pidx;
361 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
362 return 0;
363 pidx = addr_stridxptr (exp);
364 if (pidx != NULL)
366 gcc_assert (*pidx == 0);
367 *pidx = max_stridx++;
368 return *pidx;
370 return 0;
373 /* Create a new strinfo. */
375 static strinfo *
376 new_strinfo (tree ptr, int idx, tree length)
378 strinfo *si = strinfo_pool.allocate ();
379 si->length = length;
380 si->ptr = ptr;
381 si->stmt = NULL;
382 si->endptr = NULL_TREE;
383 si->refcount = 1;
384 si->idx = idx;
385 si->first = 0;
386 si->prev = 0;
387 si->next = 0;
388 si->writable = false;
389 si->dont_invalidate = false;
390 return si;
393 /* Decrease strinfo refcount and free it if not referenced anymore. */
395 static inline void
396 free_strinfo (strinfo *si)
398 if (si && --si->refcount == 0)
399 strinfo_pool.remove (si);
402 /* Set strinfo in the vector entry IDX to SI. */
404 static inline void
405 set_strinfo (int idx, strinfo *si)
407 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
408 unshare_strinfo_vec ();
409 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
410 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
411 (*stridx_to_strinfo)[idx] = si;
414 /* Return string length, or NULL if it can't be computed. */
416 static tree
417 get_string_length (strinfo *si)
419 if (si->length)
420 return si->length;
422 if (si->stmt)
424 gimple *stmt = si->stmt, *lenstmt;
425 bool with_bounds = gimple_call_with_bounds_p (stmt);
426 tree callee, lhs, fn, tem;
427 location_t loc;
428 gimple_stmt_iterator gsi;
430 gcc_assert (is_gimple_call (stmt));
431 callee = gimple_call_fndecl (stmt);
432 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
433 lhs = gimple_call_lhs (stmt);
434 /* unshare_strinfo is intentionally not called here. The (delayed)
435 transformation of strcpy or strcat into stpcpy is done at the place
436 of the former strcpy/strcat call and so can affect all the strinfos
437 with the same stmt. If they were unshared before and transformation
438 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
439 just compute the right length. */
440 switch (DECL_FUNCTION_CODE (callee))
442 case BUILT_IN_STRCAT:
443 case BUILT_IN_STRCAT_CHK:
444 case BUILT_IN_STRCAT_CHKP:
445 case BUILT_IN_STRCAT_CHK_CHKP:
446 gsi = gsi_for_stmt (stmt);
447 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
448 gcc_assert (lhs == NULL_TREE);
449 tem = unshare_expr (gimple_call_arg (stmt, 0));
450 if (with_bounds)
452 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
453 2, tem, gimple_call_arg (stmt, 1));
454 gimple_call_set_with_bounds (lenstmt, true);
456 else
457 lenstmt = gimple_build_call (fn, 1, tem);
458 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
459 gimple_call_set_lhs (lenstmt, lhs);
460 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
461 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
462 tem = gimple_call_arg (stmt, 0);
463 if (!ptrofftype_p (TREE_TYPE (lhs)))
465 lhs = convert_to_ptrofftype (lhs);
466 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
467 true, GSI_SAME_STMT);
469 lenstmt = gimple_build_assign
470 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
471 POINTER_PLUS_EXPR,tem, lhs);
472 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
473 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
474 lhs = NULL_TREE;
475 /* FALLTHRU */
476 case BUILT_IN_STRCPY:
477 case BUILT_IN_STRCPY_CHK:
478 case BUILT_IN_STRCPY_CHKP:
479 case BUILT_IN_STRCPY_CHK_CHKP:
480 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
481 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
482 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
483 else
484 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
485 if (with_bounds)
486 fn = chkp_maybe_create_clone (fn)->decl;
487 gcc_assert (lhs == NULL_TREE);
488 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
490 fprintf (dump_file, "Optimizing: ");
491 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
493 gimple_call_set_fndecl (stmt, fn);
494 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
495 gimple_call_set_lhs (stmt, lhs);
496 update_stmt (stmt);
497 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
499 fprintf (dump_file, "into: ");
500 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
502 /* FALLTHRU */
503 case BUILT_IN_STPCPY:
504 case BUILT_IN_STPCPY_CHK:
505 case BUILT_IN_STPCPY_CHKP:
506 case BUILT_IN_STPCPY_CHK_CHKP:
507 gcc_assert (lhs != NULL_TREE);
508 loc = gimple_location (stmt);
509 si->endptr = lhs;
510 si->stmt = NULL;
511 lhs = fold_convert_loc (loc, size_type_node, lhs);
512 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
513 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
514 lhs, si->length);
515 break;
516 case BUILT_IN_MALLOC:
517 break;
518 /* BUILT_IN_CALLOC always has si->length set. */
519 default:
520 gcc_unreachable ();
521 break;
525 return si->length;
528 /* Invalidate string length information for strings whose length
529 might change due to stores in stmt. */
531 static bool
532 maybe_invalidate (gimple *stmt)
534 strinfo *si;
535 unsigned int i;
536 bool nonempty = false;
538 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
539 if (si != NULL)
541 if (!si->dont_invalidate)
543 ao_ref r;
544 /* Do not use si->length. */
545 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
546 if (stmt_may_clobber_ref_p_1 (stmt, &r))
548 set_strinfo (i, NULL);
549 free_strinfo (si);
550 continue;
553 si->dont_invalidate = false;
554 nonempty = true;
556 return nonempty;
559 /* Unshare strinfo record SI, if it has refcount > 1 or
560 if stridx_to_strinfo vector is shared with some other
561 bbs. */
563 static strinfo *
564 unshare_strinfo (strinfo *si)
566 strinfo *nsi;
568 if (si->refcount == 1 && !strinfo_shared ())
569 return si;
571 nsi = new_strinfo (si->ptr, si->idx, si->length);
572 nsi->stmt = si->stmt;
573 nsi->endptr = si->endptr;
574 nsi->first = si->first;
575 nsi->prev = si->prev;
576 nsi->next = si->next;
577 nsi->writable = si->writable;
578 set_strinfo (si->idx, nsi);
579 free_strinfo (si);
580 return nsi;
583 /* Return first strinfo in the related strinfo chain
584 if all strinfos in between belong to the chain, otherwise
585 NULL. */
587 static strinfo *
588 verify_related_strinfos (strinfo *origsi)
590 strinfo *si = origsi, *psi;
592 if (origsi->first == 0)
593 return NULL;
594 for (; si->prev; si = psi)
596 if (si->first != origsi->first)
597 return NULL;
598 psi = get_strinfo (si->prev);
599 if (psi == NULL)
600 return NULL;
601 if (psi->next != si->idx)
602 return NULL;
604 if (si->idx != si->first)
605 return NULL;
606 return si;
609 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
610 strinfo if there is any. Return it's idx, or 0 if no strinfo has
611 been created. */
613 static int
614 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
616 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
618 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
619 return 0;
621 if (basesi->length == NULL_TREE
622 || TREE_CODE (basesi->length) != INTEGER_CST
623 || compare_tree_int (basesi->length, off) == -1
624 || !tree_fits_shwi_p (basesi->length))
625 return 0;
627 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
628 strinfo *si = basesi, *chainsi;
629 if (si->first || si->prev || si->next)
630 si = verify_related_strinfos (basesi);
631 if (si == NULL
632 || si->length == NULL_TREE
633 || TREE_CODE (si->length) != INTEGER_CST)
634 return 0;
636 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
637 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
639 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
640 for (chainsi = si; chainsi->next; chainsi = si)
642 si = get_strinfo (chainsi->next);
643 if (si == NULL
644 || si->first != chainsi->first
645 || si->prev != chainsi->idx
646 || si->length == NULL_TREE
647 || TREE_CODE (si->length) != INTEGER_CST)
648 break;
649 int r = compare_tree_int (si->length, len);
650 if (r != 1)
652 if (r == 0)
654 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
655 return si->idx;
657 break;
661 int idx = new_stridx (ptr);
662 if (idx == 0)
663 return 0;
664 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
665 set_strinfo (idx, si);
666 if (chainsi->next)
668 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
669 si->next = nextsi->idx;
670 nextsi->prev = idx;
672 chainsi = unshare_strinfo (chainsi);
673 if (chainsi->first == 0)
674 chainsi->first = chainsi->idx;
675 chainsi->next = idx;
676 if (chainsi->endptr == NULL_TREE && len == 0)
677 chainsi->endptr = ptr;
678 si->endptr = chainsi->endptr;
679 si->prev = chainsi->idx;
680 si->first = chainsi->first;
681 si->writable = chainsi->writable;
682 return si->idx;
685 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
686 to a zero-length string and if possible chain it to a related strinfo
687 chain whose part is or might be CHAINSI. */
689 static strinfo *
690 zero_length_string (tree ptr, strinfo *chainsi)
692 strinfo *si;
693 int idx;
694 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
695 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
696 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
697 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
699 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
700 return NULL;
701 if (chainsi != NULL)
703 si = verify_related_strinfos (chainsi);
704 if (si)
706 chainsi = si;
707 for (; chainsi->next; chainsi = si)
709 if (chainsi->endptr == NULL_TREE)
711 chainsi = unshare_strinfo (chainsi);
712 chainsi->endptr = ptr;
714 si = get_strinfo (chainsi->next);
715 if (si == NULL
716 || si->first != chainsi->first
717 || si->prev != chainsi->idx)
718 break;
720 gcc_assert (chainsi->length || chainsi->stmt);
721 if (chainsi->endptr == NULL_TREE)
723 chainsi = unshare_strinfo (chainsi);
724 chainsi->endptr = ptr;
726 if (chainsi->length && integer_zerop (chainsi->length))
728 if (chainsi->next)
730 chainsi = unshare_strinfo (chainsi);
731 chainsi->next = 0;
733 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
734 return chainsi;
737 else if (chainsi->first || chainsi->prev || chainsi->next)
739 chainsi = unshare_strinfo (chainsi);
740 chainsi->first = 0;
741 chainsi->prev = 0;
742 chainsi->next = 0;
745 idx = new_stridx (ptr);
746 if (idx == 0)
747 return NULL;
748 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
749 set_strinfo (idx, si);
750 si->endptr = ptr;
751 if (chainsi != NULL)
753 chainsi = unshare_strinfo (chainsi);
754 if (chainsi->first == 0)
755 chainsi->first = chainsi->idx;
756 chainsi->next = idx;
757 if (chainsi->endptr == NULL_TREE)
758 chainsi->endptr = ptr;
759 si->prev = chainsi->idx;
760 si->first = chainsi->first;
761 si->writable = chainsi->writable;
763 return si;
766 /* For strinfo ORIGSI whose length has been just updated
767 update also related strinfo lengths (add ADJ to each,
768 but don't adjust ORIGSI). */
770 static void
771 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
773 strinfo *si = verify_related_strinfos (origsi);
775 if (si == NULL)
776 return;
778 while (1)
780 strinfo *nsi;
782 if (si != origsi)
784 tree tem;
786 si = unshare_strinfo (si);
787 if (si->length)
789 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
790 si->length = fold_build2_loc (loc, PLUS_EXPR,
791 TREE_TYPE (si->length), si->length,
792 tem);
794 else if (si->stmt != NULL)
795 /* Delayed length computation is unaffected. */
797 else
798 gcc_unreachable ();
800 si->endptr = NULL_TREE;
801 si->dont_invalidate = true;
803 if (si->next == 0)
804 return;
805 nsi = get_strinfo (si->next);
806 if (nsi == NULL
807 || nsi->first != si->first
808 || nsi->prev != si->idx)
809 return;
810 si = nsi;
814 /* Find if there are other SSA_NAME pointers equal to PTR
815 for which we don't track their string lengths yet. If so, use
816 IDX for them. */
818 static void
819 find_equal_ptrs (tree ptr, int idx)
821 if (TREE_CODE (ptr) != SSA_NAME)
822 return;
823 while (1)
825 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
826 if (!is_gimple_assign (stmt))
827 return;
828 ptr = gimple_assign_rhs1 (stmt);
829 switch (gimple_assign_rhs_code (stmt))
831 case SSA_NAME:
832 break;
833 CASE_CONVERT:
834 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
835 return;
836 if (TREE_CODE (ptr) == SSA_NAME)
837 break;
838 if (TREE_CODE (ptr) != ADDR_EXPR)
839 return;
840 /* FALLTHRU */
841 case ADDR_EXPR:
843 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
844 if (pidx != NULL && *pidx == 0)
845 *pidx = idx;
846 return;
848 default:
849 return;
852 /* We might find an endptr created in this pass. Grow the
853 vector in that case. */
854 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
855 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
857 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
858 return;
859 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
863 /* If the last .MEM setter statement before STMT is
864 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
865 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
866 just memcpy (x, y, strlen (y)). SI must be the zero length
867 strinfo. */
869 static void
870 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
872 tree vuse, callee, len;
873 struct laststmt_struct last = laststmt;
874 strinfo *lastsi, *firstsi;
875 unsigned len_arg_no = 2;
877 laststmt.stmt = NULL;
878 laststmt.len = NULL_TREE;
879 laststmt.stridx = 0;
881 if (last.stmt == NULL)
882 return;
884 vuse = gimple_vuse (stmt);
885 if (vuse == NULL_TREE
886 || SSA_NAME_DEF_STMT (vuse) != last.stmt
887 || !has_single_use (vuse))
888 return;
890 gcc_assert (last.stridx > 0);
891 lastsi = get_strinfo (last.stridx);
892 if (lastsi == NULL)
893 return;
895 if (lastsi != si)
897 if (lastsi->first == 0 || lastsi->first != si->first)
898 return;
900 firstsi = verify_related_strinfos (si);
901 if (firstsi == NULL)
902 return;
903 while (firstsi != lastsi)
905 strinfo *nextsi;
906 if (firstsi->next == 0)
907 return;
908 nextsi = get_strinfo (firstsi->next);
909 if (nextsi == NULL
910 || nextsi->prev != firstsi->idx
911 || nextsi->first != si->first)
912 return;
913 firstsi = nextsi;
917 if (!is_strcat)
919 if (si->length == NULL_TREE || !integer_zerop (si->length))
920 return;
923 if (is_gimple_assign (last.stmt))
925 gimple_stmt_iterator gsi;
927 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
928 return;
929 if (stmt_could_throw_p (last.stmt))
930 return;
931 gsi = gsi_for_stmt (last.stmt);
932 unlink_stmt_vdef (last.stmt);
933 release_defs (last.stmt);
934 gsi_remove (&gsi, true);
935 return;
938 if (!gimple_call_builtin_p (last.stmt, BUILT_IN_NORMAL))
939 return;
941 callee = gimple_call_fndecl (last.stmt);
942 switch (DECL_FUNCTION_CODE (callee))
944 case BUILT_IN_MEMCPY:
945 case BUILT_IN_MEMCPY_CHK:
946 break;
947 case BUILT_IN_MEMCPY_CHKP:
948 case BUILT_IN_MEMCPY_CHK_CHKP:
949 len_arg_no = 4;
950 break;
951 default:
952 return;
955 len = gimple_call_arg (last.stmt, len_arg_no);
956 if (tree_fits_uhwi_p (len))
958 if (!tree_fits_uhwi_p (last.len)
959 || integer_zerop (len)
960 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
961 return;
962 /* Don't adjust the length if it is divisible by 4, it is more efficient
963 to store the extra '\0' in that case. */
964 if ((tree_to_uhwi (len) & 3) == 0)
965 return;
967 else if (TREE_CODE (len) == SSA_NAME)
969 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
970 if (!is_gimple_assign (def_stmt)
971 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
972 || gimple_assign_rhs1 (def_stmt) != last.len
973 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
974 return;
976 else
977 return;
979 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
980 update_stmt (last.stmt);
983 /* Handle a strlen call. If strlen of the argument is known, replace
984 the strlen call with the known value, otherwise remember that strlen
985 of the argument is stored in the lhs SSA_NAME. */
987 static void
988 handle_builtin_strlen (gimple_stmt_iterator *gsi)
990 int idx;
991 tree src;
992 gimple *stmt = gsi_stmt (*gsi);
993 tree lhs = gimple_call_lhs (stmt);
995 if (lhs == NULL_TREE)
996 return;
998 src = gimple_call_arg (stmt, 0);
999 idx = get_stridx (src);
1000 if (idx)
1002 strinfo *si = NULL;
1003 tree rhs;
1005 if (idx < 0)
1006 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1007 else
1009 rhs = NULL_TREE;
1010 si = get_strinfo (idx);
1011 if (si != NULL)
1012 rhs = get_string_length (si);
1014 if (rhs != NULL_TREE)
1016 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1018 fprintf (dump_file, "Optimizing: ");
1019 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1021 rhs = unshare_expr (rhs);
1022 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1023 rhs = fold_convert_loc (gimple_location (stmt),
1024 TREE_TYPE (lhs), rhs);
1025 if (!update_call_from_tree (gsi, rhs))
1026 gimplify_and_update_call_from_tree (gsi, rhs);
1027 stmt = gsi_stmt (*gsi);
1028 update_stmt (stmt);
1029 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1031 fprintf (dump_file, "into: ");
1032 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1034 if (si != NULL
1035 && TREE_CODE (si->length) != SSA_NAME
1036 && TREE_CODE (si->length) != INTEGER_CST
1037 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1039 si = unshare_strinfo (si);
1040 si->length = lhs;
1042 return;
1045 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1046 return;
1047 if (idx == 0)
1048 idx = new_stridx (src);
1049 else if (get_strinfo (idx) != NULL)
1050 return;
1051 if (idx)
1053 strinfo *si = new_strinfo (src, idx, lhs);
1054 set_strinfo (idx, si);
1055 find_equal_ptrs (src, idx);
1059 /* Handle a strchr call. If strlen of the first argument is known, replace
1060 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1061 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1063 static void
1064 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1066 int idx;
1067 tree src;
1068 gimple *stmt = gsi_stmt (*gsi);
1069 tree lhs = gimple_call_lhs (stmt);
1070 bool with_bounds = gimple_call_with_bounds_p (stmt);
1072 if (lhs == NULL_TREE)
1073 return;
1075 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1076 return;
1078 src = gimple_call_arg (stmt, 0);
1079 idx = get_stridx (src);
1080 if (idx)
1082 strinfo *si = NULL;
1083 tree rhs;
1085 if (idx < 0)
1086 rhs = build_int_cst (size_type_node, ~idx);
1087 else
1089 rhs = NULL_TREE;
1090 si = get_strinfo (idx);
1091 if (si != NULL)
1092 rhs = get_string_length (si);
1094 if (rhs != NULL_TREE)
1096 location_t loc = gimple_location (stmt);
1098 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1100 fprintf (dump_file, "Optimizing: ");
1101 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1103 if (si != NULL && si->endptr != NULL_TREE)
1105 rhs = unshare_expr (si->endptr);
1106 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1107 TREE_TYPE (rhs)))
1108 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1110 else
1112 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1113 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1114 TREE_TYPE (src), src, rhs);
1115 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1116 TREE_TYPE (rhs)))
1117 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1119 if (!update_call_from_tree (gsi, rhs))
1120 gimplify_and_update_call_from_tree (gsi, rhs);
1121 stmt = gsi_stmt (*gsi);
1122 update_stmt (stmt);
1123 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1125 fprintf (dump_file, "into: ");
1126 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1128 if (si != NULL
1129 && si->endptr == NULL_TREE
1130 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1132 si = unshare_strinfo (si);
1133 si->endptr = lhs;
1135 zero_length_string (lhs, si);
1136 return;
1139 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1140 return;
1141 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1143 if (idx == 0)
1144 idx = new_stridx (src);
1145 else if (get_strinfo (idx) != NULL)
1147 zero_length_string (lhs, NULL);
1148 return;
1150 if (idx)
1152 location_t loc = gimple_location (stmt);
1153 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1154 tree srcu = fold_convert_loc (loc, size_type_node, src);
1155 tree length = fold_build2_loc (loc, MINUS_EXPR,
1156 size_type_node, lhsu, srcu);
1157 strinfo *si = new_strinfo (src, idx, length);
1158 si->endptr = lhs;
1159 set_strinfo (idx, si);
1160 find_equal_ptrs (src, idx);
1161 zero_length_string (lhs, si);
1164 else
1165 zero_length_string (lhs, NULL);
1168 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1169 If strlen of the second argument is known, strlen of the first argument
1170 is the same after this call. Furthermore, attempt to convert it to
1171 memcpy. */
1173 static void
1174 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1176 int idx, didx;
1177 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1178 bool success;
1179 gimple *stmt = gsi_stmt (*gsi);
1180 strinfo *si, *dsi, *olddsi, *zsi;
1181 location_t loc;
1182 bool with_bounds = gimple_call_with_bounds_p (stmt);
1184 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1185 dst = gimple_call_arg (stmt, 0);
1186 lhs = gimple_call_lhs (stmt);
1187 idx = get_stridx (src);
1188 si = NULL;
1189 if (idx > 0)
1190 si = get_strinfo (idx);
1192 didx = get_stridx (dst);
1193 olddsi = NULL;
1194 oldlen = NULL_TREE;
1195 if (didx > 0)
1196 olddsi = get_strinfo (didx);
1197 else if (didx < 0)
1198 return;
1200 if (olddsi != NULL)
1201 adjust_last_stmt (olddsi, stmt, false);
1203 srclen = NULL_TREE;
1204 if (si != NULL)
1205 srclen = get_string_length (si);
1206 else if (idx < 0)
1207 srclen = build_int_cst (size_type_node, ~idx);
1209 loc = gimple_location (stmt);
1210 if (srclen == NULL_TREE)
1211 switch (bcode)
1213 case BUILT_IN_STRCPY:
1214 case BUILT_IN_STRCPY_CHK:
1215 case BUILT_IN_STRCPY_CHKP:
1216 case BUILT_IN_STRCPY_CHK_CHKP:
1217 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1218 return;
1219 break;
1220 case BUILT_IN_STPCPY:
1221 case BUILT_IN_STPCPY_CHK:
1222 case BUILT_IN_STPCPY_CHKP:
1223 case BUILT_IN_STPCPY_CHK_CHKP:
1224 if (lhs == NULL_TREE)
1225 return;
1226 else
1228 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1229 srclen = fold_convert_loc (loc, size_type_node, dst);
1230 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1231 lhsuint, srclen);
1233 break;
1234 default:
1235 gcc_unreachable ();
1238 if (didx == 0)
1240 didx = new_stridx (dst);
1241 if (didx == 0)
1242 return;
1244 if (olddsi != NULL)
1246 oldlen = olddsi->length;
1247 dsi = unshare_strinfo (olddsi);
1248 dsi->length = srclen;
1249 /* Break the chain, so adjust_related_strinfo on later pointers in
1250 the chain won't adjust this one anymore. */
1251 dsi->next = 0;
1252 dsi->stmt = NULL;
1253 dsi->endptr = NULL_TREE;
1255 else
1257 dsi = new_strinfo (dst, didx, srclen);
1258 set_strinfo (didx, dsi);
1259 find_equal_ptrs (dst, didx);
1261 dsi->writable = true;
1262 dsi->dont_invalidate = true;
1264 if (dsi->length == NULL_TREE)
1266 strinfo *chainsi;
1268 /* If string length of src is unknown, use delayed length
1269 computation. If string lenth of dst will be needed, it
1270 can be computed by transforming this strcpy call into
1271 stpcpy and subtracting dst from the return value. */
1273 /* Look for earlier strings whose length could be determined if
1274 this strcpy is turned into an stpcpy. */
1276 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1278 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1280 /* When setting a stmt for delayed length computation
1281 prevent all strinfos through dsi from being
1282 invalidated. */
1283 chainsi = unshare_strinfo (chainsi);
1284 chainsi->stmt = stmt;
1285 chainsi->length = NULL_TREE;
1286 chainsi->endptr = NULL_TREE;
1287 chainsi->dont_invalidate = true;
1290 dsi->stmt = stmt;
1291 return;
1294 if (olddsi != NULL)
1296 tree adj = NULL_TREE;
1297 if (oldlen == NULL_TREE)
1299 else if (integer_zerop (oldlen))
1300 adj = srclen;
1301 else if (TREE_CODE (oldlen) == INTEGER_CST
1302 || TREE_CODE (srclen) == INTEGER_CST)
1303 adj = fold_build2_loc (loc, MINUS_EXPR,
1304 TREE_TYPE (srclen), srclen,
1305 fold_convert_loc (loc, TREE_TYPE (srclen),
1306 oldlen));
1307 if (adj != NULL_TREE)
1308 adjust_related_strinfos (loc, dsi, adj);
1309 else
1310 dsi->prev = 0;
1312 /* strcpy src may not overlap dst, so src doesn't need to be
1313 invalidated either. */
1314 if (si != NULL)
1315 si->dont_invalidate = true;
1317 fn = NULL_TREE;
1318 zsi = NULL;
1319 switch (bcode)
1321 case BUILT_IN_STRCPY:
1322 case BUILT_IN_STRCPY_CHKP:
1323 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1324 if (lhs)
1325 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1326 break;
1327 case BUILT_IN_STRCPY_CHK:
1328 case BUILT_IN_STRCPY_CHK_CHKP:
1329 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1330 if (lhs)
1331 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1332 break;
1333 case BUILT_IN_STPCPY:
1334 case BUILT_IN_STPCPY_CHKP:
1335 /* This would need adjustment of the lhs (subtract one),
1336 or detection that the trailing '\0' doesn't need to be
1337 written, if it will be immediately overwritten.
1338 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1339 if (lhs)
1341 dsi->endptr = lhs;
1342 zsi = zero_length_string (lhs, dsi);
1344 break;
1345 case BUILT_IN_STPCPY_CHK:
1346 case BUILT_IN_STPCPY_CHK_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_CHK); */
1351 if (lhs)
1353 dsi->endptr = lhs;
1354 zsi = zero_length_string (lhs, dsi);
1356 break;
1357 default:
1358 gcc_unreachable ();
1360 if (zsi != NULL)
1361 zsi->dont_invalidate = true;
1363 if (fn == NULL_TREE)
1364 return;
1366 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1367 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1369 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1370 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1371 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1372 GSI_SAME_STMT);
1373 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1375 fprintf (dump_file, "Optimizing: ");
1376 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1378 if (with_bounds)
1380 fn = chkp_maybe_create_clone (fn)->decl;
1381 if (gimple_call_num_args (stmt) == 4)
1382 success = update_gimple_call (gsi, fn, 5, dst,
1383 gimple_call_arg (stmt, 1),
1384 src,
1385 gimple_call_arg (stmt, 3),
1386 len);
1387 else
1388 success = update_gimple_call (gsi, fn, 6, dst,
1389 gimple_call_arg (stmt, 1),
1390 src,
1391 gimple_call_arg (stmt, 3),
1392 len,
1393 gimple_call_arg (stmt, 4));
1395 else
1396 if (gimple_call_num_args (stmt) == 2)
1397 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1398 else
1399 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1400 gimple_call_arg (stmt, 2));
1401 if (success)
1403 stmt = gsi_stmt (*gsi);
1404 gimple_call_set_with_bounds (stmt, with_bounds);
1405 update_stmt (stmt);
1406 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1408 fprintf (dump_file, "into: ");
1409 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1411 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1412 laststmt.stmt = stmt;
1413 laststmt.len = srclen;
1414 laststmt.stridx = dsi->idx;
1416 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1417 fprintf (dump_file, "not possible.\n");
1420 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1421 If strlen of the second argument is known and length of the third argument
1422 is that plus one, strlen of the first argument is the same after this
1423 call. */
1425 static void
1426 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1428 int idx, didx;
1429 tree src, dst, len, lhs, oldlen, newlen;
1430 gimple *stmt = gsi_stmt (*gsi);
1431 strinfo *si, *dsi, *olddsi;
1432 bool with_bounds = gimple_call_with_bounds_p (stmt);
1434 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1435 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1436 dst = gimple_call_arg (stmt, 0);
1437 idx = get_stridx (src);
1438 if (idx == 0)
1439 return;
1441 didx = get_stridx (dst);
1442 olddsi = NULL;
1443 if (didx > 0)
1444 olddsi = get_strinfo (didx);
1445 else if (didx < 0)
1446 return;
1448 if (olddsi != NULL
1449 && tree_fits_uhwi_p (len)
1450 && !integer_zerop (len))
1451 adjust_last_stmt (olddsi, stmt, false);
1453 if (idx > 0)
1455 gimple *def_stmt;
1457 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1458 si = get_strinfo (idx);
1459 if (si == NULL || si->length == NULL_TREE)
1460 return;
1461 if (TREE_CODE (len) != SSA_NAME)
1462 return;
1463 def_stmt = SSA_NAME_DEF_STMT (len);
1464 if (!is_gimple_assign (def_stmt)
1465 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1466 || gimple_assign_rhs1 (def_stmt) != si->length
1467 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1468 return;
1470 else
1472 si = NULL;
1473 /* Handle memcpy (x, "abcd", 5) or
1474 memcpy (x, "abc\0uvw", 7). */
1475 if (!tree_fits_uhwi_p (len)
1476 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1477 return;
1480 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1481 adjust_last_stmt (olddsi, stmt, false);
1483 if (didx == 0)
1485 didx = new_stridx (dst);
1486 if (didx == 0)
1487 return;
1489 if (si != NULL)
1490 newlen = si->length;
1491 else
1492 newlen = build_int_cst (size_type_node, ~idx);
1493 oldlen = NULL_TREE;
1494 if (olddsi != NULL)
1496 dsi = unshare_strinfo (olddsi);
1497 oldlen = olddsi->length;
1498 dsi->length = newlen;
1499 /* Break the chain, so adjust_related_strinfo on later pointers in
1500 the chain won't adjust this one anymore. */
1501 dsi->next = 0;
1502 dsi->stmt = NULL;
1503 dsi->endptr = NULL_TREE;
1505 else
1507 dsi = new_strinfo (dst, didx, newlen);
1508 set_strinfo (didx, dsi);
1509 find_equal_ptrs (dst, didx);
1511 dsi->writable = true;
1512 dsi->dont_invalidate = true;
1513 if (olddsi != NULL)
1515 tree adj = NULL_TREE;
1516 location_t loc = gimple_location (stmt);
1517 if (oldlen == NULL_TREE)
1519 else if (integer_zerop (oldlen))
1520 adj = dsi->length;
1521 else if (TREE_CODE (oldlen) == INTEGER_CST
1522 || TREE_CODE (dsi->length) == INTEGER_CST)
1523 adj = fold_build2_loc (loc, MINUS_EXPR,
1524 TREE_TYPE (dsi->length), dsi->length,
1525 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1526 oldlen));
1527 if (adj != NULL_TREE)
1528 adjust_related_strinfos (loc, dsi, adj);
1529 else
1530 dsi->prev = 0;
1532 /* memcpy src may not overlap dst, so src doesn't need to be
1533 invalidated either. */
1534 if (si != NULL)
1535 si->dont_invalidate = true;
1537 lhs = gimple_call_lhs (stmt);
1538 switch (bcode)
1540 case BUILT_IN_MEMCPY:
1541 case BUILT_IN_MEMCPY_CHK:
1542 case BUILT_IN_MEMCPY_CHKP:
1543 case BUILT_IN_MEMCPY_CHK_CHKP:
1544 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1545 laststmt.stmt = stmt;
1546 laststmt.len = dsi->length;
1547 laststmt.stridx = dsi->idx;
1548 if (lhs)
1549 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1550 break;
1551 case BUILT_IN_MEMPCPY:
1552 case BUILT_IN_MEMPCPY_CHK:
1553 case BUILT_IN_MEMPCPY_CHKP:
1554 case BUILT_IN_MEMPCPY_CHK_CHKP:
1555 break;
1556 default:
1557 gcc_unreachable ();
1561 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1562 If strlen of the second argument is known, strlen of the first argument
1563 is increased by the length of the second argument. Furthermore, attempt
1564 to convert it to memcpy/strcpy if the length of the first argument
1565 is known. */
1567 static void
1568 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1570 int idx, didx;
1571 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1572 bool success;
1573 gimple *stmt = gsi_stmt (*gsi);
1574 strinfo *si, *dsi;
1575 location_t loc;
1576 bool with_bounds = gimple_call_with_bounds_p (stmt);
1578 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1579 dst = gimple_call_arg (stmt, 0);
1580 lhs = gimple_call_lhs (stmt);
1582 didx = get_stridx (dst);
1583 if (didx < 0)
1584 return;
1586 dsi = NULL;
1587 if (didx > 0)
1588 dsi = get_strinfo (didx);
1589 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1591 /* strcat (p, q) can be transformed into
1592 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1593 with length endptr - p if we need to compute the length
1594 later on. Don't do this transformation if we don't need
1595 it. */
1596 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1598 if (didx == 0)
1600 didx = new_stridx (dst);
1601 if (didx == 0)
1602 return;
1604 if (dsi == NULL)
1606 dsi = new_strinfo (dst, didx, NULL_TREE);
1607 set_strinfo (didx, dsi);
1608 find_equal_ptrs (dst, didx);
1610 else
1612 dsi = unshare_strinfo (dsi);
1613 dsi->length = NULL_TREE;
1614 dsi->next = 0;
1615 dsi->endptr = NULL_TREE;
1617 dsi->writable = true;
1618 dsi->stmt = stmt;
1619 dsi->dont_invalidate = true;
1621 return;
1624 srclen = NULL_TREE;
1625 si = NULL;
1626 idx = get_stridx (src);
1627 if (idx < 0)
1628 srclen = build_int_cst (size_type_node, ~idx);
1629 else if (idx > 0)
1631 si = get_strinfo (idx);
1632 if (si != NULL)
1633 srclen = get_string_length (si);
1636 loc = gimple_location (stmt);
1637 dstlen = dsi->length;
1638 endptr = dsi->endptr;
1640 dsi = unshare_strinfo (dsi);
1641 dsi->endptr = NULL_TREE;
1642 dsi->stmt = NULL;
1643 dsi->writable = true;
1645 if (srclen != NULL_TREE)
1647 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1648 dsi->length, srclen);
1649 adjust_related_strinfos (loc, dsi, srclen);
1650 dsi->dont_invalidate = true;
1652 else
1654 dsi->length = NULL;
1655 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1656 dsi->dont_invalidate = true;
1659 if (si != NULL)
1660 /* strcat src may not overlap dst, so src doesn't need to be
1661 invalidated either. */
1662 si->dont_invalidate = true;
1664 /* For now. Could remove the lhs from the call and add
1665 lhs = dst; afterwards. */
1666 if (lhs)
1667 return;
1669 fn = NULL_TREE;
1670 objsz = NULL_TREE;
1671 switch (bcode)
1673 case BUILT_IN_STRCAT:
1674 case BUILT_IN_STRCAT_CHKP:
1675 if (srclen != NULL_TREE)
1676 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1677 else
1678 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1679 break;
1680 case BUILT_IN_STRCAT_CHK:
1681 case BUILT_IN_STRCAT_CHK_CHKP:
1682 if (srclen != NULL_TREE)
1683 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1684 else
1685 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1686 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1687 break;
1688 default:
1689 gcc_unreachable ();
1692 if (fn == NULL_TREE)
1693 return;
1695 len = NULL_TREE;
1696 if (srclen != NULL_TREE)
1698 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1699 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1701 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1702 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1703 build_int_cst (type, 1));
1704 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1705 GSI_SAME_STMT);
1707 if (endptr)
1708 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1709 else
1710 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1711 TREE_TYPE (dst), unshare_expr (dst),
1712 fold_convert_loc (loc, sizetype,
1713 unshare_expr (dstlen)));
1714 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1715 GSI_SAME_STMT);
1716 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1718 fprintf (dump_file, "Optimizing: ");
1719 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1721 if (with_bounds)
1723 fn = chkp_maybe_create_clone (fn)->decl;
1724 if (srclen != NULL_TREE)
1725 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1726 dst,
1727 gimple_call_arg (stmt, 1),
1728 src,
1729 gimple_call_arg (stmt, 3),
1730 len, objsz);
1731 else
1732 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1733 dst,
1734 gimple_call_arg (stmt, 1),
1735 src,
1736 gimple_call_arg (stmt, 3),
1737 objsz);
1739 else
1740 if (srclen != NULL_TREE)
1741 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1742 dst, src, len, objsz);
1743 else
1744 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1745 dst, src, objsz);
1746 if (success)
1748 stmt = gsi_stmt (*gsi);
1749 gimple_call_set_with_bounds (stmt, with_bounds);
1750 update_stmt (stmt);
1751 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1753 fprintf (dump_file, "into: ");
1754 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1756 /* If srclen == NULL, note that current string length can be
1757 computed by transforming this strcpy into stpcpy. */
1758 if (srclen == NULL_TREE && dsi->dont_invalidate)
1759 dsi->stmt = stmt;
1760 adjust_last_stmt (dsi, stmt, true);
1761 if (srclen != NULL_TREE)
1763 laststmt.stmt = stmt;
1764 laststmt.len = srclen;
1765 laststmt.stridx = dsi->idx;
1768 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1769 fprintf (dump_file, "not possible.\n");
1772 /* Handle a call to malloc or calloc. */
1774 static void
1775 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1777 gimple *stmt = gsi_stmt (*gsi);
1778 tree lhs = gimple_call_lhs (stmt);
1779 gcc_assert (get_stridx (lhs) == 0);
1780 int idx = new_stridx (lhs);
1781 tree length = NULL_TREE;
1782 if (bcode == BUILT_IN_CALLOC)
1783 length = build_int_cst (size_type_node, 0);
1784 strinfo *si = new_strinfo (lhs, idx, length);
1785 if (bcode == BUILT_IN_CALLOC)
1786 si->endptr = lhs;
1787 set_strinfo (idx, si);
1788 si->writable = true;
1789 si->stmt = stmt;
1790 si->dont_invalidate = true;
1793 /* Handle a call to memset.
1794 After a call to calloc, memset(,0,) is unnecessary.
1795 memset(malloc(n),0,n) is calloc(n,1). */
1797 static bool
1798 handle_builtin_memset (gimple_stmt_iterator *gsi)
1800 gimple *stmt2 = gsi_stmt (*gsi);
1801 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1802 return true;
1803 tree ptr = gimple_call_arg (stmt2, 0);
1804 int idx1 = get_stridx (ptr);
1805 if (idx1 <= 0)
1806 return true;
1807 strinfo *si1 = get_strinfo (idx1);
1808 if (!si1)
1809 return true;
1810 gimple *stmt1 = si1->stmt;
1811 if (!stmt1 || !is_gimple_call (stmt1))
1812 return true;
1813 tree callee1 = gimple_call_fndecl (stmt1);
1814 if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL))
1815 return true;
1816 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1817 tree size = gimple_call_arg (stmt2, 2);
1818 if (code1 == BUILT_IN_CALLOC)
1819 /* Not touching stmt1 */ ;
1820 else if (code1 == BUILT_IN_MALLOC
1821 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1823 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1824 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1825 size, build_one_cst (size_type_node));
1826 si1->length = build_int_cst (size_type_node, 0);
1827 si1->stmt = gsi_stmt (gsi1);
1829 else
1830 return true;
1831 tree lhs = gimple_call_lhs (stmt2);
1832 unlink_stmt_vdef (stmt2);
1833 if (lhs)
1835 gimple *assign = gimple_build_assign (lhs, ptr);
1836 gsi_replace (gsi, assign, false);
1838 else
1840 gsi_remove (gsi, true);
1841 release_defs (stmt2);
1844 return false;
1847 /* Handle a call to memcmp. We try to handle small comparisons by
1848 converting them to load and compare, and replacing the call to memcmp
1849 with a __builtin_memcmp_eq call where possible. */
1851 static bool
1852 handle_builtin_memcmp (gimple_stmt_iterator *gsi)
1854 gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
1855 tree res = gimple_call_lhs (stmt2);
1856 tree arg1 = gimple_call_arg (stmt2, 0);
1857 tree arg2 = gimple_call_arg (stmt2, 1);
1858 tree len = gimple_call_arg (stmt2, 2);
1859 unsigned HOST_WIDE_INT leni;
1860 use_operand_p use_p;
1861 imm_use_iterator iter;
1863 if (!res)
1864 return true;
1866 FOR_EACH_IMM_USE_FAST (use_p, iter, res)
1868 gimple *ustmt = USE_STMT (use_p);
1870 if (is_gimple_debug (ustmt))
1871 continue;
1872 if (gimple_code (ustmt) == GIMPLE_ASSIGN)
1874 gassign *asgn = as_a <gassign *> (ustmt);
1875 tree_code code = gimple_assign_rhs_code (asgn);
1876 if ((code != EQ_EXPR && code != NE_EXPR)
1877 || !integer_zerop (gimple_assign_rhs2 (asgn)))
1878 return true;
1880 else if (gimple_code (ustmt) == GIMPLE_COND)
1882 tree_code code = gimple_cond_code (ustmt);
1883 if ((code != EQ_EXPR && code != NE_EXPR)
1884 || !integer_zerop (gimple_cond_rhs (ustmt)))
1885 return true;
1887 else
1888 return true;
1891 if (tree_fits_uhwi_p (len)
1892 && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
1893 && exact_log2 (leni) != -1)
1895 leni *= CHAR_TYPE_SIZE;
1896 unsigned align1 = get_pointer_alignment (arg1);
1897 unsigned align2 = get_pointer_alignment (arg2);
1898 unsigned align = MIN (align1, align2);
1899 machine_mode mode = mode_for_size (leni, MODE_INT, 1);
1900 if (mode != BLKmode
1901 && (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align)))
1903 location_t loc = gimple_location (stmt2);
1904 tree type, off;
1905 type = build_nonstandard_integer_type (leni, 1);
1906 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
1907 tree ptrtype = build_pointer_type_for_mode (char_type_node,
1908 ptr_mode, true);
1909 off = build_int_cst (ptrtype, 0);
1910 arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
1911 arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
1912 tree tem1 = fold_const_aggregate_ref (arg1);
1913 if (tem1)
1914 arg1 = tem1;
1915 tree tem2 = fold_const_aggregate_ref (arg2);
1916 if (tem2)
1917 arg2 = tem2;
1918 res = fold_convert_loc (loc, TREE_TYPE (res),
1919 fold_build2_loc (loc, NE_EXPR,
1920 boolean_type_node,
1921 arg1, arg2));
1922 gimplify_and_update_call_from_tree (gsi, res);
1923 return false;
1927 gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
1928 return false;
1931 /* Handle a POINTER_PLUS_EXPR statement.
1932 For p = "abcd" + 2; compute associated length, or if
1933 p = q + off is pointing to a '\0' character of a string, call
1934 zero_length_string on it. */
1936 static void
1937 handle_pointer_plus (gimple_stmt_iterator *gsi)
1939 gimple *stmt = gsi_stmt (*gsi);
1940 tree lhs = gimple_assign_lhs (stmt), off;
1941 int idx = get_stridx (gimple_assign_rhs1 (stmt));
1942 strinfo *si, *zsi;
1944 if (idx == 0)
1945 return;
1947 if (idx < 0)
1949 tree off = gimple_assign_rhs2 (stmt);
1950 if (tree_fits_uhwi_p (off)
1951 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
1952 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
1953 = ~(~idx - (int) tree_to_uhwi (off));
1954 return;
1957 si = get_strinfo (idx);
1958 if (si == NULL || si->length == NULL_TREE)
1959 return;
1961 off = gimple_assign_rhs2 (stmt);
1962 zsi = NULL;
1963 if (operand_equal_p (si->length, off, 0))
1964 zsi = zero_length_string (lhs, si);
1965 else if (TREE_CODE (off) == SSA_NAME)
1967 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
1968 if (gimple_assign_single_p (def_stmt)
1969 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
1970 zsi = zero_length_string (lhs, si);
1972 if (zsi != NULL
1973 && si->endptr != NULL_TREE
1974 && si->endptr != lhs
1975 && TREE_CODE (si->endptr) == SSA_NAME)
1977 enum tree_code rhs_code
1978 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
1979 ? SSA_NAME : NOP_EXPR;
1980 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
1981 gcc_assert (gsi_stmt (*gsi) == stmt);
1982 update_stmt (stmt);
1986 /* Handle a single character store. */
1988 static bool
1989 handle_char_store (gimple_stmt_iterator *gsi)
1991 int idx = -1;
1992 strinfo *si = NULL;
1993 gimple *stmt = gsi_stmt (*gsi);
1994 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
1996 if (TREE_CODE (lhs) == MEM_REF
1997 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
1999 if (integer_zerop (TREE_OPERAND (lhs, 1)))
2001 ssaname = TREE_OPERAND (lhs, 0);
2002 idx = get_stridx (ssaname);
2005 else
2006 idx = get_addr_stridx (lhs);
2008 if (idx > 0)
2010 si = get_strinfo (idx);
2011 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
2013 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
2015 /* When storing '\0', the store can be removed
2016 if we know it has been stored in the current function. */
2017 if (!stmt_could_throw_p (stmt) && si->writable)
2019 unlink_stmt_vdef (stmt);
2020 release_defs (stmt);
2021 gsi_remove (gsi, true);
2022 return false;
2024 else
2026 si->writable = true;
2027 gsi_next (gsi);
2028 return false;
2031 else
2032 /* Otherwise this statement overwrites the '\0' with
2033 something, if the previous stmt was a memcpy,
2034 its length may be decreased. */
2035 adjust_last_stmt (si, stmt, false);
2037 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
2039 si = unshare_strinfo (si);
2040 si->length = build_int_cst (size_type_node, 0);
2041 si->endptr = NULL;
2042 si->prev = 0;
2043 si->next = 0;
2044 si->stmt = NULL;
2045 si->first = 0;
2046 si->writable = true;
2047 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2048 si->endptr = ssaname;
2049 si->dont_invalidate = true;
2051 /* If si->length is non-zero constant, we aren't overwriting '\0',
2052 and if we aren't storing '\0', we know that the length of the
2053 string and any other zero terminated string in memory remains
2054 the same. In that case we move to the next gimple statement and
2055 return to signal the caller that it shouldn't invalidate anything.
2057 This is benefical for cases like:
2059 char p[20];
2060 void foo (char *q)
2062 strcpy (p, "foobar");
2063 size_t len = strlen (p); // This can be optimized into 6
2064 size_t len2 = strlen (q); // This has to be computed
2065 p[0] = 'X';
2066 size_t len3 = strlen (p); // This can be optimized into 6
2067 size_t len4 = strlen (q); // This can be optimized into len2
2068 bar (len, len2, len3, len4);
2071 else if (si != NULL && si->length != NULL_TREE
2072 && TREE_CODE (si->length) == INTEGER_CST
2073 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2075 gsi_next (gsi);
2076 return false;
2079 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2081 if (ssaname)
2083 si = zero_length_string (ssaname, NULL);
2084 if (si != NULL)
2085 si->dont_invalidate = true;
2087 else
2089 int idx = new_addr_stridx (lhs);
2090 if (idx != 0)
2092 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2093 build_int_cst (size_type_node, 0));
2094 set_strinfo (idx, si);
2095 si->dont_invalidate = true;
2098 if (si != NULL)
2099 si->writable = true;
2101 else if (idx == 0
2102 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2103 && ssaname == NULL_TREE
2104 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2106 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2107 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2108 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2110 int idx = new_addr_stridx (lhs);
2111 if (idx != 0)
2113 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2114 build_int_cst (size_type_node, l));
2115 set_strinfo (idx, si);
2116 si->dont_invalidate = true;
2121 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2123 /* Allow adjust_last_stmt to remove it if the stored '\0'
2124 is immediately overwritten. */
2125 laststmt.stmt = stmt;
2126 laststmt.len = build_int_cst (size_type_node, 1);
2127 laststmt.stridx = si->idx;
2129 return true;
2132 /* Attempt to optimize a single statement at *GSI using string length
2133 knowledge. */
2135 static bool
2136 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2138 gimple *stmt = gsi_stmt (*gsi);
2140 if (is_gimple_call (stmt))
2142 tree callee = gimple_call_fndecl (stmt);
2143 if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
2144 switch (DECL_FUNCTION_CODE (callee))
2146 case BUILT_IN_STRLEN:
2147 case BUILT_IN_STRLEN_CHKP:
2148 handle_builtin_strlen (gsi);
2149 break;
2150 case BUILT_IN_STRCHR:
2151 case BUILT_IN_STRCHR_CHKP:
2152 handle_builtin_strchr (gsi);
2153 break;
2154 case BUILT_IN_STRCPY:
2155 case BUILT_IN_STRCPY_CHK:
2156 case BUILT_IN_STPCPY:
2157 case BUILT_IN_STPCPY_CHK:
2158 case BUILT_IN_STRCPY_CHKP:
2159 case BUILT_IN_STRCPY_CHK_CHKP:
2160 case BUILT_IN_STPCPY_CHKP:
2161 case BUILT_IN_STPCPY_CHK_CHKP:
2162 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2163 break;
2164 case BUILT_IN_MEMCPY:
2165 case BUILT_IN_MEMCPY_CHK:
2166 case BUILT_IN_MEMPCPY:
2167 case BUILT_IN_MEMPCPY_CHK:
2168 case BUILT_IN_MEMCPY_CHKP:
2169 case BUILT_IN_MEMCPY_CHK_CHKP:
2170 case BUILT_IN_MEMPCPY_CHKP:
2171 case BUILT_IN_MEMPCPY_CHK_CHKP:
2172 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2173 break;
2174 case BUILT_IN_STRCAT:
2175 case BUILT_IN_STRCAT_CHK:
2176 case BUILT_IN_STRCAT_CHKP:
2177 case BUILT_IN_STRCAT_CHK_CHKP:
2178 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2179 break;
2180 case BUILT_IN_MALLOC:
2181 case BUILT_IN_CALLOC:
2182 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2183 break;
2184 case BUILT_IN_MEMSET:
2185 if (!handle_builtin_memset (gsi))
2186 return false;
2187 break;
2188 case BUILT_IN_MEMCMP:
2189 if (!handle_builtin_memcmp (gsi))
2190 return false;
2191 break;
2192 default:
2193 break;
2196 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2198 tree lhs = gimple_assign_lhs (stmt);
2200 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2202 if (gimple_assign_single_p (stmt)
2203 || (gimple_assign_cast_p (stmt)
2204 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2206 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2207 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2209 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2210 handle_pointer_plus (gsi);
2212 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2214 tree type = TREE_TYPE (lhs);
2215 if (TREE_CODE (type) == ARRAY_TYPE)
2216 type = TREE_TYPE (type);
2217 if (TREE_CODE (type) == INTEGER_TYPE
2218 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2219 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2221 if (! handle_char_store (gsi))
2222 return false;
2227 if (gimple_vdef (stmt))
2228 maybe_invalidate (stmt);
2229 return true;
2232 /* Recursively call maybe_invalidate on stmts that might be executed
2233 in between dombb and current bb and that contain a vdef. Stop when
2234 *count stmts are inspected, or if the whole strinfo vector has
2235 been invalidated. */
2237 static void
2238 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2240 unsigned int i, n = gimple_phi_num_args (phi);
2242 for (i = 0; i < n; i++)
2244 tree vuse = gimple_phi_arg_def (phi, i);
2245 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2246 basic_block bb = gimple_bb (stmt);
2247 if (bb == NULL
2248 || bb == dombb
2249 || !bitmap_set_bit (visited, bb->index)
2250 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2251 continue;
2252 while (1)
2254 if (gimple_code (stmt) == GIMPLE_PHI)
2256 do_invalidate (dombb, stmt, visited, count);
2257 if (*count == 0)
2258 return;
2259 break;
2261 if (--*count == 0)
2262 return;
2263 if (!maybe_invalidate (stmt))
2265 *count = 0;
2266 return;
2268 vuse = gimple_vuse (stmt);
2269 stmt = SSA_NAME_DEF_STMT (vuse);
2270 if (gimple_bb (stmt) != bb)
2272 bb = gimple_bb (stmt);
2273 if (bb == NULL
2274 || bb == dombb
2275 || !bitmap_set_bit (visited, bb->index)
2276 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2277 break;
2283 class strlen_dom_walker : public dom_walker
2285 public:
2286 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2288 virtual edge before_dom_children (basic_block);
2289 virtual void after_dom_children (basic_block);
2292 /* Callback for walk_dominator_tree. Attempt to optimize various
2293 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2295 edge
2296 strlen_dom_walker::before_dom_children (basic_block bb)
2298 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2300 if (dombb == NULL)
2301 stridx_to_strinfo = NULL;
2302 else
2304 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2305 if (stridx_to_strinfo)
2307 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2308 gsi_next (&gsi))
2310 gphi *phi = gsi.phi ();
2311 if (virtual_operand_p (gimple_phi_result (phi)))
2313 bitmap visited = BITMAP_ALLOC (NULL);
2314 int count_vdef = 100;
2315 do_invalidate (dombb, phi, visited, &count_vdef);
2316 BITMAP_FREE (visited);
2317 if (count_vdef == 0)
2319 /* If there were too many vdefs in between immediate
2320 dominator and current bb, invalidate everything.
2321 If stridx_to_strinfo has been unshared, we need
2322 to free it, otherwise just set it to NULL. */
2323 if (!strinfo_shared ())
2325 unsigned int i;
2326 strinfo *si;
2328 for (i = 1;
2329 vec_safe_iterate (stridx_to_strinfo, i, &si);
2330 ++i)
2332 free_strinfo (si);
2333 (*stridx_to_strinfo)[i] = NULL;
2336 else
2337 stridx_to_strinfo = NULL;
2339 break;
2345 /* If all PHI arguments have the same string index, the PHI result
2346 has it as well. */
2347 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2348 gsi_next (&gsi))
2350 gphi *phi = gsi.phi ();
2351 tree result = gimple_phi_result (phi);
2352 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2354 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2355 if (idx != 0)
2357 unsigned int i, n = gimple_phi_num_args (phi);
2358 for (i = 1; i < n; i++)
2359 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2360 break;
2361 if (i == n)
2362 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2367 /* Attempt to optimize individual statements. */
2368 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2369 if (strlen_optimize_stmt (&gsi))
2370 gsi_next (&gsi);
2372 bb->aux = stridx_to_strinfo;
2373 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2374 (*stridx_to_strinfo)[0] = (strinfo *) bb;
2375 return NULL;
2378 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2379 owned by the current bb, clear bb->aux. */
2381 void
2382 strlen_dom_walker::after_dom_children (basic_block bb)
2384 if (bb->aux)
2386 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2387 if (vec_safe_length (stridx_to_strinfo)
2388 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2390 unsigned int i;
2391 strinfo *si;
2393 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2394 free_strinfo (si);
2395 vec_free (stridx_to_strinfo);
2397 bb->aux = NULL;
2401 /* Main entry point. */
2403 namespace {
2405 const pass_data pass_data_strlen =
2407 GIMPLE_PASS, /* type */
2408 "strlen", /* name */
2409 OPTGROUP_NONE, /* optinfo_flags */
2410 TV_TREE_STRLEN, /* tv_id */
2411 ( PROP_cfg | PROP_ssa ), /* properties_required */
2412 0, /* properties_provided */
2413 0, /* properties_destroyed */
2414 0, /* todo_flags_start */
2415 0, /* todo_flags_finish */
2418 class pass_strlen : public gimple_opt_pass
2420 public:
2421 pass_strlen (gcc::context *ctxt)
2422 : gimple_opt_pass (pass_data_strlen, ctxt)
2425 /* opt_pass methods: */
2426 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2427 virtual unsigned int execute (function *);
2429 }; // class pass_strlen
2431 unsigned int
2432 pass_strlen::execute (function *fun)
2434 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2435 max_stridx = 1;
2437 calculate_dominance_info (CDI_DOMINATORS);
2439 /* String length optimization is implemented as a walk of the dominator
2440 tree and a forward walk of statements within each block. */
2441 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2443 ssa_ver_to_stridx.release ();
2444 strinfo_pool.release ();
2445 if (decl_to_stridxlist_htab)
2447 obstack_free (&stridx_obstack, NULL);
2448 delete decl_to_stridxlist_htab;
2449 decl_to_stridxlist_htab = NULL;
2451 laststmt.stmt = NULL;
2452 laststmt.len = NULL_TREE;
2453 laststmt.stridx = 0;
2455 return 0;
2458 } // anon namespace
2460 gimple_opt_pass *
2461 make_pass_strlen (gcc::context *ctxt)
2463 return new pass_strlen (ctxt);