* testsuite/26_numerics/headers/cmath/hypot.cc: XFAIL on AIX.
[official-gcc.git] / gcc / tree-ssa-strlen.c
blob339812e91c0d212628c8ed235b389cd8ec102a19
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, tree ptr)
164 HOST_WIDE_INT off;
165 struct stridxlist *list, *last = NULL;
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 if (list->offset > off)
184 return 0;
185 last = list;
186 list = list->next;
188 while (list);
190 if (ptr && last && last->idx > 0)
192 strinfo *si = get_strinfo (last->idx);
193 if (si
194 && si->length
195 && TREE_CODE (si->length) == INTEGER_CST
196 && compare_tree_int (si->length, off - last->offset) != -1)
197 return get_stridx_plus_constant (si, off - last->offset, ptr);
199 return 0;
202 /* Return string index for EXP. */
204 static int
205 get_stridx (tree exp)
207 tree s, o;
209 if (TREE_CODE (exp) == SSA_NAME)
211 if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
212 return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
213 int i;
214 tree e = exp;
215 HOST_WIDE_INT off = 0;
216 for (i = 0; i < 5; i++)
218 gimple *def_stmt = SSA_NAME_DEF_STMT (e);
219 if (!is_gimple_assign (def_stmt)
220 || gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
221 return 0;
222 tree rhs1 = gimple_assign_rhs1 (def_stmt);
223 tree rhs2 = gimple_assign_rhs2 (def_stmt);
224 if (TREE_CODE (rhs1) != SSA_NAME
225 || !tree_fits_shwi_p (rhs2))
226 return 0;
227 HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
228 if (this_off < 0)
229 return 0;
230 off = (unsigned HOST_WIDE_INT) off + this_off;
231 if (off < 0)
232 return 0;
233 if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
235 strinfo *si
236 = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
237 if (si
238 && si->length
239 && TREE_CODE (si->length) == INTEGER_CST
240 && compare_tree_int (si->length, off) != -1)
241 return get_stridx_plus_constant (si, off, exp);
243 e = rhs1;
245 return 0;
248 if (TREE_CODE (exp) == ADDR_EXPR)
250 int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp);
251 if (idx != 0)
252 return idx;
255 s = string_constant (exp, &o);
256 if (s != NULL_TREE
257 && (o == NULL_TREE || tree_fits_shwi_p (o))
258 && TREE_STRING_LENGTH (s) > 0)
260 HOST_WIDE_INT offset = o ? tree_to_shwi (o) : 0;
261 const char *p = TREE_STRING_POINTER (s);
262 int max = TREE_STRING_LENGTH (s) - 1;
264 if (p[max] == '\0' && offset >= 0 && offset <= max)
265 return ~(int) strlen (p + offset);
267 return 0;
270 /* Return true if strinfo vector is shared with the immediate dominator. */
272 static inline bool
273 strinfo_shared (void)
275 return vec_safe_length (stridx_to_strinfo)
276 && (*stridx_to_strinfo)[0] != NULL;
279 /* Unshare strinfo vector that is shared with the immediate dominator. */
281 static void
282 unshare_strinfo_vec (void)
284 strinfo *si;
285 unsigned int i = 0;
287 gcc_assert (strinfo_shared ());
288 stridx_to_strinfo = vec_safe_copy (stridx_to_strinfo);
289 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
290 if (si != NULL)
291 si->refcount++;
292 (*stridx_to_strinfo)[0] = NULL;
295 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
296 Return a pointer to the location where the string index can
297 be stored (if 0) or is stored, or NULL if this can't be tracked. */
299 static int *
300 addr_stridxptr (tree exp)
302 HOST_WIDE_INT off;
304 tree base = get_addr_base_and_unit_offset (exp, &off);
305 if (base == NULL_TREE || !DECL_P (base))
306 return NULL;
308 if (!decl_to_stridxlist_htab)
310 decl_to_stridxlist_htab
311 = new hash_map<tree_decl_hash, stridxlist> (64);
312 gcc_obstack_init (&stridx_obstack);
315 bool existed;
316 stridxlist *list = &decl_to_stridxlist_htab->get_or_insert (base, &existed);
317 if (existed)
319 int i;
320 stridxlist *before = NULL;
321 for (i = 0; i < 32; i++)
323 if (list->offset == off)
324 return &list->idx;
325 if (list->offset > off && before == NULL)
326 before = list;
327 if (list->next == NULL)
328 break;
329 list = list->next;
331 if (i == 32)
332 return NULL;
333 if (before)
335 list = before;
336 before = XOBNEW (&stridx_obstack, struct stridxlist);
337 *before = *list;
338 list->next = before;
339 list->offset = off;
340 list->idx = 0;
341 return &list->idx;
343 list->next = XOBNEW (&stridx_obstack, struct stridxlist);
344 list = list->next;
347 list->next = NULL;
348 list->offset = off;
349 list->idx = 0;
350 return &list->idx;
353 /* Create a new string index, or return 0 if reached limit. */
355 static int
356 new_stridx (tree exp)
358 int idx;
359 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
360 return 0;
361 if (TREE_CODE (exp) == SSA_NAME)
363 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp))
364 return 0;
365 idx = max_stridx++;
366 ssa_ver_to_stridx[SSA_NAME_VERSION (exp)] = idx;
367 return idx;
369 if (TREE_CODE (exp) == ADDR_EXPR)
371 int *pidx = addr_stridxptr (TREE_OPERAND (exp, 0));
372 if (pidx != NULL)
374 gcc_assert (*pidx == 0);
375 *pidx = max_stridx++;
376 return *pidx;
379 return 0;
382 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
384 static int
385 new_addr_stridx (tree exp)
387 int *pidx;
388 if (max_stridx >= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS))
389 return 0;
390 pidx = addr_stridxptr (exp);
391 if (pidx != NULL)
393 gcc_assert (*pidx == 0);
394 *pidx = max_stridx++;
395 return *pidx;
397 return 0;
400 /* Create a new strinfo. */
402 static strinfo *
403 new_strinfo (tree ptr, int idx, tree length)
405 strinfo *si = strinfo_pool.allocate ();
406 si->length = length;
407 si->ptr = ptr;
408 si->stmt = NULL;
409 si->endptr = NULL_TREE;
410 si->refcount = 1;
411 si->idx = idx;
412 si->first = 0;
413 si->prev = 0;
414 si->next = 0;
415 si->writable = false;
416 si->dont_invalidate = false;
417 return si;
420 /* Decrease strinfo refcount and free it if not referenced anymore. */
422 static inline void
423 free_strinfo (strinfo *si)
425 if (si && --si->refcount == 0)
426 strinfo_pool.remove (si);
429 /* Set strinfo in the vector entry IDX to SI. */
431 static inline void
432 set_strinfo (int idx, strinfo *si)
434 if (vec_safe_length (stridx_to_strinfo) && (*stridx_to_strinfo)[0])
435 unshare_strinfo_vec ();
436 if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
437 vec_safe_grow_cleared (stridx_to_strinfo, idx + 1);
438 (*stridx_to_strinfo)[idx] = si;
441 /* Return string length, or NULL if it can't be computed. */
443 static tree
444 get_string_length (strinfo *si)
446 if (si->length)
447 return si->length;
449 if (si->stmt)
451 gimple *stmt = si->stmt, *lenstmt;
452 bool with_bounds = gimple_call_with_bounds_p (stmt);
453 tree callee, lhs, fn, tem;
454 location_t loc;
455 gimple_stmt_iterator gsi;
457 gcc_assert (is_gimple_call (stmt));
458 callee = gimple_call_fndecl (stmt);
459 gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
460 lhs = gimple_call_lhs (stmt);
461 /* unshare_strinfo is intentionally not called here. The (delayed)
462 transformation of strcpy or strcat into stpcpy is done at the place
463 of the former strcpy/strcat call and so can affect all the strinfos
464 with the same stmt. If they were unshared before and transformation
465 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
466 just compute the right length. */
467 switch (DECL_FUNCTION_CODE (callee))
469 case BUILT_IN_STRCAT:
470 case BUILT_IN_STRCAT_CHK:
471 case BUILT_IN_STRCAT_CHKP:
472 case BUILT_IN_STRCAT_CHK_CHKP:
473 gsi = gsi_for_stmt (stmt);
474 fn = builtin_decl_implicit (BUILT_IN_STRLEN);
475 gcc_assert (lhs == NULL_TREE);
476 tem = unshare_expr (gimple_call_arg (stmt, 0));
477 if (with_bounds)
479 lenstmt = gimple_build_call (chkp_maybe_create_clone (fn)->decl,
480 2, tem, gimple_call_arg (stmt, 1));
481 gimple_call_set_with_bounds (lenstmt, true);
483 else
484 lenstmt = gimple_build_call (fn, 1, tem);
485 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), lenstmt);
486 gimple_call_set_lhs (lenstmt, lhs);
487 gimple_set_vuse (lenstmt, gimple_vuse (stmt));
488 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
489 tem = gimple_call_arg (stmt, 0);
490 if (!ptrofftype_p (TREE_TYPE (lhs)))
492 lhs = convert_to_ptrofftype (lhs);
493 lhs = force_gimple_operand_gsi (&gsi, lhs, true, NULL_TREE,
494 true, GSI_SAME_STMT);
496 lenstmt = gimple_build_assign
497 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt, 0))),
498 POINTER_PLUS_EXPR,tem, lhs);
499 gsi_insert_before (&gsi, lenstmt, GSI_SAME_STMT);
500 gimple_call_set_arg (stmt, 0, gimple_assign_lhs (lenstmt));
501 lhs = NULL_TREE;
502 /* FALLTHRU */
503 case BUILT_IN_STRCPY:
504 case BUILT_IN_STRCPY_CHK:
505 case BUILT_IN_STRCPY_CHKP:
506 case BUILT_IN_STRCPY_CHK_CHKP:
507 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
508 if (gimple_call_num_args (stmt) == (with_bounds ? 4 : 2))
509 fn = builtin_decl_implicit (BUILT_IN_STPCPY);
510 else
511 fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
512 if (with_bounds)
513 fn = chkp_maybe_create_clone (fn)->decl;
514 gcc_assert (lhs == NULL_TREE);
515 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
517 fprintf (dump_file, "Optimizing: ");
518 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
520 gimple_call_set_fndecl (stmt, fn);
521 lhs = make_ssa_name (TREE_TYPE (TREE_TYPE (fn)), stmt);
522 gimple_call_set_lhs (stmt, lhs);
523 update_stmt (stmt);
524 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
526 fprintf (dump_file, "into: ");
527 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
529 /* FALLTHRU */
530 case BUILT_IN_STPCPY:
531 case BUILT_IN_STPCPY_CHK:
532 case BUILT_IN_STPCPY_CHKP:
533 case BUILT_IN_STPCPY_CHK_CHKP:
534 gcc_assert (lhs != NULL_TREE);
535 loc = gimple_location (stmt);
536 si->endptr = lhs;
537 si->stmt = NULL;
538 lhs = fold_convert_loc (loc, size_type_node, lhs);
539 si->length = fold_convert_loc (loc, size_type_node, si->ptr);
540 si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
541 lhs, si->length);
542 break;
543 case BUILT_IN_MALLOC:
544 break;
545 /* BUILT_IN_CALLOC always has si->length set. */
546 default:
547 gcc_unreachable ();
548 break;
552 return si->length;
555 /* Invalidate string length information for strings whose length
556 might change due to stores in stmt. */
558 static bool
559 maybe_invalidate (gimple *stmt)
561 strinfo *si;
562 unsigned int i;
563 bool nonempty = false;
565 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
566 if (si != NULL)
568 if (!si->dont_invalidate)
570 ao_ref r;
571 /* Do not use si->length. */
572 ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
573 if (stmt_may_clobber_ref_p_1 (stmt, &r))
575 set_strinfo (i, NULL);
576 free_strinfo (si);
577 continue;
580 si->dont_invalidate = false;
581 nonempty = true;
583 return nonempty;
586 /* Unshare strinfo record SI, if it has refcount > 1 or
587 if stridx_to_strinfo vector is shared with some other
588 bbs. */
590 static strinfo *
591 unshare_strinfo (strinfo *si)
593 strinfo *nsi;
595 if (si->refcount == 1 && !strinfo_shared ())
596 return si;
598 nsi = new_strinfo (si->ptr, si->idx, si->length);
599 nsi->stmt = si->stmt;
600 nsi->endptr = si->endptr;
601 nsi->first = si->first;
602 nsi->prev = si->prev;
603 nsi->next = si->next;
604 nsi->writable = si->writable;
605 set_strinfo (si->idx, nsi);
606 free_strinfo (si);
607 return nsi;
610 /* Return first strinfo in the related strinfo chain
611 if all strinfos in between belong to the chain, otherwise
612 NULL. */
614 static strinfo *
615 verify_related_strinfos (strinfo *origsi)
617 strinfo *si = origsi, *psi;
619 if (origsi->first == 0)
620 return NULL;
621 for (; si->prev; si = psi)
623 if (si->first != origsi->first)
624 return NULL;
625 psi = get_strinfo (si->prev);
626 if (psi == NULL)
627 return NULL;
628 if (psi->next != si->idx)
629 return NULL;
631 if (si->idx != si->first)
632 return NULL;
633 return si;
636 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
637 strinfo if there is any. Return it's idx, or 0 if no strinfo has
638 been created. */
640 static int
641 get_stridx_plus_constant (strinfo *basesi, HOST_WIDE_INT off, tree ptr)
643 if (TREE_CODE (ptr) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
644 return 0;
646 if (basesi->length == NULL_TREE
647 || TREE_CODE (basesi->length) != INTEGER_CST
648 || compare_tree_int (basesi->length, off) == -1
649 || !tree_fits_shwi_p (basesi->length))
650 return 0;
652 HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
653 strinfo *si = basesi, *chainsi;
654 if (si->first || si->prev || si->next)
655 si = verify_related_strinfos (basesi);
656 if (si == NULL
657 || si->length == NULL_TREE
658 || TREE_CODE (si->length) != INTEGER_CST)
659 return 0;
661 if (TREE_CODE (ptr) == SSA_NAME
662 && ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
663 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
665 gcc_checking_assert (compare_tree_int (si->length, off) != -1);
666 for (chainsi = si; chainsi->next; chainsi = si)
668 si = get_strinfo (chainsi->next);
669 if (si == NULL
670 || si->first != chainsi->first
671 || si->prev != chainsi->idx
672 || si->length == NULL_TREE
673 || TREE_CODE (si->length) != INTEGER_CST)
674 break;
675 int r = compare_tree_int (si->length, len);
676 if (r != 1)
678 if (r == 0)
680 if (TREE_CODE (ptr) == SSA_NAME)
681 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
682 else
684 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
685 if (pidx != NULL && *pidx == 0)
686 *pidx = si->idx;
688 return si->idx;
690 break;
694 int idx = new_stridx (ptr);
695 if (idx == 0)
696 return 0;
697 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
698 set_strinfo (idx, si);
699 if (chainsi->next)
701 strinfo *nextsi = unshare_strinfo (get_strinfo (chainsi->next));
702 si->next = nextsi->idx;
703 nextsi->prev = idx;
705 chainsi = unshare_strinfo (chainsi);
706 if (chainsi->first == 0)
707 chainsi->first = chainsi->idx;
708 chainsi->next = idx;
709 if (chainsi->endptr == NULL_TREE && len == 0)
710 chainsi->endptr = ptr;
711 si->endptr = chainsi->endptr;
712 si->prev = chainsi->idx;
713 si->first = chainsi->first;
714 si->writable = chainsi->writable;
715 return si->idx;
718 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
719 to a zero-length string and if possible chain it to a related strinfo
720 chain whose part is or might be CHAINSI. */
722 static strinfo *
723 zero_length_string (tree ptr, strinfo *chainsi)
725 strinfo *si;
726 int idx;
727 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
728 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
729 gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
730 && ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
732 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
733 return NULL;
734 if (chainsi != NULL)
736 si = verify_related_strinfos (chainsi);
737 if (si)
739 chainsi = si;
740 for (; chainsi->next; chainsi = si)
742 if (chainsi->endptr == NULL_TREE)
744 chainsi = unshare_strinfo (chainsi);
745 chainsi->endptr = ptr;
747 si = get_strinfo (chainsi->next);
748 if (si == NULL
749 || si->first != chainsi->first
750 || si->prev != chainsi->idx)
751 break;
753 gcc_assert (chainsi->length || chainsi->stmt);
754 if (chainsi->endptr == NULL_TREE)
756 chainsi = unshare_strinfo (chainsi);
757 chainsi->endptr = ptr;
759 if (chainsi->length && integer_zerop (chainsi->length))
761 if (chainsi->next)
763 chainsi = unshare_strinfo (chainsi);
764 chainsi->next = 0;
766 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = chainsi->idx;
767 return chainsi;
770 else if (chainsi->first || chainsi->prev || chainsi->next)
772 chainsi = unshare_strinfo (chainsi);
773 chainsi->first = 0;
774 chainsi->prev = 0;
775 chainsi->next = 0;
778 idx = new_stridx (ptr);
779 if (idx == 0)
780 return NULL;
781 si = new_strinfo (ptr, idx, build_int_cst (size_type_node, 0));
782 set_strinfo (idx, si);
783 si->endptr = ptr;
784 if (chainsi != NULL)
786 chainsi = unshare_strinfo (chainsi);
787 if (chainsi->first == 0)
788 chainsi->first = chainsi->idx;
789 chainsi->next = idx;
790 if (chainsi->endptr == NULL_TREE)
791 chainsi->endptr = ptr;
792 si->prev = chainsi->idx;
793 si->first = chainsi->first;
794 si->writable = chainsi->writable;
796 return si;
799 /* For strinfo ORIGSI whose length has been just updated
800 update also related strinfo lengths (add ADJ to each,
801 but don't adjust ORIGSI). */
803 static void
804 adjust_related_strinfos (location_t loc, strinfo *origsi, tree adj)
806 strinfo *si = verify_related_strinfos (origsi);
808 if (si == NULL)
809 return;
811 while (1)
813 strinfo *nsi;
815 if (si != origsi)
817 tree tem;
819 si = unshare_strinfo (si);
820 if (si->length)
822 tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
823 si->length = fold_build2_loc (loc, PLUS_EXPR,
824 TREE_TYPE (si->length), si->length,
825 tem);
827 else if (si->stmt != NULL)
828 /* Delayed length computation is unaffected. */
830 else
831 gcc_unreachable ();
833 si->endptr = NULL_TREE;
834 si->dont_invalidate = true;
836 if (si->next == 0)
837 return;
838 nsi = get_strinfo (si->next);
839 if (nsi == NULL
840 || nsi->first != si->first
841 || nsi->prev != si->idx)
842 return;
843 si = nsi;
847 /* Find if there are other SSA_NAME pointers equal to PTR
848 for which we don't track their string lengths yet. If so, use
849 IDX for them. */
851 static void
852 find_equal_ptrs (tree ptr, int idx)
854 if (TREE_CODE (ptr) != SSA_NAME)
855 return;
856 while (1)
858 gimple *stmt = SSA_NAME_DEF_STMT (ptr);
859 if (!is_gimple_assign (stmt))
860 return;
861 ptr = gimple_assign_rhs1 (stmt);
862 switch (gimple_assign_rhs_code (stmt))
864 case SSA_NAME:
865 break;
866 CASE_CONVERT:
867 if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
868 return;
869 if (TREE_CODE (ptr) == SSA_NAME)
870 break;
871 if (TREE_CODE (ptr) != ADDR_EXPR)
872 return;
873 /* FALLTHRU */
874 case ADDR_EXPR:
876 int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
877 if (pidx != NULL && *pidx == 0)
878 *pidx = idx;
879 return;
881 default:
882 return;
885 /* We might find an endptr created in this pass. Grow the
886 vector in that case. */
887 if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
888 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
890 if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] != 0)
891 return;
892 ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = idx;
896 /* Return true if STMT is a call to a builtin function with the right
897 arguments and attributes that should be considered for optimization
898 by this pass. */
900 static bool
901 valid_builtin_call (gimple *stmt)
903 if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
904 return false;
906 tree callee = gimple_call_fndecl (stmt);
907 switch (DECL_FUNCTION_CODE (callee))
909 case BUILT_IN_MEMCMP:
910 case BUILT_IN_MEMCMP_EQ:
911 case BUILT_IN_STRCHR:
912 case BUILT_IN_STRCHR_CHKP:
913 case BUILT_IN_STRLEN:
914 case BUILT_IN_STRLEN_CHKP:
915 /* The above functions should be pure. Punt if they aren't. */
916 if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE)
917 return false;
918 break;
920 case BUILT_IN_CALLOC:
921 case BUILT_IN_MALLOC:
922 case BUILT_IN_MEMCPY:
923 case BUILT_IN_MEMCPY_CHK:
924 case BUILT_IN_MEMCPY_CHKP:
925 case BUILT_IN_MEMCPY_CHK_CHKP:
926 case BUILT_IN_MEMPCPY:
927 case BUILT_IN_MEMPCPY_CHK:
928 case BUILT_IN_MEMPCPY_CHKP:
929 case BUILT_IN_MEMPCPY_CHK_CHKP:
930 case BUILT_IN_MEMSET:
931 case BUILT_IN_STPCPY:
932 case BUILT_IN_STPCPY_CHK:
933 case BUILT_IN_STPCPY_CHKP:
934 case BUILT_IN_STPCPY_CHK_CHKP:
935 case BUILT_IN_STRCAT:
936 case BUILT_IN_STRCAT_CHK:
937 case BUILT_IN_STRCAT_CHKP:
938 case BUILT_IN_STRCAT_CHK_CHKP:
939 case BUILT_IN_STRCPY:
940 case BUILT_IN_STRCPY_CHK:
941 case BUILT_IN_STRCPY_CHKP:
942 case BUILT_IN_STRCPY_CHK_CHKP:
943 /* The above functions should be neither const nor pure. Punt if they
944 aren't. */
945 if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE)
946 return false;
947 break;
949 default:
950 break;
953 return true;
956 /* If the last .MEM setter statement before STMT is
957 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
958 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
959 just memcpy (x, y, strlen (y)). SI must be the zero length
960 strinfo. */
962 static void
963 adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
965 tree vuse, callee, len;
966 struct laststmt_struct last = laststmt;
967 strinfo *lastsi, *firstsi;
968 unsigned len_arg_no = 2;
970 laststmt.stmt = NULL;
971 laststmt.len = NULL_TREE;
972 laststmt.stridx = 0;
974 if (last.stmt == NULL)
975 return;
977 vuse = gimple_vuse (stmt);
978 if (vuse == NULL_TREE
979 || SSA_NAME_DEF_STMT (vuse) != last.stmt
980 || !has_single_use (vuse))
981 return;
983 gcc_assert (last.stridx > 0);
984 lastsi = get_strinfo (last.stridx);
985 if (lastsi == NULL)
986 return;
988 if (lastsi != si)
990 if (lastsi->first == 0 || lastsi->first != si->first)
991 return;
993 firstsi = verify_related_strinfos (si);
994 if (firstsi == NULL)
995 return;
996 while (firstsi != lastsi)
998 strinfo *nextsi;
999 if (firstsi->next == 0)
1000 return;
1001 nextsi = get_strinfo (firstsi->next);
1002 if (nextsi == NULL
1003 || nextsi->prev != firstsi->idx
1004 || nextsi->first != si->first)
1005 return;
1006 firstsi = nextsi;
1010 if (!is_strcat)
1012 if (si->length == NULL_TREE || !integer_zerop (si->length))
1013 return;
1016 if (is_gimple_assign (last.stmt))
1018 gimple_stmt_iterator gsi;
1020 if (!integer_zerop (gimple_assign_rhs1 (last.stmt)))
1021 return;
1022 if (stmt_could_throw_p (last.stmt))
1023 return;
1024 gsi = gsi_for_stmt (last.stmt);
1025 unlink_stmt_vdef (last.stmt);
1026 release_defs (last.stmt);
1027 gsi_remove (&gsi, true);
1028 return;
1031 if (!valid_builtin_call (last.stmt))
1032 return;
1034 callee = gimple_call_fndecl (last.stmt);
1035 switch (DECL_FUNCTION_CODE (callee))
1037 case BUILT_IN_MEMCPY:
1038 case BUILT_IN_MEMCPY_CHK:
1039 break;
1040 case BUILT_IN_MEMCPY_CHKP:
1041 case BUILT_IN_MEMCPY_CHK_CHKP:
1042 len_arg_no = 4;
1043 break;
1044 default:
1045 return;
1048 len = gimple_call_arg (last.stmt, len_arg_no);
1049 if (tree_fits_uhwi_p (len))
1051 if (!tree_fits_uhwi_p (last.len)
1052 || integer_zerop (len)
1053 || tree_to_uhwi (len) != tree_to_uhwi (last.len) + 1)
1054 return;
1055 /* Don't adjust the length if it is divisible by 4, it is more efficient
1056 to store the extra '\0' in that case. */
1057 if ((tree_to_uhwi (len) & 3) == 0)
1058 return;
1060 else if (TREE_CODE (len) == SSA_NAME)
1062 gimple *def_stmt = SSA_NAME_DEF_STMT (len);
1063 if (!is_gimple_assign (def_stmt)
1064 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1065 || gimple_assign_rhs1 (def_stmt) != last.len
1066 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1067 return;
1069 else
1070 return;
1072 gimple_call_set_arg (last.stmt, len_arg_no, last.len);
1073 update_stmt (last.stmt);
1076 /* Handle a strlen call. If strlen of the argument is known, replace
1077 the strlen call with the known value, otherwise remember that strlen
1078 of the argument is stored in the lhs SSA_NAME. */
1080 static void
1081 handle_builtin_strlen (gimple_stmt_iterator *gsi)
1083 int idx;
1084 tree src;
1085 gimple *stmt = gsi_stmt (*gsi);
1086 tree lhs = gimple_call_lhs (stmt);
1088 if (lhs == NULL_TREE)
1089 return;
1091 src = gimple_call_arg (stmt, 0);
1092 idx = get_stridx (src);
1093 if (idx)
1095 strinfo *si = NULL;
1096 tree rhs;
1098 if (idx < 0)
1099 rhs = build_int_cst (TREE_TYPE (lhs), ~idx);
1100 else
1102 rhs = NULL_TREE;
1103 si = get_strinfo (idx);
1104 if (si != NULL)
1105 rhs = get_string_length (si);
1107 if (rhs != NULL_TREE)
1109 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1111 fprintf (dump_file, "Optimizing: ");
1112 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1114 rhs = unshare_expr (rhs);
1115 if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1116 rhs = fold_convert_loc (gimple_location (stmt),
1117 TREE_TYPE (lhs), rhs);
1118 if (!update_call_from_tree (gsi, rhs))
1119 gimplify_and_update_call_from_tree (gsi, rhs);
1120 stmt = gsi_stmt (*gsi);
1121 update_stmt (stmt);
1122 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1124 fprintf (dump_file, "into: ");
1125 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1127 if (si != NULL
1128 && TREE_CODE (si->length) != SSA_NAME
1129 && TREE_CODE (si->length) != INTEGER_CST
1130 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1132 si = unshare_strinfo (si);
1133 si->length = lhs;
1135 return;
1138 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1139 return;
1140 if (idx == 0)
1141 idx = new_stridx (src);
1142 else if (get_strinfo (idx) != NULL)
1143 return;
1144 if (idx)
1146 strinfo *si = new_strinfo (src, idx, lhs);
1147 set_strinfo (idx, si);
1148 find_equal_ptrs (src, idx);
1152 /* Handle a strchr call. If strlen of the first argument is known, replace
1153 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1154 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1156 static void
1157 handle_builtin_strchr (gimple_stmt_iterator *gsi)
1159 int idx;
1160 tree src;
1161 gimple *stmt = gsi_stmt (*gsi);
1162 tree lhs = gimple_call_lhs (stmt);
1163 bool with_bounds = gimple_call_with_bounds_p (stmt);
1165 if (lhs == NULL_TREE)
1166 return;
1168 if (!integer_zerop (gimple_call_arg (stmt, with_bounds ? 2 : 1)))
1169 return;
1171 src = gimple_call_arg (stmt, 0);
1172 idx = get_stridx (src);
1173 if (idx)
1175 strinfo *si = NULL;
1176 tree rhs;
1178 if (idx < 0)
1179 rhs = build_int_cst (size_type_node, ~idx);
1180 else
1182 rhs = NULL_TREE;
1183 si = get_strinfo (idx);
1184 if (si != NULL)
1185 rhs = get_string_length (si);
1187 if (rhs != NULL_TREE)
1189 location_t loc = gimple_location (stmt);
1191 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1193 fprintf (dump_file, "Optimizing: ");
1194 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1196 if (si != NULL && si->endptr != NULL_TREE)
1198 rhs = unshare_expr (si->endptr);
1199 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1200 TREE_TYPE (rhs)))
1201 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1203 else
1205 rhs = fold_convert_loc (loc, sizetype, unshare_expr (rhs));
1206 rhs = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1207 TREE_TYPE (src), src, rhs);
1208 if (!useless_type_conversion_p (TREE_TYPE (lhs),
1209 TREE_TYPE (rhs)))
1210 rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs);
1212 if (!update_call_from_tree (gsi, rhs))
1213 gimplify_and_update_call_from_tree (gsi, rhs);
1214 stmt = gsi_stmt (*gsi);
1215 update_stmt (stmt);
1216 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1218 fprintf (dump_file, "into: ");
1219 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1221 if (si != NULL
1222 && si->endptr == NULL_TREE
1223 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1225 si = unshare_strinfo (si);
1226 si->endptr = lhs;
1228 zero_length_string (lhs, si);
1229 return;
1232 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
1233 return;
1234 if (TREE_CODE (src) != SSA_NAME || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src))
1236 if (idx == 0)
1237 idx = new_stridx (src);
1238 else if (get_strinfo (idx) != NULL)
1240 zero_length_string (lhs, NULL);
1241 return;
1243 if (idx)
1245 location_t loc = gimple_location (stmt);
1246 tree lhsu = fold_convert_loc (loc, size_type_node, lhs);
1247 tree srcu = fold_convert_loc (loc, size_type_node, src);
1248 tree length = fold_build2_loc (loc, MINUS_EXPR,
1249 size_type_node, lhsu, srcu);
1250 strinfo *si = new_strinfo (src, idx, length);
1251 si->endptr = lhs;
1252 set_strinfo (idx, si);
1253 find_equal_ptrs (src, idx);
1254 zero_length_string (lhs, si);
1257 else
1258 zero_length_string (lhs, NULL);
1261 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1262 If strlen of the second argument is known, strlen of the first argument
1263 is the same after this call. Furthermore, attempt to convert it to
1264 memcpy. */
1266 static void
1267 handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1269 int idx, didx;
1270 tree src, dst, srclen, len, lhs, args, type, fn, oldlen;
1271 bool success;
1272 gimple *stmt = gsi_stmt (*gsi);
1273 strinfo *si, *dsi, *olddsi, *zsi;
1274 location_t loc;
1275 bool with_bounds = gimple_call_with_bounds_p (stmt);
1277 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1278 dst = gimple_call_arg (stmt, 0);
1279 lhs = gimple_call_lhs (stmt);
1280 idx = get_stridx (src);
1281 si = NULL;
1282 if (idx > 0)
1283 si = get_strinfo (idx);
1285 didx = get_stridx (dst);
1286 olddsi = NULL;
1287 oldlen = NULL_TREE;
1288 if (didx > 0)
1289 olddsi = get_strinfo (didx);
1290 else if (didx < 0)
1291 return;
1293 if (olddsi != NULL)
1294 adjust_last_stmt (olddsi, stmt, false);
1296 srclen = NULL_TREE;
1297 if (si != NULL)
1298 srclen = get_string_length (si);
1299 else if (idx < 0)
1300 srclen = build_int_cst (size_type_node, ~idx);
1302 loc = gimple_location (stmt);
1303 if (srclen == NULL_TREE)
1304 switch (bcode)
1306 case BUILT_IN_STRCPY:
1307 case BUILT_IN_STRCPY_CHK:
1308 case BUILT_IN_STRCPY_CHKP:
1309 case BUILT_IN_STRCPY_CHK_CHKP:
1310 if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
1311 return;
1312 break;
1313 case BUILT_IN_STPCPY:
1314 case BUILT_IN_STPCPY_CHK:
1315 case BUILT_IN_STPCPY_CHKP:
1316 case BUILT_IN_STPCPY_CHK_CHKP:
1317 if (lhs == NULL_TREE)
1318 return;
1319 else
1321 tree lhsuint = fold_convert_loc (loc, size_type_node, lhs);
1322 srclen = fold_convert_loc (loc, size_type_node, dst);
1323 srclen = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
1324 lhsuint, srclen);
1326 break;
1327 default:
1328 gcc_unreachable ();
1331 if (didx == 0)
1333 didx = new_stridx (dst);
1334 if (didx == 0)
1335 return;
1337 if (olddsi != NULL)
1339 oldlen = olddsi->length;
1340 dsi = unshare_strinfo (olddsi);
1341 dsi->length = srclen;
1342 /* Break the chain, so adjust_related_strinfo on later pointers in
1343 the chain won't adjust this one anymore. */
1344 dsi->next = 0;
1345 dsi->stmt = NULL;
1346 dsi->endptr = NULL_TREE;
1348 else
1350 dsi = new_strinfo (dst, didx, srclen);
1351 set_strinfo (didx, dsi);
1352 find_equal_ptrs (dst, didx);
1354 dsi->writable = true;
1355 dsi->dont_invalidate = true;
1357 if (dsi->length == NULL_TREE)
1359 strinfo *chainsi;
1361 /* If string length of src is unknown, use delayed length
1362 computation. If string lenth of dst will be needed, it
1363 can be computed by transforming this strcpy call into
1364 stpcpy and subtracting dst from the return value. */
1366 /* Look for earlier strings whose length could be determined if
1367 this strcpy is turned into an stpcpy. */
1369 if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
1371 for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
1373 /* When setting a stmt for delayed length computation
1374 prevent all strinfos through dsi from being
1375 invalidated. */
1376 chainsi = unshare_strinfo (chainsi);
1377 chainsi->stmt = stmt;
1378 chainsi->length = NULL_TREE;
1379 chainsi->endptr = NULL_TREE;
1380 chainsi->dont_invalidate = true;
1383 dsi->stmt = stmt;
1384 return;
1387 if (olddsi != NULL)
1389 tree adj = NULL_TREE;
1390 if (oldlen == NULL_TREE)
1392 else if (integer_zerop (oldlen))
1393 adj = srclen;
1394 else if (TREE_CODE (oldlen) == INTEGER_CST
1395 || TREE_CODE (srclen) == INTEGER_CST)
1396 adj = fold_build2_loc (loc, MINUS_EXPR,
1397 TREE_TYPE (srclen), srclen,
1398 fold_convert_loc (loc, TREE_TYPE (srclen),
1399 oldlen));
1400 if (adj != NULL_TREE)
1401 adjust_related_strinfos (loc, dsi, adj);
1402 else
1403 dsi->prev = 0;
1405 /* strcpy src may not overlap dst, so src doesn't need to be
1406 invalidated either. */
1407 if (si != NULL)
1408 si->dont_invalidate = true;
1410 fn = NULL_TREE;
1411 zsi = NULL;
1412 switch (bcode)
1414 case BUILT_IN_STRCPY:
1415 case BUILT_IN_STRCPY_CHKP:
1416 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1417 if (lhs)
1418 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1419 break;
1420 case BUILT_IN_STRCPY_CHK:
1421 case BUILT_IN_STRCPY_CHK_CHKP:
1422 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1423 if (lhs)
1424 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1425 break;
1426 case BUILT_IN_STPCPY:
1427 case BUILT_IN_STPCPY_CHKP:
1428 /* This would need adjustment of the lhs (subtract one),
1429 or detection that the trailing '\0' doesn't need to be
1430 written, if it will be immediately overwritten.
1431 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1432 if (lhs)
1434 dsi->endptr = lhs;
1435 zsi = zero_length_string (lhs, dsi);
1437 break;
1438 case BUILT_IN_STPCPY_CHK:
1439 case BUILT_IN_STPCPY_CHK_CHKP:
1440 /* This would need adjustment of the lhs (subtract one),
1441 or detection that the trailing '\0' doesn't need to be
1442 written, if it will be immediately overwritten.
1443 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1444 if (lhs)
1446 dsi->endptr = lhs;
1447 zsi = zero_length_string (lhs, dsi);
1449 break;
1450 default:
1451 gcc_unreachable ();
1453 if (zsi != NULL)
1454 zsi->dont_invalidate = true;
1456 if (fn == NULL_TREE)
1457 return;
1459 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1460 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1462 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1463 len = fold_build2_loc (loc, PLUS_EXPR, type, len, build_int_cst (type, 1));
1464 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1465 GSI_SAME_STMT);
1466 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1468 fprintf (dump_file, "Optimizing: ");
1469 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1471 if (with_bounds)
1473 fn = chkp_maybe_create_clone (fn)->decl;
1474 if (gimple_call_num_args (stmt) == 4)
1475 success = update_gimple_call (gsi, fn, 5, dst,
1476 gimple_call_arg (stmt, 1),
1477 src,
1478 gimple_call_arg (stmt, 3),
1479 len);
1480 else
1481 success = update_gimple_call (gsi, fn, 6, dst,
1482 gimple_call_arg (stmt, 1),
1483 src,
1484 gimple_call_arg (stmt, 3),
1485 len,
1486 gimple_call_arg (stmt, 4));
1488 else
1489 if (gimple_call_num_args (stmt) == 2)
1490 success = update_gimple_call (gsi, fn, 3, dst, src, len);
1491 else
1492 success = update_gimple_call (gsi, fn, 4, dst, src, len,
1493 gimple_call_arg (stmt, 2));
1494 if (success)
1496 stmt = gsi_stmt (*gsi);
1497 gimple_call_set_with_bounds (stmt, with_bounds);
1498 update_stmt (stmt);
1499 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1501 fprintf (dump_file, "into: ");
1502 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1504 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1505 laststmt.stmt = stmt;
1506 laststmt.len = srclen;
1507 laststmt.stridx = dsi->idx;
1509 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1510 fprintf (dump_file, "not possible.\n");
1513 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1514 If strlen of the second argument is known and length of the third argument
1515 is that plus one, strlen of the first argument is the same after this
1516 call. */
1518 static void
1519 handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1521 int idx, didx;
1522 tree src, dst, len, lhs, oldlen, newlen;
1523 gimple *stmt = gsi_stmt (*gsi);
1524 strinfo *si, *dsi, *olddsi;
1525 bool with_bounds = gimple_call_with_bounds_p (stmt);
1527 len = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1528 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1529 dst = gimple_call_arg (stmt, 0);
1530 idx = get_stridx (src);
1531 if (idx == 0)
1532 return;
1534 didx = get_stridx (dst);
1535 olddsi = NULL;
1536 if (didx > 0)
1537 olddsi = get_strinfo (didx);
1538 else if (didx < 0)
1539 return;
1541 if (olddsi != NULL
1542 && tree_fits_uhwi_p (len)
1543 && !integer_zerop (len))
1544 adjust_last_stmt (olddsi, stmt, false);
1546 if (idx > 0)
1548 gimple *def_stmt;
1550 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1551 si = get_strinfo (idx);
1552 if (si == NULL || si->length == NULL_TREE)
1553 return;
1554 if (TREE_CODE (len) != SSA_NAME)
1555 return;
1556 def_stmt = SSA_NAME_DEF_STMT (len);
1557 if (!is_gimple_assign (def_stmt)
1558 || gimple_assign_rhs_code (def_stmt) != PLUS_EXPR
1559 || gimple_assign_rhs1 (def_stmt) != si->length
1560 || !integer_onep (gimple_assign_rhs2 (def_stmt)))
1561 return;
1563 else
1565 si = NULL;
1566 /* Handle memcpy (x, "abcd", 5) or
1567 memcpy (x, "abc\0uvw", 7). */
1568 if (!tree_fits_uhwi_p (len)
1569 || tree_to_uhwi (len) <= (unsigned HOST_WIDE_INT) ~idx)
1570 return;
1573 if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
1574 adjust_last_stmt (olddsi, stmt, false);
1576 if (didx == 0)
1578 didx = new_stridx (dst);
1579 if (didx == 0)
1580 return;
1582 if (si != NULL)
1583 newlen = si->length;
1584 else
1585 newlen = build_int_cst (size_type_node, ~idx);
1586 oldlen = NULL_TREE;
1587 if (olddsi != NULL)
1589 dsi = unshare_strinfo (olddsi);
1590 oldlen = olddsi->length;
1591 dsi->length = newlen;
1592 /* Break the chain, so adjust_related_strinfo on later pointers in
1593 the chain won't adjust this one anymore. */
1594 dsi->next = 0;
1595 dsi->stmt = NULL;
1596 dsi->endptr = NULL_TREE;
1598 else
1600 dsi = new_strinfo (dst, didx, newlen);
1601 set_strinfo (didx, dsi);
1602 find_equal_ptrs (dst, didx);
1604 dsi->writable = true;
1605 dsi->dont_invalidate = true;
1606 if (olddsi != NULL)
1608 tree adj = NULL_TREE;
1609 location_t loc = gimple_location (stmt);
1610 if (oldlen == NULL_TREE)
1612 else if (integer_zerop (oldlen))
1613 adj = dsi->length;
1614 else if (TREE_CODE (oldlen) == INTEGER_CST
1615 || TREE_CODE (dsi->length) == INTEGER_CST)
1616 adj = fold_build2_loc (loc, MINUS_EXPR,
1617 TREE_TYPE (dsi->length), dsi->length,
1618 fold_convert_loc (loc, TREE_TYPE (dsi->length),
1619 oldlen));
1620 if (adj != NULL_TREE)
1621 adjust_related_strinfos (loc, dsi, adj);
1622 else
1623 dsi->prev = 0;
1625 /* memcpy src may not overlap dst, so src doesn't need to be
1626 invalidated either. */
1627 if (si != NULL)
1628 si->dont_invalidate = true;
1630 lhs = gimple_call_lhs (stmt);
1631 switch (bcode)
1633 case BUILT_IN_MEMCPY:
1634 case BUILT_IN_MEMCPY_CHK:
1635 case BUILT_IN_MEMCPY_CHKP:
1636 case BUILT_IN_MEMCPY_CHK_CHKP:
1637 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1638 laststmt.stmt = stmt;
1639 laststmt.len = dsi->length;
1640 laststmt.stridx = dsi->idx;
1641 if (lhs)
1642 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = didx;
1643 break;
1644 case BUILT_IN_MEMPCPY:
1645 case BUILT_IN_MEMPCPY_CHK:
1646 case BUILT_IN_MEMPCPY_CHKP:
1647 case BUILT_IN_MEMPCPY_CHK_CHKP:
1648 break;
1649 default:
1650 gcc_unreachable ();
1654 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1655 If strlen of the second argument is known, strlen of the first argument
1656 is increased by the length of the second argument. Furthermore, attempt
1657 to convert it to memcpy/strcpy if the length of the first argument
1658 is known. */
1660 static void
1661 handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1663 int idx, didx;
1664 tree src, dst, srclen, dstlen, len, lhs, args, type, fn, objsz, endptr;
1665 bool success;
1666 gimple *stmt = gsi_stmt (*gsi);
1667 strinfo *si, *dsi;
1668 location_t loc;
1669 bool with_bounds = gimple_call_with_bounds_p (stmt);
1671 src = gimple_call_arg (stmt, with_bounds ? 2 : 1);
1672 dst = gimple_call_arg (stmt, 0);
1673 lhs = gimple_call_lhs (stmt);
1675 didx = get_stridx (dst);
1676 if (didx < 0)
1677 return;
1679 dsi = NULL;
1680 if (didx > 0)
1681 dsi = get_strinfo (didx);
1682 if (dsi == NULL || get_string_length (dsi) == NULL_TREE)
1684 /* strcat (p, q) can be transformed into
1685 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1686 with length endptr - p if we need to compute the length
1687 later on. Don't do this transformation if we don't need
1688 it. */
1689 if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
1691 if (didx == 0)
1693 didx = new_stridx (dst);
1694 if (didx == 0)
1695 return;
1697 if (dsi == NULL)
1699 dsi = new_strinfo (dst, didx, NULL_TREE);
1700 set_strinfo (didx, dsi);
1701 find_equal_ptrs (dst, didx);
1703 else
1705 dsi = unshare_strinfo (dsi);
1706 dsi->length = NULL_TREE;
1707 dsi->next = 0;
1708 dsi->endptr = NULL_TREE;
1710 dsi->writable = true;
1711 dsi->stmt = stmt;
1712 dsi->dont_invalidate = true;
1714 return;
1717 srclen = NULL_TREE;
1718 si = NULL;
1719 idx = get_stridx (src);
1720 if (idx < 0)
1721 srclen = build_int_cst (size_type_node, ~idx);
1722 else if (idx > 0)
1724 si = get_strinfo (idx);
1725 if (si != NULL)
1726 srclen = get_string_length (si);
1729 loc = gimple_location (stmt);
1730 dstlen = dsi->length;
1731 endptr = dsi->endptr;
1733 dsi = unshare_strinfo (dsi);
1734 dsi->endptr = NULL_TREE;
1735 dsi->stmt = NULL;
1736 dsi->writable = true;
1738 if (srclen != NULL_TREE)
1740 dsi->length = fold_build2_loc (loc, PLUS_EXPR, TREE_TYPE (dsi->length),
1741 dsi->length, srclen);
1742 adjust_related_strinfos (loc, dsi, srclen);
1743 dsi->dont_invalidate = true;
1745 else
1747 dsi->length = NULL;
1748 if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
1749 dsi->dont_invalidate = true;
1752 if (si != NULL)
1753 /* strcat src may not overlap dst, so src doesn't need to be
1754 invalidated either. */
1755 si->dont_invalidate = true;
1757 /* For now. Could remove the lhs from the call and add
1758 lhs = dst; afterwards. */
1759 if (lhs)
1760 return;
1762 fn = NULL_TREE;
1763 objsz = NULL_TREE;
1764 switch (bcode)
1766 case BUILT_IN_STRCAT:
1767 case BUILT_IN_STRCAT_CHKP:
1768 if (srclen != NULL_TREE)
1769 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
1770 else
1771 fn = builtin_decl_implicit (BUILT_IN_STRCPY);
1772 break;
1773 case BUILT_IN_STRCAT_CHK:
1774 case BUILT_IN_STRCAT_CHK_CHKP:
1775 if (srclen != NULL_TREE)
1776 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
1777 else
1778 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
1779 objsz = gimple_call_arg (stmt, with_bounds ? 4 : 2);
1780 break;
1781 default:
1782 gcc_unreachable ();
1785 if (fn == NULL_TREE)
1786 return;
1788 len = NULL_TREE;
1789 if (srclen != NULL_TREE)
1791 args = TYPE_ARG_TYPES (TREE_TYPE (fn));
1792 type = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
1794 len = fold_convert_loc (loc, type, unshare_expr (srclen));
1795 len = fold_build2_loc (loc, PLUS_EXPR, type, len,
1796 build_int_cst (type, 1));
1797 len = force_gimple_operand_gsi (gsi, len, true, NULL_TREE, true,
1798 GSI_SAME_STMT);
1800 if (endptr)
1801 dst = fold_convert_loc (loc, TREE_TYPE (dst), unshare_expr (endptr));
1802 else
1803 dst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
1804 TREE_TYPE (dst), unshare_expr (dst),
1805 fold_convert_loc (loc, sizetype,
1806 unshare_expr (dstlen)));
1807 dst = force_gimple_operand_gsi (gsi, dst, true, NULL_TREE, true,
1808 GSI_SAME_STMT);
1809 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1811 fprintf (dump_file, "Optimizing: ");
1812 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1814 if (with_bounds)
1816 fn = chkp_maybe_create_clone (fn)->decl;
1817 if (srclen != NULL_TREE)
1818 success = update_gimple_call (gsi, fn, 5 + (objsz != NULL_TREE),
1819 dst,
1820 gimple_call_arg (stmt, 1),
1821 src,
1822 gimple_call_arg (stmt, 3),
1823 len, objsz);
1824 else
1825 success = update_gimple_call (gsi, fn, 4 + (objsz != NULL_TREE),
1826 dst,
1827 gimple_call_arg (stmt, 1),
1828 src,
1829 gimple_call_arg (stmt, 3),
1830 objsz);
1832 else
1833 if (srclen != NULL_TREE)
1834 success = update_gimple_call (gsi, fn, 3 + (objsz != NULL_TREE),
1835 dst, src, len, objsz);
1836 else
1837 success = update_gimple_call (gsi, fn, 2 + (objsz != NULL_TREE),
1838 dst, src, objsz);
1839 if (success)
1841 stmt = gsi_stmt (*gsi);
1842 gimple_call_set_with_bounds (stmt, with_bounds);
1843 update_stmt (stmt);
1844 if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1846 fprintf (dump_file, "into: ");
1847 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1849 /* If srclen == NULL, note that current string length can be
1850 computed by transforming this strcpy into stpcpy. */
1851 if (srclen == NULL_TREE && dsi->dont_invalidate)
1852 dsi->stmt = stmt;
1853 adjust_last_stmt (dsi, stmt, true);
1854 if (srclen != NULL_TREE)
1856 laststmt.stmt = stmt;
1857 laststmt.len = srclen;
1858 laststmt.stridx = dsi->idx;
1861 else if (dump_file && (dump_flags & TDF_DETAILS) != 0)
1862 fprintf (dump_file, "not possible.\n");
1865 /* Handle a call to malloc or calloc. */
1867 static void
1868 handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi)
1870 gimple *stmt = gsi_stmt (*gsi);
1871 tree lhs = gimple_call_lhs (stmt);
1872 gcc_assert (get_stridx (lhs) == 0);
1873 int idx = new_stridx (lhs);
1874 tree length = NULL_TREE;
1875 if (bcode == BUILT_IN_CALLOC)
1876 length = build_int_cst (size_type_node, 0);
1877 strinfo *si = new_strinfo (lhs, idx, length);
1878 if (bcode == BUILT_IN_CALLOC)
1879 si->endptr = lhs;
1880 set_strinfo (idx, si);
1881 si->writable = true;
1882 si->stmt = stmt;
1883 si->dont_invalidate = true;
1886 /* Handle a call to memset.
1887 After a call to calloc, memset(,0,) is unnecessary.
1888 memset(malloc(n),0,n) is calloc(n,1). */
1890 static bool
1891 handle_builtin_memset (gimple_stmt_iterator *gsi)
1893 gimple *stmt2 = gsi_stmt (*gsi);
1894 if (!integer_zerop (gimple_call_arg (stmt2, 1)))
1895 return true;
1896 tree ptr = gimple_call_arg (stmt2, 0);
1897 int idx1 = get_stridx (ptr);
1898 if (idx1 <= 0)
1899 return true;
1900 strinfo *si1 = get_strinfo (idx1);
1901 if (!si1)
1902 return true;
1903 gimple *stmt1 = si1->stmt;
1904 if (!stmt1 || !is_gimple_call (stmt1))
1905 return true;
1906 tree callee1 = gimple_call_fndecl (stmt1);
1907 if (!valid_builtin_call (stmt1))
1908 return true;
1909 enum built_in_function code1 = DECL_FUNCTION_CODE (callee1);
1910 tree size = gimple_call_arg (stmt2, 2);
1911 if (code1 == BUILT_IN_CALLOC)
1912 /* Not touching stmt1 */ ;
1913 else if (code1 == BUILT_IN_MALLOC
1914 && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0))
1916 gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1);
1917 update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2,
1918 size, build_one_cst (size_type_node));
1919 si1->length = build_int_cst (size_type_node, 0);
1920 si1->stmt = gsi_stmt (gsi1);
1922 else
1923 return true;
1924 tree lhs = gimple_call_lhs (stmt2);
1925 unlink_stmt_vdef (stmt2);
1926 if (lhs)
1928 gimple *assign = gimple_build_assign (lhs, ptr);
1929 gsi_replace (gsi, assign, false);
1931 else
1933 gsi_remove (gsi, true);
1934 release_defs (stmt2);
1937 return false;
1940 /* Handle a call to memcmp. We try to handle small comparisons by
1941 converting them to load and compare, and replacing the call to memcmp
1942 with a __builtin_memcmp_eq call where possible. */
1944 static bool
1945 handle_builtin_memcmp (gimple_stmt_iterator *gsi)
1947 gcall *stmt2 = as_a <gcall *> (gsi_stmt (*gsi));
1948 tree res = gimple_call_lhs (stmt2);
1949 tree arg1 = gimple_call_arg (stmt2, 0);
1950 tree arg2 = gimple_call_arg (stmt2, 1);
1951 tree len = gimple_call_arg (stmt2, 2);
1952 unsigned HOST_WIDE_INT leni;
1953 use_operand_p use_p;
1954 imm_use_iterator iter;
1956 if (!res)
1957 return true;
1959 FOR_EACH_IMM_USE_FAST (use_p, iter, res)
1961 gimple *ustmt = USE_STMT (use_p);
1963 if (is_gimple_debug (ustmt))
1964 continue;
1965 if (gimple_code (ustmt) == GIMPLE_ASSIGN)
1967 gassign *asgn = as_a <gassign *> (ustmt);
1968 tree_code code = gimple_assign_rhs_code (asgn);
1969 if ((code != EQ_EXPR && code != NE_EXPR)
1970 || !integer_zerop (gimple_assign_rhs2 (asgn)))
1971 return true;
1973 else if (gimple_code (ustmt) == GIMPLE_COND)
1975 tree_code code = gimple_cond_code (ustmt);
1976 if ((code != EQ_EXPR && code != NE_EXPR)
1977 || !integer_zerop (gimple_cond_rhs (ustmt)))
1978 return true;
1980 else
1981 return true;
1984 if (tree_fits_uhwi_p (len)
1985 && (leni = tree_to_uhwi (len)) <= GET_MODE_SIZE (word_mode)
1986 && pow2p_hwi (leni))
1988 leni *= CHAR_TYPE_SIZE;
1989 unsigned align1 = get_pointer_alignment (arg1);
1990 unsigned align2 = get_pointer_alignment (arg2);
1991 unsigned align = MIN (align1, align2);
1992 machine_mode mode = mode_for_size (leni, MODE_INT, 1);
1993 if (mode != BLKmode
1994 && (align >= leni || !SLOW_UNALIGNED_ACCESS (mode, align)))
1996 location_t loc = gimple_location (stmt2);
1997 tree type, off;
1998 type = build_nonstandard_integer_type (leni, 1);
1999 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type)) == leni);
2000 tree ptrtype = build_pointer_type_for_mode (char_type_node,
2001 ptr_mode, true);
2002 off = build_int_cst (ptrtype, 0);
2003 arg1 = build2_loc (loc, MEM_REF, type, arg1, off);
2004 arg2 = build2_loc (loc, MEM_REF, type, arg2, off);
2005 tree tem1 = fold_const_aggregate_ref (arg1);
2006 if (tem1)
2007 arg1 = tem1;
2008 tree tem2 = fold_const_aggregate_ref (arg2);
2009 if (tem2)
2010 arg2 = tem2;
2011 res = fold_convert_loc (loc, TREE_TYPE (res),
2012 fold_build2_loc (loc, NE_EXPR,
2013 boolean_type_node,
2014 arg1, arg2));
2015 gimplify_and_update_call_from_tree (gsi, res);
2016 return false;
2020 gimple_call_set_fndecl (stmt2, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ));
2021 return false;
2024 /* Handle a POINTER_PLUS_EXPR statement.
2025 For p = "abcd" + 2; compute associated length, or if
2026 p = q + off is pointing to a '\0' character of a string, call
2027 zero_length_string on it. */
2029 static void
2030 handle_pointer_plus (gimple_stmt_iterator *gsi)
2032 gimple *stmt = gsi_stmt (*gsi);
2033 tree lhs = gimple_assign_lhs (stmt), off;
2034 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2035 strinfo *si, *zsi;
2037 if (idx == 0)
2038 return;
2040 if (idx < 0)
2042 tree off = gimple_assign_rhs2 (stmt);
2043 if (tree_fits_uhwi_p (off)
2044 && tree_to_uhwi (off) <= (unsigned HOST_WIDE_INT) ~idx)
2045 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)]
2046 = ~(~idx - (int) tree_to_uhwi (off));
2047 return;
2050 si = get_strinfo (idx);
2051 if (si == NULL || si->length == NULL_TREE)
2052 return;
2054 off = gimple_assign_rhs2 (stmt);
2055 zsi = NULL;
2056 if (operand_equal_p (si->length, off, 0))
2057 zsi = zero_length_string (lhs, si);
2058 else if (TREE_CODE (off) == SSA_NAME)
2060 gimple *def_stmt = SSA_NAME_DEF_STMT (off);
2061 if (gimple_assign_single_p (def_stmt)
2062 && operand_equal_p (si->length, gimple_assign_rhs1 (def_stmt), 0))
2063 zsi = zero_length_string (lhs, si);
2065 if (zsi != NULL
2066 && si->endptr != NULL_TREE
2067 && si->endptr != lhs
2068 && TREE_CODE (si->endptr) == SSA_NAME)
2070 enum tree_code rhs_code
2071 = useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (si->endptr))
2072 ? SSA_NAME : NOP_EXPR;
2073 gimple_assign_set_rhs_with_ops (gsi, rhs_code, si->endptr);
2074 gcc_assert (gsi_stmt (*gsi) == stmt);
2075 update_stmt (stmt);
2079 /* Handle a single character store. */
2081 static bool
2082 handle_char_store (gimple_stmt_iterator *gsi)
2084 int idx = -1;
2085 strinfo *si = NULL;
2086 gimple *stmt = gsi_stmt (*gsi);
2087 tree ssaname = NULL_TREE, lhs = gimple_assign_lhs (stmt);
2089 if (TREE_CODE (lhs) == MEM_REF
2090 && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME)
2092 if (integer_zerop (TREE_OPERAND (lhs, 1)))
2094 ssaname = TREE_OPERAND (lhs, 0);
2095 idx = get_stridx (ssaname);
2098 else
2099 idx = get_addr_stridx (lhs, NULL_TREE);
2101 if (idx > 0)
2103 si = get_strinfo (idx);
2104 if (si != NULL && si->length != NULL_TREE && integer_zerop (si->length))
2106 if (initializer_zerop (gimple_assign_rhs1 (stmt)))
2108 /* When storing '\0', the store can be removed
2109 if we know it has been stored in the current function. */
2110 if (!stmt_could_throw_p (stmt) && si->writable)
2112 unlink_stmt_vdef (stmt);
2113 release_defs (stmt);
2114 gsi_remove (gsi, true);
2115 return false;
2117 else
2119 si->writable = true;
2120 gsi_next (gsi);
2121 return false;
2124 else
2125 /* Otherwise this statement overwrites the '\0' with
2126 something, if the previous stmt was a memcpy,
2127 its length may be decreased. */
2128 adjust_last_stmt (si, stmt, false);
2130 else if (si != NULL && integer_zerop (gimple_assign_rhs1 (stmt)))
2132 si = unshare_strinfo (si);
2133 si->length = build_int_cst (size_type_node, 0);
2134 si->endptr = NULL;
2135 si->prev = 0;
2136 si->next = 0;
2137 si->stmt = NULL;
2138 si->first = 0;
2139 si->writable = true;
2140 if (ssaname && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
2141 si->endptr = ssaname;
2142 si->dont_invalidate = true;
2144 /* If si->length is non-zero constant, we aren't overwriting '\0',
2145 and if we aren't storing '\0', we know that the length of the
2146 string and any other zero terminated string in memory remains
2147 the same. In that case we move to the next gimple statement and
2148 return to signal the caller that it shouldn't invalidate anything.
2150 This is benefical for cases like:
2152 char p[20];
2153 void foo (char *q)
2155 strcpy (p, "foobar");
2156 size_t len = strlen (p); // This can be optimized into 6
2157 size_t len2 = strlen (q); // This has to be computed
2158 p[0] = 'X';
2159 size_t len3 = strlen (p); // This can be optimized into 6
2160 size_t len4 = strlen (q); // This can be optimized into len2
2161 bar (len, len2, len3, len4);
2164 else if (si != NULL && si->length != NULL_TREE
2165 && TREE_CODE (si->length) == INTEGER_CST
2166 && integer_nonzerop (gimple_assign_rhs1 (stmt)))
2168 gsi_next (gsi);
2169 return false;
2172 else if (idx == 0 && initializer_zerop (gimple_assign_rhs1 (stmt)))
2174 if (ssaname)
2176 si = zero_length_string (ssaname, NULL);
2177 if (si != NULL)
2178 si->dont_invalidate = true;
2180 else
2182 int idx = new_addr_stridx (lhs);
2183 if (idx != 0)
2185 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2186 build_int_cst (size_type_node, 0));
2187 set_strinfo (idx, si);
2188 si->dont_invalidate = true;
2191 if (si != NULL)
2192 si->writable = true;
2194 else if (idx == 0
2195 && TREE_CODE (gimple_assign_rhs1 (stmt)) == STRING_CST
2196 && ssaname == NULL_TREE
2197 && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
2199 size_t l = strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt)));
2200 HOST_WIDE_INT a = int_size_in_bytes (TREE_TYPE (lhs));
2201 if (a > 0 && (unsigned HOST_WIDE_INT) a > l)
2203 int idx = new_addr_stridx (lhs);
2204 if (idx != 0)
2206 si = new_strinfo (build_fold_addr_expr (lhs), idx,
2207 build_int_cst (size_type_node, l));
2208 set_strinfo (idx, si);
2209 si->dont_invalidate = true;
2214 if (si != NULL && initializer_zerop (gimple_assign_rhs1 (stmt)))
2216 /* Allow adjust_last_stmt to remove it if the stored '\0'
2217 is immediately overwritten. */
2218 laststmt.stmt = stmt;
2219 laststmt.len = build_int_cst (size_type_node, 1);
2220 laststmt.stridx = si->idx;
2222 return true;
2225 /* Attempt to optimize a single statement at *GSI using string length
2226 knowledge. */
2228 static bool
2229 strlen_optimize_stmt (gimple_stmt_iterator *gsi)
2231 gimple *stmt = gsi_stmt (*gsi);
2233 if (is_gimple_call (stmt))
2235 tree callee = gimple_call_fndecl (stmt);
2236 if (valid_builtin_call (stmt))
2237 switch (DECL_FUNCTION_CODE (callee))
2239 case BUILT_IN_STRLEN:
2240 case BUILT_IN_STRLEN_CHKP:
2241 handle_builtin_strlen (gsi);
2242 break;
2243 case BUILT_IN_STRCHR:
2244 case BUILT_IN_STRCHR_CHKP:
2245 handle_builtin_strchr (gsi);
2246 break;
2247 case BUILT_IN_STRCPY:
2248 case BUILT_IN_STRCPY_CHK:
2249 case BUILT_IN_STPCPY:
2250 case BUILT_IN_STPCPY_CHK:
2251 case BUILT_IN_STRCPY_CHKP:
2252 case BUILT_IN_STRCPY_CHK_CHKP:
2253 case BUILT_IN_STPCPY_CHKP:
2254 case BUILT_IN_STPCPY_CHK_CHKP:
2255 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee), gsi);
2256 break;
2257 case BUILT_IN_MEMCPY:
2258 case BUILT_IN_MEMCPY_CHK:
2259 case BUILT_IN_MEMPCPY:
2260 case BUILT_IN_MEMPCPY_CHK:
2261 case BUILT_IN_MEMCPY_CHKP:
2262 case BUILT_IN_MEMCPY_CHK_CHKP:
2263 case BUILT_IN_MEMPCPY_CHKP:
2264 case BUILT_IN_MEMPCPY_CHK_CHKP:
2265 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee), gsi);
2266 break;
2267 case BUILT_IN_STRCAT:
2268 case BUILT_IN_STRCAT_CHK:
2269 case BUILT_IN_STRCAT_CHKP:
2270 case BUILT_IN_STRCAT_CHK_CHKP:
2271 handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
2272 break;
2273 case BUILT_IN_MALLOC:
2274 case BUILT_IN_CALLOC:
2275 handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi);
2276 break;
2277 case BUILT_IN_MEMSET:
2278 if (!handle_builtin_memset (gsi))
2279 return false;
2280 break;
2281 case BUILT_IN_MEMCMP:
2282 if (!handle_builtin_memcmp (gsi))
2283 return false;
2284 break;
2285 default:
2286 break;
2289 else if (is_gimple_assign (stmt) && !gimple_clobber_p (stmt))
2291 tree lhs = gimple_assign_lhs (stmt);
2293 if (TREE_CODE (lhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (lhs)))
2295 if (gimple_assign_single_p (stmt)
2296 || (gimple_assign_cast_p (stmt)
2297 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
2299 int idx = get_stridx (gimple_assign_rhs1 (stmt));
2300 ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
2302 else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
2303 handle_pointer_plus (gsi);
2305 else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
2307 tree type = TREE_TYPE (lhs);
2308 if (TREE_CODE (type) == ARRAY_TYPE)
2309 type = TREE_TYPE (type);
2310 if (TREE_CODE (type) == INTEGER_TYPE
2311 && TYPE_MODE (type) == TYPE_MODE (char_type_node)
2312 && TYPE_PRECISION (type) == TYPE_PRECISION (char_type_node))
2314 if (! handle_char_store (gsi))
2315 return false;
2320 if (gimple_vdef (stmt))
2321 maybe_invalidate (stmt);
2322 return true;
2325 /* Recursively call maybe_invalidate on stmts that might be executed
2326 in between dombb and current bb and that contain a vdef. Stop when
2327 *count stmts are inspected, or if the whole strinfo vector has
2328 been invalidated. */
2330 static void
2331 do_invalidate (basic_block dombb, gimple *phi, bitmap visited, int *count)
2333 unsigned int i, n = gimple_phi_num_args (phi);
2335 for (i = 0; i < n; i++)
2337 tree vuse = gimple_phi_arg_def (phi, i);
2338 gimple *stmt = SSA_NAME_DEF_STMT (vuse);
2339 basic_block bb = gimple_bb (stmt);
2340 if (bb == NULL
2341 || bb == dombb
2342 || !bitmap_set_bit (visited, bb->index)
2343 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2344 continue;
2345 while (1)
2347 if (gimple_code (stmt) == GIMPLE_PHI)
2349 do_invalidate (dombb, stmt, visited, count);
2350 if (*count == 0)
2351 return;
2352 break;
2354 if (--*count == 0)
2355 return;
2356 if (!maybe_invalidate (stmt))
2358 *count = 0;
2359 return;
2361 vuse = gimple_vuse (stmt);
2362 stmt = SSA_NAME_DEF_STMT (vuse);
2363 if (gimple_bb (stmt) != bb)
2365 bb = gimple_bb (stmt);
2366 if (bb == NULL
2367 || bb == dombb
2368 || !bitmap_set_bit (visited, bb->index)
2369 || !dominated_by_p (CDI_DOMINATORS, bb, dombb))
2370 break;
2376 class strlen_dom_walker : public dom_walker
2378 public:
2379 strlen_dom_walker (cdi_direction direction) : dom_walker (direction) {}
2381 virtual edge before_dom_children (basic_block);
2382 virtual void after_dom_children (basic_block);
2385 /* Callback for walk_dominator_tree. Attempt to optimize various
2386 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */
2388 edge
2389 strlen_dom_walker::before_dom_children (basic_block bb)
2391 basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
2393 if (dombb == NULL)
2394 stridx_to_strinfo = NULL;
2395 else
2397 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) dombb->aux);
2398 if (stridx_to_strinfo)
2400 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2401 gsi_next (&gsi))
2403 gphi *phi = gsi.phi ();
2404 if (virtual_operand_p (gimple_phi_result (phi)))
2406 bitmap visited = BITMAP_ALLOC (NULL);
2407 int count_vdef = 100;
2408 do_invalidate (dombb, phi, visited, &count_vdef);
2409 BITMAP_FREE (visited);
2410 if (count_vdef == 0)
2412 /* If there were too many vdefs in between immediate
2413 dominator and current bb, invalidate everything.
2414 If stridx_to_strinfo has been unshared, we need
2415 to free it, otherwise just set it to NULL. */
2416 if (!strinfo_shared ())
2418 unsigned int i;
2419 strinfo *si;
2421 for (i = 1;
2422 vec_safe_iterate (stridx_to_strinfo, i, &si);
2423 ++i)
2425 free_strinfo (si);
2426 (*stridx_to_strinfo)[i] = NULL;
2429 else
2430 stridx_to_strinfo = NULL;
2432 break;
2438 /* If all PHI arguments have the same string index, the PHI result
2439 has it as well. */
2440 for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
2441 gsi_next (&gsi))
2443 gphi *phi = gsi.phi ();
2444 tree result = gimple_phi_result (phi);
2445 if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
2447 int idx = get_stridx (gimple_phi_arg_def (phi, 0));
2448 if (idx != 0)
2450 unsigned int i, n = gimple_phi_num_args (phi);
2451 for (i = 1; i < n; i++)
2452 if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
2453 break;
2454 if (i == n)
2455 ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
2460 /* Attempt to optimize individual statements. */
2461 for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
2462 if (strlen_optimize_stmt (&gsi))
2463 gsi_next (&gsi);
2465 bb->aux = stridx_to_strinfo;
2466 if (vec_safe_length (stridx_to_strinfo) && !strinfo_shared ())
2467 (*stridx_to_strinfo)[0] = (strinfo *) bb;
2468 return NULL;
2471 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2472 owned by the current bb, clear bb->aux. */
2474 void
2475 strlen_dom_walker::after_dom_children (basic_block bb)
2477 if (bb->aux)
2479 stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);
2480 if (vec_safe_length (stridx_to_strinfo)
2481 && (*stridx_to_strinfo)[0] == (strinfo *) bb)
2483 unsigned int i;
2484 strinfo *si;
2486 for (i = 1; vec_safe_iterate (stridx_to_strinfo, i, &si); ++i)
2487 free_strinfo (si);
2488 vec_free (stridx_to_strinfo);
2490 bb->aux = NULL;
2494 /* Main entry point. */
2496 namespace {
2498 const pass_data pass_data_strlen =
2500 GIMPLE_PASS, /* type */
2501 "strlen", /* name */
2502 OPTGROUP_NONE, /* optinfo_flags */
2503 TV_TREE_STRLEN, /* tv_id */
2504 ( PROP_cfg | PROP_ssa ), /* properties_required */
2505 0, /* properties_provided */
2506 0, /* properties_destroyed */
2507 0, /* todo_flags_start */
2508 0, /* todo_flags_finish */
2511 class pass_strlen : public gimple_opt_pass
2513 public:
2514 pass_strlen (gcc::context *ctxt)
2515 : gimple_opt_pass (pass_data_strlen, ctxt)
2518 /* opt_pass methods: */
2519 virtual bool gate (function *) { return flag_optimize_strlen != 0; }
2520 virtual unsigned int execute (function *);
2522 }; // class pass_strlen
2524 unsigned int
2525 pass_strlen::execute (function *fun)
2527 ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
2528 max_stridx = 1;
2530 calculate_dominance_info (CDI_DOMINATORS);
2532 /* String length optimization is implemented as a walk of the dominator
2533 tree and a forward walk of statements within each block. */
2534 strlen_dom_walker (CDI_DOMINATORS).walk (fun->cfg->x_entry_block_ptr);
2536 ssa_ver_to_stridx.release ();
2537 strinfo_pool.release ();
2538 if (decl_to_stridxlist_htab)
2540 obstack_free (&stridx_obstack, NULL);
2541 delete decl_to_stridxlist_htab;
2542 decl_to_stridxlist_htab = NULL;
2544 laststmt.stmt = NULL;
2545 laststmt.len = NULL_TREE;
2546 laststmt.stridx = 0;
2548 return 0;
2551 } // anon namespace
2553 gimple_opt_pass *
2554 make_pass_strlen (gcc::context *ctxt)
2556 return new pass_strlen (ctxt);