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