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