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