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