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