Emit SIMD moves as mov
[official-gcc.git] / gcc / tree-ssa-strlen.c
blobe4f18dba1e7d7f27bb15e4d0d4c979e7a1553cee
1 /* String length optimization
2 Copyright (C) 2011-2017 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 /* Get the next strinfo in the chain after SI, or null if none. */
161 static inline strinfo *
162 get_next_strinfo (strinfo *si)
164 if (si->next == 0)
165 return NULL;
166 strinfo *nextsi = get_strinfo (si->next);
167 if (nextsi == NULL || nextsi->first != si->first || nextsi->prev != si->idx)
168 return NULL;
169 return nextsi;
172 /* Helper function for get_stridx. */
174 static int
175 get_addr_stridx (tree exp, tree ptr)
177 HOST_WIDE_INT off;
178 struct stridxlist *list, *last = NULL;
179 tree base;
181 if (!decl_to_stridxlist_htab)
182 return 0;
184 base = get_addr_base_and_unit_offset (exp, &off);
185 if (base == NULL || !DECL_P (base))
186 return 0;
188 list = decl_to_stridxlist_htab->get (base);
189 if (list == NULL)
190 return 0;
194 if (list->offset == off)
195 return list->idx;
196 if (list->offset > off)
197 return 0;
198 last = list;
199 list = list->next;
201 while (list);
203 if (ptr && last && last->idx > 0)
205 strinfo *si = get_strinfo (last->idx);
206 if (si
207 && si->length
208 && TREE_CODE (si->length) == INTEGER_CST
209 && compare_tree_int (si->length, off - last->offset) != -1)
210 return get_stridx_plus_constant (si, off - last->offset, ptr);
212 return 0;
215 /* Return string index for EXP. */
217 static int
218 get_stridx (tree exp)
220 tree s, o;
222 if (TREE_CODE (exp) == SSA_NAME)
224 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
225 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
226 int i;
227 tree e = exp;
228 HOST_WIDE_INT off = 0;
229 for (i = 0; i < 5; i++)
231 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
232 if (!is_gimple_assign (def_stmt)
233 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
234 return 0;
235 tree rhs1 = gimple_assign_rhs1 (def_stmt);
236 tree rhs2 = gimple_assign_rhs2 (def_stmt);
237 if (TREE_CODE (rhs1) != SSA_NAME
238 || !tree_fits_shwi_p (rhs2))
239 return 0;
240 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
241 if (this_off < 0)
242 return 0;
243 off = (unsigned HOST_WIDE_INT) off + this_off;
244 if (off < 0)
245 return 0;
246 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
248 strinfo *si
249 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
250 if (si
251 && si->length
252 && TREE_CODE (si->length) == INTEGER_CST
253 && compare_tree_int (si->length, off) != -1)
254 return get_stridx_plus_constant (si, off, exp);
256 e = rhs1;
258 return 0;
261 if (TREE_CODE (exp) == ADDR_EXPR)
263 int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp);
264 if (idx != 0)
265 return idx;
268 s = string_constant (exp, &o);
269 if (s != NULL_TREE
270 && (o == NULL_TREE || tree_fits_shwi_p (o))
271 && TREE_STRING_LENGTH (s) > 0)
273 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
274 const char *p = TREE_STRING_POINTER (s);
275 int max = TREE_STRING_LENGTH (s) - 1;
277 if (p[max] == '\0' && offset >= 0 && offset <= max)
278 return ~(int) strlen (p + offset);
280 return 0;
283 /* Return true if strinfo vector is shared with the immediate dominator. */
285 static inline bool
286 strinfo_shared (void)
288 return vec_safe_length (stridx_to_strinfo)
289 && (*stridx_to_strinfo)[0] != NULL;
292 /* Unshare strinfo vector that is shared with the immediate dominator. */
294 static void
295 unshare_strinfo_vec (void)
297 strinfo *si;
298 unsigned int i = 0;
300 gcc_assert (strinfo_shared ());
301 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
302 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
303 if (si != NULL)
304 si->refcount++;
305 (*stridx_to_strinfo)[0] = NULL;
308 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
309 Return a pointer to the location where the string index can
310 be stored (if 0) or is stored, or NULL if this can't be tracked. */
312 static int *
313 addr_stridxptr (tree exp)
315 HOST_WIDE_INT off;
317 tree base = get_addr_base_and_unit_offset (exp, &off);
318 if (base == NULL_TREE || !DECL_P (base))
319 return NULL;
321 if (!decl_to_stridxlist_htab)
323 decl_to_stridxlist_htab
324 = new hash_map<tree_decl_hash, stridxlist> (64);
325 gcc_obstack_init (&stridx_obstack);
328 bool existed;
329 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
330 if (existed)
332 int i;
333 stridxlist *before = NULL;
334 for (i = 0; i < 32; i++)
336 if (list->offset == off)
337 return &list->idx;
338 if (list->offset > off && before == NULL)
339 before = list;
340 if (list->next == NULL)
341 break;
342 list = list->next;
344 if (i == 32)
345 return NULL;
346 if (before)
348 list = before;
349 before = XOBNEW (&stridx_obstack, struct stridxlist);
350 *before = *list;
351 list->next = before;
352 list->offset = off;
353 list->idx = 0;
354 return &list->idx;
356 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
357 list = list->next;
360 list->next = NULL;
361 list->offset = off;
362 list->idx = 0;
363 return &list->idx;
366 /* Create a new string index, or return 0 if reached limit. */
368 static int
369 new_stridx (tree exp)
371 int idx;
372 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
373 return 0;
374 if (TREE_CODE (exp) == SSA_NAME)
376 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
377 return 0;
378 idx = max_stridx++;
379 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
380 return idx;
382 if (TREE_CODE (exp) == ADDR_EXPR)
384 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
385 if (pidx != NULL)
387 gcc_assert (*pidx == 0);
388 *pidx = max_stridx++;
389 return *pidx;
392 return 0;
395 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
397 static int
398 new_addr_stridx (tree exp)
400 int *pidx;
401 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
402 return 0;
403 pidx = addr_stridxptr (exp);
404 if (pidx != NULL)
406 gcc_assert (*pidx == 0);
407 *pidx = max_stridx++;
408 return *pidx;
410 return 0;
413 /* Create a new strinfo. */
415 static strinfo *
416 new_strinfo (tree ptr, int idx, tree length)
418 strinfo *si = strinfo_pool.allocate ();
419 si->length = length;
420 si->ptr = ptr;
421 si->stmt = NULL;
422 si->endptr = NULL_TREE;
423 si->refcount = 1;
424 si->idx = idx;
425 si->first = 0;
426 si->prev = 0;
427 si->next = 0;
428 si->writable = false;
429 si->dont_invalidate = false;
430 return si;
433 /* Decrease strinfo refcount and free it if not referenced anymore. */
435 static inline void
436 free_strinfo (strinfo *si)
438 if (si && --si->refcount == 0)
439 strinfo_pool.remove (si);
442 /* Set strinfo in the vector entry IDX to SI. */
444 static inline void
445 set_strinfo (int idx, strinfo *si)
447 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
448 unshare_strinfo_vec ();
449 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
450 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
451 (*stridx_to_strinfo)[idx] = si;
454 /* Return string length, or NULL if it can't be computed. */
456 static tree
457 get_string_length (strinfo *si)
459 if (si->length)
460 return si->length;
462 if (si->stmt)
464 gimple *stmt = si->stmt, *lenstmt;
465 bool with_bounds = gimple_call_with_bounds_p (stmt);
466 tree callee, lhs, fn, tem;
467 location_t loc;
468 gimple_stmt_iterator gsi;
470 gcc_assert (is_gimple_call (stmt));
471 callee = gimple_call_fndecl (stmt);
472 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
473 lhs = gimple_call_lhs (stmt);
474 /* unshare_strinfo is intentionally not called here. The (delayed)
475 transformation of strcpy or strcat into stpcpy is done at the place
476 of the former strcpy/strcat call and so can affect all the strinfos
477 with the same stmt. If they were unshared before and transformation
478 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
479 just compute the right length. */
480 switch (DECL_FUNCTION_CODE (callee))
482 case BUILT_IN_STRCAT:
483 case BUILT_IN_STRCAT_CHK:
484 case BUILT_IN_STRCAT_CHKP:
485 case BUILT_IN_STRCAT_CHK_CHKP:
486 gsi = gsi_for_stmt (stmt);
487 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
488 gcc_assert (lhs == NULL_TREE);
489 tem = unshare_expr (gimple_call_arg (stmt, 0));
490 if (with_bounds)
492 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
493 2, tem, gimple_call_arg (stmt, 1));
494 gimple_call_set_with_bounds (lenstmt, true);
496 else
497 lenstmt = gimple_build_call (fn, 1, tem);
498 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
499 gimple_call_set_lhs (lenstmt, lhs);
500 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
501 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
502 tem = gimple_call_arg (stmt, 0);
503 if (!ptrofftype_p (TREE_TYPE (lhs)))
505 lhs = convert_to_ptrofftype (lhs);
506 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
507 true, GSI_SAME_STMT);
509 lenstmt = gimple_build_assign
510 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
511 POINTER_PLUS_EXPR,tem, lhs);
512 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
513 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
514 lhs = NULL_TREE;
515 /* FALLTHRU */
516 case BUILT_IN_STRCPY:
517 case BUILT_IN_STRCPY_CHK:
518 case BUILT_IN_STRCPY_CHKP:
519 case BUILT_IN_STRCPY_CHK_CHKP:
520 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
521 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
522 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
523 else
524 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
525 if (with_bounds)
526 fn = chkp_maybe_create_clone (fn)->decl;
527 gcc_assert (lhs == NULL_TREE);
528 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
530 fprintf (dump_file, "Optimizing: ");
531 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
533 gimple_call_set_fndecl (stmt, fn);
534 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
535 gimple_call_set_lhs (stmt, lhs);
536 update_stmt (stmt);
537 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
539 fprintf (dump_file, "into: ");
540 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
542 /* FALLTHRU */
543 case BUILT_IN_STPCPY:
544 case BUILT_IN_STPCPY_CHK:
545 case BUILT_IN_STPCPY_CHKP:
546 case BUILT_IN_STPCPY_CHK_CHKP:
547 gcc_assert (lhs != NULL_TREE);
548 loc = gimple_location (stmt);
549 si->endptr = lhs;
550 si->stmt = NULL;
551 lhs = fold_convert_loc (loc, size_type_node, lhs);
552 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
553 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
554 lhs, si->length);
555 break;
556 case BUILT_IN_MALLOC:
557 break;
558 /* BUILT_IN_CALLOC always has si->length set. */
559 default:
560 gcc_unreachable ();
561 break;
565 return si->length;
568 /* Invalidate string length information for strings whose length
569 might change due to stores in stmt. */
571 static bool
572 maybe_invalidate (gimple *stmt)
574 strinfo *si;
575 unsigned int i;
576 bool nonempty = false;
578 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
579 if (si != NULL)
581 if (!si->dont_invalidate)
583 ao_ref r;
584 /* Do not use si->length. */
585 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
586 if (stmt_may_clobber_ref_p_1 (stmt, &r))
588 set_strinfo (i, NULL);
589 free_strinfo (si);
590 continue;
593 si->dont_invalidate = false;
594 nonempty = true;
596 return nonempty;
599 /* Unshare strinfo record SI, if it has refcount > 1 or
600 if stridx_to_strinfo vector is shared with some other
601 bbs. */
603 static strinfo *
604 unshare_strinfo (strinfo *si)
606 strinfo *nsi;
608 if (si->refcount == 1 && !strinfo_shared ())
609 return si;
611 nsi = new_strinfo (si->ptr, si->idx, si->length);
612 nsi->stmt = si->stmt;
613 nsi->endptr = si->endptr;
614 nsi->first = si->first;
615 nsi->prev = si->prev;
616 nsi->next = si->next;
617 nsi->writable = si->writable;
618 set_strinfo (si->idx, nsi);
619 free_strinfo (si);
620 return nsi;
623 /* Return first strinfo in the related strinfo chain
624 if all strinfos in between belong to the chain, otherwise
625 NULL. */
627 static strinfo *
628 verify_related_strinfos (strinfo *origsi)
630 strinfo *si = origsi, *psi;
632 if (origsi->first == 0)
633 return NULL;
634 for (; si->prev; si = psi)
636 if (si->first != origsi->first)
637 return NULL;
638 psi = get_strinfo (si->prev);
639 if (psi == NULL)
640 return NULL;
641 if (psi->next != si->idx)
642 return NULL;
644 if (si->idx != si->first)
645 return NULL;
646 return si;
649 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
650 strinfo if there is any. Return it's idx, or 0 if no strinfo has
651 been created. */
653 static int
654 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
656 if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
657 return 0;
659 if (basesi->length == NULL_TREE
660 || TREE_CODE (basesi->length) != INTEGER_CST
661 || compare_tree_int (basesi->length, off) == -1
662 || !tree_fits_shwi_p (basesi->length))
663 return 0;
665 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
666 strinfo *si = basesi, *chainsi;
667 if (si->first || si->prev || si->next)
668 si = verify_related_strinfos (basesi);
669 if (si == NULL
670 || si->length == NULL_TREE
671 || TREE_CODE (si->length) != INTEGER_CST)
672 return 0;
674 if (TREE_CODE (ptr) == SSA_NAME
675 && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
676 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
678 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
679 for (chainsi = si; chainsi->next; chainsi = si)
681 si = get_next_strinfo (chainsi);
682 if (si == NULL
683 || si->length == NULL_TREE
684 || TREE_CODE (si->length) != INTEGER_CST)
685 break;
686 int r = compare_tree_int (si->length, len);
687 if (r != 1)
689 if (r == 0)
691 if (TREE_CODE (ptr) == SSA_NAME)
692 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
693 else
695 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
696 if (pidx != NULL && *pidx == 0)
697 *pidx = si->idx;
699 return si->idx;
701 break;
705 int idx = new_stridx (ptr);
706 if (idx == 0)
707 return 0;
708 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
709 set_strinfo (idx, si);
710 if (chainsi->next)
712 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
713 si->next = nextsi->idx;
714 nextsi->prev = idx;
716 chainsi = unshare_strinfo (chainsi);
717 if (chainsi->first == 0)
718 chainsi->first = chainsi->idx;
719 chainsi->next = idx;
720 if (chainsi->endptr == NULL_TREE && len == 0)
721 chainsi->endptr = ptr;
722 si->endptr = chainsi->endptr;
723 si->prev = chainsi->idx;
724 si->first = chainsi->first;
725 si->writable = chainsi->writable;
726 return si->idx;
729 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
730 to a zero-length string and if possible chain it to a related strinfo
731 chain whose part is or might be CHAINSI. */
733 static strinfo *
734 zero_length_string (tree ptr, strinfo *chainsi)
736 strinfo *si;
737 int idx;
738 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
739 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
740 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
741 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
743 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
744 return NULL;
745 if (chainsi != NULL)
747 si = verify_related_strinfos (chainsi);
748 if (si)
752 gcc_assert (si->length || si->stmt);
753 if (si->endptr == NULL_TREE)
755 si = unshare_strinfo (si);
756 si->endptr = ptr;
758 chainsi = si;
759 si = get_next_strinfo (si);
761 while (si != NULL);
762 if (chainsi->length && integer_zerop (chainsi->length))
764 if (chainsi->next)
766 chainsi = unshare_strinfo (chainsi);
767 chainsi->next = 0;
769 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
770 return chainsi;
773 else if (chainsi->first || chainsi->prev || chainsi->next)
775 chainsi = unshare_strinfo (chainsi);
776 chainsi->first = 0;
777 chainsi->prev = 0;
778 chainsi->next = 0;
781 idx = new_stridx (ptr);
782 if (idx == 0)
783 return NULL;
784 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
785 set_strinfo (idx, si);
786 si->endptr = ptr;
787 if (chainsi != NULL)
789 chainsi = unshare_strinfo (chainsi);
790 if (chainsi->first == 0)
791 chainsi->first = chainsi->idx;
792 chainsi->next = idx;
793 if (chainsi->endptr == NULL_TREE)
794 chainsi->endptr = ptr;
795 si->prev = chainsi->idx;
796 si->first = chainsi->first;
797 si->writable = chainsi->writable;
799 return si;
802 /* For strinfo ORIGSI whose length has been just updated
803 update also related strinfo lengths (add ADJ to each,
804 but don't adjust ORIGSI). */
806 static void
807 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
809 strinfo *si = verify_related_strinfos (origsi);
811 if (si == NULL)
812 return;
814 while (1)
816 strinfo *nsi;
818 if (si != origsi)
820 tree tem;
822 si = unshare_strinfo (si);
823 if (si->length)
825 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
826 si->length = fold_build2_loc (loc, PLUS_EXPR,
827 TREE_TYPE (si->length), si->length,
828 tem);
830 else if (si->stmt != NULL)
831 /* Delayed length computation is unaffected. */
833 else
834 gcc_unreachable ();
836 si->endptr = NULL_TREE;
837 si->dont_invalidate = true;
839 nsi = get_next_strinfo (si);
840 if (nsi == NULL)
841 return;
842 si = nsi;
846 /* Find if there are other SSA_NAME pointers equal to PTR
847 for which we don't track their string lengths yet. If so, use
848 IDX for them. */
850 static void
851 find_equal_ptrs (tree ptr, int idx)
853 if (TREE_CODE (ptr) != SSA_NAME)
854 return;
855 while (1)
857 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
858 if (!is_gimple_assign (stmt))
859 return;
860 ptr = gimple_assign_rhs1 (stmt);
861 switch (gimple_assign_rhs_code (stmt))
863 case SSA_NAME:
864 break;
865 CASE_CONVERT:
866 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
867 return;
868 if (TREE_CODE (ptr) == SSA_NAME)
869 break;
870 if (TREE_CODE (ptr) != ADDR_EXPR)
871 return;
872 /* FALLTHRU */
873 case ADDR_EXPR:
875 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
876 if (pidx != NULL && *pidx == 0)
877 *pidx = idx;
878 return;
880 default:
881 return;
884 /* We might find an endptr created in this pass. Grow the
885 vector in that case. */
886 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
887 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
889 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
890 return;
891 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
895 /* Return true if STMT is a call to a builtin function with the right
896 arguments and attributes that should be considered for optimization
897 by this pass. */
899 static bool
900 valid_builtin_call (gimple *stmt)
902 if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
903 return false;
905 tree callee = gimple_call_fndecl (stmt);
906 switch (DECL_FUNCTION_CODE (callee))
908 case BUILT_IN_MEMCMP:
909 case BUILT_IN_MEMCMP_EQ:
910 case BUILT_IN_STRCHR:
911 case BUILT_IN_STRCHR_CHKP:
912 case BUILT_IN_STRLEN:
913 case BUILT_IN_STRLEN_CHKP:
914 /* The above functions should be pure. Punt if they aren't. */
915 if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
916 return false;
917 break;
919 case BUILT_IN_CALLOC:
920 case BUILT_IN_MALLOC:
921 case BUILT_IN_MEMCPY:
922 case BUILT_IN_MEMCPY_CHK:
923 case BUILT_IN_MEMCPY_CHKP:
924 case BUILT_IN_MEMCPY_CHK_CHKP:
925 case BUILT_IN_MEMPCPY:
926 case BUILT_IN_MEMPCPY_CHK:
927 case BUILT_IN_MEMPCPY_CHKP:
928 case BUILT_IN_MEMPCPY_CHK_CHKP:
929 case BUILT_IN_MEMSET:
930 case BUILT_IN_STPCPY:
931 case BUILT_IN_STPCPY_CHK:
932 case BUILT_IN_STPCPY_CHKP:
933 case BUILT_IN_STPCPY_CHK_CHKP:
934 case BUILT_IN_STRCAT:
935 case BUILT_IN_STRCAT_CHK:
936 case BUILT_IN_STRCAT_CHKP:
937 case BUILT_IN_STRCAT_CHK_CHKP:
938 case BUILT_IN_STRCPY:
939 case BUILT_IN_STRCPY_CHK:
940 case BUILT_IN_STRCPY_CHKP:
941 case BUILT_IN_STRCPY_CHK_CHKP:
942 /* The above functions should be neither const nor pure. Punt if they
943 aren't. */
944 if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
945 return false;
946 break;
948 default:
949 break;
952 return true;
955 /* If the last .MEM setter statement before STMT is
956 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
957 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
958 just memcpy (x, y, strlen (y)). SI must be the zero length
959 strinfo. */
961 static void
962 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
964 tree vuse, callee, len;
965 struct laststmt_struct last = laststmt;
966 strinfo *lastsi, *firstsi;
967 unsigned len_arg_no = 2;
969 laststmt.stmt = NULL;
970 laststmt.len = NULL_TREE;
971 laststmt.stridx = 0;
973 if (last.stmt == NULL)
974 return;
976 vuse = gimple_vuse (stmt);
977 if (vuse == NULL_TREE
978 || SSA_NAME_DEF_STMT (vuse) != last.stmt
979 || !has_single_use (vuse))
980 return;
982 gcc_assert (last.stridx > 0);
983 lastsi = get_strinfo (last.stridx);
984 if (lastsi == NULL)
985 return;
987 if (lastsi != si)
989 if (lastsi->first == 0 || lastsi->first != si->first)
990 return;
992 firstsi = verify_related_strinfos (si);
993 if (firstsi == NULL)
994 return;
995 while (firstsi != lastsi)
997 firstsi = get_next_strinfo (firstsi);
998 if (firstsi == NULL)
999 return;
1003 if (!is_strcat)
1005 if (si->length == NULL_TREE || !integer_zerop (si->length))
1006 return;
1009 if (is_gimple_assign (last.stmt))
1011 gimple_stmt_iterator gsi;
1013 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
1014 return;
1015 if (stmt_could_throw_p (last.stmt))
1016 return;
1017 gsi = gsi_for_stmt (last.stmt);
1018 unlink_stmt_vdef (last.stmt);
1019 release_defs (last.stmt);
1020 gsi_remove (&gsi, true);
1021 return;
1024 if (!valid_builtin_call (last.stmt))
1025 return;
1027 callee = gimple_call_fndecl (last.stmt);
1028 switch (DECL_FUNCTION_CODE (callee))
1030 case BUILT_IN_MEMCPY:
1031 case BUILT_IN_MEMCPY_CHK:
1032 break;
1033 case BUILT_IN_MEMCPY_CHKP:
1034 case BUILT_IN_MEMCPY_CHK_CHKP:
1035 len_arg_no = 4;
1036 break;
1037 default:
1038 return;
1041 len = gimple_call_arg (last.stmt, len_arg_no);
1042 if (tree_fits_uhwi_p (len))
1044 if (!tree_fits_uhwi_p (last.len)
1045 || integer_zerop (len)
1046 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1047 return;
1048 /* Don't adjust the length if it is divisible by 4, it is more efficient
1049 to store the extra '\0' in that case. */
1050 if ((tree_to_uhwi (len) & 3) == 0)
1051 return;
1053 else if (TREE_CODE (len) == SSA_NAME)
1055 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1056 if (!is_gimple_assign (def_stmt)
1057 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1058 || gimple_assign_rhs1 (def_stmt) != last.len
1059 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1060 return;
1062 else
1063 return;
1065 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1066 update_stmt (last.stmt);
1069 /* Handle a strlen call. If strlen of the argument is known, replace
1070 the strlen call with the known value, otherwise remember that strlen
1071 of the argument is stored in the lhs SSA_NAME. */
1073 static void
1074 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1076 int idx;
1077 tree src;
1078 gimple *stmt = gsi_stmt (*gsi);
1079 tree lhs = gimple_call_lhs (stmt);
1081 if (lhs == NULL_TREE)
1082 return;
1084 src = gimple_call_arg (stmt, 0);
1085 idx = get_stridx (src);
1086 if (idx)
1088 strinfo *si = NULL;
1089 tree rhs;
1091 if (idx < 0)
1092 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1093 else
1095 rhs = NULL_TREE;
1096 si = get_strinfo (idx);
1097 if (si != NULL)
1098 rhs = get_string_length (si);
1100 if (rhs != NULL_TREE)
1102 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1104 fprintf (dump_file, "Optimizing: ");
1105 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1107 rhs = unshare_expr (rhs);
1108 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1109 rhs = fold_convert_loc (gimple_location (stmt),
1110 TREE_TYPE (lhs), rhs);
1111 if (!update_call_from_tree (gsi, rhs))
1112 gimplify_and_update_call_from_tree (gsi, rhs);
1113 stmt = gsi_stmt (*gsi);
1114 update_stmt (stmt);
1115 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1117 fprintf (dump_file, "into: ");
1118 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1120 if (si != NULL
1121 && TREE_CODE (si->length) != SSA_NAME
1122 && TREE_CODE (si->length) != INTEGER_CST
1123 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1125 si = unshare_strinfo (si);
1126 si->length = lhs;
1128 return;
1131 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1132 return;
1133 if (idx == 0)
1134 idx = new_stridx (src);
1135 else if (get_strinfo (idx) != NULL)
1136 return;
1137 if (idx)
1139 strinfo *si = new_strinfo (src, idx, lhs);
1140 set_strinfo (idx, si);
1141 find_equal_ptrs (src, idx);
1145 /* Handle a strchr call. If strlen of the first argument is known, replace
1146 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1147 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1149 static void
1150 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1152 int idx;
1153 tree src;
1154 gimple *stmt = gsi_stmt (*gsi);
1155 tree lhs = gimple_call_lhs (stmt);
1156 bool with_bounds = gimple_call_with_bounds_p (stmt);
1158 if (lhs == NULL_TREE)
1159 return;
1161 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1162 return;
1164 src = gimple_call_arg (stmt, 0);
1165 idx = get_stridx (src);
1166 if (idx)
1168 strinfo *si = NULL;
1169 tree rhs;
1171 if (idx < 0)
1172 rhs = build_int_cst (size_type_node, ~idx);
1173 else
1175 rhs = NULL_TREE;
1176 si = get_strinfo (idx);
1177 if (si != NULL)
1178 rhs = get_string_length (si);
1180 if (rhs != NULL_TREE)
1182 location_t loc = gimple_location (stmt);
1184 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1186 fprintf (dump_file, "Optimizing: ");
1187 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1189 if (si != NULL && si->endptr != NULL_TREE)
1191 rhs = unshare_expr (si->endptr);
1192 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1193 TREE_TYPE (rhs)))
1194 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1196 else
1198 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1199 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1200 TREE_TYPE (src), src, rhs);
1201 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1202 TREE_TYPE (rhs)))
1203 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1205 if (!update_call_from_tree (gsi, rhs))
1206 gimplify_and_update_call_from_tree (gsi, rhs);
1207 stmt = gsi_stmt (*gsi);
1208 update_stmt (stmt);
1209 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1211 fprintf (dump_file, "into: ");
1212 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1214 if (si != NULL
1215 && si->endptr == NULL_TREE
1216 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1218 si = unshare_strinfo (si);
1219 si->endptr = lhs;
1221 zero_length_string (lhs, si);
1222 return;
1225 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1226 return;
1227 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1229 if (idx == 0)
1230 idx = new_stridx (src);
1231 else if (get_strinfo (idx) != NULL)
1233 zero_length_string (lhs, NULL);
1234 return;
1236 if (idx)
1238 location_t loc = gimple_location (stmt);
1239 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1240 tree srcu = fold_convert_loc (loc, size_type_node, src);
1241 tree length = fold_build2_loc (loc, MINUS_EXPR,
1242 size_type_node, lhsu, srcu);
1243 strinfo *si = new_strinfo (src, idx, length);
1244 si->endptr = lhs;
1245 set_strinfo (idx, si);
1246 find_equal_ptrs (src, idx);
1247 zero_length_string (lhs, si);
1250 else
1251 zero_length_string (lhs, NULL);
1254 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1255 If strlen of the second argument is known, strlen of the first argument
1256 is the same after this call. Furthermore, attempt to convert it to
1257 memcpy. */
1259 static void
1260 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1262 int idx, didx;
1263 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1264 bool success;
1265 gimple *stmt = gsi_stmt (*gsi);
1266 strinfo *si, *dsi, *olddsi, *zsi;
1267 location_t loc;
1268 bool with_bounds = gimple_call_with_bounds_p (stmt);
1270 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1271 dst = gimple_call_arg (stmt, 0);
1272 lhs = gimple_call_lhs (stmt);
1273 idx = get_stridx (src);
1274 si = NULL;
1275 if (idx > 0)
1276 si = get_strinfo (idx);
1278 didx = get_stridx (dst);
1279 olddsi = NULL;
1280 oldlen = NULL_TREE;
1281 if (didx > 0)
1282 olddsi = get_strinfo (didx);
1283 else if (didx < 0)
1284 return;
1286 if (olddsi != NULL)
1287 adjust_last_stmt (olddsi, stmt, false);
1289 srclen = NULL_TREE;
1290 if (si != NULL)
1291 srclen = get_string_length (si);
1292 else if (idx < 0)
1293 srclen = build_int_cst (size_type_node, ~idx);
1295 loc = gimple_location (stmt);
1296 if (srclen == NULL_TREE)
1297 switch (bcode)
1299 case BUILT_IN_STRCPY:
1300 case BUILT_IN_STRCPY_CHK:
1301 case BUILT_IN_STRCPY_CHKP:
1302 case BUILT_IN_STRCPY_CHK_CHKP:
1303 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1304 return;
1305 break;
1306 case BUILT_IN_STPCPY:
1307 case BUILT_IN_STPCPY_CHK:
1308 case BUILT_IN_STPCPY_CHKP:
1309 case BUILT_IN_STPCPY_CHK_CHKP:
1310 if (lhs == NULL_TREE)
1311 return;
1312 else
1314 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1315 srclen = fold_convert_loc (loc, size_type_node, dst);
1316 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1317 lhsuint, srclen);
1319 break;
1320 default:
1321 gcc_unreachable ();
1324 if (didx == 0)
1326 didx = new_stridx (dst);
1327 if (didx == 0)
1328 return;
1330 if (olddsi != NULL)
1332 oldlen = olddsi->length;
1333 dsi = unshare_strinfo (olddsi);
1334 dsi->length = srclen;
1335 /* Break the chain, so adjust_related_strinfo on later pointers in
1336 the chain won't adjust this one anymore. */
1337 dsi->next = 0;
1338 dsi->stmt = NULL;
1339 dsi->endptr = NULL_TREE;
1341 else
1343 dsi = new_strinfo (dst, didx, srclen);
1344 set_strinfo (didx, dsi);
1345 find_equal_ptrs (dst, didx);
1347 dsi->writable = true;
1348 dsi->dont_invalidate = true;
1350 if (dsi->length == NULL_TREE)
1352 strinfo *chainsi;
1354 /* If string length of src is unknown, use delayed length
1355 computation. If string lenth of dst will be needed, it
1356 can be computed by transforming this strcpy call into
1357 stpcpy and subtracting dst from the return value. */
1359 /* Look for earlier strings whose length could be determined if
1360 this strcpy is turned into an stpcpy. */
1362 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1364 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1366 /* When setting a stmt for delayed length computation
1367 prevent all strinfos through dsi from being
1368 invalidated. */
1369 chainsi = unshare_strinfo (chainsi);
1370 chainsi->stmt = stmt;
1371 chainsi->length = NULL_TREE;
1372 chainsi->endptr = NULL_TREE;
1373 chainsi->dont_invalidate = true;
1376 dsi->stmt = stmt;
1377 return;
1380 if (olddsi != NULL)
1382 tree adj = NULL_TREE;
1383 if (oldlen == NULL_TREE)
1385 else if (integer_zerop (oldlen))
1386 adj = srclen;
1387 else if (TREE_CODE (oldlen) == INTEGER_CST
1388 || TREE_CODE (srclen) == INTEGER_CST)
1389 adj = fold_build2_loc (loc, MINUS_EXPR,
1390 TREE_TYPE (srclen), srclen,
1391 fold_convert_loc (loc, TREE_TYPE (srclen),
1392 oldlen));
1393 if (adj != NULL_TREE)
1394 adjust_related_strinfos (loc, dsi, adj);
1395 else
1396 dsi->prev = 0;
1398 /* strcpy src may not overlap dst, so src doesn't need to be
1399 invalidated either. */
1400 if (si != NULL)
1401 si->dont_invalidate = true;
1403 fn = NULL_TREE;
1404 zsi = NULL;
1405 switch (bcode)
1407 case BUILT_IN_STRCPY:
1408 case BUILT_IN_STRCPY_CHKP:
1409 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1410 if (lhs)
1411 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1412 break;
1413 case BUILT_IN_STRCPY_CHK:
1414 case BUILT_IN_STRCPY_CHK_CHKP:
1415 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1416 if (lhs)
1417 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1418 break;
1419 case BUILT_IN_STPCPY:
1420 case BUILT_IN_STPCPY_CHKP:
1421 /* This would need adjustment of the lhs (subtract one),
1422 or detection that the trailing '\0' doesn't need to be
1423 written, if it will be immediately overwritten.
1424 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1425 if (lhs)
1427 dsi->endptr = lhs;
1428 zsi = zero_length_string (lhs, dsi);
1430 break;
1431 case BUILT_IN_STPCPY_CHK:
1432 case BUILT_IN_STPCPY_CHK_CHKP:
1433 /* This would need adjustment of the lhs (subtract one),
1434 or detection that the trailing '\0' doesn't need to be
1435 written, if it will be immediately overwritten.
1436 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1437 if (lhs)
1439 dsi->endptr = lhs;
1440 zsi = zero_length_string (lhs, dsi);
1442 break;
1443 default:
1444 gcc_unreachable ();
1446 if (zsi != NULL)
1447 zsi->dont_invalidate = true;
1449 if (fn == NULL_TREE)
1450 return;
1452 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1453 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1455 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1456 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1457 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1458 GSI_SAME_STMT);
1459 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1461 fprintf (dump_file, "Optimizing: ");
1462 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1464 if (with_bounds)
1466 fn = chkp_maybe_create_clone (fn)->decl;
1467 if (gimple_call_num_args (stmt) == 4)
1468 success = update_gimple_call (gsi, fn, 5, dst,
1469 gimple_call_arg (stmt, 1),
1470 src,
1471 gimple_call_arg (stmt, 3),
1472 len);
1473 else
1474 success = update_gimple_call (gsi, fn, 6, dst,
1475 gimple_call_arg (stmt, 1),
1476 src,
1477 gimple_call_arg (stmt, 3),
1478 len,
1479 gimple_call_arg (stmt, 4));
1481 else
1482 if (gimple_call_num_args (stmt) == 2)
1483 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1484 else
1485 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1486 gimple_call_arg (stmt, 2));
1487 if (success)
1489 stmt = gsi_stmt (*gsi);
1490 gimple_call_set_with_bounds (stmt, with_bounds);
1491 update_stmt (stmt);
1492 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1494 fprintf (dump_file, "into: ");
1495 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1497 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1498 laststmt.stmt = stmt;
1499 laststmt.len = srclen;
1500 laststmt.stridx = dsi->idx;
1502 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1503 fprintf (dump_file, "not possible.\n");
1506 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1507 If strlen of the second argument is known and length of the third argument
1508 is that plus one, strlen of the first argument is the same after this
1509 call. */
1511 static void
1512 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1514 int idx, didx;
1515 tree src, dst, len, lhs, oldlen, newlen;
1516 gimple *stmt = gsi_stmt (*gsi);
1517 strinfo *si, *dsi, *olddsi;
1518 bool with_bounds = gimple_call_with_bounds_p (stmt);
1520 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1521 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1522 dst = gimple_call_arg (stmt, 0);
1523 idx = get_stridx (src);
1524 if (idx == 0)
1525 return;
1527 didx = get_stridx (dst);
1528 olddsi = NULL;
1529 if (didx > 0)
1530 olddsi = get_strinfo (didx);
1531 else if (didx < 0)
1532 return;
1534 if (olddsi != NULL
1535 && tree_fits_uhwi_p (len)
1536 && !integer_zerop (len))
1537 adjust_last_stmt (olddsi, stmt, false);
1539 if (idx > 0)
1541 gimple *def_stmt;
1543 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1544 si = get_strinfo (idx);
1545 if (si == NULL || si->length == NULL_TREE)
1546 return;
1547 if (TREE_CODE (len) != SSA_NAME)
1548 return;
1549 def_stmt = SSA_NAME_DEF_STMT (len);
1550 if (!is_gimple_assign (def_stmt)
1551 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1552 || gimple_assign_rhs1 (def_stmt) != si->length
1553 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1554 return;
1556 else
1558 si = NULL;
1559 /* Handle memcpy (x, "abcd", 5) or
1560 memcpy (x, "abc\0uvw", 7). */
1561 if (!tree_fits_uhwi_p (len)
1562 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1563 return;
1566 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1567 adjust_last_stmt (olddsi, stmt, false);
1569 if (didx == 0)
1571 didx = new_stridx (dst);
1572 if (didx == 0)
1573 return;
1575 if (si != NULL)
1576 newlen = si->length;
1577 else
1578 newlen = build_int_cst (size_type_node, ~idx);
1579 oldlen = NULL_TREE;
1580 if (olddsi != NULL)
1582 dsi = unshare_strinfo (olddsi);
1583 oldlen = olddsi->length;
1584 dsi->length = newlen;
1585 /* Break the chain, so adjust_related_strinfo on later pointers in
1586 the chain won't adjust this one anymore. */
1587 dsi->next = 0;
1588 dsi->stmt = NULL;
1589 dsi->endptr = NULL_TREE;
1591 else
1593 dsi = new_strinfo (dst, didx, newlen);
1594 set_strinfo (didx, dsi);
1595 find_equal_ptrs (dst, didx);
1597 dsi->writable = true;
1598 dsi->dont_invalidate = true;
1599 if (olddsi != NULL)
1601 tree adj = NULL_TREE;
1602 location_t loc = gimple_location (stmt);
1603 if (oldlen == NULL_TREE)
1605 else if (integer_zerop (oldlen))
1606 adj = dsi->length;
1607 else if (TREE_CODE (oldlen) == INTEGER_CST
1608 || TREE_CODE (dsi->length) == INTEGER_CST)
1609 adj = fold_build2_loc (loc, MINUS_EXPR,
1610 TREE_TYPE (dsi->length), dsi->length,
1611 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1612 oldlen));
1613 if (adj != NULL_TREE)
1614 adjust_related_strinfos (loc, dsi, adj);
1615 else
1616 dsi->prev = 0;
1618 /* memcpy src may not overlap dst, so src doesn't need to be
1619 invalidated either. */
1620 if (si != NULL)
1621 si->dont_invalidate = true;
1623 lhs = gimple_call_lhs (stmt);
1624 switch (bcode)
1626 case BUILT_IN_MEMCPY:
1627 case BUILT_IN_MEMCPY_CHK:
1628 case BUILT_IN_MEMCPY_CHKP:
1629 case BUILT_IN_MEMCPY_CHK_CHKP:
1630 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1631 laststmt.stmt = stmt;
1632 laststmt.len = dsi->length;
1633 laststmt.stridx = dsi->idx;
1634 if (lhs)
1635 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1636 break;
1637 case BUILT_IN_MEMPCPY:
1638 case BUILT_IN_MEMPCPY_CHK:
1639 case BUILT_IN_MEMPCPY_CHKP:
1640 case BUILT_IN_MEMPCPY_CHK_CHKP:
1641 break;
1642 default:
1643 gcc_unreachable ();
1647 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1648 If strlen of the second argument is known, strlen of the first argument
1649 is increased by the length of the second argument. Furthermore, attempt
1650 to convert it to memcpy/strcpy if the length of the first argument
1651 is known. */
1653 static void
1654 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1656 int idx, didx;
1657 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1658 bool success;
1659 gimple *stmt = gsi_stmt (*gsi);
1660 strinfo *si, *dsi;
1661 location_t loc;
1662 bool with_bounds = gimple_call_with_bounds_p (stmt);
1664 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1665 dst = gimple_call_arg (stmt, 0);
1666 lhs = gimple_call_lhs (stmt);
1668 didx = get_stridx (dst);
1669 if (didx < 0)
1670 return;
1672 dsi = NULL;
1673 if (didx > 0)
1674 dsi = get_strinfo (didx);
1675 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1677 /* strcat (p, q) can be transformed into
1678 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1679 with length endptr - p if we need to compute the length
1680 later on. Don't do this transformation if we don't need
1681 it. */
1682 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1684 if (didx == 0)
1686 didx = new_stridx (dst);
1687 if (didx == 0)
1688 return;
1690 if (dsi == NULL)
1692 dsi = new_strinfo (dst, didx, NULL_TREE);
1693 set_strinfo (didx, dsi);
1694 find_equal_ptrs (dst, didx);
1696 else
1698 dsi = unshare_strinfo (dsi);
1699 dsi->length = NULL_TREE;
1700 dsi->next = 0;
1701 dsi->endptr = NULL_TREE;
1703 dsi->writable = true;
1704 dsi->stmt = stmt;
1705 dsi->dont_invalidate = true;
1707 return;
1710 srclen = NULL_TREE;
1711 si = NULL;
1712 idx = get_stridx (src);
1713 if (idx < 0)
1714 srclen = build_int_cst (size_type_node, ~idx);
1715 else if (idx > 0)
1717 si = get_strinfo (idx);
1718 if (si != NULL)
1719 srclen = get_string_length (si);
1722 loc = gimple_location (stmt);
1723 dstlen = dsi->length;
1724 endptr = dsi->endptr;
1726 dsi = unshare_strinfo (dsi);
1727 dsi->endptr = NULL_TREE;
1728 dsi->stmt = NULL;
1729 dsi->writable = true;
1731 if (srclen != NULL_TREE)
1733 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1734 dsi->length, srclen);
1735 adjust_related_strinfos (loc, dsi, srclen);
1736 dsi->dont_invalidate = true;
1738 else
1740 dsi->length = NULL;
1741 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1742 dsi->dont_invalidate = true;
1745 if (si != NULL)
1746 /* strcat src may not overlap dst, so src doesn't need to be
1747 invalidated either. */
1748 si->dont_invalidate = true;
1750 /* For now. Could remove the lhs from the call and add
1751 lhs = dst; afterwards. */
1752 if (lhs)
1753 return;
1755 fn = NULL_TREE;
1756 objsz = NULL_TREE;
1757 switch (bcode)
1759 case BUILT_IN_STRCAT:
1760 case BUILT_IN_STRCAT_CHKP:
1761 if (srclen != NULL_TREE)
1762 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1763 else
1764 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1765 break;
1766 case BUILT_IN_STRCAT_CHK:
1767 case BUILT_IN_STRCAT_CHK_CHKP:
1768 if (srclen != NULL_TREE)
1769 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1770 else
1771 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1772 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1773 break;
1774 default:
1775 gcc_unreachable ();
1778 if (fn == NULL_TREE)
1779 return;
1781 len = NULL_TREE;
1782 if (srclen != NULL_TREE)
1784 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1785 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1787 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1788 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1789 build_int_cst (type, 1));
1790 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1791 GSI_SAME_STMT);
1793 if (endptr)
1794 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1795 else
1796 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1797 TREE_TYPE (dst), unshare_expr (dst),
1798 fold_convert_loc (loc, sizetype,
1799 unshare_expr (dstlen)));
1800 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1801 GSI_SAME_STMT);
1802 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1804 fprintf (dump_file, "Optimizing: ");
1805 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1807 if (with_bounds)
1809 fn = chkp_maybe_create_clone (fn)->decl;
1810 if (srclen != NULL_TREE)
1811 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1812 dst,
1813 gimple_call_arg (stmt, 1),
1814 src,
1815 gimple_call_arg (stmt, 3),
1816 len, objsz);
1817 else
1818 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1819 dst,
1820 gimple_call_arg (stmt, 1),
1821 src,
1822 gimple_call_arg (stmt, 3),
1823 objsz);
1825 else
1826 if (srclen != NULL_TREE)
1827 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1828 dst, src, len, objsz);
1829 else
1830 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1831 dst, src, objsz);
1832 if (success)
1834 stmt = gsi_stmt (*gsi);
1835 gimple_call_set_with_bounds (stmt, with_bounds);
1836 update_stmt (stmt);
1837 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1839 fprintf (dump_file, "into: ");
1840 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1842 /* If srclen == NULL, note that current string length can be
1843 computed by transforming this strcpy into stpcpy. */
1844 if (srclen == NULL_TREE && dsi->dont_invalidate)
1845 dsi->stmt = stmt;
1846 adjust_last_stmt (dsi, stmt, true);
1847 if (srclen != NULL_TREE)
1849 laststmt.stmt = stmt;
1850 laststmt.len = srclen;
1851 laststmt.stridx = dsi->idx;
1854 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1855 fprintf (dump_file, "not possible.\n");
1858 /* Handle a call to malloc or calloc. */
1860 static void
1861 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1863 gimple *stmt = gsi_stmt (*gsi);
1864 tree lhs = gimple_call_lhs (stmt);
1865 if (lhs == NULL_TREE)
1866 return;
1868 gcc_assert (get_stridx (lhs) == 0);
1869 int idx = new_stridx (lhs);
1870 tree length = NULL_TREE;
1871 if (bcode == BUILT_IN_CALLOC)
1872 length = build_int_cst (size_type_node, 0);
1873 strinfo *si = new_strinfo (lhs, idx, length);
1874 if (bcode == BUILT_IN_CALLOC)
1875 si->endptr = lhs;
1876 set_strinfo (idx, si);
1877 si->writable = true;
1878 si->stmt = stmt;
1879 si->dont_invalidate = true;
1882 /* Handle a call to memset.
1883 After a call to calloc, memset(,0,) is unnecessary.
1884 memset(malloc(n),0,n) is calloc(n,1). */
1886 static bool
1887 handle_builtin_memset (gimple_stmt_iterator *gsi)
1889 gimple *stmt2 = gsi_stmt (*gsi);
1890 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1891 return true;
1892 tree ptr = gimple_call_arg (stmt2, 0);
1893 int idx1 = get_stridx (ptr);
1894 if (idx1 <= 0)
1895 return true;
1896 strinfo *si1 = get_strinfo (idx1);
1897 if (!si1)
1898 return true;
1899 gimple *stmt1 = si1->stmt;
1900 if (!stmt1 || !is_gimple_call (stmt1))
1901 return true;
1902 tree callee1 = gimple_call_fndecl (stmt1);
1903 if (!valid_builtin_call (stmt1))
1904 return true;
1905 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1906 tree size = gimple_call_arg (stmt2, 2);
1907 if (code1 == BUILT_IN_CALLOC)
1908 /* Not touching stmt1 */ ;
1909 else if (code1 == BUILT_IN_MALLOC
1910 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1912 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1913 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1914 size, build_one_cst (size_type_node));
1915 si1->length = build_int_cst (size_type_node, 0);
1916 si1->stmt = gsi_stmt (gsi1);
1918 else
1919 return true;
1920 tree lhs = gimple_call_lhs (stmt2);
1921 unlink_stmt_vdef (stmt2);
1922 if (lhs)
1924 gimple *assign = gimple_build_assign (lhs, ptr);
1925 gsi_replace (gsi, assign, false);
1927 else
1929 gsi_remove (gsi, true);
1930 release_defs (stmt2);
1933 return false;
1936 /* Handle a call to memcmp. We try to handle small comparisons by
1937 converting them to load and compare, and replacing the call to memcmp
1938 with a __builtin_memcmp_eq call where possible. */
1940 static bool
1941 handle_builtin_memcmp (gimple_stmt_iterator *gsi)
1943 gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
1944 tree res = gimple_call_lhs (stmt2);
1945 tree arg1 = gimple_call_arg (stmt2, 0);
1946 tree arg2 = gimple_call_arg (stmt2, 1);
1947 tree len = gimple_call_arg (stmt2, 2);
1948 unsigned HOST_WIDE_INT leni;
1949 use_operand_p use_p;
1950 imm_use_iterator iter;
1952 if (!res)
1953 return true;
1955 FOR_EACH_IMM_USE_FAST (use_p, iter, res)
1957 gimple *ustmt = USE_STMT (use_p);
1959 if (is_gimple_debug (ustmt))
1960 continue;
1961 if (gimple_code (ustmt) == GIMPLE_ASSIGN)
1963 gassign *asgn = as_a <gassign *> (ustmt);
1964 tree_code code = gimple_assign_rhs_code (asgn);
1965 if ((code != EQ_EXPR && code != NE_EXPR)
1966 || !integer_zerop (gimple_assign_rhs2 (asgn)))
1967 return true;
1969 else if (gimple_code (ustmt) == GIMPLE_COND)
1971 tree_code code = gimple_cond_code (ustmt);
1972 if ((code != EQ_EXPR && code != NE_EXPR)
1973 || !integer_zerop (gimple_cond_rhs (ustmt)))
1974 return true;
1976 else
1977 return true;
1980 if (tree_fits_uhwi_p (len)
1981 && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
1982 && pow2p_hwi (leni))
1984 leni *= CHAR_TYPE_SIZE;
1985 unsigned align1 = get_pointer_alignment (arg1);
1986 unsigned align2 = get_pointer_alignment (arg2);
1987 unsigned align = MIN (align1, align2);
1988 machine_mode mode = mode_for_size (leni, MODE_INT, 1);
1989 if (mode != BLKmode
1990 && (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align)))
1992 location_t loc = gimple_location (stmt2);
1993 tree type, off;
1994 type = build_nonstandard_integer_type (leni, 1);
1995 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
1996 tree ptrtype = build_pointer_type_for_mode (char_type_node,
1997 ptr_mode, true);
1998 off = build_int_cst (ptrtype, 0);
1999 arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
2000 arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
2001 tree tem1 = fold_const_aggregate_ref (arg1);
2002 if (tem1)
2003 arg1 = tem1;
2004 tree tem2 = fold_const_aggregate_ref (arg2);
2005 if (tem2)
2006 arg2 = tem2;
2007 res = fold_convert_loc (loc, TREE_TYPE (res),
2008 fold_build2_loc (loc, NE_EXPR,
2009 boolean_type_node,
2010 arg1, arg2));
2011 gimplify_and_update_call_from_tree (gsi, res);
2012 return false;
2016 gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
2017 return false;
2020 /* Handle a POINTER_PLUS_EXPR statement.
2021 For p = "abcd" + 2; compute associated length, or if
2022 p = q + off is pointing to a '\0' character of a string, call
2023 zero_length_string on it. */
2025 static void
2026 handle_pointer_plus (gimple_stmt_iterator *gsi)
2028 gimple *stmt = gsi_stmt (*gsi);
2029 tree lhs = gimple_assign_lhs (stmt), off;
2030 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2031 strinfo *si, *zsi;
2033 if (idx == 0)
2034 return;
2036 if (idx < 0)
2038 tree off = gimple_assign_rhs2 (stmt);
2039 if (tree_fits_uhwi_p (off)
2040 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
2041 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
2042 = ~(~idx - (int) tree_to_uhwi (off));
2043 return;
2046 si = get_strinfo (idx);
2047 if (si == NULL || si->length == NULL_TREE)
2048 return;
2050 off = gimple_assign_rhs2 (stmt);
2051 zsi = NULL;
2052 if (operand_equal_p (si->length, off, 0))
2053 zsi = zero_length_string (lhs, si);
2054 else if (TREE_CODE (off) == SSA_NAME)
2056 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
2057 if (gimple_assign_single_p (def_stmt)
2058 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
2059 zsi = zero_length_string (lhs, si);
2061 if (zsi != NULL
2062 && si->endptr != NULL_TREE
2063 && si->endptr != lhs
2064 && TREE_CODE (si->endptr) == SSA_NAME)
2066 enum tree_code rhs_code
2067 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
2068 ? SSA_NAME : NOP_EXPR;
2069 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
2070 gcc_assert (gsi_stmt (*gsi) == stmt);
2071 update_stmt (stmt);
2075 /* Handle a single character store. */
2077 static bool
2078 handle_char_store (gimple_stmt_iterator *gsi)
2080 int idx = -1;
2081 strinfo *si = NULL;
2082 gimple *stmt = gsi_stmt (*gsi);
2083 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
2085 if (TREE_CODE (lhs) == MEM_REF
2086 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
2088 if (integer_zerop (TREE_OPERAND (lhs, 1)))
2090 ssaname = TREE_OPERAND (lhs, 0);
2091 idx = get_stridx (ssaname);
2094 else
2095 idx = get_addr_stridx (lhs, NULL_TREE);
2097 if (idx > 0)
2099 si = get_strinfo (idx);
2100 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
2102 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
2104 /* When storing '\0', the store can be removed
2105 if we know it has been stored in the current function. */
2106 if (!stmt_could_throw_p (stmt) && si->writable)
2108 unlink_stmt_vdef (stmt);
2109 release_defs (stmt);
2110 gsi_remove (gsi, true);
2111 return false;
2113 else
2115 si->writable = true;
2116 gsi_next (gsi);
2117 return false;
2120 else
2121 /* Otherwise this statement overwrites the '\0' with
2122 something, if the previous stmt was a memcpy,
2123 its length may be decreased. */
2124 adjust_last_stmt (si, stmt, false);
2126 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
2128 si = unshare_strinfo (si);
2129 si->length = build_int_cst (size_type_node, 0);
2130 si->endptr = NULL;
2131 si->prev = 0;
2132 si->next = 0;
2133 si->stmt = NULL;
2134 si->first = 0;
2135 si->writable = true;
2136 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2137 si->endptr = ssaname;
2138 si->dont_invalidate = true;
2140 /* If si->length is non-zero constant, we aren't overwriting '\0',
2141 and if we aren't storing '\0', we know that the length of the
2142 string and any other zero terminated string in memory remains
2143 the same. In that case we move to the next gimple statement and
2144 return to signal the caller that it shouldn't invalidate anything.
2146 This is benefical for cases like:
2148 char p[20];
2149 void foo (char *q)
2151 strcpy (p, "foobar");
2152 size_t len = strlen (p); // This can be optimized into 6
2153 size_t len2 = strlen (q); // This has to be computed
2154 p[0] = 'X';
2155 size_t len3 = strlen (p); // This can be optimized into 6
2156 size_t len4 = strlen (q); // This can be optimized into len2
2157 bar (len, len2, len3, len4);
2160 else if (si != NULL && si->length != NULL_TREE
2161 && TREE_CODE (si->length) == INTEGER_CST
2162 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2164 gsi_next (gsi);
2165 return false;
2168 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2170 if (ssaname)
2172 si = zero_length_string (ssaname, NULL);
2173 if (si != NULL)
2174 si->dont_invalidate = true;
2176 else
2178 int idx = new_addr_stridx (lhs);
2179 if (idx != 0)
2181 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2182 build_int_cst (size_type_node, 0));
2183 set_strinfo (idx, si);
2184 si->dont_invalidate = true;
2187 if (si != NULL)
2188 si->writable = true;
2190 else if (idx == 0
2191 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2192 && ssaname == NULL_TREE
2193 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2195 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2196 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2197 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2199 int idx = new_addr_stridx (lhs);
2200 if (idx != 0)
2202 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2203 build_int_cst (size_type_node, l));
2204 set_strinfo (idx, si);
2205 si->dont_invalidate = true;
2210 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2212 /* Allow adjust_last_stmt to remove it if the stored '\0'
2213 is immediately overwritten. */
2214 laststmt.stmt = stmt;
2215 laststmt.len = build_int_cst (size_type_node, 1);
2216 laststmt.stridx = si->idx;
2218 return true;
2221 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0. */
2223 static void
2224 fold_strstr_to_strncmp (tree rhs1, tree rhs2, gimple *stmt)
2226 if (TREE_CODE (rhs1) != SSA_NAME
2227 || TREE_CODE (rhs2) != SSA_NAME)
2228 return;
2230 gimple *call_stmt = NULL;
2231 for (int pass = 0; pass < 2; pass++)
2233 gimple *g = SSA_NAME_DEF_STMT (rhs1);
2234 if (gimple_call_builtin_p (g, BUILT_IN_STRSTR)
2235 && has_single_use (rhs1)
2236 && gimple_call_arg (g, 0) == rhs2)
2238 call_stmt = g;
2239 break;
2241 std::swap (rhs1, rhs2);
2244 if (call_stmt)
2246 tree arg0 = gimple_call_arg (call_stmt, 0);
2248 if (arg0 == rhs2)
2250 tree arg1 = gimple_call_arg (call_stmt, 1);
2251 tree arg1_len = NULL_TREE;
2252 int idx = get_stridx (arg1);
2254 if (idx)
2256 if (idx < 0)
2257 arg1_len = build_int_cst (size_type_node, ~idx);
2258 else
2260 strinfo *si = get_strinfo (idx);
2261 if (si)
2262 arg1_len = get_string_length (si);
2266 if (arg1_len != NULL_TREE)
2268 gimple_stmt_iterator gsi = gsi_for_stmt (call_stmt);
2269 tree strncmp_decl = builtin_decl_explicit (BUILT_IN_STRNCMP);
2270 gcall *strncmp_call = gimple_build_call (strncmp_decl, 3,
2271 arg0, arg1, arg1_len);
2272 tree strncmp_lhs = make_ssa_name (integer_type_node);
2273 gimple_set_vuse (strncmp_call, gimple_vuse (call_stmt));
2274 gimple_call_set_lhs (strncmp_call, strncmp_lhs);
2275 gsi_remove (&gsi, true);
2276 gsi_insert_before (&gsi, strncmp_call, GSI_SAME_STMT);
2277 tree zero = build_zero_cst (TREE_TYPE (strncmp_lhs));
2279 if (is_gimple_assign (stmt))
2281 if (gimple_assign_rhs_code (stmt) == COND_EXPR)
2283 tree cond = gimple_assign_rhs1 (stmt);
2284 TREE_OPERAND (cond, 0) = strncmp_lhs;
2285 TREE_OPERAND (cond, 1) = zero;
2287 else
2289 gimple_assign_set_rhs1 (stmt, strncmp_lhs);
2290 gimple_assign_set_rhs2 (stmt, zero);
2293 else
2295 gcond *cond = as_a<gcond *> (stmt);
2296 gimple_cond_set_lhs (cond, strncmp_lhs);
2297 gimple_cond_set_rhs (cond, zero);
2299 update_stmt (stmt);
2305 /* Attempt to optimize a single statement at *GSI using string length
2306 knowledge. */
2308 static bool
2309 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2311 gimple *stmt = gsi_stmt (*gsi);
2313 if (is_gimple_call (stmt))
2315 tree callee = gimple_call_fndecl (stmt);
2316 if (valid_builtin_call (stmt))
2317 switch (DECL_FUNCTION_CODE (callee))
2319 case BUILT_IN_STRLEN:
2320 case BUILT_IN_STRLEN_CHKP:
2321 handle_builtin_strlen (gsi);
2322 break;
2323 case BUILT_IN_STRCHR:
2324 case BUILT_IN_STRCHR_CHKP:
2325 handle_builtin_strchr (gsi);
2326 break;
2327 case BUILT_IN_STRCPY:
2328 case BUILT_IN_STRCPY_CHK:
2329 case BUILT_IN_STPCPY:
2330 case BUILT_IN_STPCPY_CHK:
2331 case BUILT_IN_STRCPY_CHKP:
2332 case BUILT_IN_STRCPY_CHK_CHKP:
2333 case BUILT_IN_STPCPY_CHKP:
2334 case BUILT_IN_STPCPY_CHK_CHKP:
2335 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2336 break;
2337 case BUILT_IN_MEMCPY:
2338 case BUILT_IN_MEMCPY_CHK:
2339 case BUILT_IN_MEMPCPY:
2340 case BUILT_IN_MEMPCPY_CHK:
2341 case BUILT_IN_MEMCPY_CHKP:
2342 case BUILT_IN_MEMCPY_CHK_CHKP:
2343 case BUILT_IN_MEMPCPY_CHKP:
2344 case BUILT_IN_MEMPCPY_CHK_CHKP:
2345 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2346 break;
2347 case BUILT_IN_STRCAT:
2348 case BUILT_IN_STRCAT_CHK:
2349 case BUILT_IN_STRCAT_CHKP:
2350 case BUILT_IN_STRCAT_CHK_CHKP:
2351 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2352 break;
2353 case BUILT_IN_MALLOC:
2354 case BUILT_IN_CALLOC:
2355 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2356 break;
2357 case BUILT_IN_MEMSET:
2358 if (!handle_builtin_memset (gsi))
2359 return false;
2360 break;
2361 case BUILT_IN_MEMCMP:
2362 if (!handle_builtin_memcmp (gsi))
2363 return false;
2364 break;
2365 default:
2366 break;
2369 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2371 tree lhs = gimple_assign_lhs (stmt);
2373 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2375 if (gimple_assign_single_p (stmt)
2376 || (gimple_assign_cast_p (stmt)
2377 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2379 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2380 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2382 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2383 handle_pointer_plus (gsi);
2385 else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
2387 enum tree_code code = gimple_assign_rhs_code (stmt);
2388 if (code == COND_EXPR)
2390 tree cond = gimple_assign_rhs1 (stmt);
2391 enum tree_code cond_code = TREE_CODE (cond);
2393 if (cond_code == EQ_EXPR || cond_code == NE_EXPR)
2394 fold_strstr_to_strncmp (TREE_OPERAND (cond, 0),
2395 TREE_OPERAND (cond, 1), stmt);
2397 else if (code == EQ_EXPR || code == NE_EXPR)
2398 fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt),
2399 gimple_assign_rhs2 (stmt), stmt);
2401 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2403 tree type = TREE_TYPE (lhs);
2404 if (TREE_CODE (type) == ARRAY_TYPE)
2405 type = TREE_TYPE (type);
2406 if (TREE_CODE (type) == INTEGER_TYPE
2407 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2408 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2410 if (! handle_char_store (gsi))
2411 return false;
2415 else if (gcond *cond = dyn_cast<gcond *> (stmt))
2417 enum tree_code code = gimple_cond_code (cond);
2418 if (code == EQ_EXPR || code == NE_EXPR)
2419 fold_strstr_to_strncmp (gimple_cond_lhs (stmt),
2420 gimple_cond_rhs (stmt), stmt);
2423 if (gimple_vdef (stmt))
2424 maybe_invalidate (stmt);
2425 return true;
2428 /* Recursively call maybe_invalidate on stmts that might be executed
2429 in between dombb and current bb and that contain a vdef. Stop when
2430 *count stmts are inspected, or if the whole strinfo vector has
2431 been invalidated. */
2433 static void
2434 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2436 unsigned int i, n = gimple_phi_num_args (phi);
2438 for (i = 0; i < n; i++)
2440 tree vuse = gimple_phi_arg_def (phi, i);
2441 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2442 basic_block bb = gimple_bb (stmt);
2443 if (bb == NULL
2444 || bb == dombb
2445 || !bitmap_set_bit (visited, bb->index)
2446 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2447 continue;
2448 while (1)
2450 if (gimple_code (stmt) == GIMPLE_PHI)
2452 do_invalidate (dombb, stmt, visited, count);
2453 if (*count == 0)
2454 return;
2455 break;
2457 if (--*count == 0)
2458 return;
2459 if (!maybe_invalidate (stmt))
2461 *count = 0;
2462 return;
2464 vuse = gimple_vuse (stmt);
2465 stmt = SSA_NAME_DEF_STMT (vuse);
2466 if (gimple_bb (stmt) != bb)
2468 bb = gimple_bb (stmt);
2469 if (bb == NULL
2470 || bb == dombb
2471 || !bitmap_set_bit (visited, bb->index)
2472 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2473 break;
2479 class strlen_dom_walker : public dom_walker
2481 public:
2482 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2484 virtual edge before_dom_children (basic_block);
2485 virtual void after_dom_children (basic_block);
2488 /* Callback for walk_dominator_tree. Attempt to optimize various
2489 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */
2491 edge
2492 strlen_dom_walker::before_dom_children (basic_block bb)
2494 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2496 if (dombb == NULL)
2497 stridx_to_strinfo = NULL;
2498 else
2500 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2501 if (stridx_to_strinfo)
2503 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2504 gsi_next (&gsi))
2506 gphi *phi = gsi.phi ();
2507 if (virtual_operand_p (gimple_phi_result (phi)))
2509 bitmap visited = BITMAP_ALLOC (NULL);
2510 int count_vdef = 100;
2511 do_invalidate (dombb, phi, visited, &count_vdef);
2512 BITMAP_FREE (visited);
2513 if (count_vdef == 0)
2515 /* If there were too many vdefs in between immediate
2516 dominator and current bb, invalidate everything.
2517 If stridx_to_strinfo has been unshared, we need
2518 to free it, otherwise just set it to NULL. */
2519 if (!strinfo_shared ())
2521 unsigned int i;
2522 strinfo *si;
2524 for (i = 1;
2525 vec_safe_iterate (stridx_to_strinfo, i, &si);
2526 ++i)
2528 free_strinfo (si);
2529 (*stridx_to_strinfo)[i] = NULL;
2532 else
2533 stridx_to_strinfo = NULL;
2535 break;
2541 /* If all PHI arguments have the same string index, the PHI result
2542 has it as well. */
2543 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2544 gsi_next (&gsi))
2546 gphi *phi = gsi.phi ();
2547 tree result = gimple_phi_result (phi);
2548 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2550 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2551 if (idx != 0)
2553 unsigned int i, n = gimple_phi_num_args (phi);
2554 for (i = 1; i < n; i++)
2555 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2556 break;
2557 if (i == n)
2558 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2563 /* Attempt to optimize individual statements. */
2564 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2565 if (strlen_optimize_stmt (&gsi))
2566 gsi_next (&gsi);
2568 bb->aux = stridx_to_strinfo;
2569 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2570 (*stridx_to_strinfo)[0] = (strinfo *) bb;
2571 return NULL;
2574 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2575 owned by the current bb, clear bb->aux. */
2577 void
2578 strlen_dom_walker::after_dom_children (basic_block bb)
2580 if (bb->aux)
2582 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2583 if (vec_safe_length (stridx_to_strinfo)
2584 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2586 unsigned int i;
2587 strinfo *si;
2589 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2590 free_strinfo (si);
2591 vec_free (stridx_to_strinfo);
2593 bb->aux = NULL;
2597 /* Main entry point. */
2599 namespace {
2601 const pass_data pass_data_strlen =
2603 GIMPLE_PASS, /* type */
2604 "strlen", /* name */
2605 OPTGROUP_NONE, /* optinfo_flags */
2606 TV_TREE_STRLEN, /* tv_id */
2607 ( PROP_cfg | PROP_ssa ), /* properties_required */
2608 0, /* properties_provided */
2609 0, /* properties_destroyed */
2610 0, /* todo_flags_start */
2611 0, /* todo_flags_finish */
2614 class pass_strlen : public gimple_opt_pass
2616 public:
2617 pass_strlen (gcc::context *ctxt)
2618 : gimple_opt_pass (pass_data_strlen, ctxt)
2621 /* opt_pass methods: */
2622 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2623 virtual unsigned int execute (function *);
2625 }; // class pass_strlen
2627 unsigned int
2628 pass_strlen::execute (function *fun)
2630 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2631 max_stridx = 1;
2633 calculate_dominance_info (CDI_DOMINATORS);
2635 /* String length optimization is implemented as a walk of the dominator
2636 tree and a forward walk of statements within each block. */
2637 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2639 ssa_ver_to_stridx.release ();
2640 strinfo_pool.release ();
2641 if (decl_to_stridxlist_htab)
2643 obstack_free (&stridx_obstack, NULL);
2644 delete decl_to_stridxlist_htab;
2645 decl_to_stridxlist_htab = NULL;
2647 laststmt.stmt = NULL;
2648 laststmt.len = NULL_TREE;
2649 laststmt.stridx = 0;
2651 return 0;
2654 } // anon namespace
2656 gimple_opt_pass *
2657 make_pass_strlen (gcc::context *ctxt)
2659 return new pass_strlen (ctxt);