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