1 /* String length optimization
2 Copyright (C) 2011-2014 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"
25 #include "stor-layout.h"
26 #include "hash-table.h"
29 #include "basic-block.h"
30 #include "tree-ssa-alias.h"
31 #include "internal-fn.h"
32 #include "gimple-fold.h"
34 #include "gimple-expr.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
40 #include "gimple-ssa.h"
41 #include "tree-phinodes.h"
42 #include "ssa-iterators.h"
43 #include "stringpool.h"
44 #include "tree-ssanames.h"
47 #include "tree-pass.h"
49 #include "alloc-pool.h"
50 #include "tree-ssa-propagate.h"
51 #include "gimple-pretty-print.h"
55 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
56 is an index into strinfo vector, negative value stands for
57 string length of a string literal (~strlen). */
58 static vec
<int> ssa_ver_to_stridx
;
60 /* Number of currently active string indexes plus one. */
61 static int max_stridx
;
63 /* String information record. */
64 typedef struct strinfo_struct
66 /* String length of this string. */
68 /* Any of the corresponding pointers for querying alias oracle. */
70 /* Statement for delayed length computation. */
72 /* Pointer to '\0' if known, if NULL, it can be computed as
75 /* Reference count. Any changes to strinfo entry possibly shared
76 with dominating basic blocks need unshare_strinfo first, except
77 for dont_invalidate which affects only the immediately next
80 /* Copy of index. get_strinfo (si->idx) should return si; */
82 /* These 3 fields are for chaining related string pointers together.
84 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
85 strcpy (c, d); e = c + dl;
86 strinfo(a) -> strinfo(c) -> strinfo(e)
87 All have ->first field equal to strinfo(a)->idx and are doubly
88 chained through prev/next fields. The later strinfos are required
89 to point into the same string with zero or more bytes after
90 the previous pointer and all bytes in between the two pointers
91 must be non-zero. Functions like strcpy or memcpy are supposed
92 to adjust all previous strinfo lengths, but not following strinfo
93 lengths (those are uncertain, usually invalidated during
94 maybe_invalidate, except when the alias oracle knows better).
95 Functions like strcat on the other side adjust the whole
96 related strinfo chain.
97 They are updated lazily, so to use the chain the same first fields
98 and si->prev->next == si->idx needs to be verified. */
102 /* A flag whether the string is known to be written in the current
105 /* A flag for the next maybe_invalidate that this strinfo shouldn't
106 be invalidated. Always cleared by maybe_invalidate. */
107 bool dont_invalidate
;
110 /* Pool for allocating strinfo_struct entries. */
111 static alloc_pool strinfo_pool
;
113 /* Vector mapping positive string indexes to strinfo, for the
114 current basic block. The first pointer in the vector is special,
115 it is either NULL, meaning the vector isn't shared, or it is
116 a basic block pointer to the owner basic_block if shared.
117 If some other bb wants to modify the vector, the vector needs
118 to be unshared first, and only the owner bb is supposed to free it. */
119 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
121 /* One OFFSET->IDX mapping. */
124 struct stridxlist
*next
;
125 HOST_WIDE_INT offset
;
129 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
130 struct decl_stridxlist_map
132 struct tree_map_base base
;
133 struct stridxlist list
;
136 /* stridxlist hashtable helpers. */
138 struct stridxlist_hash_traits
: default_hashmap_traits
140 static inline hashval_t
hash (tree
);
143 /* Hash a from tree in a decl_stridxlist_map. */
146 stridxlist_hash_traits::hash (tree item
)
148 return DECL_UID (item
);
151 /* Hash table for mapping decls to a chained list of offset -> idx
153 static hash_map
<tree
, stridxlist
, stridxlist_hash_traits
>
154 *decl_to_stridxlist_htab
;
156 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
157 static struct obstack stridx_obstack
;
159 /* Last memcpy statement if it could be adjusted if the trailing
160 '\0' written is immediately overwritten, or
161 *x = '\0' store that could be removed if it is immediately overwritten. */
162 struct laststmt_struct
169 /* Helper function for get_stridx. */
172 get_addr_stridx (tree exp
)
175 struct stridxlist
*list
;
178 if (!decl_to_stridxlist_htab
)
181 base
= get_addr_base_and_unit_offset (exp
, &off
);
182 if (base
== NULL
|| !DECL_P (base
))
185 list
= decl_to_stridxlist_htab
->get (base
);
191 if (list
->offset
== off
)
199 /* Return string index for EXP. */
202 get_stridx (tree exp
)
206 if (TREE_CODE (exp
) == SSA_NAME
)
207 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
209 if (TREE_CODE (exp
) == ADDR_EXPR
)
211 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
216 s
= string_constant (exp
, &o
);
218 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
219 && TREE_STRING_LENGTH (s
) > 0)
221 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
222 const char *p
= TREE_STRING_POINTER (s
);
223 int max
= TREE_STRING_LENGTH (s
) - 1;
225 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
226 return ~(int) strlen (p
+ offset
);
231 /* Return true if strinfo vector is shared with the immediate dominator. */
234 strinfo_shared (void)
236 return vec_safe_length (stridx_to_strinfo
)
237 && (*stridx_to_strinfo
)[0] != NULL
;
240 /* Unshare strinfo vector that is shared with the immediate dominator. */
243 unshare_strinfo_vec (void)
248 gcc_assert (strinfo_shared ());
249 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
250 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
253 (*stridx_to_strinfo
)[0] = NULL
;
256 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
257 Return a pointer to the location where the string index can
258 be stored (if 0) or is stored, or NULL if this can't be tracked. */
261 addr_stridxptr (tree exp
)
265 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
266 if (base
== NULL_TREE
|| !DECL_P (base
))
269 if (!decl_to_stridxlist_htab
)
271 decl_to_stridxlist_htab
272 = new hash_map
<tree
, stridxlist
, stridxlist_hash_traits
> (64);
273 gcc_obstack_init (&stridx_obstack
);
277 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
281 for (i
= 0; i
< 16; i
++)
283 if (list
->offset
== off
)
285 if (list
->next
== NULL
)
290 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
300 /* Create a new string index, or return 0 if reached limit. */
303 new_stridx (tree exp
)
306 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
308 if (TREE_CODE (exp
) == SSA_NAME
)
310 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
313 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
316 if (TREE_CODE (exp
) == ADDR_EXPR
)
318 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
321 gcc_assert (*pidx
== 0);
322 *pidx
= max_stridx
++;
329 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
332 new_addr_stridx (tree exp
)
335 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
337 pidx
= addr_stridxptr (exp
);
340 gcc_assert (*pidx
== 0);
341 *pidx
= max_stridx
++;
347 /* Create a new strinfo. */
350 new_strinfo (tree ptr
, int idx
, tree length
)
352 strinfo si
= (strinfo
) pool_alloc (strinfo_pool
);
356 si
->endptr
= NULL_TREE
;
362 si
->writable
= false;
363 si
->dont_invalidate
= false;
367 /* Decrease strinfo refcount and free it if not referenced anymore. */
370 free_strinfo (strinfo si
)
372 if (si
&& --si
->refcount
== 0)
373 pool_free (strinfo_pool
, si
);
376 /* Return strinfo vector entry IDX. */
378 static inline strinfo
379 get_strinfo (int idx
)
381 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
383 return (*stridx_to_strinfo
)[idx
];
386 /* Set strinfo in the vector entry IDX to SI. */
389 set_strinfo (int idx
, strinfo si
)
391 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
392 unshare_strinfo_vec ();
393 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
394 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
395 (*stridx_to_strinfo
)[idx
] = si
;
398 /* Return string length, or NULL if it can't be computed. */
401 get_string_length (strinfo si
)
408 gimple stmt
= si
->stmt
, lenstmt
;
409 tree callee
, lhs
, fn
, tem
;
411 gimple_stmt_iterator gsi
;
413 gcc_assert (is_gimple_call (stmt
));
414 callee
= gimple_call_fndecl (stmt
);
415 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
416 lhs
= gimple_call_lhs (stmt
);
417 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
418 /* unshare_strinfo is intentionally not called here. The (delayed)
419 transformation of strcpy or strcat into stpcpy is done at the place
420 of the former strcpy/strcat call and so can affect all the strinfos
421 with the same stmt. If they were unshared before and transformation
422 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
423 just compute the right length. */
424 switch (DECL_FUNCTION_CODE (callee
))
426 case BUILT_IN_STRCAT
:
427 case BUILT_IN_STRCAT_CHK
:
428 gsi
= gsi_for_stmt (stmt
);
429 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
430 gcc_assert (lhs
== NULL_TREE
);
431 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
432 lenstmt
= gimple_build_call (fn
, 1, tem
);
433 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
434 gimple_call_set_lhs (lenstmt
, lhs
);
435 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
436 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
437 tem
= gimple_call_arg (stmt
, 0);
438 if (!ptrofftype_p (TREE_TYPE (lhs
)))
440 lhs
= convert_to_ptrofftype (lhs
);
441 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
442 true, GSI_SAME_STMT
);
445 = gimple_build_assign_with_ops
447 make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0)), NULL
),
449 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
450 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
453 case BUILT_IN_STRCPY
:
454 case BUILT_IN_STRCPY_CHK
:
455 if (gimple_call_num_args (stmt
) == 2)
456 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
458 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
459 gcc_assert (lhs
== NULL_TREE
);
460 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
462 fprintf (dump_file
, "Optimizing: ");
463 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
465 gimple_call_set_fndecl (stmt
, fn
);
466 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
467 gimple_call_set_lhs (stmt
, lhs
);
469 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
471 fprintf (dump_file
, "into: ");
472 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
475 case BUILT_IN_STPCPY
:
476 case BUILT_IN_STPCPY_CHK
:
477 gcc_assert (lhs
!= NULL_TREE
);
478 loc
= gimple_location (stmt
);
481 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
482 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
483 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
486 case BUILT_IN_MALLOC
:
488 /* BUILT_IN_CALLOC always has si->length set. */
498 /* Invalidate string length information for strings whose length
499 might change due to stores in stmt. */
502 maybe_invalidate (gimple stmt
)
506 bool nonempty
= false;
508 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
511 if (!si
->dont_invalidate
)
514 /* Do not use si->length. */
515 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
516 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
518 set_strinfo (i
, NULL
);
523 si
->dont_invalidate
= false;
529 /* Unshare strinfo record SI, if it has recount > 1 or
530 if stridx_to_strinfo vector is shared with some other
534 unshare_strinfo (strinfo si
)
538 if (si
->refcount
== 1 && !strinfo_shared ())
541 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
542 nsi
->stmt
= si
->stmt
;
543 nsi
->endptr
= si
->endptr
;
544 nsi
->first
= si
->first
;
545 nsi
->prev
= si
->prev
;
546 nsi
->next
= si
->next
;
547 nsi
->writable
= si
->writable
;
548 set_strinfo (si
->idx
, nsi
);
553 /* Return first strinfo in the related strinfo chain
554 if all strinfos in between belong to the chain, otherwise
558 verify_related_strinfos (strinfo origsi
)
560 strinfo si
= origsi
, psi
;
562 if (origsi
->first
== 0)
564 for (; si
->prev
; si
= psi
)
566 if (si
->first
!= origsi
->first
)
568 psi
= get_strinfo (si
->prev
);
571 if (psi
->next
!= si
->idx
)
574 if (si
->idx
!= si
->first
)
579 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
580 to a zero-length string and if possible chain it to a related strinfo
581 chain whose part is or might be CHAINSI. */
584 zero_length_string (tree ptr
, strinfo chainsi
)
588 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
589 && get_stridx (ptr
) == 0);
591 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
595 si
= verify_related_strinfos (chainsi
);
599 for (; chainsi
->next
; chainsi
= si
)
601 if (chainsi
->endptr
== NULL_TREE
)
603 chainsi
= unshare_strinfo (chainsi
);
604 chainsi
->endptr
= ptr
;
606 si
= get_strinfo (chainsi
->next
);
608 || si
->first
!= chainsi
->first
609 || si
->prev
!= chainsi
->idx
)
612 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
613 if (chainsi
->endptr
== NULL_TREE
)
615 chainsi
= unshare_strinfo (chainsi
);
616 chainsi
->endptr
= ptr
;
618 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
622 chainsi
= unshare_strinfo (chainsi
);
625 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
629 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
631 chainsi
= unshare_strinfo (chainsi
);
637 idx
= new_stridx (ptr
);
640 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
641 set_strinfo (idx
, si
);
645 chainsi
= unshare_strinfo (chainsi
);
646 if (chainsi
->first
== 0)
647 chainsi
->first
= chainsi
->idx
;
649 if (chainsi
->endptr
== NULL_TREE
)
650 chainsi
->endptr
= ptr
;
651 si
->prev
= chainsi
->idx
;
652 si
->first
= chainsi
->first
;
653 si
->writable
= chainsi
->writable
;
658 /* For strinfo ORIGSI whose length has been just updated
659 update also related strinfo lengths (add ADJ to each,
660 but don't adjust ORIGSI). */
663 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
665 strinfo si
= verify_related_strinfos (origsi
);
678 si
= unshare_strinfo (si
);
681 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
682 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
683 TREE_TYPE (si
->length
), si
->length
,
686 else if (si
->stmt
!= NULL
)
687 /* Delayed length computation is unaffected. */
692 si
->endptr
= NULL_TREE
;
693 si
->dont_invalidate
= true;
697 nsi
= get_strinfo (si
->next
);
699 || nsi
->first
!= si
->first
700 || nsi
->prev
!= si
->idx
)
706 /* Find if there are other SSA_NAME pointers equal to PTR
707 for which we don't track their string lengths yet. If so, use
711 find_equal_ptrs (tree ptr
, int idx
)
713 if (TREE_CODE (ptr
) != SSA_NAME
)
717 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
718 if (!is_gimple_assign (stmt
))
720 ptr
= gimple_assign_rhs1 (stmt
);
721 switch (gimple_assign_rhs_code (stmt
))
726 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
728 if (TREE_CODE (ptr
) == SSA_NAME
)
730 if (TREE_CODE (ptr
) != ADDR_EXPR
)
735 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
736 if (pidx
!= NULL
&& *pidx
== 0)
744 /* We might find an endptr created in this pass. Grow the
745 vector in that case. */
746 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
747 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
749 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
751 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
755 /* If the last .MEM setter statement before STMT is
756 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
757 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
758 just memcpy (x, y, strlen (y)). SI must be the zero length
762 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
764 tree vuse
, callee
, len
;
765 struct laststmt_struct last
= laststmt
;
766 strinfo lastsi
, firstsi
;
768 laststmt
.stmt
= NULL
;
769 laststmt
.len
= NULL_TREE
;
772 if (last
.stmt
== NULL
)
775 vuse
= gimple_vuse (stmt
);
776 if (vuse
== NULL_TREE
777 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
778 || !has_single_use (vuse
))
781 gcc_assert (last
.stridx
> 0);
782 lastsi
= get_strinfo (last
.stridx
);
788 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
791 firstsi
= verify_related_strinfos (si
);
794 while (firstsi
!= lastsi
)
797 if (firstsi
->next
== 0)
799 nextsi
= get_strinfo (firstsi
->next
);
801 || nextsi
->prev
!= firstsi
->idx
802 || nextsi
->first
!= si
->first
)
810 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
814 if (is_gimple_assign (last
.stmt
))
816 gimple_stmt_iterator gsi
;
818 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
820 if (stmt_could_throw_p (last
.stmt
))
822 gsi
= gsi_for_stmt (last
.stmt
);
823 unlink_stmt_vdef (last
.stmt
);
824 release_defs (last
.stmt
);
825 gsi_remove (&gsi
, true);
829 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
832 callee
= gimple_call_fndecl (last
.stmt
);
833 switch (DECL_FUNCTION_CODE (callee
))
835 case BUILT_IN_MEMCPY
:
836 case BUILT_IN_MEMCPY_CHK
:
842 len
= gimple_call_arg (last
.stmt
, 2);
843 if (tree_fits_uhwi_p (len
))
845 if (!tree_fits_uhwi_p (last
.len
)
846 || integer_zerop (len
)
847 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
849 /* Don't adjust the length if it is divisible by 4, it is more efficient
850 to store the extra '\0' in that case. */
851 if ((tree_to_uhwi (len
) & 3) == 0)
854 else if (TREE_CODE (len
) == SSA_NAME
)
856 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
857 if (!is_gimple_assign (def_stmt
)
858 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
859 || gimple_assign_rhs1 (def_stmt
) != last
.len
860 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
866 gimple_call_set_arg (last
.stmt
, 2, last
.len
);
867 update_stmt (last
.stmt
);
870 /* Handle a strlen call. If strlen of the argument is known, replace
871 the strlen call with the known value, otherwise remember that strlen
872 of the argument is stored in the lhs SSA_NAME. */
875 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
879 gimple stmt
= gsi_stmt (*gsi
);
880 tree lhs
= gimple_call_lhs (stmt
);
882 if (lhs
== NULL_TREE
)
885 src
= gimple_call_arg (stmt
, 0);
886 idx
= get_stridx (src
);
893 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
897 si
= get_strinfo (idx
);
899 rhs
= get_string_length (si
);
901 if (rhs
!= NULL_TREE
)
903 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
905 fprintf (dump_file
, "Optimizing: ");
906 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
908 rhs
= unshare_expr (rhs
);
909 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
910 rhs
= fold_convert_loc (gimple_location (stmt
),
911 TREE_TYPE (lhs
), rhs
);
912 if (!update_call_from_tree (gsi
, rhs
))
913 gimplify_and_update_call_from_tree (gsi
, rhs
);
914 stmt
= gsi_stmt (*gsi
);
916 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
918 fprintf (dump_file
, "into: ");
919 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
922 && TREE_CODE (si
->length
) != SSA_NAME
923 && TREE_CODE (si
->length
) != INTEGER_CST
924 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
926 si
= unshare_strinfo (si
);
932 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
935 idx
= new_stridx (src
);
936 else if (get_strinfo (idx
) != NULL
)
940 strinfo si
= new_strinfo (src
, idx
, lhs
);
941 set_strinfo (idx
, si
);
942 find_equal_ptrs (src
, idx
);
946 /* Handle a strchr call. If strlen of the first argument is known, replace
947 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
948 that lhs of the call is endptr and strlen of the argument is endptr - x. */
951 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
955 gimple stmt
= gsi_stmt (*gsi
);
956 tree lhs
= gimple_call_lhs (stmt
);
958 if (lhs
== NULL_TREE
)
961 if (!integer_zerop (gimple_call_arg (stmt
, 1)))
964 src
= gimple_call_arg (stmt
, 0);
965 idx
= get_stridx (src
);
972 rhs
= build_int_cst (size_type_node
, ~idx
);
976 si
= get_strinfo (idx
);
978 rhs
= get_string_length (si
);
980 if (rhs
!= NULL_TREE
)
982 location_t loc
= gimple_location (stmt
);
984 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
986 fprintf (dump_file
, "Optimizing: ");
987 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
989 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
991 rhs
= unshare_expr (si
->endptr
);
992 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
994 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
998 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
999 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1000 TREE_TYPE (src
), src
, rhs
);
1001 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1003 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1005 if (!update_call_from_tree (gsi
, rhs
))
1006 gimplify_and_update_call_from_tree (gsi
, rhs
);
1007 stmt
= gsi_stmt (*gsi
);
1009 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1011 fprintf (dump_file
, "into: ");
1012 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1015 && si
->endptr
== NULL_TREE
1016 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1018 si
= unshare_strinfo (si
);
1021 zero_length_string (lhs
, si
);
1025 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1027 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1030 idx
= new_stridx (src
);
1031 else if (get_strinfo (idx
) != NULL
)
1033 zero_length_string (lhs
, NULL
);
1038 location_t loc
= gimple_location (stmt
);
1039 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1040 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1041 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1042 size_type_node
, lhsu
, srcu
);
1043 strinfo si
= new_strinfo (src
, idx
, length
);
1045 set_strinfo (idx
, si
);
1046 find_equal_ptrs (src
, idx
);
1047 zero_length_string (lhs
, si
);
1051 zero_length_string (lhs
, NULL
);
1054 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1055 If strlen of the second argument is known, strlen of the first argument
1056 is the same after this call. Furthermore, attempt to convert it to
1060 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1063 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1065 gimple stmt
= gsi_stmt (*gsi
);
1066 strinfo si
, dsi
, olddsi
, zsi
;
1069 src
= gimple_call_arg (stmt
, 1);
1070 dst
= gimple_call_arg (stmt
, 0);
1071 lhs
= gimple_call_lhs (stmt
);
1072 idx
= get_stridx (src
);
1075 si
= get_strinfo (idx
);
1077 didx
= get_stridx (dst
);
1081 olddsi
= get_strinfo (didx
);
1086 adjust_last_stmt (olddsi
, stmt
, false);
1090 srclen
= get_string_length (si
);
1092 srclen
= build_int_cst (size_type_node
, ~idx
);
1094 loc
= gimple_location (stmt
);
1095 if (srclen
== NULL_TREE
)
1098 case BUILT_IN_STRCPY
:
1099 case BUILT_IN_STRCPY_CHK
:
1100 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1103 case BUILT_IN_STPCPY
:
1104 case BUILT_IN_STPCPY_CHK
:
1105 if (lhs
== NULL_TREE
)
1109 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1110 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1111 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1121 didx
= new_stridx (dst
);
1127 oldlen
= olddsi
->length
;
1128 dsi
= unshare_strinfo (olddsi
);
1129 dsi
->length
= srclen
;
1130 /* Break the chain, so adjust_related_strinfo on later pointers in
1131 the chain won't adjust this one anymore. */
1134 dsi
->endptr
= NULL_TREE
;
1138 dsi
= new_strinfo (dst
, didx
, srclen
);
1139 set_strinfo (didx
, dsi
);
1140 find_equal_ptrs (dst
, didx
);
1142 dsi
->writable
= true;
1143 dsi
->dont_invalidate
= true;
1145 if (dsi
->length
== NULL_TREE
)
1149 /* If string length of src is unknown, use delayed length
1150 computation. If string lenth of dst will be needed, it
1151 can be computed by transforming this strcpy call into
1152 stpcpy and subtracting dst from the return value. */
1154 /* Look for earlier strings whose length could be determined if
1155 this strcpy is turned into an stpcpy. */
1157 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1159 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1161 /* When setting a stmt for delayed length computation
1162 prevent all strinfos through dsi from being
1164 chainsi
= unshare_strinfo (chainsi
);
1165 chainsi
->stmt
= stmt
;
1166 chainsi
->length
= NULL_TREE
;
1167 chainsi
->endptr
= NULL_TREE
;
1168 chainsi
->dont_invalidate
= true;
1177 tree adj
= NULL_TREE
;
1178 if (oldlen
== NULL_TREE
)
1180 else if (integer_zerop (oldlen
))
1182 else if (TREE_CODE (oldlen
) == INTEGER_CST
1183 || TREE_CODE (srclen
) == INTEGER_CST
)
1184 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1185 TREE_TYPE (srclen
), srclen
,
1186 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1188 if (adj
!= NULL_TREE
)
1189 adjust_related_strinfos (loc
, dsi
, adj
);
1193 /* strcpy src may not overlap dst, so src doesn't need to be
1194 invalidated either. */
1196 si
->dont_invalidate
= true;
1202 case BUILT_IN_STRCPY
:
1203 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1205 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1207 case BUILT_IN_STRCPY_CHK
:
1208 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1210 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1212 case BUILT_IN_STPCPY
:
1213 /* This would need adjustment of the lhs (subtract one),
1214 or detection that the trailing '\0' doesn't need to be
1215 written, if it will be immediately overwritten.
1216 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1220 zsi
= zero_length_string (lhs
, dsi
);
1223 case BUILT_IN_STPCPY_CHK
:
1224 /* This would need adjustment of the lhs (subtract one),
1225 or detection that the trailing '\0' doesn't need to be
1226 written, if it will be immediately overwritten.
1227 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1231 zsi
= zero_length_string (lhs
, dsi
);
1238 zsi
->dont_invalidate
= true;
1240 if (fn
== NULL_TREE
)
1243 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1244 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1246 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1247 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1248 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1250 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1252 fprintf (dump_file
, "Optimizing: ");
1253 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1255 if (gimple_call_num_args (stmt
) == 2)
1256 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1258 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1259 gimple_call_arg (stmt
, 2));
1262 stmt
= gsi_stmt (*gsi
);
1264 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1266 fprintf (dump_file
, "into: ");
1267 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1269 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1270 laststmt
.stmt
= stmt
;
1271 laststmt
.len
= srclen
;
1272 laststmt
.stridx
= dsi
->idx
;
1274 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1275 fprintf (dump_file
, "not possible.\n");
1278 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1279 If strlen of the second argument is known and length of the third argument
1280 is that plus one, strlen of the first argument is the same after this
1284 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1287 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1288 gimple stmt
= gsi_stmt (*gsi
);
1289 strinfo si
, dsi
, olddsi
;
1291 len
= gimple_call_arg (stmt
, 2);
1292 src
= gimple_call_arg (stmt
, 1);
1293 dst
= gimple_call_arg (stmt
, 0);
1294 idx
= get_stridx (src
);
1298 didx
= get_stridx (dst
);
1301 olddsi
= get_strinfo (didx
);
1306 && tree_fits_uhwi_p (len
)
1307 && !integer_zerop (len
))
1308 adjust_last_stmt (olddsi
, stmt
, false);
1314 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1315 si
= get_strinfo (idx
);
1316 if (si
== NULL
|| si
->length
== NULL_TREE
)
1318 if (TREE_CODE (len
) != SSA_NAME
)
1320 def_stmt
= SSA_NAME_DEF_STMT (len
);
1321 if (!is_gimple_assign (def_stmt
)
1322 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1323 || gimple_assign_rhs1 (def_stmt
) != si
->length
1324 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1330 /* Handle memcpy (x, "abcd", 5) or
1331 memcpy (x, "abc\0uvw", 7). */
1332 if (!tree_fits_uhwi_p (len
)
1333 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1337 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1338 adjust_last_stmt (olddsi
, stmt
, false);
1342 didx
= new_stridx (dst
);
1347 newlen
= si
->length
;
1349 newlen
= build_int_cst (size_type_node
, ~idx
);
1353 dsi
= unshare_strinfo (olddsi
);
1354 oldlen
= olddsi
->length
;
1355 dsi
->length
= newlen
;
1356 /* Break the chain, so adjust_related_strinfo on later pointers in
1357 the chain won't adjust this one anymore. */
1360 dsi
->endptr
= NULL_TREE
;
1364 dsi
= new_strinfo (dst
, didx
, newlen
);
1365 set_strinfo (didx
, dsi
);
1366 find_equal_ptrs (dst
, didx
);
1368 dsi
->writable
= true;
1369 dsi
->dont_invalidate
= true;
1372 tree adj
= NULL_TREE
;
1373 location_t loc
= gimple_location (stmt
);
1374 if (oldlen
== NULL_TREE
)
1376 else if (integer_zerop (oldlen
))
1378 else if (TREE_CODE (oldlen
) == INTEGER_CST
1379 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1380 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1381 TREE_TYPE (dsi
->length
), dsi
->length
,
1382 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1384 if (adj
!= NULL_TREE
)
1385 adjust_related_strinfos (loc
, dsi
, adj
);
1389 /* memcpy src may not overlap dst, so src doesn't need to be
1390 invalidated either. */
1392 si
->dont_invalidate
= true;
1394 lhs
= gimple_call_lhs (stmt
);
1397 case BUILT_IN_MEMCPY
:
1398 case BUILT_IN_MEMCPY_CHK
:
1399 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1400 laststmt
.stmt
= stmt
;
1401 laststmt
.len
= dsi
->length
;
1402 laststmt
.stridx
= dsi
->idx
;
1404 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1406 case BUILT_IN_MEMPCPY
:
1407 case BUILT_IN_MEMPCPY_CHK
:
1414 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1415 If strlen of the second argument is known, strlen of the first argument
1416 is increased by the length of the second argument. Furthermore, attempt
1417 to convert it to memcpy/strcpy if the length of the first argument
1421 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1424 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1426 gimple stmt
= gsi_stmt (*gsi
);
1430 src
= gimple_call_arg (stmt
, 1);
1431 dst
= gimple_call_arg (stmt
, 0);
1432 lhs
= gimple_call_lhs (stmt
);
1434 didx
= get_stridx (dst
);
1440 dsi
= get_strinfo (didx
);
1441 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1443 /* strcat (p, q) can be transformed into
1444 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1445 with length endptr - p if we need to compute the length
1446 later on. Don't do this transformation if we don't need
1448 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1452 didx
= new_stridx (dst
);
1458 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1459 set_strinfo (didx
, dsi
);
1460 find_equal_ptrs (dst
, didx
);
1464 dsi
= unshare_strinfo (dsi
);
1465 dsi
->length
= NULL_TREE
;
1467 dsi
->endptr
= NULL_TREE
;
1469 dsi
->writable
= true;
1471 dsi
->dont_invalidate
= true;
1478 idx
= get_stridx (src
);
1480 srclen
= build_int_cst (size_type_node
, ~idx
);
1483 si
= get_strinfo (idx
);
1485 srclen
= get_string_length (si
);
1488 loc
= gimple_location (stmt
);
1489 dstlen
= dsi
->length
;
1490 endptr
= dsi
->endptr
;
1492 dsi
= unshare_strinfo (dsi
);
1493 dsi
->endptr
= NULL_TREE
;
1495 dsi
->writable
= true;
1497 if (srclen
!= NULL_TREE
)
1499 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1500 dsi
->length
, srclen
);
1501 adjust_related_strinfos (loc
, dsi
, srclen
);
1502 dsi
->dont_invalidate
= true;
1507 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1508 dsi
->dont_invalidate
= true;
1512 /* strcat src may not overlap dst, so src doesn't need to be
1513 invalidated either. */
1514 si
->dont_invalidate
= true;
1516 /* For now. Could remove the lhs from the call and add
1517 lhs = dst; afterwards. */
1525 case BUILT_IN_STRCAT
:
1526 if (srclen
!= NULL_TREE
)
1527 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1529 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1531 case BUILT_IN_STRCAT_CHK
:
1532 if (srclen
!= NULL_TREE
)
1533 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1535 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1536 objsz
= gimple_call_arg (stmt
, 2);
1542 if (fn
== NULL_TREE
)
1546 if (srclen
!= NULL_TREE
)
1548 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1549 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1551 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1552 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1553 build_int_cst (type
, 1));
1554 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1558 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1560 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1561 TREE_TYPE (dst
), unshare_expr (dst
),
1562 fold_convert_loc (loc
, sizetype
,
1563 unshare_expr (dstlen
)));
1564 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1566 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1568 fprintf (dump_file
, "Optimizing: ");
1569 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1571 if (srclen
!= NULL_TREE
)
1572 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1573 dst
, src
, len
, objsz
);
1575 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1579 stmt
= gsi_stmt (*gsi
);
1581 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1583 fprintf (dump_file
, "into: ");
1584 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1586 /* If srclen == NULL, note that current string length can be
1587 computed by transforming this strcpy into stpcpy. */
1588 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1590 adjust_last_stmt (dsi
, stmt
, true);
1591 if (srclen
!= NULL_TREE
)
1593 laststmt
.stmt
= stmt
;
1594 laststmt
.len
= srclen
;
1595 laststmt
.stridx
= dsi
->idx
;
1598 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1599 fprintf (dump_file
, "not possible.\n");
1602 /* Handle a call to malloc or calloc. */
1605 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1607 gimple stmt
= gsi_stmt (*gsi
);
1608 tree lhs
= gimple_call_lhs (stmt
);
1609 gcc_assert (get_stridx (lhs
) == 0);
1610 int idx
= new_stridx (lhs
);
1611 tree length
= NULL_TREE
;
1612 if (bcode
== BUILT_IN_CALLOC
)
1613 length
= build_int_cst (size_type_node
, 0);
1614 strinfo si
= new_strinfo (lhs
, idx
, length
);
1615 if (bcode
== BUILT_IN_CALLOC
)
1617 set_strinfo (idx
, si
);
1618 si
->writable
= true;
1620 si
->dont_invalidate
= true;
1623 /* Handle a call to memset.
1624 After a call to calloc, memset(,0,) is unnecessary.
1625 memset(malloc(n),0,n) is calloc(n,1). */
1628 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1630 gimple stmt2
= gsi_stmt (*gsi
);
1631 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1633 tree ptr
= gimple_call_arg (stmt2
, 0);
1634 int idx1
= get_stridx (ptr
);
1637 strinfo si1
= get_strinfo (idx1
);
1640 gimple stmt1
= si1
->stmt
;
1641 if (!stmt1
|| !is_gimple_call (stmt1
))
1643 tree callee1
= gimple_call_fndecl (stmt1
);
1644 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1646 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1647 tree size
= gimple_call_arg (stmt2
, 2);
1648 if (code1
== BUILT_IN_CALLOC
)
1649 /* Not touching stmt1 */ ;
1650 else if (code1
== BUILT_IN_MALLOC
1651 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1653 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1654 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1655 size
, build_one_cst (size_type_node
));
1656 si1
->length
= build_int_cst (size_type_node
, 0);
1657 si1
->stmt
= gsi_stmt (gsi1
);
1661 tree lhs
= gimple_call_lhs (stmt2
);
1662 unlink_stmt_vdef (stmt2
);
1665 gimple assign
= gimple_build_assign (lhs
, ptr
);
1666 gsi_replace (gsi
, assign
, false);
1670 gsi_remove (gsi
, true);
1671 release_defs (stmt2
);
1677 /* Handle a POINTER_PLUS_EXPR statement.
1678 For p = "abcd" + 2; compute associated length, or if
1679 p = q + off is pointing to a '\0' character of a string, call
1680 zero_length_string on it. */
1683 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1685 gimple stmt
= gsi_stmt (*gsi
);
1686 tree lhs
= gimple_assign_lhs (stmt
), off
;
1687 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1695 tree off
= gimple_assign_rhs2 (stmt
);
1696 if (tree_fits_uhwi_p (off
)
1697 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1698 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1699 = ~(~idx
- (int) tree_to_uhwi (off
));
1703 si
= get_strinfo (idx
);
1704 if (si
== NULL
|| si
->length
== NULL_TREE
)
1707 off
= gimple_assign_rhs2 (stmt
);
1709 if (operand_equal_p (si
->length
, off
, 0))
1710 zsi
= zero_length_string (lhs
, si
);
1711 else if (TREE_CODE (off
) == SSA_NAME
)
1713 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1714 if (gimple_assign_single_p (def_stmt
)
1715 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1716 zsi
= zero_length_string (lhs
, si
);
1719 && si
->endptr
!= NULL_TREE
1720 && si
->endptr
!= lhs
1721 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1723 enum tree_code rhs_code
1724 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1725 ? SSA_NAME
: NOP_EXPR
;
1726 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
, NULL_TREE
);
1727 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1732 /* Handle a single character store. */
1735 handle_char_store (gimple_stmt_iterator
*gsi
)
1739 gimple stmt
= gsi_stmt (*gsi
);
1740 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1742 if (TREE_CODE (lhs
) == MEM_REF
1743 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1745 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1747 ssaname
= TREE_OPERAND (lhs
, 0);
1748 idx
= get_stridx (ssaname
);
1752 idx
= get_addr_stridx (lhs
);
1756 si
= get_strinfo (idx
);
1757 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1759 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1761 /* When storing '\0', the store can be removed
1762 if we know it has been stored in the current function. */
1763 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1765 unlink_stmt_vdef (stmt
);
1766 release_defs (stmt
);
1767 gsi_remove (gsi
, true);
1772 si
->writable
= true;
1778 /* Otherwise this statement overwrites the '\0' with
1779 something, if the previous stmt was a memcpy,
1780 its length may be decreased. */
1781 adjust_last_stmt (si
, stmt
, false);
1783 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1785 si
= unshare_strinfo (si
);
1786 si
->length
= build_int_cst (size_type_node
, 0);
1792 si
->writable
= true;
1793 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1794 si
->endptr
= ssaname
;
1795 si
->dont_invalidate
= true;
1797 /* If si->length is non-zero constant, we aren't overwriting '\0',
1798 and if we aren't storing '\0', we know that the length of the
1799 string and any other zero terminated string in memory remains
1800 the same. In that case we move to the next gimple statement and
1801 return to signal the caller that it shouldn't invalidate anything.
1803 This is benefical for cases like:
1808 strcpy (p, "foobar");
1809 size_t len = strlen (p); // This can be optimized into 6
1810 size_t len2 = strlen (q); // This has to be computed
1812 size_t len3 = strlen (p); // This can be optimized into 6
1813 size_t len4 = strlen (q); // This can be optimized into len2
1814 bar (len, len2, len3, len4);
1817 else if (si
!= NULL
&& si
->length
!= NULL_TREE
1818 && TREE_CODE (si
->length
) == INTEGER_CST
1819 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
1825 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1829 si
= zero_length_string (ssaname
, NULL
);
1831 si
->dont_invalidate
= true;
1835 int idx
= new_addr_stridx (lhs
);
1838 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1839 build_int_cst (size_type_node
, 0));
1840 set_strinfo (idx
, si
);
1841 si
->dont_invalidate
= true;
1845 si
->writable
= true;
1848 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
1849 && ssaname
== NULL_TREE
1850 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
1852 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
1853 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
1854 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
1856 int idx
= new_addr_stridx (lhs
);
1859 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1860 build_int_cst (size_type_node
, l
));
1861 set_strinfo (idx
, si
);
1862 si
->dont_invalidate
= true;
1867 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
1869 /* Allow adjust_last_stmt to remove it if the stored '\0'
1870 is immediately overwritten. */
1871 laststmt
.stmt
= stmt
;
1872 laststmt
.len
= build_int_cst (size_type_node
, 1);
1873 laststmt
.stridx
= si
->idx
;
1878 /* Attempt to optimize a single statement at *GSI using string length
1882 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
1884 gimple stmt
= gsi_stmt (*gsi
);
1886 if (is_gimple_call (stmt
))
1888 tree callee
= gimple_call_fndecl (stmt
);
1889 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
1890 switch (DECL_FUNCTION_CODE (callee
))
1892 case BUILT_IN_STRLEN
:
1893 handle_builtin_strlen (gsi
);
1895 case BUILT_IN_STRCHR
:
1896 handle_builtin_strchr (gsi
);
1898 case BUILT_IN_STRCPY
:
1899 case BUILT_IN_STRCPY_CHK
:
1900 case BUILT_IN_STPCPY
:
1901 case BUILT_IN_STPCPY_CHK
:
1902 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1904 case BUILT_IN_MEMCPY
:
1905 case BUILT_IN_MEMCPY_CHK
:
1906 case BUILT_IN_MEMPCPY
:
1907 case BUILT_IN_MEMPCPY_CHK
:
1908 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1910 case BUILT_IN_STRCAT
:
1911 case BUILT_IN_STRCAT_CHK
:
1912 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
1914 case BUILT_IN_MALLOC
:
1915 case BUILT_IN_CALLOC
:
1916 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
1918 case BUILT_IN_MEMSET
:
1919 if (!handle_builtin_memset (gsi
))
1926 else if (is_gimple_assign (stmt
))
1928 tree lhs
= gimple_assign_lhs (stmt
);
1930 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
1932 if (gimple_assign_single_p (stmt
)
1933 || (gimple_assign_cast_p (stmt
)
1934 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
1936 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1937 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
1939 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
1940 handle_pointer_plus (gsi
);
1942 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
1944 tree type
= TREE_TYPE (lhs
);
1945 if (TREE_CODE (type
) == ARRAY_TYPE
)
1946 type
= TREE_TYPE (type
);
1947 if (TREE_CODE (type
) == INTEGER_TYPE
1948 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
1949 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
1951 if (! handle_char_store (gsi
))
1957 if (gimple_vdef (stmt
))
1958 maybe_invalidate (stmt
);
1962 /* Recursively call maybe_invalidate on stmts that might be executed
1963 in between dombb and current bb and that contain a vdef. Stop when
1964 *count stmts are inspected, or if the whole strinfo vector has
1965 been invalidated. */
1968 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
1970 unsigned int i
, n
= gimple_phi_num_args (phi
);
1972 for (i
= 0; i
< n
; i
++)
1974 tree vuse
= gimple_phi_arg_def (phi
, i
);
1975 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
1976 basic_block bb
= gimple_bb (stmt
);
1979 || !bitmap_set_bit (visited
, bb
->index
)
1980 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1984 if (gimple_code (stmt
) == GIMPLE_PHI
)
1986 do_invalidate (dombb
, stmt
, visited
, count
);
1993 if (!maybe_invalidate (stmt
))
1998 vuse
= gimple_vuse (stmt
);
1999 stmt
= SSA_NAME_DEF_STMT (vuse
);
2000 if (gimple_bb (stmt
) != bb
)
2002 bb
= gimple_bb (stmt
);
2005 || !bitmap_set_bit (visited
, bb
->index
)
2006 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2013 class strlen_dom_walker
: public dom_walker
2016 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2018 virtual void before_dom_children (basic_block
);
2019 virtual void after_dom_children (basic_block
);
2022 /* Callback for walk_dominator_tree. Attempt to optimize various
2023 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2026 strlen_dom_walker::before_dom_children (basic_block bb
)
2028 gimple_stmt_iterator gsi
;
2029 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2032 stridx_to_strinfo
= NULL
;
2035 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
2036 if (stridx_to_strinfo
)
2038 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
2040 gimple phi
= gsi_stmt (gsi
);
2041 if (virtual_operand_p (gimple_phi_result (phi
)))
2043 bitmap visited
= BITMAP_ALLOC (NULL
);
2044 int count_vdef
= 100;
2045 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2046 BITMAP_FREE (visited
);
2047 if (count_vdef
== 0)
2049 /* If there were too many vdefs in between immediate
2050 dominator and current bb, invalidate everything.
2051 If stridx_to_strinfo has been unshared, we need
2052 to free it, otherwise just set it to NULL. */
2053 if (!strinfo_shared ())
2059 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2063 (*stridx_to_strinfo
)[i
] = NULL
;
2067 stridx_to_strinfo
= NULL
;
2075 /* If all PHI arguments have the same string index, the PHI result
2077 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
2079 gimple phi
= gsi_stmt (gsi
);
2080 tree result
= gimple_phi_result (phi
);
2081 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2083 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2086 unsigned int i
, n
= gimple_phi_num_args (phi
);
2087 for (i
= 1; i
< n
; i
++)
2088 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2091 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2096 /* Attempt to optimize individual statements. */
2097 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2098 if (strlen_optimize_stmt (&gsi
))
2101 bb
->aux
= stridx_to_strinfo
;
2102 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2103 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2106 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2107 owned by the current bb, clear bb->aux. */
2110 strlen_dom_walker::after_dom_children (basic_block bb
)
2114 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2115 if (vec_safe_length (stridx_to_strinfo
)
2116 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2121 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2123 vec_free (stridx_to_strinfo
);
2129 /* Main entry point. */
2133 const pass_data pass_data_strlen
=
2135 GIMPLE_PASS
, /* type */
2136 "strlen", /* name */
2137 OPTGROUP_NONE
, /* optinfo_flags */
2138 TV_TREE_STRLEN
, /* tv_id */
2139 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2140 0, /* properties_provided */
2141 0, /* properties_destroyed */
2142 0, /* todo_flags_start */
2143 0, /* todo_flags_finish */
2146 class pass_strlen
: public gimple_opt_pass
2149 pass_strlen (gcc::context
*ctxt
)
2150 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2153 /* opt_pass methods: */
2154 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2155 virtual unsigned int execute (function
*);
2157 }; // class pass_strlen
2160 pass_strlen::execute (function
*fun
)
2162 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2164 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
2165 sizeof (struct strinfo_struct
), 64);
2167 calculate_dominance_info (CDI_DOMINATORS
);
2169 /* String length optimization is implemented as a walk of the dominator
2170 tree and a forward walk of statements within each block. */
2171 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2173 ssa_ver_to_stridx
.release ();
2174 free_alloc_pool (strinfo_pool
);
2175 if (decl_to_stridxlist_htab
)
2177 obstack_free (&stridx_obstack
, NULL
);
2178 delete decl_to_stridxlist_htab
;
2179 decl_to_stridxlist_htab
= NULL
;
2181 laststmt
.stmt
= NULL
;
2182 laststmt
.len
= NULL_TREE
;
2183 laststmt
.stridx
= 0;
2191 make_pass_strlen (gcc::context
*ctxt
)
2193 return new pass_strlen (ctxt
);