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