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