1 /* String length optimization
2 Copyright (C) 2011-2016 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
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)
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.
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/>. */
23 #include "coretypes.h"
28 #include "alloc-pool.h"
29 #include "tree-pass.h"
32 #include "gimple-pretty-print.h"
33 #include "fold-const.h"
34 #include "stor-layout.h"
35 #include "gimple-fold.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
43 #include "tree-ssa-propagate.h"
46 #include "tree-hash-traits.h"
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). */
52 static vec
<int> ssa_ver_to_stridx
;
54 /* Number of currently active string indexes plus one. */
55 static int max_stridx
;
57 /* String information record. */
60 /* String length of this string. */
62 /* Any of the corresponding pointers for querying alias oracle. */
64 /* Statement for delayed length computation. */
66 /* Pointer to '\0' if known, if NULL, it can be computed as
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
74 /* Copy of index. get_strinfo (si->idx) should return si; */
76 /* These 3 fields are for chaining related string pointers together.
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. */
96 /* A flag whether the string is known to be written in the current
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
;
104 /* Pool for allocating strinfo_struct entries. */
105 static object_allocator
<strinfo
> strinfo_pool ("strinfo pool");
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. */
113 static vec
<strinfo
*, va_heap
, vl_embed
> *stridx_to_strinfo
;
115 /* One OFFSET->IDX mapping. */
118 struct stridxlist
*next
;
119 HOST_WIDE_INT offset
;
123 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
124 struct decl_stridxlist_map
126 struct tree_map_base base
;
127 struct stridxlist list
;
130 /* Hash table for mapping decls to a chained list of offset -> idx
132 static hash_map
<tree_decl_hash
, stridxlist
> *decl_to_stridxlist_htab
;
134 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
135 static struct obstack stridx_obstack
;
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. */
140 struct laststmt_struct
147 static int get_stridx_plus_constant (strinfo
*, HOST_WIDE_INT
, tree
);
149 /* Return strinfo vector entry IDX. */
151 static inline strinfo
*
152 get_strinfo (int idx
)
154 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
156 return (*stridx_to_strinfo
)[idx
];
159 /* Helper function for get_stridx. */
162 get_addr_stridx (tree exp
)
165 struct stridxlist
*list
;
168 if (!decl_to_stridxlist_htab
)
171 base
= get_addr_base_and_unit_offset (exp
, &off
);
172 if (base
== NULL
|| !DECL_P (base
))
175 list
= decl_to_stridxlist_htab
->get (base
);
181 if (list
->offset
== off
)
189 /* Return string index for EXP. */
192 get_stridx (tree exp
)
196 if (TREE_CODE (exp
) == SSA_NAME
)
198 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
199 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
202 HOST_WIDE_INT off
= 0;
203 for (i
= 0; i
< 5; i
++)
205 gimple
*def_stmt
= SSA_NAME_DEF_STMT (e
);
206 if (!is_gimple_assign (def_stmt
)
207 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
209 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
210 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
211 if (TREE_CODE (rhs1
) != SSA_NAME
212 || !tree_fits_shwi_p (rhs2
))
214 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
217 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
220 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
223 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
226 && TREE_CODE (si
->length
) == INTEGER_CST
227 && compare_tree_int (si
->length
, off
) != -1)
228 return get_stridx_plus_constant (si
, off
, exp
);
235 if (TREE_CODE (exp
) == ADDR_EXPR
)
237 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
242 s
= string_constant (exp
, &o
);
244 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
245 && TREE_STRING_LENGTH (s
) > 0)
247 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
248 const char *p
= TREE_STRING_POINTER (s
);
249 int max
= TREE_STRING_LENGTH (s
) - 1;
251 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
252 return ~(int) strlen (p
+ offset
);
257 /* Return true if strinfo vector is shared with the immediate dominator. */
260 strinfo_shared (void)
262 return vec_safe_length (stridx_to_strinfo
)
263 && (*stridx_to_strinfo
)[0] != NULL
;
266 /* Unshare strinfo vector that is shared with the immediate dominator. */
269 unshare_strinfo_vec (void)
274 gcc_assert (strinfo_shared ());
275 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
276 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
279 (*stridx_to_strinfo
)[0] = NULL
;
282 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
283 Return a pointer to the location where the string index can
284 be stored (if 0) or is stored, or NULL if this can't be tracked. */
287 addr_stridxptr (tree exp
)
291 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
292 if (base
== NULL_TREE
|| !DECL_P (base
))
295 if (!decl_to_stridxlist_htab
)
297 decl_to_stridxlist_htab
298 = new hash_map
<tree_decl_hash
, stridxlist
> (64);
299 gcc_obstack_init (&stridx_obstack
);
303 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
307 for (i
= 0; i
< 16; i
++)
309 if (list
->offset
== off
)
311 if (list
->next
== NULL
)
316 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
326 /* Create a new string index, or return 0 if reached limit. */
329 new_stridx (tree exp
)
332 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
334 if (TREE_CODE (exp
) == SSA_NAME
)
336 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
339 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
342 if (TREE_CODE (exp
) == ADDR_EXPR
)
344 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
347 gcc_assert (*pidx
== 0);
348 *pidx
= max_stridx
++;
355 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
358 new_addr_stridx (tree exp
)
361 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
363 pidx
= addr_stridxptr (exp
);
366 gcc_assert (*pidx
== 0);
367 *pidx
= max_stridx
++;
373 /* Create a new strinfo. */
376 new_strinfo (tree ptr
, int idx
, tree length
)
378 strinfo
*si
= strinfo_pool
.allocate ();
382 si
->endptr
= NULL_TREE
;
388 si
->writable
= false;
389 si
->dont_invalidate
= false;
393 /* Decrease strinfo refcount and free it if not referenced anymore. */
396 free_strinfo (strinfo
*si
)
398 if (si
&& --si
->refcount
== 0)
399 strinfo_pool
.remove (si
);
402 /* Set strinfo in the vector entry IDX to SI. */
405 set_strinfo (int idx
, strinfo
*si
)
407 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
408 unshare_strinfo_vec ();
409 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
410 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
411 (*stridx_to_strinfo
)[idx
] = si
;
414 /* Return string length, or NULL if it can't be computed. */
417 get_string_length (strinfo
*si
)
424 gimple
*stmt
= si
->stmt
, *lenstmt
;
425 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
426 tree callee
, lhs
, fn
, tem
;
428 gimple_stmt_iterator gsi
;
430 gcc_assert (is_gimple_call (stmt
));
431 callee
= gimple_call_fndecl (stmt
);
432 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
433 lhs
= gimple_call_lhs (stmt
);
434 /* unshare_strinfo is intentionally not called here. The (delayed)
435 transformation of strcpy or strcat into stpcpy is done at the place
436 of the former strcpy/strcat call and so can affect all the strinfos
437 with the same stmt. If they were unshared before and transformation
438 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
439 just compute the right length. */
440 switch (DECL_FUNCTION_CODE (callee
))
442 case BUILT_IN_STRCAT
:
443 case BUILT_IN_STRCAT_CHK
:
444 case BUILT_IN_STRCAT_CHKP
:
445 case BUILT_IN_STRCAT_CHK_CHKP
:
446 gsi
= gsi_for_stmt (stmt
);
447 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
448 gcc_assert (lhs
== NULL_TREE
);
449 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
452 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
453 2, tem
, gimple_call_arg (stmt
, 1));
454 gimple_call_set_with_bounds (lenstmt
, true);
457 lenstmt
= gimple_build_call (fn
, 1, tem
);
458 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
459 gimple_call_set_lhs (lenstmt
, lhs
);
460 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
461 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
462 tem
= gimple_call_arg (stmt
, 0);
463 if (!ptrofftype_p (TREE_TYPE (lhs
)))
465 lhs
= convert_to_ptrofftype (lhs
);
466 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
467 true, GSI_SAME_STMT
);
469 lenstmt
= gimple_build_assign
470 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
471 POINTER_PLUS_EXPR
,tem
, lhs
);
472 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
473 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
476 case BUILT_IN_STRCPY
:
477 case BUILT_IN_STRCPY_CHK
:
478 case BUILT_IN_STRCPY_CHKP
:
479 case BUILT_IN_STRCPY_CHK_CHKP
:
480 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
481 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
482 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
484 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
486 fn
= chkp_maybe_create_clone (fn
)->decl
;
487 gcc_assert (lhs
== NULL_TREE
);
488 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
490 fprintf (dump_file
, "Optimizing: ");
491 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
493 gimple_call_set_fndecl (stmt
, fn
);
494 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
495 gimple_call_set_lhs (stmt
, lhs
);
497 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
499 fprintf (dump_file
, "into: ");
500 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
503 case BUILT_IN_STPCPY
:
504 case BUILT_IN_STPCPY_CHK
:
505 case BUILT_IN_STPCPY_CHKP
:
506 case BUILT_IN_STPCPY_CHK_CHKP
:
507 gcc_assert (lhs
!= NULL_TREE
);
508 loc
= gimple_location (stmt
);
511 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
512 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
513 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
516 case BUILT_IN_MALLOC
:
518 /* BUILT_IN_CALLOC always has si->length set. */
528 /* Invalidate string length information for strings whose length
529 might change due to stores in stmt. */
532 maybe_invalidate (gimple
*stmt
)
536 bool nonempty
= false;
538 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
541 if (!si
->dont_invalidate
)
544 /* Do not use si->length. */
545 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
546 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
548 set_strinfo (i
, NULL
);
553 si
->dont_invalidate
= false;
559 /* Unshare strinfo record SI, if it has refcount > 1 or
560 if stridx_to_strinfo vector is shared with some other
564 unshare_strinfo (strinfo
*si
)
568 if (si
->refcount
== 1 && !strinfo_shared ())
571 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
572 nsi
->stmt
= si
->stmt
;
573 nsi
->endptr
= si
->endptr
;
574 nsi
->first
= si
->first
;
575 nsi
->prev
= si
->prev
;
576 nsi
->next
= si
->next
;
577 nsi
->writable
= si
->writable
;
578 set_strinfo (si
->idx
, nsi
);
583 /* Return first strinfo in the related strinfo chain
584 if all strinfos in between belong to the chain, otherwise
588 verify_related_strinfos (strinfo
*origsi
)
590 strinfo
*si
= origsi
, *psi
;
592 if (origsi
->first
== 0)
594 for (; si
->prev
; si
= psi
)
596 if (si
->first
!= origsi
->first
)
598 psi
= get_strinfo (si
->prev
);
601 if (psi
->next
!= si
->idx
)
604 if (si
->idx
!= si
->first
)
609 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
610 strinfo if there is any. Return it's idx, or 0 if no strinfo has
614 get_stridx_plus_constant (strinfo
*basesi
, HOST_WIDE_INT off
, tree ptr
)
616 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
618 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
621 if (basesi
->length
== NULL_TREE
622 || TREE_CODE (basesi
->length
) != INTEGER_CST
623 || compare_tree_int (basesi
->length
, off
) == -1
624 || !tree_fits_shwi_p (basesi
->length
))
627 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
628 strinfo
*si
= basesi
, *chainsi
;
629 if (si
->first
|| si
->prev
|| si
->next
)
630 si
= verify_related_strinfos (basesi
);
632 || si
->length
== NULL_TREE
633 || TREE_CODE (si
->length
) != INTEGER_CST
)
636 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
637 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
639 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
640 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
642 si
= get_strinfo (chainsi
->next
);
644 || si
->first
!= chainsi
->first
645 || si
->prev
!= chainsi
->idx
646 || si
->length
== NULL_TREE
647 || TREE_CODE (si
->length
) != INTEGER_CST
)
649 int r
= compare_tree_int (si
->length
, len
);
654 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
661 int idx
= new_stridx (ptr
);
664 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
665 set_strinfo (idx
, si
);
668 strinfo
*nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
669 si
->next
= nextsi
->idx
;
672 chainsi
= unshare_strinfo (chainsi
);
673 if (chainsi
->first
== 0)
674 chainsi
->first
= chainsi
->idx
;
676 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
677 chainsi
->endptr
= ptr
;
678 si
->endptr
= chainsi
->endptr
;
679 si
->prev
= chainsi
->idx
;
680 si
->first
= chainsi
->first
;
681 si
->writable
= chainsi
->writable
;
685 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
686 to a zero-length string and if possible chain it to a related strinfo
687 chain whose part is or might be CHAINSI. */
690 zero_length_string (tree ptr
, strinfo
*chainsi
)
694 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
695 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
696 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
697 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
699 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
703 si
= verify_related_strinfos (chainsi
);
707 for (; chainsi
->next
; chainsi
= si
)
709 if (chainsi
->endptr
== NULL_TREE
)
711 chainsi
= unshare_strinfo (chainsi
);
712 chainsi
->endptr
= ptr
;
714 si
= get_strinfo (chainsi
->next
);
716 || si
->first
!= chainsi
->first
717 || si
->prev
!= chainsi
->idx
)
720 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
721 if (chainsi
->endptr
== NULL_TREE
)
723 chainsi
= unshare_strinfo (chainsi
);
724 chainsi
->endptr
= ptr
;
726 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
730 chainsi
= unshare_strinfo (chainsi
);
733 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
737 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
739 chainsi
= unshare_strinfo (chainsi
);
745 idx
= new_stridx (ptr
);
748 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
749 set_strinfo (idx
, si
);
753 chainsi
= unshare_strinfo (chainsi
);
754 if (chainsi
->first
== 0)
755 chainsi
->first
= chainsi
->idx
;
757 if (chainsi
->endptr
== NULL_TREE
)
758 chainsi
->endptr
= ptr
;
759 si
->prev
= chainsi
->idx
;
760 si
->first
= chainsi
->first
;
761 si
->writable
= chainsi
->writable
;
766 /* For strinfo ORIGSI whose length has been just updated
767 update also related strinfo lengths (add ADJ to each,
768 but don't adjust ORIGSI). */
771 adjust_related_strinfos (location_t loc
, strinfo
*origsi
, tree adj
)
773 strinfo
*si
= verify_related_strinfos (origsi
);
786 si
= unshare_strinfo (si
);
789 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
790 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
791 TREE_TYPE (si
->length
), si
->length
,
794 else if (si
->stmt
!= NULL
)
795 /* Delayed length computation is unaffected. */
800 si
->endptr
= NULL_TREE
;
801 si
->dont_invalidate
= true;
805 nsi
= get_strinfo (si
->next
);
807 || nsi
->first
!= si
->first
808 || nsi
->prev
!= si
->idx
)
814 /* Find if there are other SSA_NAME pointers equal to PTR
815 for which we don't track their string lengths yet. If so, use
819 find_equal_ptrs (tree ptr
, int idx
)
821 if (TREE_CODE (ptr
) != SSA_NAME
)
825 gimple
*stmt
= SSA_NAME_DEF_STMT (ptr
);
826 if (!is_gimple_assign (stmt
))
828 ptr
= gimple_assign_rhs1 (stmt
);
829 switch (gimple_assign_rhs_code (stmt
))
834 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
836 if (TREE_CODE (ptr
) == SSA_NAME
)
838 if (TREE_CODE (ptr
) != ADDR_EXPR
)
843 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
844 if (pidx
!= NULL
&& *pidx
== 0)
852 /* We might find an endptr created in this pass. Grow the
853 vector in that case. */
854 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
855 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
857 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
859 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
863 /* If the last .MEM setter statement before STMT is
864 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
865 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
866 just memcpy (x, y, strlen (y)). SI must be the zero length
870 adjust_last_stmt (strinfo
*si
, gimple
*stmt
, bool is_strcat
)
872 tree vuse
, callee
, len
;
873 struct laststmt_struct last
= laststmt
;
874 strinfo
*lastsi
, *firstsi
;
875 unsigned len_arg_no
= 2;
877 laststmt
.stmt
= NULL
;
878 laststmt
.len
= NULL_TREE
;
881 if (last
.stmt
== NULL
)
884 vuse
= gimple_vuse (stmt
);
885 if (vuse
== NULL_TREE
886 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
887 || !has_single_use (vuse
))
890 gcc_assert (last
.stridx
> 0);
891 lastsi
= get_strinfo (last
.stridx
);
897 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
900 firstsi
= verify_related_strinfos (si
);
903 while (firstsi
!= lastsi
)
906 if (firstsi
->next
== 0)
908 nextsi
= get_strinfo (firstsi
->next
);
910 || nextsi
->prev
!= firstsi
->idx
911 || nextsi
->first
!= si
->first
)
919 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
923 if (is_gimple_assign (last
.stmt
))
925 gimple_stmt_iterator gsi
;
927 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
929 if (stmt_could_throw_p (last
.stmt
))
931 gsi
= gsi_for_stmt (last
.stmt
);
932 unlink_stmt_vdef (last
.stmt
);
933 release_defs (last
.stmt
);
934 gsi_remove (&gsi
, true);
938 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
941 callee
= gimple_call_fndecl (last
.stmt
);
942 switch (DECL_FUNCTION_CODE (callee
))
944 case BUILT_IN_MEMCPY
:
945 case BUILT_IN_MEMCPY_CHK
:
947 case BUILT_IN_MEMCPY_CHKP
:
948 case BUILT_IN_MEMCPY_CHK_CHKP
:
955 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
956 if (tree_fits_uhwi_p (len
))
958 if (!tree_fits_uhwi_p (last
.len
)
959 || integer_zerop (len
)
960 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
962 /* Don't adjust the length if it is divisible by 4, it is more efficient
963 to store the extra '\0' in that case. */
964 if ((tree_to_uhwi (len
) & 3) == 0)
967 else if (TREE_CODE (len
) == SSA_NAME
)
969 gimple
*def_stmt
= SSA_NAME_DEF_STMT (len
);
970 if (!is_gimple_assign (def_stmt
)
971 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
972 || gimple_assign_rhs1 (def_stmt
) != last
.len
973 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
979 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
980 update_stmt (last
.stmt
);
983 /* Handle a strlen call. If strlen of the argument is known, replace
984 the strlen call with the known value, otherwise remember that strlen
985 of the argument is stored in the lhs SSA_NAME. */
988 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
992 gimple
*stmt
= gsi_stmt (*gsi
);
993 tree lhs
= gimple_call_lhs (stmt
);
995 if (lhs
== NULL_TREE
)
998 src
= gimple_call_arg (stmt
, 0);
999 idx
= get_stridx (src
);
1006 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1010 si
= get_strinfo (idx
);
1012 rhs
= get_string_length (si
);
1014 if (rhs
!= NULL_TREE
)
1016 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1018 fprintf (dump_file
, "Optimizing: ");
1019 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1021 rhs
= unshare_expr (rhs
);
1022 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1023 rhs
= fold_convert_loc (gimple_location (stmt
),
1024 TREE_TYPE (lhs
), rhs
);
1025 if (!update_call_from_tree (gsi
, rhs
))
1026 gimplify_and_update_call_from_tree (gsi
, rhs
);
1027 stmt
= gsi_stmt (*gsi
);
1029 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1031 fprintf (dump_file
, "into: ");
1032 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1035 && TREE_CODE (si
->length
) != SSA_NAME
1036 && TREE_CODE (si
->length
) != INTEGER_CST
1037 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1039 si
= unshare_strinfo (si
);
1045 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1048 idx
= new_stridx (src
);
1049 else if (get_strinfo (idx
) != NULL
)
1053 strinfo
*si
= new_strinfo (src
, idx
, lhs
);
1054 set_strinfo (idx
, si
);
1055 find_equal_ptrs (src
, idx
);
1059 /* Handle a strchr call. If strlen of the first argument is known, replace
1060 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1061 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1064 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1068 gimple
*stmt
= gsi_stmt (*gsi
);
1069 tree lhs
= gimple_call_lhs (stmt
);
1070 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1072 if (lhs
== NULL_TREE
)
1075 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1078 src
= gimple_call_arg (stmt
, 0);
1079 idx
= get_stridx (src
);
1086 rhs
= build_int_cst (size_type_node
, ~idx
);
1090 si
= get_strinfo (idx
);
1092 rhs
= get_string_length (si
);
1094 if (rhs
!= NULL_TREE
)
1096 location_t loc
= gimple_location (stmt
);
1098 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1100 fprintf (dump_file
, "Optimizing: ");
1101 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1103 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1105 rhs
= unshare_expr (si
->endptr
);
1106 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1108 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1112 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1113 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1114 TREE_TYPE (src
), src
, rhs
);
1115 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1117 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1119 if (!update_call_from_tree (gsi
, rhs
))
1120 gimplify_and_update_call_from_tree (gsi
, rhs
);
1121 stmt
= gsi_stmt (*gsi
);
1123 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1125 fprintf (dump_file
, "into: ");
1126 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1129 && si
->endptr
== NULL_TREE
1130 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1132 si
= unshare_strinfo (si
);
1135 zero_length_string (lhs
, si
);
1139 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1141 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1144 idx
= new_stridx (src
);
1145 else if (get_strinfo (idx
) != NULL
)
1147 zero_length_string (lhs
, NULL
);
1152 location_t loc
= gimple_location (stmt
);
1153 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1154 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1155 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1156 size_type_node
, lhsu
, srcu
);
1157 strinfo
*si
= new_strinfo (src
, idx
, length
);
1159 set_strinfo (idx
, si
);
1160 find_equal_ptrs (src
, idx
);
1161 zero_length_string (lhs
, si
);
1165 zero_length_string (lhs
, NULL
);
1168 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1169 If strlen of the second argument is known, strlen of the first argument
1170 is the same after this call. Furthermore, attempt to convert it to
1174 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1177 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1179 gimple
*stmt
= gsi_stmt (*gsi
);
1180 strinfo
*si
, *dsi
, *olddsi
, *zsi
;
1182 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1184 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1185 dst
= gimple_call_arg (stmt
, 0);
1186 lhs
= gimple_call_lhs (stmt
);
1187 idx
= get_stridx (src
);
1190 si
= get_strinfo (idx
);
1192 didx
= get_stridx (dst
);
1196 olddsi
= get_strinfo (didx
);
1201 adjust_last_stmt (olddsi
, stmt
, false);
1205 srclen
= get_string_length (si
);
1207 srclen
= build_int_cst (size_type_node
, ~idx
);
1209 loc
= gimple_location (stmt
);
1210 if (srclen
== NULL_TREE
)
1213 case BUILT_IN_STRCPY
:
1214 case BUILT_IN_STRCPY_CHK
:
1215 case BUILT_IN_STRCPY_CHKP
:
1216 case BUILT_IN_STRCPY_CHK_CHKP
:
1217 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1220 case BUILT_IN_STPCPY
:
1221 case BUILT_IN_STPCPY_CHK
:
1222 case BUILT_IN_STPCPY_CHKP
:
1223 case BUILT_IN_STPCPY_CHK_CHKP
:
1224 if (lhs
== NULL_TREE
)
1228 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1229 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1230 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1240 didx
= new_stridx (dst
);
1246 oldlen
= olddsi
->length
;
1247 dsi
= unshare_strinfo (olddsi
);
1248 dsi
->length
= srclen
;
1249 /* Break the chain, so adjust_related_strinfo on later pointers in
1250 the chain won't adjust this one anymore. */
1253 dsi
->endptr
= NULL_TREE
;
1257 dsi
= new_strinfo (dst
, didx
, srclen
);
1258 set_strinfo (didx
, dsi
);
1259 find_equal_ptrs (dst
, didx
);
1261 dsi
->writable
= true;
1262 dsi
->dont_invalidate
= true;
1264 if (dsi
->length
== NULL_TREE
)
1268 /* If string length of src is unknown, use delayed length
1269 computation. If string lenth of dst will be needed, it
1270 can be computed by transforming this strcpy call into
1271 stpcpy and subtracting dst from the return value. */
1273 /* Look for earlier strings whose length could be determined if
1274 this strcpy is turned into an stpcpy. */
1276 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1278 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1280 /* When setting a stmt for delayed length computation
1281 prevent all strinfos through dsi from being
1283 chainsi
= unshare_strinfo (chainsi
);
1284 chainsi
->stmt
= stmt
;
1285 chainsi
->length
= NULL_TREE
;
1286 chainsi
->endptr
= NULL_TREE
;
1287 chainsi
->dont_invalidate
= true;
1296 tree adj
= NULL_TREE
;
1297 if (oldlen
== NULL_TREE
)
1299 else if (integer_zerop (oldlen
))
1301 else if (TREE_CODE (oldlen
) == INTEGER_CST
1302 || TREE_CODE (srclen
) == INTEGER_CST
)
1303 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1304 TREE_TYPE (srclen
), srclen
,
1305 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1307 if (adj
!= NULL_TREE
)
1308 adjust_related_strinfos (loc
, dsi
, adj
);
1312 /* strcpy src may not overlap dst, so src doesn't need to be
1313 invalidated either. */
1315 si
->dont_invalidate
= true;
1321 case BUILT_IN_STRCPY
:
1322 case BUILT_IN_STRCPY_CHKP
:
1323 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1325 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1327 case BUILT_IN_STRCPY_CHK
:
1328 case BUILT_IN_STRCPY_CHK_CHKP
:
1329 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1331 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1333 case BUILT_IN_STPCPY
:
1334 case BUILT_IN_STPCPY_CHKP
:
1335 /* This would need adjustment of the lhs (subtract one),
1336 or detection that the trailing '\0' doesn't need to be
1337 written, if it will be immediately overwritten.
1338 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1342 zsi
= zero_length_string (lhs
, dsi
);
1345 case BUILT_IN_STPCPY_CHK
:
1346 case BUILT_IN_STPCPY_CHK_CHKP
:
1347 /* This would need adjustment of the lhs (subtract one),
1348 or detection that the trailing '\0' doesn't need to be
1349 written, if it will be immediately overwritten.
1350 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1354 zsi
= zero_length_string (lhs
, dsi
);
1361 zsi
->dont_invalidate
= true;
1363 if (fn
== NULL_TREE
)
1366 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1367 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1369 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1370 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1371 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1373 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1375 fprintf (dump_file
, "Optimizing: ");
1376 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1380 fn
= chkp_maybe_create_clone (fn
)->decl
;
1381 if (gimple_call_num_args (stmt
) == 4)
1382 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1383 gimple_call_arg (stmt
, 1),
1385 gimple_call_arg (stmt
, 3),
1388 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1389 gimple_call_arg (stmt
, 1),
1391 gimple_call_arg (stmt
, 3),
1393 gimple_call_arg (stmt
, 4));
1396 if (gimple_call_num_args (stmt
) == 2)
1397 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1399 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1400 gimple_call_arg (stmt
, 2));
1403 stmt
= gsi_stmt (*gsi
);
1404 gimple_call_set_with_bounds (stmt
, with_bounds
);
1406 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1408 fprintf (dump_file
, "into: ");
1409 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1411 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1412 laststmt
.stmt
= stmt
;
1413 laststmt
.len
= srclen
;
1414 laststmt
.stridx
= dsi
->idx
;
1416 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1417 fprintf (dump_file
, "not possible.\n");
1420 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1421 If strlen of the second argument is known and length of the third argument
1422 is that plus one, strlen of the first argument is the same after this
1426 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1429 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1430 gimple
*stmt
= gsi_stmt (*gsi
);
1431 strinfo
*si
, *dsi
, *olddsi
;
1432 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1434 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1435 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1436 dst
= gimple_call_arg (stmt
, 0);
1437 idx
= get_stridx (src
);
1441 didx
= get_stridx (dst
);
1444 olddsi
= get_strinfo (didx
);
1449 && tree_fits_uhwi_p (len
)
1450 && !integer_zerop (len
))
1451 adjust_last_stmt (olddsi
, stmt
, false);
1457 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1458 si
= get_strinfo (idx
);
1459 if (si
== NULL
|| si
->length
== NULL_TREE
)
1461 if (TREE_CODE (len
) != SSA_NAME
)
1463 def_stmt
= SSA_NAME_DEF_STMT (len
);
1464 if (!is_gimple_assign (def_stmt
)
1465 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1466 || gimple_assign_rhs1 (def_stmt
) != si
->length
1467 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1473 /* Handle memcpy (x, "abcd", 5) or
1474 memcpy (x, "abc\0uvw", 7). */
1475 if (!tree_fits_uhwi_p (len
)
1476 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1480 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1481 adjust_last_stmt (olddsi
, stmt
, false);
1485 didx
= new_stridx (dst
);
1490 newlen
= si
->length
;
1492 newlen
= build_int_cst (size_type_node
, ~idx
);
1496 dsi
= unshare_strinfo (olddsi
);
1497 oldlen
= olddsi
->length
;
1498 dsi
->length
= newlen
;
1499 /* Break the chain, so adjust_related_strinfo on later pointers in
1500 the chain won't adjust this one anymore. */
1503 dsi
->endptr
= NULL_TREE
;
1507 dsi
= new_strinfo (dst
, didx
, newlen
);
1508 set_strinfo (didx
, dsi
);
1509 find_equal_ptrs (dst
, didx
);
1511 dsi
->writable
= true;
1512 dsi
->dont_invalidate
= true;
1515 tree adj
= NULL_TREE
;
1516 location_t loc
= gimple_location (stmt
);
1517 if (oldlen
== NULL_TREE
)
1519 else if (integer_zerop (oldlen
))
1521 else if (TREE_CODE (oldlen
) == INTEGER_CST
1522 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1523 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1524 TREE_TYPE (dsi
->length
), dsi
->length
,
1525 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1527 if (adj
!= NULL_TREE
)
1528 adjust_related_strinfos (loc
, dsi
, adj
);
1532 /* memcpy src may not overlap dst, so src doesn't need to be
1533 invalidated either. */
1535 si
->dont_invalidate
= true;
1537 lhs
= gimple_call_lhs (stmt
);
1540 case BUILT_IN_MEMCPY
:
1541 case BUILT_IN_MEMCPY_CHK
:
1542 case BUILT_IN_MEMCPY_CHKP
:
1543 case BUILT_IN_MEMCPY_CHK_CHKP
:
1544 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1545 laststmt
.stmt
= stmt
;
1546 laststmt
.len
= dsi
->length
;
1547 laststmt
.stridx
= dsi
->idx
;
1549 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1551 case BUILT_IN_MEMPCPY
:
1552 case BUILT_IN_MEMPCPY_CHK
:
1553 case BUILT_IN_MEMPCPY_CHKP
:
1554 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1561 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1562 If strlen of the second argument is known, strlen of the first argument
1563 is increased by the length of the second argument. Furthermore, attempt
1564 to convert it to memcpy/strcpy if the length of the first argument
1568 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1571 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1573 gimple
*stmt
= gsi_stmt (*gsi
);
1576 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1578 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1579 dst
= gimple_call_arg (stmt
, 0);
1580 lhs
= gimple_call_lhs (stmt
);
1582 didx
= get_stridx (dst
);
1588 dsi
= get_strinfo (didx
);
1589 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1591 /* strcat (p, q) can be transformed into
1592 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1593 with length endptr - p if we need to compute the length
1594 later on. Don't do this transformation if we don't need
1596 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1600 didx
= new_stridx (dst
);
1606 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1607 set_strinfo (didx
, dsi
);
1608 find_equal_ptrs (dst
, didx
);
1612 dsi
= unshare_strinfo (dsi
);
1613 dsi
->length
= NULL_TREE
;
1615 dsi
->endptr
= NULL_TREE
;
1617 dsi
->writable
= true;
1619 dsi
->dont_invalidate
= true;
1626 idx
= get_stridx (src
);
1628 srclen
= build_int_cst (size_type_node
, ~idx
);
1631 si
= get_strinfo (idx
);
1633 srclen
= get_string_length (si
);
1636 loc
= gimple_location (stmt
);
1637 dstlen
= dsi
->length
;
1638 endptr
= dsi
->endptr
;
1640 dsi
= unshare_strinfo (dsi
);
1641 dsi
->endptr
= NULL_TREE
;
1643 dsi
->writable
= true;
1645 if (srclen
!= NULL_TREE
)
1647 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1648 dsi
->length
, srclen
);
1649 adjust_related_strinfos (loc
, dsi
, srclen
);
1650 dsi
->dont_invalidate
= true;
1655 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1656 dsi
->dont_invalidate
= true;
1660 /* strcat src may not overlap dst, so src doesn't need to be
1661 invalidated either. */
1662 si
->dont_invalidate
= true;
1664 /* For now. Could remove the lhs from the call and add
1665 lhs = dst; afterwards. */
1673 case BUILT_IN_STRCAT
:
1674 case BUILT_IN_STRCAT_CHKP
:
1675 if (srclen
!= NULL_TREE
)
1676 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1678 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1680 case BUILT_IN_STRCAT_CHK
:
1681 case BUILT_IN_STRCAT_CHK_CHKP
:
1682 if (srclen
!= NULL_TREE
)
1683 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1685 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1686 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1692 if (fn
== NULL_TREE
)
1696 if (srclen
!= NULL_TREE
)
1698 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1699 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1701 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1702 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1703 build_int_cst (type
, 1));
1704 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1708 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1710 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1711 TREE_TYPE (dst
), unshare_expr (dst
),
1712 fold_convert_loc (loc
, sizetype
,
1713 unshare_expr (dstlen
)));
1714 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1716 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1718 fprintf (dump_file
, "Optimizing: ");
1719 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1723 fn
= chkp_maybe_create_clone (fn
)->decl
;
1724 if (srclen
!= NULL_TREE
)
1725 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1727 gimple_call_arg (stmt
, 1),
1729 gimple_call_arg (stmt
, 3),
1732 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1734 gimple_call_arg (stmt
, 1),
1736 gimple_call_arg (stmt
, 3),
1740 if (srclen
!= NULL_TREE
)
1741 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1742 dst
, src
, len
, objsz
);
1744 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1748 stmt
= gsi_stmt (*gsi
);
1749 gimple_call_set_with_bounds (stmt
, with_bounds
);
1751 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1753 fprintf (dump_file
, "into: ");
1754 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1756 /* If srclen == NULL, note that current string length can be
1757 computed by transforming this strcpy into stpcpy. */
1758 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1760 adjust_last_stmt (dsi
, stmt
, true);
1761 if (srclen
!= NULL_TREE
)
1763 laststmt
.stmt
= stmt
;
1764 laststmt
.len
= srclen
;
1765 laststmt
.stridx
= dsi
->idx
;
1768 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1769 fprintf (dump_file
, "not possible.\n");
1772 /* Handle a call to malloc or calloc. */
1775 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1777 gimple
*stmt
= gsi_stmt (*gsi
);
1778 tree lhs
= gimple_call_lhs (stmt
);
1779 gcc_assert (get_stridx (lhs
) == 0);
1780 int idx
= new_stridx (lhs
);
1781 tree length
= NULL_TREE
;
1782 if (bcode
== BUILT_IN_CALLOC
)
1783 length
= build_int_cst (size_type_node
, 0);
1784 strinfo
*si
= new_strinfo (lhs
, idx
, length
);
1785 if (bcode
== BUILT_IN_CALLOC
)
1787 set_strinfo (idx
, si
);
1788 si
->writable
= true;
1790 si
->dont_invalidate
= true;
1793 /* Handle a call to memset.
1794 After a call to calloc, memset(,0,) is unnecessary.
1795 memset(malloc(n),0,n) is calloc(n,1). */
1798 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1800 gimple
*stmt2
= gsi_stmt (*gsi
);
1801 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1803 tree ptr
= gimple_call_arg (stmt2
, 0);
1804 int idx1
= get_stridx (ptr
);
1807 strinfo
*si1
= get_strinfo (idx1
);
1810 gimple
*stmt1
= si1
->stmt
;
1811 if (!stmt1
|| !is_gimple_call (stmt1
))
1813 tree callee1
= gimple_call_fndecl (stmt1
);
1814 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1816 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1817 tree size
= gimple_call_arg (stmt2
, 2);
1818 if (code1
== BUILT_IN_CALLOC
)
1819 /* Not touching stmt1 */ ;
1820 else if (code1
== BUILT_IN_MALLOC
1821 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1823 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1824 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1825 size
, build_one_cst (size_type_node
));
1826 si1
->length
= build_int_cst (size_type_node
, 0);
1827 si1
->stmt
= gsi_stmt (gsi1
);
1831 tree lhs
= gimple_call_lhs (stmt2
);
1832 unlink_stmt_vdef (stmt2
);
1835 gimple
*assign
= gimple_build_assign (lhs
, ptr
);
1836 gsi_replace (gsi
, assign
, false);
1840 gsi_remove (gsi
, true);
1841 release_defs (stmt2
);
1847 /* Handle a call to memcmp. We try to handle small comparisons by
1848 converting them to load and compare, and replacing the call to memcmp
1849 with a __builtin_memcmp_eq call where possible. */
1852 handle_builtin_memcmp (gimple_stmt_iterator
*gsi
)
1854 gcall
*stmt2
= as_a
<gcall
*> (gsi_stmt (*gsi
));
1855 tree res
= gimple_call_lhs (stmt2
);
1856 tree arg1
= gimple_call_arg (stmt2
, 0);
1857 tree arg2
= gimple_call_arg (stmt2
, 1);
1858 tree len
= gimple_call_arg (stmt2
, 2);
1859 unsigned HOST_WIDE_INT leni
;
1860 use_operand_p use_p
;
1861 imm_use_iterator iter
;
1866 FOR_EACH_IMM_USE_FAST (use_p
, iter
, res
)
1868 gimple
*ustmt
= USE_STMT (use_p
);
1870 if (is_gimple_debug (ustmt
))
1872 if (gimple_code (ustmt
) == GIMPLE_ASSIGN
)
1874 gassign
*asgn
= as_a
<gassign
*> (ustmt
);
1875 tree_code code
= gimple_assign_rhs_code (asgn
);
1876 if ((code
!= EQ_EXPR
&& code
!= NE_EXPR
)
1877 || !integer_zerop (gimple_assign_rhs2 (asgn
)))
1880 else if (gimple_code (ustmt
) == GIMPLE_COND
)
1882 tree_code code
= gimple_cond_code (ustmt
);
1883 if ((code
!= EQ_EXPR
&& code
!= NE_EXPR
)
1884 || !integer_zerop (gimple_cond_rhs (ustmt
)))
1891 if (tree_fits_uhwi_p (len
)
1892 && (leni
= tree_to_uhwi (len
)) <= GET_MODE_SIZE (word_mode
)
1893 && exact_log2 (leni
) != -1)
1895 leni
*= CHAR_TYPE_SIZE
;
1896 unsigned align1
= get_pointer_alignment (arg1
);
1897 unsigned align2
= get_pointer_alignment (arg2
);
1898 unsigned align
= MIN (align1
, align2
);
1899 machine_mode mode
= mode_for_size (leni
, MODE_INT
, 1);
1901 && (align
>= leni
|| !SLOW_UNALIGNED_ACCESS (mode
, align
)))
1903 location_t loc
= gimple_location (stmt2
);
1905 type
= build_nonstandard_integer_type (leni
, 1);
1906 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type
)) == leni
);
1907 tree ptrtype
= build_pointer_type_for_mode (char_type_node
,
1909 off
= build_int_cst (ptrtype
, 0);
1910 arg1
= build2_loc (loc
, MEM_REF
, type
, arg1
, off
);
1911 arg2
= build2_loc (loc
, MEM_REF
, type
, arg2
, off
);
1912 tree tem1
= fold_const_aggregate_ref (arg1
);
1915 tree tem2
= fold_const_aggregate_ref (arg2
);
1918 res
= fold_convert_loc (loc
, TREE_TYPE (res
),
1919 fold_build2_loc (loc
, NE_EXPR
,
1922 gimplify_and_update_call_from_tree (gsi
, res
);
1927 gimple_call_set_fndecl (stmt2
, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ
));
1931 /* Handle a POINTER_PLUS_EXPR statement.
1932 For p = "abcd" + 2; compute associated length, or if
1933 p = q + off is pointing to a '\0' character of a string, call
1934 zero_length_string on it. */
1937 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1939 gimple
*stmt
= gsi_stmt (*gsi
);
1940 tree lhs
= gimple_assign_lhs (stmt
), off
;
1941 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1949 tree off
= gimple_assign_rhs2 (stmt
);
1950 if (tree_fits_uhwi_p (off
)
1951 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1952 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1953 = ~(~idx
- (int) tree_to_uhwi (off
));
1957 si
= get_strinfo (idx
);
1958 if (si
== NULL
|| si
->length
== NULL_TREE
)
1961 off
= gimple_assign_rhs2 (stmt
);
1963 if (operand_equal_p (si
->length
, off
, 0))
1964 zsi
= zero_length_string (lhs
, si
);
1965 else if (TREE_CODE (off
) == SSA_NAME
)
1967 gimple
*def_stmt
= SSA_NAME_DEF_STMT (off
);
1968 if (gimple_assign_single_p (def_stmt
)
1969 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1970 zsi
= zero_length_string (lhs
, si
);
1973 && si
->endptr
!= NULL_TREE
1974 && si
->endptr
!= lhs
1975 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1977 enum tree_code rhs_code
1978 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1979 ? SSA_NAME
: NOP_EXPR
;
1980 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1981 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1986 /* Handle a single character store. */
1989 handle_char_store (gimple_stmt_iterator
*gsi
)
1993 gimple
*stmt
= gsi_stmt (*gsi
);
1994 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1996 if (TREE_CODE (lhs
) == MEM_REF
1997 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1999 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
2001 ssaname
= TREE_OPERAND (lhs
, 0);
2002 idx
= get_stridx (ssaname
);
2006 idx
= get_addr_stridx (lhs
);
2010 si
= get_strinfo (idx
);
2011 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
2013 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
2015 /* When storing '\0', the store can be removed
2016 if we know it has been stored in the current function. */
2017 if (!stmt_could_throw_p (stmt
) && si
->writable
)
2019 unlink_stmt_vdef (stmt
);
2020 release_defs (stmt
);
2021 gsi_remove (gsi
, true);
2026 si
->writable
= true;
2032 /* Otherwise this statement overwrites the '\0' with
2033 something, if the previous stmt was a memcpy,
2034 its length may be decreased. */
2035 adjust_last_stmt (si
, stmt
, false);
2037 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
2039 si
= unshare_strinfo (si
);
2040 si
->length
= build_int_cst (size_type_node
, 0);
2046 si
->writable
= true;
2047 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2048 si
->endptr
= ssaname
;
2049 si
->dont_invalidate
= true;
2051 /* If si->length is non-zero constant, we aren't overwriting '\0',
2052 and if we aren't storing '\0', we know that the length of the
2053 string and any other zero terminated string in memory remains
2054 the same. In that case we move to the next gimple statement and
2055 return to signal the caller that it shouldn't invalidate anything.
2057 This is benefical for cases like:
2062 strcpy (p, "foobar");
2063 size_t len = strlen (p); // This can be optimized into 6
2064 size_t len2 = strlen (q); // This has to be computed
2066 size_t len3 = strlen (p); // This can be optimized into 6
2067 size_t len4 = strlen (q); // This can be optimized into len2
2068 bar (len, len2, len3, len4);
2071 else if (si
!= NULL
&& si
->length
!= NULL_TREE
2072 && TREE_CODE (si
->length
) == INTEGER_CST
2073 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2079 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2083 si
= zero_length_string (ssaname
, NULL
);
2085 si
->dont_invalidate
= true;
2089 int idx
= new_addr_stridx (lhs
);
2092 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2093 build_int_cst (size_type_node
, 0));
2094 set_strinfo (idx
, si
);
2095 si
->dont_invalidate
= true;
2099 si
->writable
= true;
2102 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2103 && ssaname
== NULL_TREE
2104 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2106 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2107 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2108 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2110 int idx
= new_addr_stridx (lhs
);
2113 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2114 build_int_cst (size_type_node
, l
));
2115 set_strinfo (idx
, si
);
2116 si
->dont_invalidate
= true;
2121 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2123 /* Allow adjust_last_stmt to remove it if the stored '\0'
2124 is immediately overwritten. */
2125 laststmt
.stmt
= stmt
;
2126 laststmt
.len
= build_int_cst (size_type_node
, 1);
2127 laststmt
.stridx
= si
->idx
;
2132 /* Attempt to optimize a single statement at *GSI using string length
2136 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2138 gimple
*stmt
= gsi_stmt (*gsi
);
2140 if (is_gimple_call (stmt
))
2142 tree callee
= gimple_call_fndecl (stmt
);
2143 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2144 switch (DECL_FUNCTION_CODE (callee
))
2146 case BUILT_IN_STRLEN
:
2147 case BUILT_IN_STRLEN_CHKP
:
2148 handle_builtin_strlen (gsi
);
2150 case BUILT_IN_STRCHR
:
2151 case BUILT_IN_STRCHR_CHKP
:
2152 handle_builtin_strchr (gsi
);
2154 case BUILT_IN_STRCPY
:
2155 case BUILT_IN_STRCPY_CHK
:
2156 case BUILT_IN_STPCPY
:
2157 case BUILT_IN_STPCPY_CHK
:
2158 case BUILT_IN_STRCPY_CHKP
:
2159 case BUILT_IN_STRCPY_CHK_CHKP
:
2160 case BUILT_IN_STPCPY_CHKP
:
2161 case BUILT_IN_STPCPY_CHK_CHKP
:
2162 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2164 case BUILT_IN_MEMCPY
:
2165 case BUILT_IN_MEMCPY_CHK
:
2166 case BUILT_IN_MEMPCPY
:
2167 case BUILT_IN_MEMPCPY_CHK
:
2168 case BUILT_IN_MEMCPY_CHKP
:
2169 case BUILT_IN_MEMCPY_CHK_CHKP
:
2170 case BUILT_IN_MEMPCPY_CHKP
:
2171 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2172 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2174 case BUILT_IN_STRCAT
:
2175 case BUILT_IN_STRCAT_CHK
:
2176 case BUILT_IN_STRCAT_CHKP
:
2177 case BUILT_IN_STRCAT_CHK_CHKP
:
2178 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2180 case BUILT_IN_MALLOC
:
2181 case BUILT_IN_CALLOC
:
2182 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2184 case BUILT_IN_MEMSET
:
2185 if (!handle_builtin_memset (gsi
))
2188 case BUILT_IN_MEMCMP
:
2189 if (!handle_builtin_memcmp (gsi
))
2196 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2198 tree lhs
= gimple_assign_lhs (stmt
);
2200 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2202 if (gimple_assign_single_p (stmt
)
2203 || (gimple_assign_cast_p (stmt
)
2204 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2206 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2207 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2209 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2210 handle_pointer_plus (gsi
);
2212 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2214 tree type
= TREE_TYPE (lhs
);
2215 if (TREE_CODE (type
) == ARRAY_TYPE
)
2216 type
= TREE_TYPE (type
);
2217 if (TREE_CODE (type
) == INTEGER_TYPE
2218 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2219 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2221 if (! handle_char_store (gsi
))
2227 if (gimple_vdef (stmt
))
2228 maybe_invalidate (stmt
);
2232 /* Recursively call maybe_invalidate on stmts that might be executed
2233 in between dombb and current bb and that contain a vdef. Stop when
2234 *count stmts are inspected, or if the whole strinfo vector has
2235 been invalidated. */
2238 do_invalidate (basic_block dombb
, gimple
*phi
, bitmap visited
, int *count
)
2240 unsigned int i
, n
= gimple_phi_num_args (phi
);
2242 for (i
= 0; i
< n
; i
++)
2244 tree vuse
= gimple_phi_arg_def (phi
, i
);
2245 gimple
*stmt
= SSA_NAME_DEF_STMT (vuse
);
2246 basic_block bb
= gimple_bb (stmt
);
2249 || !bitmap_set_bit (visited
, bb
->index
)
2250 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2254 if (gimple_code (stmt
) == GIMPLE_PHI
)
2256 do_invalidate (dombb
, stmt
, visited
, count
);
2263 if (!maybe_invalidate (stmt
))
2268 vuse
= gimple_vuse (stmt
);
2269 stmt
= SSA_NAME_DEF_STMT (vuse
);
2270 if (gimple_bb (stmt
) != bb
)
2272 bb
= gimple_bb (stmt
);
2275 || !bitmap_set_bit (visited
, bb
->index
)
2276 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2283 class strlen_dom_walker
: public dom_walker
2286 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2288 virtual edge
before_dom_children (basic_block
);
2289 virtual void after_dom_children (basic_block
);
2292 /* Callback for walk_dominator_tree. Attempt to optimize various
2293 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2296 strlen_dom_walker::before_dom_children (basic_block bb
)
2298 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2301 stridx_to_strinfo
= NULL
;
2304 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) dombb
->aux
);
2305 if (stridx_to_strinfo
)
2307 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2310 gphi
*phi
= gsi
.phi ();
2311 if (virtual_operand_p (gimple_phi_result (phi
)))
2313 bitmap visited
= BITMAP_ALLOC (NULL
);
2314 int count_vdef
= 100;
2315 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2316 BITMAP_FREE (visited
);
2317 if (count_vdef
== 0)
2319 /* If there were too many vdefs in between immediate
2320 dominator and current bb, invalidate everything.
2321 If stridx_to_strinfo has been unshared, we need
2322 to free it, otherwise just set it to NULL. */
2323 if (!strinfo_shared ())
2329 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2333 (*stridx_to_strinfo
)[i
] = NULL
;
2337 stridx_to_strinfo
= NULL
;
2345 /* If all PHI arguments have the same string index, the PHI result
2347 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2350 gphi
*phi
= gsi
.phi ();
2351 tree result
= gimple_phi_result (phi
);
2352 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2354 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2357 unsigned int i
, n
= gimple_phi_num_args (phi
);
2358 for (i
= 1; i
< n
; i
++)
2359 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2362 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2367 /* Attempt to optimize individual statements. */
2368 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2369 if (strlen_optimize_stmt (&gsi
))
2372 bb
->aux
= stridx_to_strinfo
;
2373 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2374 (*stridx_to_strinfo
)[0] = (strinfo
*) bb
;
2378 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2379 owned by the current bb, clear bb->aux. */
2382 strlen_dom_walker::after_dom_children (basic_block bb
)
2386 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) bb
->aux
);
2387 if (vec_safe_length (stridx_to_strinfo
)
2388 && (*stridx_to_strinfo
)[0] == (strinfo
*) bb
)
2393 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2395 vec_free (stridx_to_strinfo
);
2401 /* Main entry point. */
2405 const pass_data pass_data_strlen
=
2407 GIMPLE_PASS
, /* type */
2408 "strlen", /* name */
2409 OPTGROUP_NONE
, /* optinfo_flags */
2410 TV_TREE_STRLEN
, /* tv_id */
2411 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2412 0, /* properties_provided */
2413 0, /* properties_destroyed */
2414 0, /* todo_flags_start */
2415 0, /* todo_flags_finish */
2418 class pass_strlen
: public gimple_opt_pass
2421 pass_strlen (gcc::context
*ctxt
)
2422 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2425 /* opt_pass methods: */
2426 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2427 virtual unsigned int execute (function
*);
2429 }; // class pass_strlen
2432 pass_strlen::execute (function
*fun
)
2434 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2437 calculate_dominance_info (CDI_DOMINATORS
);
2439 /* String length optimization is implemented as a walk of the dominator
2440 tree and a forward walk of statements within each block. */
2441 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2443 ssa_ver_to_stridx
.release ();
2444 strinfo_pool
.release ();
2445 if (decl_to_stridxlist_htab
)
2447 obstack_free (&stridx_obstack
, NULL
);
2448 delete decl_to_stridxlist_htab
;
2449 decl_to_stridxlist_htab
= NULL
;
2451 laststmt
.stmt
= NULL
;
2452 laststmt
.len
= NULL_TREE
;
2453 laststmt
.stridx
= 0;
2461 make_pass_strlen (gcc::context
*ctxt
)
2463 return new pass_strlen (ctxt
);