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"
28 #include "basic-block.h"
29 #include "tree-ssa-alias.h"
30 #include "internal-fn.h"
31 #include "gimple-fold.h"
33 #include "gimple-expr.h"
37 #include "gimple-iterator.h"
38 #include "gimplify-me.h"
39 #include "gimple-ssa.h"
40 #include "tree-phinodes.h"
41 #include "ssa-iterators.h"
42 #include "stringpool.h"
43 #include "tree-ssanames.h"
46 #include "tree-pass.h"
48 #include "alloc-pool.h"
49 #include "tree-ssa-propagate.h"
50 #include "gimple-pretty-print.h"
54 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
55 is an index into strinfo vector, negative value stands for
56 string length of a string literal (~strlen). */
57 static vec
<int> ssa_ver_to_stridx
;
59 /* Number of currently active string indexes plus one. */
60 static int max_stridx
;
62 /* String information record. */
63 typedef struct strinfo_struct
65 /* String length of this string. */
67 /* Any of the corresponding pointers for querying alias oracle. */
69 /* Statement for delayed length computation. */
71 /* Pointer to '\0' if known, if NULL, it can be computed as
74 /* Reference count. Any changes to strinfo entry possibly shared
75 with dominating basic blocks need unshare_strinfo first, except
76 for dont_invalidate which affects only the immediately next
79 /* Copy of index. get_strinfo (si->idx) should return si; */
81 /* These 3 fields are for chaining related string pointers together.
83 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
84 strcpy (c, d); e = c + dl;
85 strinfo(a) -> strinfo(c) -> strinfo(e)
86 All have ->first field equal to strinfo(a)->idx and are doubly
87 chained through prev/next fields. The later strinfos are required
88 to point into the same string with zero or more bytes after
89 the previous pointer and all bytes in between the two pointers
90 must be non-zero. Functions like strcpy or memcpy are supposed
91 to adjust all previous strinfo lengths, but not following strinfo
92 lengths (those are uncertain, usually invalidated during
93 maybe_invalidate, except when the alias oracle knows better).
94 Functions like strcat on the other side adjust the whole
95 related strinfo chain.
96 They are updated lazily, so to use the chain the same first fields
97 and si->prev->next == si->idx needs to be verified. */
101 /* A flag whether the string is known to be written in the current
104 /* A flag for the next maybe_invalidate that this strinfo shouldn't
105 be invalidated. Always cleared by maybe_invalidate. */
106 bool dont_invalidate
;
109 /* Pool for allocating strinfo_struct entries. */
110 static alloc_pool strinfo_pool
;
112 /* Vector mapping positive string indexes to strinfo, for the
113 current basic block. The first pointer in the vector is special,
114 it is either NULL, meaning the vector isn't shared, or it is
115 a basic block pointer to the owner basic_block if shared.
116 If some other bb wants to modify the vector, the vector needs
117 to be unshared first, and only the owner bb is supposed to free it. */
118 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
120 /* One OFFSET->IDX mapping. */
123 struct stridxlist
*next
;
124 HOST_WIDE_INT offset
;
128 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
129 struct decl_stridxlist_map
131 struct tree_map_base base
;
132 struct stridxlist list
;
135 /* stridxlist hashtable helpers. */
137 struct stridxlist_hasher
: typed_noop_remove
<decl_stridxlist_map
>
139 typedef decl_stridxlist_map value_type
;
140 typedef decl_stridxlist_map compare_type
;
141 static inline hashval_t
hash (const value_type
*);
142 static inline bool equal (const value_type
*, const compare_type
*);
145 /* Hash a from tree in a decl_stridxlist_map. */
148 stridxlist_hasher::hash (const value_type
*item
)
150 return DECL_UID (item
->base
.from
);
154 stridxlist_hasher::equal (const value_type
*v
, const compare_type
*c
)
156 return tree_map_base_eq (&v
->base
, &c
->base
);
159 /* Hash table for mapping decls to a chained list of offset -> idx
161 static hash_table
<stridxlist_hasher
> decl_to_stridxlist_htab
;
163 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
164 static struct obstack stridx_obstack
;
166 /* Last memcpy statement if it could be adjusted if the trailing
167 '\0' written is immediately overwritten, or
168 *x = '\0' store that could be removed if it is immediately overwritten. */
169 struct laststmt_struct
176 /* Helper function for get_stridx. */
179 get_addr_stridx (tree exp
)
182 struct decl_stridxlist_map ent
, *e
;
183 struct stridxlist
*list
;
186 if (!decl_to_stridxlist_htab
.is_created ())
189 base
= get_addr_base_and_unit_offset (exp
, &off
);
190 if (base
== NULL
|| !DECL_P (base
))
193 ent
.base
.from
= base
;
194 e
= decl_to_stridxlist_htab
.find_with_hash (&ent
, DECL_UID (base
));
201 if (list
->offset
== off
)
209 /* Return string index for EXP. */
212 get_stridx (tree exp
)
216 if (TREE_CODE (exp
) == SSA_NAME
)
217 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
219 if (TREE_CODE (exp
) == ADDR_EXPR
)
221 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
226 s
= string_constant (exp
, &o
);
228 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
229 && TREE_STRING_LENGTH (s
) > 0)
231 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
232 const char *p
= TREE_STRING_POINTER (s
);
233 int max
= TREE_STRING_LENGTH (s
) - 1;
235 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
236 return ~(int) strlen (p
+ offset
);
241 /* Return true if strinfo vector is shared with the immediate dominator. */
244 strinfo_shared (void)
246 return vec_safe_length (stridx_to_strinfo
)
247 && (*stridx_to_strinfo
)[0] != NULL
;
250 /* Unshare strinfo vector that is shared with the immediate dominator. */
253 unshare_strinfo_vec (void)
258 gcc_assert (strinfo_shared ());
259 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
260 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
263 (*stridx_to_strinfo
)[0] = NULL
;
266 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
267 Return a pointer to the location where the string index can
268 be stored (if 0) or is stored, or NULL if this can't be tracked. */
271 addr_stridxptr (tree exp
)
273 decl_stridxlist_map
**slot
;
274 struct decl_stridxlist_map ent
;
275 struct stridxlist
*list
;
278 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
279 if (base
== NULL_TREE
|| !DECL_P (base
))
282 if (!decl_to_stridxlist_htab
.is_created ())
284 decl_to_stridxlist_htab
.create (64);
285 gcc_obstack_init (&stridx_obstack
);
287 ent
.base
.from
= base
;
288 slot
= decl_to_stridxlist_htab
.find_slot_with_hash (&ent
, DECL_UID (base
),
293 list
= &(*slot
)->list
;
294 for (i
= 0; i
< 16; i
++)
296 if (list
->offset
== off
)
298 if (list
->next
== NULL
)
303 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
308 struct decl_stridxlist_map
*e
309 = XOBNEW (&stridx_obstack
, struct decl_stridxlist_map
);
320 /* Create a new string index, or return 0 if reached limit. */
323 new_stridx (tree exp
)
326 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
328 if (TREE_CODE (exp
) == SSA_NAME
)
330 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
333 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
336 if (TREE_CODE (exp
) == ADDR_EXPR
)
338 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
341 gcc_assert (*pidx
== 0);
342 *pidx
= max_stridx
++;
349 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
352 new_addr_stridx (tree exp
)
355 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
357 pidx
= addr_stridxptr (exp
);
360 gcc_assert (*pidx
== 0);
361 *pidx
= max_stridx
++;
367 /* Create a new strinfo. */
370 new_strinfo (tree ptr
, int idx
, tree length
)
372 strinfo si
= (strinfo
) pool_alloc (strinfo_pool
);
376 si
->endptr
= NULL_TREE
;
382 si
->writable
= false;
383 si
->dont_invalidate
= false;
387 /* Decrease strinfo refcount and free it if not referenced anymore. */
390 free_strinfo (strinfo si
)
392 if (si
&& --si
->refcount
== 0)
393 pool_free (strinfo_pool
, si
);
396 /* Return strinfo vector entry IDX. */
398 static inline strinfo
399 get_strinfo (int idx
)
401 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
403 return (*stridx_to_strinfo
)[idx
];
406 /* Set strinfo in the vector entry IDX to SI. */
409 set_strinfo (int idx
, strinfo si
)
411 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
412 unshare_strinfo_vec ();
413 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
414 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
415 (*stridx_to_strinfo
)[idx
] = si
;
418 /* Return string length, or NULL if it can't be computed. */
421 get_string_length (strinfo si
)
428 gimple stmt
= si
->stmt
, lenstmt
;
429 tree callee
, lhs
, fn
, tem
;
431 gimple_stmt_iterator gsi
;
433 gcc_assert (is_gimple_call (stmt
));
434 callee
= gimple_call_fndecl (stmt
);
435 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
436 lhs
= gimple_call_lhs (stmt
);
437 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
438 /* unshare_strinfo is intentionally not called here. The (delayed)
439 transformation of strcpy or strcat into stpcpy is done at the place
440 of the former strcpy/strcat call and so can affect all the strinfos
441 with the same stmt. If they were unshared before and transformation
442 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
443 just compute the right length. */
444 switch (DECL_FUNCTION_CODE (callee
))
446 case BUILT_IN_STRCAT
:
447 case BUILT_IN_STRCAT_CHK
:
448 gsi
= gsi_for_stmt (stmt
);
449 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
450 gcc_assert (lhs
== NULL_TREE
);
451 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
452 lenstmt
= gimple_build_call (fn
, 1, tem
);
453 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
454 gimple_call_set_lhs (lenstmt
, lhs
);
455 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
456 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
457 tem
= gimple_call_arg (stmt
, 0);
458 if (!ptrofftype_p (TREE_TYPE (lhs
)))
460 lhs
= convert_to_ptrofftype (lhs
);
461 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
462 true, GSI_SAME_STMT
);
465 = gimple_build_assign_with_ops
467 make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0)), NULL
),
469 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
470 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
473 case BUILT_IN_STRCPY
:
474 case BUILT_IN_STRCPY_CHK
:
475 if (gimple_call_num_args (stmt
) == 2)
476 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
478 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
479 gcc_assert (lhs
== NULL_TREE
);
480 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
482 fprintf (dump_file
, "Optimizing: ");
483 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
485 gimple_call_set_fndecl (stmt
, fn
);
486 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
487 gimple_call_set_lhs (stmt
, lhs
);
489 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
491 fprintf (dump_file
, "into: ");
492 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
495 case BUILT_IN_STPCPY
:
496 case BUILT_IN_STPCPY_CHK
:
497 gcc_assert (lhs
!= NULL_TREE
);
498 loc
= gimple_location (stmt
);
501 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
502 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
503 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
515 /* Invalidate string length information for strings whose length
516 might change due to stores in stmt. */
519 maybe_invalidate (gimple stmt
)
523 bool nonempty
= false;
525 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
528 if (!si
->dont_invalidate
)
531 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
532 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
534 set_strinfo (i
, NULL
);
539 si
->dont_invalidate
= false;
545 /* Unshare strinfo record SI, if it has recount > 1 or
546 if stridx_to_strinfo vector is shared with some other
550 unshare_strinfo (strinfo si
)
554 if (si
->refcount
== 1 && !strinfo_shared ())
557 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
558 nsi
->stmt
= si
->stmt
;
559 nsi
->endptr
= si
->endptr
;
560 nsi
->first
= si
->first
;
561 nsi
->prev
= si
->prev
;
562 nsi
->next
= si
->next
;
563 nsi
->writable
= si
->writable
;
564 set_strinfo (si
->idx
, nsi
);
569 /* Return first strinfo in the related strinfo chain
570 if all strinfos in between belong to the chain, otherwise
574 verify_related_strinfos (strinfo origsi
)
576 strinfo si
= origsi
, psi
;
578 if (origsi
->first
== 0)
580 for (; si
->prev
; si
= psi
)
582 if (si
->first
!= origsi
->first
)
584 psi
= get_strinfo (si
->prev
);
587 if (psi
->next
!= si
->idx
)
590 if (si
->idx
!= si
->first
)
595 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
596 to a zero-length string and if possible chain it to a related strinfo
597 chain whose part is or might be CHAINSI. */
600 zero_length_string (tree ptr
, strinfo chainsi
)
604 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
605 && get_stridx (ptr
) == 0);
607 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
611 si
= verify_related_strinfos (chainsi
);
615 for (; chainsi
->next
; chainsi
= si
)
617 if (chainsi
->endptr
== NULL_TREE
)
619 chainsi
= unshare_strinfo (chainsi
);
620 chainsi
->endptr
= ptr
;
622 si
= get_strinfo (chainsi
->next
);
624 || si
->first
!= chainsi
->first
625 || si
->prev
!= chainsi
->idx
)
628 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
629 if (chainsi
->endptr
== NULL_TREE
)
631 chainsi
= unshare_strinfo (chainsi
);
632 chainsi
->endptr
= ptr
;
634 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
638 chainsi
= unshare_strinfo (chainsi
);
641 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
645 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
647 chainsi
= unshare_strinfo (chainsi
);
653 idx
= new_stridx (ptr
);
656 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
657 set_strinfo (idx
, si
);
661 chainsi
= unshare_strinfo (chainsi
);
662 if (chainsi
->first
== 0)
663 chainsi
->first
= chainsi
->idx
;
665 if (chainsi
->endptr
== NULL_TREE
)
666 chainsi
->endptr
= ptr
;
667 si
->prev
= chainsi
->idx
;
668 si
->first
= chainsi
->first
;
669 si
->writable
= chainsi
->writable
;
674 /* For strinfo ORIGSI whose length has been just updated
675 update also related strinfo lengths (add ADJ to each,
676 but don't adjust ORIGSI). */
679 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
681 strinfo si
= verify_related_strinfos (origsi
);
694 si
= unshare_strinfo (si
);
697 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
698 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
699 TREE_TYPE (si
->length
), si
->length
,
702 else if (si
->stmt
!= NULL
)
703 /* Delayed length computation is unaffected. */
708 si
->endptr
= NULL_TREE
;
709 si
->dont_invalidate
= true;
713 nsi
= get_strinfo (si
->next
);
715 || nsi
->first
!= si
->first
716 || nsi
->prev
!= si
->idx
)
722 /* Find if there are other SSA_NAME pointers equal to PTR
723 for which we don't track their string lengths yet. If so, use
727 find_equal_ptrs (tree ptr
, int idx
)
729 if (TREE_CODE (ptr
) != SSA_NAME
)
733 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
734 if (!is_gimple_assign (stmt
))
736 ptr
= gimple_assign_rhs1 (stmt
);
737 switch (gimple_assign_rhs_code (stmt
))
742 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
744 if (TREE_CODE (ptr
) == SSA_NAME
)
746 if (TREE_CODE (ptr
) != ADDR_EXPR
)
751 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
752 if (pidx
!= NULL
&& *pidx
== 0)
760 /* We might find an endptr created in this pass. Grow the
761 vector in that case. */
762 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
763 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
765 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
767 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
771 /* If the last .MEM setter statement before STMT is
772 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
773 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
774 just memcpy (x, y, strlen (y)). SI must be the zero length
778 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
780 tree vuse
, callee
, len
;
781 struct laststmt_struct last
= laststmt
;
782 strinfo lastsi
, firstsi
;
784 laststmt
.stmt
= NULL
;
785 laststmt
.len
= NULL_TREE
;
788 if (last
.stmt
== NULL
)
791 vuse
= gimple_vuse (stmt
);
792 if (vuse
== NULL_TREE
793 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
794 || !has_single_use (vuse
))
797 gcc_assert (last
.stridx
> 0);
798 lastsi
= get_strinfo (last
.stridx
);
804 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
807 firstsi
= verify_related_strinfos (si
);
810 while (firstsi
!= lastsi
)
813 if (firstsi
->next
== 0)
815 nextsi
= get_strinfo (firstsi
->next
);
817 || nextsi
->prev
!= firstsi
->idx
818 || nextsi
->first
!= si
->first
)
826 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
830 if (is_gimple_assign (last
.stmt
))
832 gimple_stmt_iterator gsi
;
834 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
836 if (stmt_could_throw_p (last
.stmt
))
838 gsi
= gsi_for_stmt (last
.stmt
);
839 unlink_stmt_vdef (last
.stmt
);
840 release_defs (last
.stmt
);
841 gsi_remove (&gsi
, true);
845 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
848 callee
= gimple_call_fndecl (last
.stmt
);
849 switch (DECL_FUNCTION_CODE (callee
))
851 case BUILT_IN_MEMCPY
:
852 case BUILT_IN_MEMCPY_CHK
:
858 len
= gimple_call_arg (last
.stmt
, 2);
859 if (tree_fits_uhwi_p (len
))
861 if (!tree_fits_uhwi_p (last
.len
)
862 || integer_zerop (len
)
863 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
865 /* Don't adjust the length if it is divisible by 4, it is more efficient
866 to store the extra '\0' in that case. */
867 if ((tree_to_uhwi (len
) & 3) == 0)
870 else if (TREE_CODE (len
) == SSA_NAME
)
872 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
873 if (!is_gimple_assign (def_stmt
)
874 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
875 || gimple_assign_rhs1 (def_stmt
) != last
.len
876 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
882 gimple_call_set_arg (last
.stmt
, 2, last
.len
);
883 update_stmt (last
.stmt
);
886 /* Handle a strlen call. If strlen of the argument is known, replace
887 the strlen call with the known value, otherwise remember that strlen
888 of the argument is stored in the lhs SSA_NAME. */
891 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
895 gimple stmt
= gsi_stmt (*gsi
);
896 tree lhs
= gimple_call_lhs (stmt
);
898 if (lhs
== NULL_TREE
)
901 src
= gimple_call_arg (stmt
, 0);
902 idx
= get_stridx (src
);
909 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
913 si
= get_strinfo (idx
);
915 rhs
= get_string_length (si
);
917 if (rhs
!= NULL_TREE
)
919 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
921 fprintf (dump_file
, "Optimizing: ");
922 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
924 rhs
= unshare_expr (rhs
);
925 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
926 rhs
= fold_convert_loc (gimple_location (stmt
),
927 TREE_TYPE (lhs
), rhs
);
928 if (!update_call_from_tree (gsi
, rhs
))
929 gimplify_and_update_call_from_tree (gsi
, rhs
);
930 stmt
= gsi_stmt (*gsi
);
932 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
934 fprintf (dump_file
, "into: ");
935 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
938 && TREE_CODE (si
->length
) != SSA_NAME
939 && TREE_CODE (si
->length
) != INTEGER_CST
940 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
942 si
= unshare_strinfo (si
);
948 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
951 idx
= new_stridx (src
);
952 else if (get_strinfo (idx
) != NULL
)
956 strinfo si
= new_strinfo (src
, idx
, lhs
);
957 set_strinfo (idx
, si
);
958 find_equal_ptrs (src
, idx
);
962 /* Handle a strchr call. If strlen of the first argument is known, replace
963 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
964 that lhs of the call is endptr and strlen of the argument is endptr - x. */
967 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
971 gimple stmt
= gsi_stmt (*gsi
);
972 tree lhs
= gimple_call_lhs (stmt
);
974 if (lhs
== NULL_TREE
)
977 if (!integer_zerop (gimple_call_arg (stmt
, 1)))
980 src
= gimple_call_arg (stmt
, 0);
981 idx
= get_stridx (src
);
988 rhs
= build_int_cst (size_type_node
, ~idx
);
992 si
= get_strinfo (idx
);
994 rhs
= get_string_length (si
);
996 if (rhs
!= NULL_TREE
)
998 location_t loc
= gimple_location (stmt
);
1000 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1002 fprintf (dump_file
, "Optimizing: ");
1003 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1005 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1007 rhs
= unshare_expr (si
->endptr
);
1008 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1010 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1014 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1015 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1016 TREE_TYPE (src
), src
, rhs
);
1017 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1019 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1021 if (!update_call_from_tree (gsi
, rhs
))
1022 gimplify_and_update_call_from_tree (gsi
, rhs
);
1023 stmt
= gsi_stmt (*gsi
);
1025 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1027 fprintf (dump_file
, "into: ");
1028 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1031 && si
->endptr
== NULL_TREE
1032 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1034 si
= unshare_strinfo (si
);
1037 zero_length_string (lhs
, si
);
1041 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1043 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1046 idx
= new_stridx (src
);
1047 else if (get_strinfo (idx
) != NULL
)
1049 zero_length_string (lhs
, NULL
);
1054 location_t loc
= gimple_location (stmt
);
1055 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1056 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1057 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1058 size_type_node
, lhsu
, srcu
);
1059 strinfo si
= new_strinfo (src
, idx
, length
);
1061 set_strinfo (idx
, si
);
1062 find_equal_ptrs (src
, idx
);
1063 zero_length_string (lhs
, si
);
1067 zero_length_string (lhs
, NULL
);
1070 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1071 If strlen of the second argument is known, strlen of the first argument
1072 is the same after this call. Furthermore, attempt to convert it to
1076 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1079 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1081 gimple stmt
= gsi_stmt (*gsi
);
1082 strinfo si
, dsi
, olddsi
, zsi
;
1085 src
= gimple_call_arg (stmt
, 1);
1086 dst
= gimple_call_arg (stmt
, 0);
1087 lhs
= gimple_call_lhs (stmt
);
1088 idx
= get_stridx (src
);
1091 si
= get_strinfo (idx
);
1093 didx
= get_stridx (dst
);
1097 olddsi
= get_strinfo (didx
);
1102 adjust_last_stmt (olddsi
, stmt
, false);
1106 srclen
= get_string_length (si
);
1108 srclen
= build_int_cst (size_type_node
, ~idx
);
1110 loc
= gimple_location (stmt
);
1111 if (srclen
== NULL_TREE
)
1114 case BUILT_IN_STRCPY
:
1115 case BUILT_IN_STRCPY_CHK
:
1116 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1119 case BUILT_IN_STPCPY
:
1120 case BUILT_IN_STPCPY_CHK
:
1121 if (lhs
== NULL_TREE
)
1125 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1126 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1127 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1137 didx
= new_stridx (dst
);
1143 oldlen
= olddsi
->length
;
1144 dsi
= unshare_strinfo (olddsi
);
1145 dsi
->length
= srclen
;
1146 /* Break the chain, so adjust_related_strinfo on later pointers in
1147 the chain won't adjust this one anymore. */
1150 dsi
->endptr
= NULL_TREE
;
1154 dsi
= new_strinfo (dst
, didx
, srclen
);
1155 set_strinfo (didx
, dsi
);
1156 find_equal_ptrs (dst
, didx
);
1158 dsi
->writable
= true;
1159 dsi
->dont_invalidate
= true;
1161 if (dsi
->length
== NULL_TREE
)
1165 /* If string length of src is unknown, use delayed length
1166 computation. If string lenth of dst will be needed, it
1167 can be computed by transforming this strcpy call into
1168 stpcpy and subtracting dst from the return value. */
1170 /* Look for earlier strings whose length could be determined if
1171 this strcpy is turned into an stpcpy. */
1173 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1175 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1177 /* When setting a stmt for delayed length computation
1178 prevent all strinfos through dsi from being
1180 chainsi
= unshare_strinfo (chainsi
);
1181 chainsi
->stmt
= stmt
;
1182 chainsi
->length
= NULL_TREE
;
1183 chainsi
->endptr
= NULL_TREE
;
1184 chainsi
->dont_invalidate
= true;
1193 tree adj
= NULL_TREE
;
1194 if (oldlen
== NULL_TREE
)
1196 else if (integer_zerop (oldlen
))
1198 else if (TREE_CODE (oldlen
) == INTEGER_CST
1199 || TREE_CODE (srclen
) == INTEGER_CST
)
1200 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1201 TREE_TYPE (srclen
), srclen
,
1202 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1204 if (adj
!= NULL_TREE
)
1205 adjust_related_strinfos (loc
, dsi
, adj
);
1209 /* strcpy src may not overlap dst, so src doesn't need to be
1210 invalidated either. */
1212 si
->dont_invalidate
= true;
1218 case BUILT_IN_STRCPY
:
1219 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1221 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1223 case BUILT_IN_STRCPY_CHK
:
1224 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1226 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1228 case BUILT_IN_STPCPY
:
1229 /* This would need adjustment of the lhs (subtract one),
1230 or detection that the trailing '\0' doesn't need to be
1231 written, if it will be immediately overwritten.
1232 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1236 zsi
= zero_length_string (lhs
, dsi
);
1239 case BUILT_IN_STPCPY_CHK
:
1240 /* This would need adjustment of the lhs (subtract one),
1241 or detection that the trailing '\0' doesn't need to be
1242 written, if it will be immediately overwritten.
1243 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1247 zsi
= zero_length_string (lhs
, dsi
);
1254 zsi
->dont_invalidate
= true;
1256 if (fn
== NULL_TREE
)
1259 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1260 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1262 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1263 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1264 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1266 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1268 fprintf (dump_file
, "Optimizing: ");
1269 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1271 if (gimple_call_num_args (stmt
) == 2)
1272 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1274 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1275 gimple_call_arg (stmt
, 2));
1278 stmt
= gsi_stmt (*gsi
);
1280 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1282 fprintf (dump_file
, "into: ");
1283 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1285 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1286 laststmt
.stmt
= stmt
;
1287 laststmt
.len
= srclen
;
1288 laststmt
.stridx
= dsi
->idx
;
1290 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1291 fprintf (dump_file
, "not possible.\n");
1294 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1295 If strlen of the second argument is known and length of the third argument
1296 is that plus one, strlen of the first argument is the same after this
1300 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1303 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1304 gimple stmt
= gsi_stmt (*gsi
);
1305 strinfo si
, dsi
, olddsi
;
1307 len
= gimple_call_arg (stmt
, 2);
1308 src
= gimple_call_arg (stmt
, 1);
1309 dst
= gimple_call_arg (stmt
, 0);
1310 idx
= get_stridx (src
);
1314 didx
= get_stridx (dst
);
1317 olddsi
= get_strinfo (didx
);
1322 && tree_fits_uhwi_p (len
)
1323 && !integer_zerop (len
))
1324 adjust_last_stmt (olddsi
, stmt
, false);
1330 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1331 si
= get_strinfo (idx
);
1332 if (si
== NULL
|| si
->length
== NULL_TREE
)
1334 if (TREE_CODE (len
) != SSA_NAME
)
1336 def_stmt
= SSA_NAME_DEF_STMT (len
);
1337 if (!is_gimple_assign (def_stmt
)
1338 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1339 || gimple_assign_rhs1 (def_stmt
) != si
->length
1340 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1346 /* Handle memcpy (x, "abcd", 5) or
1347 memcpy (x, "abc\0uvw", 7). */
1348 if (!tree_fits_uhwi_p (len
)
1349 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1353 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1354 adjust_last_stmt (olddsi
, stmt
, false);
1358 didx
= new_stridx (dst
);
1363 newlen
= si
->length
;
1365 newlen
= build_int_cst (size_type_node
, ~idx
);
1369 dsi
= unshare_strinfo (olddsi
);
1370 oldlen
= olddsi
->length
;
1371 dsi
->length
= newlen
;
1372 /* Break the chain, so adjust_related_strinfo on later pointers in
1373 the chain won't adjust this one anymore. */
1376 dsi
->endptr
= NULL_TREE
;
1380 dsi
= new_strinfo (dst
, didx
, newlen
);
1381 set_strinfo (didx
, dsi
);
1382 find_equal_ptrs (dst
, didx
);
1384 dsi
->writable
= true;
1385 dsi
->dont_invalidate
= true;
1388 tree adj
= NULL_TREE
;
1389 location_t loc
= gimple_location (stmt
);
1390 if (oldlen
== NULL_TREE
)
1392 else if (integer_zerop (oldlen
))
1394 else if (TREE_CODE (oldlen
) == INTEGER_CST
1395 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1396 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1397 TREE_TYPE (dsi
->length
), dsi
->length
,
1398 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1400 if (adj
!= NULL_TREE
)
1401 adjust_related_strinfos (loc
, dsi
, adj
);
1405 /* memcpy src may not overlap dst, so src doesn't need to be
1406 invalidated either. */
1408 si
->dont_invalidate
= true;
1410 lhs
= gimple_call_lhs (stmt
);
1413 case BUILT_IN_MEMCPY
:
1414 case BUILT_IN_MEMCPY_CHK
:
1415 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1416 laststmt
.stmt
= stmt
;
1417 laststmt
.len
= dsi
->length
;
1418 laststmt
.stridx
= dsi
->idx
;
1420 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1422 case BUILT_IN_MEMPCPY
:
1423 case BUILT_IN_MEMPCPY_CHK
:
1430 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1431 If strlen of the second argument is known, strlen of the first argument
1432 is increased by the length of the second argument. Furthermore, attempt
1433 to convert it to memcpy/strcpy if the length of the first argument
1437 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1440 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1442 gimple stmt
= gsi_stmt (*gsi
);
1446 src
= gimple_call_arg (stmt
, 1);
1447 dst
= gimple_call_arg (stmt
, 0);
1448 lhs
= gimple_call_lhs (stmt
);
1450 didx
= get_stridx (dst
);
1456 dsi
= get_strinfo (didx
);
1457 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1459 /* strcat (p, q) can be transformed into
1460 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1461 with length endptr - p if we need to compute the length
1462 later on. Don't do this transformation if we don't need
1464 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1468 didx
= new_stridx (dst
);
1474 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1475 set_strinfo (didx
, dsi
);
1476 find_equal_ptrs (dst
, didx
);
1480 dsi
= unshare_strinfo (dsi
);
1481 dsi
->length
= NULL_TREE
;
1483 dsi
->endptr
= NULL_TREE
;
1485 dsi
->writable
= true;
1487 dsi
->dont_invalidate
= true;
1494 idx
= get_stridx (src
);
1496 srclen
= build_int_cst (size_type_node
, ~idx
);
1499 si
= get_strinfo (idx
);
1501 srclen
= get_string_length (si
);
1504 loc
= gimple_location (stmt
);
1505 dstlen
= dsi
->length
;
1506 endptr
= dsi
->endptr
;
1508 dsi
= unshare_strinfo (dsi
);
1509 dsi
->endptr
= NULL_TREE
;
1511 dsi
->writable
= true;
1513 if (srclen
!= NULL_TREE
)
1515 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1516 dsi
->length
, srclen
);
1517 adjust_related_strinfos (loc
, dsi
, srclen
);
1518 dsi
->dont_invalidate
= true;
1523 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1524 dsi
->dont_invalidate
= true;
1528 /* strcat src may not overlap dst, so src doesn't need to be
1529 invalidated either. */
1530 si
->dont_invalidate
= true;
1532 /* For now. Could remove the lhs from the call and add
1533 lhs = dst; afterwards. */
1541 case BUILT_IN_STRCAT
:
1542 if (srclen
!= NULL_TREE
)
1543 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1545 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1547 case BUILT_IN_STRCAT_CHK
:
1548 if (srclen
!= NULL_TREE
)
1549 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1551 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1552 objsz
= gimple_call_arg (stmt
, 2);
1558 if (fn
== NULL_TREE
)
1562 if (srclen
!= NULL_TREE
)
1564 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1565 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1567 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1568 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1569 build_int_cst (type
, 1));
1570 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1574 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1576 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1577 TREE_TYPE (dst
), unshare_expr (dst
),
1578 fold_convert_loc (loc
, sizetype
,
1579 unshare_expr (dstlen
)));
1580 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1582 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1584 fprintf (dump_file
, "Optimizing: ");
1585 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1587 if (srclen
!= NULL_TREE
)
1588 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1589 dst
, src
, len
, objsz
);
1591 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1595 stmt
= gsi_stmt (*gsi
);
1597 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1599 fprintf (dump_file
, "into: ");
1600 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1602 /* If srclen == NULL, note that current string length can be
1603 computed by transforming this strcpy into stpcpy. */
1604 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1606 adjust_last_stmt (dsi
, stmt
, true);
1607 if (srclen
!= NULL_TREE
)
1609 laststmt
.stmt
= stmt
;
1610 laststmt
.len
= srclen
;
1611 laststmt
.stridx
= dsi
->idx
;
1614 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1615 fprintf (dump_file
, "not possible.\n");
1618 /* Handle a POINTER_PLUS_EXPR statement.
1619 For p = "abcd" + 2; compute associated length, or if
1620 p = q + off is pointing to a '\0' character of a string, call
1621 zero_length_string on it. */
1624 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1626 gimple stmt
= gsi_stmt (*gsi
);
1627 tree lhs
= gimple_assign_lhs (stmt
), off
;
1628 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1636 tree off
= gimple_assign_rhs2 (stmt
);
1637 if (tree_fits_uhwi_p (off
)
1638 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1639 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1640 = ~(~idx
- (int) tree_to_uhwi (off
));
1644 si
= get_strinfo (idx
);
1645 if (si
== NULL
|| si
->length
== NULL_TREE
)
1648 off
= gimple_assign_rhs2 (stmt
);
1650 if (operand_equal_p (si
->length
, off
, 0))
1651 zsi
= zero_length_string (lhs
, si
);
1652 else if (TREE_CODE (off
) == SSA_NAME
)
1654 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1655 if (gimple_assign_single_p (def_stmt
)
1656 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1657 zsi
= zero_length_string (lhs
, si
);
1660 && si
->endptr
!= NULL_TREE
1661 && si
->endptr
!= lhs
1662 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1664 enum tree_code rhs_code
1665 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1666 ? SSA_NAME
: NOP_EXPR
;
1667 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
, NULL_TREE
);
1668 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1673 /* Handle a single character store. */
1676 handle_char_store (gimple_stmt_iterator
*gsi
)
1680 gimple stmt
= gsi_stmt (*gsi
);
1681 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1683 if (TREE_CODE (lhs
) == MEM_REF
1684 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1686 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1688 ssaname
= TREE_OPERAND (lhs
, 0);
1689 idx
= get_stridx (ssaname
);
1693 idx
= get_addr_stridx (lhs
);
1697 si
= get_strinfo (idx
);
1698 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1700 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1702 /* When storing '\0', the store can be removed
1703 if we know it has been stored in the current function. */
1704 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1706 unlink_stmt_vdef (stmt
);
1707 release_defs (stmt
);
1708 gsi_remove (gsi
, true);
1713 si
->writable
= true;
1719 /* Otherwise this statement overwrites the '\0' with
1720 something, if the previous stmt was a memcpy,
1721 its length may be decreased. */
1722 adjust_last_stmt (si
, stmt
, false);
1724 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1726 si
= unshare_strinfo (si
);
1727 si
->length
= build_int_cst (size_type_node
, 0);
1733 si
->writable
= true;
1734 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1735 si
->endptr
= ssaname
;
1736 si
->dont_invalidate
= true;
1738 /* If si->length is non-zero constant, we aren't overwriting '\0',
1739 and if we aren't storing '\0', we know that the length of the
1740 string and any other zero terminated string in memory remains
1741 the same. In that case we move to the next gimple statement and
1742 return to signal the caller that it shouldn't invalidate anything.
1744 This is benefical for cases like:
1749 strcpy (p, "foobar");
1750 size_t len = strlen (p); // This can be optimized into 6
1751 size_t len2 = strlen (q); // This has to be computed
1753 size_t len3 = strlen (p); // This can be optimized into 6
1754 size_t len4 = strlen (q); // This can be optimized into len2
1755 bar (len, len2, len3, len4);
1758 else if (si
!= NULL
&& si
->length
!= NULL_TREE
1759 && TREE_CODE (si
->length
) == INTEGER_CST
1760 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
1766 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1770 si
= zero_length_string (ssaname
, NULL
);
1772 si
->dont_invalidate
= true;
1776 int idx
= new_addr_stridx (lhs
);
1779 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1780 build_int_cst (size_type_node
, 0));
1781 set_strinfo (idx
, si
);
1782 si
->dont_invalidate
= true;
1786 si
->writable
= true;
1789 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
1790 && ssaname
== NULL_TREE
1791 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
1793 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
1794 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
1795 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
1797 int idx
= new_addr_stridx (lhs
);
1800 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1801 build_int_cst (size_type_node
, l
));
1802 set_strinfo (idx
, si
);
1803 si
->dont_invalidate
= true;
1808 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
1810 /* Allow adjust_last_stmt to remove it if the stored '\0'
1811 is immediately overwritten. */
1812 laststmt
.stmt
= stmt
;
1813 laststmt
.len
= build_int_cst (size_type_node
, 1);
1814 laststmt
.stridx
= si
->idx
;
1819 /* Attempt to optimize a single statement at *GSI using string length
1823 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
1825 gimple stmt
= gsi_stmt (*gsi
);
1827 if (is_gimple_call (stmt
))
1829 tree callee
= gimple_call_fndecl (stmt
);
1830 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
1831 switch (DECL_FUNCTION_CODE (callee
))
1833 case BUILT_IN_STRLEN
:
1834 handle_builtin_strlen (gsi
);
1836 case BUILT_IN_STRCHR
:
1837 handle_builtin_strchr (gsi
);
1839 case BUILT_IN_STRCPY
:
1840 case BUILT_IN_STRCPY_CHK
:
1841 case BUILT_IN_STPCPY
:
1842 case BUILT_IN_STPCPY_CHK
:
1843 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1845 case BUILT_IN_MEMCPY
:
1846 case BUILT_IN_MEMCPY_CHK
:
1847 case BUILT_IN_MEMPCPY
:
1848 case BUILT_IN_MEMPCPY_CHK
:
1849 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1851 case BUILT_IN_STRCAT
:
1852 case BUILT_IN_STRCAT_CHK
:
1853 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
1859 else if (is_gimple_assign (stmt
))
1861 tree lhs
= gimple_assign_lhs (stmt
);
1863 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
1865 if (gimple_assign_single_p (stmt
)
1866 || (gimple_assign_cast_p (stmt
)
1867 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
1869 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1870 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
1872 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
1873 handle_pointer_plus (gsi
);
1875 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
1877 tree type
= TREE_TYPE (lhs
);
1878 if (TREE_CODE (type
) == ARRAY_TYPE
)
1879 type
= TREE_TYPE (type
);
1880 if (TREE_CODE (type
) == INTEGER_TYPE
1881 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
1882 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
1884 if (! handle_char_store (gsi
))
1890 if (gimple_vdef (stmt
))
1891 maybe_invalidate (stmt
);
1895 /* Recursively call maybe_invalidate on stmts that might be executed
1896 in between dombb and current bb and that contain a vdef. Stop when
1897 *count stmts are inspected, or if the whole strinfo vector has
1898 been invalidated. */
1901 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
1903 unsigned int i
, n
= gimple_phi_num_args (phi
);
1905 for (i
= 0; i
< n
; i
++)
1907 tree vuse
= gimple_phi_arg_def (phi
, i
);
1908 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
1909 basic_block bb
= gimple_bb (stmt
);
1912 || !bitmap_set_bit (visited
, bb
->index
)
1913 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1917 if (gimple_code (stmt
) == GIMPLE_PHI
)
1919 do_invalidate (dombb
, stmt
, visited
, count
);
1926 if (!maybe_invalidate (stmt
))
1931 vuse
= gimple_vuse (stmt
);
1932 stmt
= SSA_NAME_DEF_STMT (vuse
);
1933 if (gimple_bb (stmt
) != bb
)
1935 bb
= gimple_bb (stmt
);
1938 || !bitmap_set_bit (visited
, bb
->index
)
1939 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1946 class strlen_dom_walker
: public dom_walker
1949 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
1951 virtual void before_dom_children (basic_block
);
1952 virtual void after_dom_children (basic_block
);
1955 /* Callback for walk_dominator_tree. Attempt to optimize various
1956 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1959 strlen_dom_walker::before_dom_children (basic_block bb
)
1961 gimple_stmt_iterator gsi
;
1962 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
1965 stridx_to_strinfo
= NULL
;
1968 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
1969 if (stridx_to_strinfo
)
1971 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1973 gimple phi
= gsi_stmt (gsi
);
1974 if (virtual_operand_p (gimple_phi_result (phi
)))
1976 bitmap visited
= BITMAP_ALLOC (NULL
);
1977 int count_vdef
= 100;
1978 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
1979 BITMAP_FREE (visited
);
1980 if (count_vdef
== 0)
1982 /* If there were too many vdefs in between immediate
1983 dominator and current bb, invalidate everything.
1984 If stridx_to_strinfo has been unshared, we need
1985 to free it, otherwise just set it to NULL. */
1986 if (!strinfo_shared ())
1992 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
1996 (*stridx_to_strinfo
)[i
] = NULL
;
2000 stridx_to_strinfo
= NULL
;
2008 /* If all PHI arguments have the same string index, the PHI result
2010 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
2012 gimple phi
= gsi_stmt (gsi
);
2013 tree result
= gimple_phi_result (phi
);
2014 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2016 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2019 unsigned int i
, n
= gimple_phi_num_args (phi
);
2020 for (i
= 1; i
< n
; i
++)
2021 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2024 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2029 /* Attempt to optimize individual statements. */
2030 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2031 if (strlen_optimize_stmt (&gsi
))
2034 bb
->aux
= stridx_to_strinfo
;
2035 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2036 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2039 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2040 owned by the current bb, clear bb->aux. */
2043 strlen_dom_walker::after_dom_children (basic_block bb
)
2047 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2048 if (vec_safe_length (stridx_to_strinfo
)
2049 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2054 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2056 vec_free (stridx_to_strinfo
);
2062 /* Main entry point. */
2065 tree_ssa_strlen (void)
2067 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2069 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
2070 sizeof (struct strinfo_struct
), 64);
2072 calculate_dominance_info (CDI_DOMINATORS
);
2074 /* String length optimization is implemented as a walk of the dominator
2075 tree and a forward walk of statements within each block. */
2076 strlen_dom_walker (CDI_DOMINATORS
).walk (cfun
->cfg
->x_entry_block_ptr
);
2078 ssa_ver_to_stridx
.release ();
2079 free_alloc_pool (strinfo_pool
);
2080 if (decl_to_stridxlist_htab
.is_created ())
2082 obstack_free (&stridx_obstack
, NULL
);
2083 decl_to_stridxlist_htab
.dispose ();
2085 laststmt
.stmt
= NULL
;
2086 laststmt
.len
= NULL_TREE
;
2087 laststmt
.stridx
= 0;
2095 return flag_optimize_strlen
!= 0;
2100 const pass_data pass_data_strlen
=
2102 GIMPLE_PASS
, /* type */
2103 "strlen", /* name */
2104 OPTGROUP_NONE
, /* optinfo_flags */
2105 true, /* has_gate */
2106 true, /* has_execute */
2107 TV_TREE_STRLEN
, /* tv_id */
2108 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2109 0, /* properties_provided */
2110 0, /* properties_destroyed */
2111 0, /* todo_flags_start */
2112 TODO_verify_ssa
, /* todo_flags_finish */
2115 class pass_strlen
: public gimple_opt_pass
2118 pass_strlen (gcc::context
*ctxt
)
2119 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2122 /* opt_pass methods: */
2123 bool gate () { return gate_strlen (); }
2124 unsigned int execute () { return tree_ssa_strlen (); }
2126 }; // class pass_strlen
2131 make_pass_strlen (gcc::context
*ctxt
)
2133 return new pass_strlen (ctxt
);