1 /* String length optimization
2 Copyright (C) 2011-2013 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"
24 #include "hash-table.h"
25 #include "tree-flow.h"
26 #include "tree-pass.h"
28 #include "alloc-pool.h"
29 #include "tree-ssa-propagate.h"
30 #include "gimple-pretty-print.h"
34 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
35 is an index into strinfo vector, negative value stands for
36 string length of a string literal (~strlen). */
37 static vec
<int> ssa_ver_to_stridx
;
39 /* Number of currently active string indexes plus one. */
40 static int max_stridx
;
42 /* String information record. */
43 typedef struct strinfo_struct
45 /* String length of this string. */
47 /* Any of the corresponding pointers for querying alias oracle. */
49 /* Statement for delayed length computation. */
51 /* Pointer to '\0' if known, if NULL, it can be computed as
54 /* Reference count. Any changes to strinfo entry possibly shared
55 with dominating basic blocks need unshare_strinfo first, except
56 for dont_invalidate which affects only the immediately next
59 /* Copy of index. get_strinfo (si->idx) should return si; */
61 /* These 3 fields are for chaining related string pointers together.
63 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
64 strcpy (c, d); e = c + dl;
65 strinfo(a) -> strinfo(c) -> strinfo(e)
66 All have ->first field equal to strinfo(a)->idx and are doubly
67 chained through prev/next fields. The later strinfos are required
68 to point into the same string with zero or more bytes after
69 the previous pointer and all bytes in between the two pointers
70 must be non-zero. Functions like strcpy or memcpy are supposed
71 to adjust all previous strinfo lengths, but not following strinfo
72 lengths (those are uncertain, usually invalidated during
73 maybe_invalidate, except when the alias oracle knows better).
74 Functions like strcat on the other side adjust the whole
75 related strinfo chain.
76 They are updated lazily, so to use the chain the same first fields
77 and si->prev->next == si->idx needs to be verified. */
81 /* A flag whether the string is known to be written in the current
84 /* A flag for the next maybe_invalidate that this strinfo shouldn't
85 be invalidated. Always cleared by maybe_invalidate. */
89 /* Pool for allocating strinfo_struct entries. */
90 static alloc_pool strinfo_pool
;
92 /* Vector mapping positive string indexes to strinfo, for the
93 current basic block. The first pointer in the vector is special,
94 it is either NULL, meaning the vector isn't shared, or it is
95 a basic block pointer to the owner basic_block if shared.
96 If some other bb wants to modify the vector, the vector needs
97 to be unshared first, and only the owner bb is supposed to free it. */
98 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
100 /* One OFFSET->IDX mapping. */
103 struct stridxlist
*next
;
104 HOST_WIDE_INT offset
;
108 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
109 struct decl_stridxlist_map
111 struct tree_map_base base
;
112 struct stridxlist list
;
115 /* stridxlist hashtable helpers. */
117 struct stridxlist_hasher
: typed_noop_remove
<decl_stridxlist_map
>
119 typedef decl_stridxlist_map value_type
;
120 typedef decl_stridxlist_map compare_type
;
121 static inline hashval_t
hash (const value_type
*);
122 static inline bool equal (const value_type
*, const compare_type
*);
125 /* Hash a from tree in a decl_stridxlist_map. */
128 stridxlist_hasher::hash (const value_type
*item
)
130 return DECL_UID (item
->base
.from
);
134 stridxlist_hasher::equal (const value_type
*v
, const compare_type
*c
)
136 return tree_map_base_eq (&v
->base
, &c
->base
);
139 /* Hash table for mapping decls to a chained list of offset -> idx
141 static hash_table
<stridxlist_hasher
> decl_to_stridxlist_htab
;
143 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
144 static struct obstack stridx_obstack
;
146 /* Last memcpy statement if it could be adjusted if the trailing
147 '\0' written is immediately overwritten, or
148 *x = '\0' store that could be removed if it is immediately overwritten. */
149 struct laststmt_struct
156 /* Helper function for get_stridx. */
159 get_addr_stridx (tree exp
)
162 struct decl_stridxlist_map ent
, *e
;
163 struct stridxlist
*list
;
166 if (!decl_to_stridxlist_htab
.is_created ())
169 base
= get_addr_base_and_unit_offset (exp
, &off
);
170 if (base
== NULL
|| !DECL_P (base
))
173 ent
.base
.from
= base
;
174 e
= decl_to_stridxlist_htab
.find_with_hash (&ent
, DECL_UID (base
));
181 if (list
->offset
== off
)
189 /* Return string index for EXP. */
192 get_stridx (tree exp
)
196 if (TREE_CODE (exp
) == SSA_NAME
)
197 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
199 if (TREE_CODE (exp
) == ADDR_EXPR
)
201 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
206 s
= string_constant (exp
, &o
);
208 && (o
== NULL_TREE
|| host_integerp (o
, 0))
209 && TREE_STRING_LENGTH (s
) > 0)
211 HOST_WIDE_INT offset
= o
? tree_low_cst (o
, 0) : 0;
212 const char *p
= TREE_STRING_POINTER (s
);
213 int max
= TREE_STRING_LENGTH (s
) - 1;
215 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
216 return ~(int) strlen (p
+ offset
);
221 /* Return true if strinfo vector is shared with the immediate dominator. */
224 strinfo_shared (void)
226 return vec_safe_length (stridx_to_strinfo
)
227 && (*stridx_to_strinfo
)[0] != NULL
;
230 /* Unshare strinfo vector that is shared with the immediate dominator. */
233 unshare_strinfo_vec (void)
238 gcc_assert (strinfo_shared ());
239 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
240 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
243 (*stridx_to_strinfo
)[0] = NULL
;
246 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
247 Return a pointer to the location where the string index can
248 be stored (if 0) or is stored, or NULL if this can't be tracked. */
251 addr_stridxptr (tree exp
)
253 decl_stridxlist_map
**slot
;
254 struct decl_stridxlist_map ent
;
255 struct stridxlist
*list
;
258 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
259 if (base
== NULL_TREE
|| !DECL_P (base
))
262 if (!decl_to_stridxlist_htab
.is_created ())
264 decl_to_stridxlist_htab
.create (64);
265 gcc_obstack_init (&stridx_obstack
);
267 ent
.base
.from
= base
;
268 slot
= decl_to_stridxlist_htab
.find_slot_with_hash (&ent
, DECL_UID (base
),
273 list
= &(*slot
)->list
;
274 for (i
= 0; i
< 16; i
++)
276 if (list
->offset
== off
)
278 if (list
->next
== NULL
)
283 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
288 struct decl_stridxlist_map
*e
289 = XOBNEW (&stridx_obstack
, struct decl_stridxlist_map
);
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
,
495 /* Invalidate string length information for strings whose length
496 might change due to stores in stmt. */
499 maybe_invalidate (gimple stmt
)
503 bool nonempty
= false;
505 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
508 if (!si
->dont_invalidate
)
511 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
512 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
514 set_strinfo (i
, NULL
);
519 si
->dont_invalidate
= false;
525 /* Unshare strinfo record SI, if it has recount > 1 or
526 if stridx_to_strinfo vector is shared with some other
530 unshare_strinfo (strinfo si
)
534 if (si
->refcount
== 1 && !strinfo_shared ())
537 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
538 nsi
->stmt
= si
->stmt
;
539 nsi
->endptr
= si
->endptr
;
540 nsi
->first
= si
->first
;
541 nsi
->prev
= si
->prev
;
542 nsi
->next
= si
->next
;
543 nsi
->writable
= si
->writable
;
544 set_strinfo (si
->idx
, nsi
);
549 /* Return first strinfo in the related strinfo chain
550 if all strinfos in between belong to the chain, otherwise
554 verify_related_strinfos (strinfo origsi
)
556 strinfo si
= origsi
, psi
;
558 if (origsi
->first
== 0)
560 for (; si
->prev
; si
= psi
)
562 if (si
->first
!= origsi
->first
)
564 psi
= get_strinfo (si
->prev
);
567 if (psi
->next
!= si
->idx
)
570 if (si
->idx
!= si
->first
)
575 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
576 to a zero-length string and if possible chain it to a related strinfo
577 chain whose part is or might be CHAINSI. */
580 zero_length_string (tree ptr
, strinfo chainsi
)
584 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
585 && get_stridx (ptr
) == 0);
587 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
591 si
= verify_related_strinfos (chainsi
);
595 for (; chainsi
->next
; chainsi
= si
)
597 if (chainsi
->endptr
== NULL_TREE
)
599 chainsi
= unshare_strinfo (chainsi
);
600 chainsi
->endptr
= ptr
;
602 si
= get_strinfo (chainsi
->next
);
604 || si
->first
!= chainsi
->first
605 || si
->prev
!= chainsi
->idx
)
608 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
609 if (chainsi
->endptr
== NULL_TREE
)
611 chainsi
= unshare_strinfo (chainsi
);
612 chainsi
->endptr
= ptr
;
614 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
618 chainsi
= unshare_strinfo (chainsi
);
621 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
625 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
627 chainsi
= unshare_strinfo (chainsi
);
633 idx
= new_stridx (ptr
);
636 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
637 set_strinfo (idx
, si
);
641 chainsi
= unshare_strinfo (chainsi
);
642 if (chainsi
->first
== 0)
643 chainsi
->first
= chainsi
->idx
;
645 if (chainsi
->endptr
== NULL_TREE
)
646 chainsi
->endptr
= ptr
;
647 si
->prev
= chainsi
->idx
;
648 si
->first
= chainsi
->first
;
649 si
->writable
= chainsi
->writable
;
654 /* For strinfo ORIGSI whose length has been just updated
655 update also related strinfo lengths (add ADJ to each,
656 but don't adjust ORIGSI). */
659 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
661 strinfo si
= verify_related_strinfos (origsi
);
674 si
= unshare_strinfo (si
);
677 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
678 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
679 TREE_TYPE (si
->length
), si
->length
,
682 else if (si
->stmt
!= NULL
)
683 /* Delayed length computation is unaffected. */
688 si
->endptr
= NULL_TREE
;
689 si
->dont_invalidate
= true;
693 nsi
= get_strinfo (si
->next
);
695 || nsi
->first
!= si
->first
696 || nsi
->prev
!= si
->idx
)
702 /* Find if there are other SSA_NAME pointers equal to PTR
703 for which we don't track their string lengths yet. If so, use
707 find_equal_ptrs (tree ptr
, int idx
)
709 if (TREE_CODE (ptr
) != SSA_NAME
)
713 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
714 if (!is_gimple_assign (stmt
))
716 ptr
= gimple_assign_rhs1 (stmt
);
717 switch (gimple_assign_rhs_code (stmt
))
722 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
724 if (TREE_CODE (ptr
) == SSA_NAME
)
726 if (TREE_CODE (ptr
) != ADDR_EXPR
)
731 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
732 if (pidx
!= NULL
&& *pidx
== 0)
740 /* We might find an endptr created in this pass. Grow the
741 vector in that case. */
742 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
743 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
745 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
747 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
751 /* If the last .MEM setter statement before STMT is
752 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
753 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
754 just memcpy (x, y, strlen (y)). SI must be the zero length
758 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
760 tree vuse
, callee
, len
;
761 struct laststmt_struct last
= laststmt
;
762 strinfo lastsi
, firstsi
;
764 laststmt
.stmt
= NULL
;
765 laststmt
.len
= NULL_TREE
;
768 if (last
.stmt
== NULL
)
771 vuse
= gimple_vuse (stmt
);
772 if (vuse
== NULL_TREE
773 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
774 || !has_single_use (vuse
))
777 gcc_assert (last
.stridx
> 0);
778 lastsi
= get_strinfo (last
.stridx
);
784 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
787 firstsi
= verify_related_strinfos (si
);
790 while (firstsi
!= lastsi
)
793 if (firstsi
->next
== 0)
795 nextsi
= get_strinfo (firstsi
->next
);
797 || nextsi
->prev
!= firstsi
->idx
798 || nextsi
->first
!= si
->first
)
806 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
810 if (is_gimple_assign (last
.stmt
))
812 gimple_stmt_iterator gsi
;
814 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
816 if (stmt_could_throw_p (last
.stmt
))
818 gsi
= gsi_for_stmt (last
.stmt
);
819 unlink_stmt_vdef (last
.stmt
);
820 release_defs (last
.stmt
);
821 gsi_remove (&gsi
, true);
825 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
828 callee
= gimple_call_fndecl (last
.stmt
);
829 switch (DECL_FUNCTION_CODE (callee
))
831 case BUILT_IN_MEMCPY
:
832 case BUILT_IN_MEMCPY_CHK
:
838 len
= gimple_call_arg (last
.stmt
, 2);
839 if (host_integerp (len
, 1))
841 if (!host_integerp (last
.len
, 1)
842 || integer_zerop (len
)
843 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
844 != (unsigned HOST_WIDE_INT
) tree_low_cst (last
.len
, 1) + 1)
846 /* Don't adjust the length if it is divisible by 4, it is more efficient
847 to store the extra '\0' in that case. */
848 if ((((unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)) & 3) == 0)
851 else if (TREE_CODE (len
) == SSA_NAME
)
853 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
854 if (!is_gimple_assign (def_stmt
)
855 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
856 || gimple_assign_rhs1 (def_stmt
) != last
.len
857 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
863 gimple_call_set_arg (last
.stmt
, 2, last
.len
);
864 update_stmt (last
.stmt
);
867 /* Handle a strlen call. If strlen of the argument is known, replace
868 the strlen call with the known value, otherwise remember that strlen
869 of the argument is stored in the lhs SSA_NAME. */
872 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
876 gimple stmt
= gsi_stmt (*gsi
);
877 tree lhs
= gimple_call_lhs (stmt
);
879 if (lhs
== NULL_TREE
)
882 src
= gimple_call_arg (stmt
, 0);
883 idx
= get_stridx (src
);
890 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
894 si
= get_strinfo (idx
);
896 rhs
= get_string_length (si
);
898 if (rhs
!= NULL_TREE
)
900 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
902 fprintf (dump_file
, "Optimizing: ");
903 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
905 rhs
= unshare_expr (rhs
);
906 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
907 rhs
= fold_convert_loc (gimple_location (stmt
),
908 TREE_TYPE (lhs
), rhs
);
909 if (!update_call_from_tree (gsi
, rhs
))
910 gimplify_and_update_call_from_tree (gsi
, rhs
);
911 stmt
= gsi_stmt (*gsi
);
913 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
915 fprintf (dump_file
, "into: ");
916 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
919 && TREE_CODE (si
->length
) != SSA_NAME
920 && TREE_CODE (si
->length
) != INTEGER_CST
921 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
923 si
= unshare_strinfo (si
);
929 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
932 idx
= new_stridx (src
);
933 else if (get_strinfo (idx
) != NULL
)
937 strinfo si
= new_strinfo (src
, idx
, lhs
);
938 set_strinfo (idx
, si
);
939 find_equal_ptrs (src
, idx
);
943 /* Handle a strchr call. If strlen of the first argument is known, replace
944 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
945 that lhs of the call is endptr and strlen of the argument is endptr - x. */
948 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
952 gimple stmt
= gsi_stmt (*gsi
);
953 tree lhs
= gimple_call_lhs (stmt
);
955 if (lhs
== NULL_TREE
)
958 if (!integer_zerop (gimple_call_arg (stmt
, 1)))
961 src
= gimple_call_arg (stmt
, 0);
962 idx
= get_stridx (src
);
969 rhs
= build_int_cst (size_type_node
, ~idx
);
973 si
= get_strinfo (idx
);
975 rhs
= get_string_length (si
);
977 if (rhs
!= NULL_TREE
)
979 location_t loc
= gimple_location (stmt
);
981 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
983 fprintf (dump_file
, "Optimizing: ");
984 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
986 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
988 rhs
= unshare_expr (si
->endptr
);
989 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
991 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
995 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
996 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
997 TREE_TYPE (src
), src
, rhs
);
998 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1000 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1002 if (!update_call_from_tree (gsi
, rhs
))
1003 gimplify_and_update_call_from_tree (gsi
, rhs
);
1004 stmt
= gsi_stmt (*gsi
);
1006 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1008 fprintf (dump_file
, "into: ");
1009 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1012 && si
->endptr
== NULL_TREE
1013 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1015 si
= unshare_strinfo (si
);
1018 zero_length_string (lhs
, si
);
1022 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1024 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1027 idx
= new_stridx (src
);
1028 else if (get_strinfo (idx
) != NULL
)
1030 zero_length_string (lhs
, NULL
);
1035 location_t loc
= gimple_location (stmt
);
1036 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1037 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1038 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1039 size_type_node
, lhsu
, srcu
);
1040 strinfo si
= new_strinfo (src
, idx
, length
);
1042 set_strinfo (idx
, si
);
1043 find_equal_ptrs (src
, idx
);
1044 zero_length_string (lhs
, si
);
1048 zero_length_string (lhs
, NULL
);
1051 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1052 If strlen of the second argument is known, strlen of the first argument
1053 is the same after this call. Furthermore, attempt to convert it to
1057 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1060 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1062 gimple stmt
= gsi_stmt (*gsi
);
1063 strinfo si
, dsi
, olddsi
, zsi
;
1066 src
= gimple_call_arg (stmt
, 1);
1067 dst
= gimple_call_arg (stmt
, 0);
1068 lhs
= gimple_call_lhs (stmt
);
1069 idx
= get_stridx (src
);
1072 si
= get_strinfo (idx
);
1074 didx
= get_stridx (dst
);
1078 olddsi
= get_strinfo (didx
);
1083 adjust_last_stmt (olddsi
, stmt
, false);
1087 srclen
= get_string_length (si
);
1089 srclen
= build_int_cst (size_type_node
, ~idx
);
1091 loc
= gimple_location (stmt
);
1092 if (srclen
== NULL_TREE
)
1095 case BUILT_IN_STRCPY
:
1096 case BUILT_IN_STRCPY_CHK
:
1097 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1100 case BUILT_IN_STPCPY
:
1101 case BUILT_IN_STPCPY_CHK
:
1102 if (lhs
== NULL_TREE
)
1106 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1107 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1108 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1118 didx
= new_stridx (dst
);
1124 oldlen
= olddsi
->length
;
1125 dsi
= unshare_strinfo (olddsi
);
1126 dsi
->length
= srclen
;
1127 /* Break the chain, so adjust_related_strinfo on later pointers in
1128 the chain won't adjust this one anymore. */
1131 dsi
->endptr
= NULL_TREE
;
1135 dsi
= new_strinfo (dst
, didx
, srclen
);
1136 set_strinfo (didx
, dsi
);
1137 find_equal_ptrs (dst
, didx
);
1139 dsi
->writable
= true;
1140 dsi
->dont_invalidate
= true;
1142 if (dsi
->length
== NULL_TREE
)
1146 /* If string length of src is unknown, use delayed length
1147 computation. If string lenth of dst will be needed, it
1148 can be computed by transforming this strcpy call into
1149 stpcpy and subtracting dst from the return value. */
1151 /* Look for earlier strings whose length could be determined if
1152 this strcpy is turned into an stpcpy. */
1154 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1156 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1158 /* When setting a stmt for delayed length computation
1159 prevent all strinfos through dsi from being
1161 chainsi
= unshare_strinfo (chainsi
);
1162 chainsi
->stmt
= stmt
;
1163 chainsi
->length
= NULL_TREE
;
1164 chainsi
->endptr
= NULL_TREE
;
1165 chainsi
->dont_invalidate
= true;
1174 tree adj
= NULL_TREE
;
1175 if (oldlen
== NULL_TREE
)
1177 else if (integer_zerop (oldlen
))
1179 else if (TREE_CODE (oldlen
) == INTEGER_CST
1180 || TREE_CODE (srclen
) == INTEGER_CST
)
1181 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1182 TREE_TYPE (srclen
), srclen
,
1183 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1185 if (adj
!= NULL_TREE
)
1186 adjust_related_strinfos (loc
, dsi
, adj
);
1190 /* strcpy src may not overlap dst, so src doesn't need to be
1191 invalidated either. */
1193 si
->dont_invalidate
= true;
1199 case BUILT_IN_STRCPY
:
1200 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1202 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1204 case BUILT_IN_STRCPY_CHK
:
1205 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1207 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1209 case BUILT_IN_STPCPY
:
1210 /* This would need adjustment of the lhs (subtract one),
1211 or detection that the trailing '\0' doesn't need to be
1212 written, if it will be immediately overwritten.
1213 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1217 zsi
= zero_length_string (lhs
, dsi
);
1220 case BUILT_IN_STPCPY_CHK
:
1221 /* This would need adjustment of the lhs (subtract one),
1222 or detection that the trailing '\0' doesn't need to be
1223 written, if it will be immediately overwritten.
1224 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1228 zsi
= zero_length_string (lhs
, dsi
);
1235 zsi
->dont_invalidate
= true;
1237 if (fn
== NULL_TREE
)
1240 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1241 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1243 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1244 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1245 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1247 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1249 fprintf (dump_file
, "Optimizing: ");
1250 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1252 if (gimple_call_num_args (stmt
) == 2)
1253 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1255 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1256 gimple_call_arg (stmt
, 2));
1259 stmt
= gsi_stmt (*gsi
);
1261 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1263 fprintf (dump_file
, "into: ");
1264 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1266 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1267 laststmt
.stmt
= stmt
;
1268 laststmt
.len
= srclen
;
1269 laststmt
.stridx
= dsi
->idx
;
1271 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1272 fprintf (dump_file
, "not possible.\n");
1275 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1276 If strlen of the second argument is known and length of the third argument
1277 is that plus one, strlen of the first argument is the same after this
1281 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1284 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1285 gimple stmt
= gsi_stmt (*gsi
);
1286 strinfo si
, dsi
, olddsi
;
1288 len
= gimple_call_arg (stmt
, 2);
1289 src
= gimple_call_arg (stmt
, 1);
1290 dst
= gimple_call_arg (stmt
, 0);
1291 idx
= get_stridx (src
);
1295 didx
= get_stridx (dst
);
1298 olddsi
= get_strinfo (didx
);
1303 && host_integerp (len
, 1)
1304 && !integer_zerop (len
))
1305 adjust_last_stmt (olddsi
, stmt
, false);
1311 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1312 si
= get_strinfo (idx
);
1313 if (si
== NULL
|| si
->length
== NULL_TREE
)
1315 if (TREE_CODE (len
) != SSA_NAME
)
1317 def_stmt
= SSA_NAME_DEF_STMT (len
);
1318 if (!is_gimple_assign (def_stmt
)
1319 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1320 || gimple_assign_rhs1 (def_stmt
) != si
->length
1321 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1327 /* Handle memcpy (x, "abcd", 5) or
1328 memcpy (x, "abc\0uvw", 7). */
1329 if (!host_integerp (len
, 1)
1330 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
1331 <= (unsigned HOST_WIDE_INT
) ~idx
)
1335 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1336 adjust_last_stmt (olddsi
, stmt
, false);
1340 didx
= new_stridx (dst
);
1345 newlen
= si
->length
;
1347 newlen
= build_int_cst (size_type_node
, ~idx
);
1351 dsi
= unshare_strinfo (olddsi
);
1352 oldlen
= olddsi
->length
;
1353 dsi
->length
= newlen
;
1354 /* Break the chain, so adjust_related_strinfo on later pointers in
1355 the chain won't adjust this one anymore. */
1358 dsi
->endptr
= NULL_TREE
;
1362 dsi
= new_strinfo (dst
, didx
, newlen
);
1363 set_strinfo (didx
, dsi
);
1364 find_equal_ptrs (dst
, didx
);
1366 dsi
->writable
= true;
1367 dsi
->dont_invalidate
= true;
1370 tree adj
= NULL_TREE
;
1371 location_t loc
= gimple_location (stmt
);
1372 if (oldlen
== NULL_TREE
)
1374 else if (integer_zerop (oldlen
))
1376 else if (TREE_CODE (oldlen
) == INTEGER_CST
1377 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1378 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1379 TREE_TYPE (dsi
->length
), dsi
->length
,
1380 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1382 if (adj
!= NULL_TREE
)
1383 adjust_related_strinfos (loc
, dsi
, adj
);
1387 /* memcpy src may not overlap dst, so src doesn't need to be
1388 invalidated either. */
1390 si
->dont_invalidate
= true;
1392 lhs
= gimple_call_lhs (stmt
);
1395 case BUILT_IN_MEMCPY
:
1396 case BUILT_IN_MEMCPY_CHK
:
1397 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1398 laststmt
.stmt
= stmt
;
1399 laststmt
.len
= dsi
->length
;
1400 laststmt
.stridx
= dsi
->idx
;
1402 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1404 case BUILT_IN_MEMPCPY
:
1405 case BUILT_IN_MEMPCPY_CHK
:
1412 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1413 If strlen of the second argument is known, strlen of the first argument
1414 is increased by the length of the second argument. Furthermore, attempt
1415 to convert it to memcpy/strcpy if the length of the first argument
1419 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1422 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1424 gimple stmt
= gsi_stmt (*gsi
);
1428 src
= gimple_call_arg (stmt
, 1);
1429 dst
= gimple_call_arg (stmt
, 0);
1430 lhs
= gimple_call_lhs (stmt
);
1432 didx
= get_stridx (dst
);
1438 dsi
= get_strinfo (didx
);
1439 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1441 /* strcat (p, q) can be transformed into
1442 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1443 with length endptr - p if we need to compute the length
1444 later on. Don't do this transformation if we don't need
1446 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1450 didx
= new_stridx (dst
);
1456 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1457 set_strinfo (didx
, dsi
);
1458 find_equal_ptrs (dst
, didx
);
1462 dsi
= unshare_strinfo (dsi
);
1463 dsi
->length
= NULL_TREE
;
1465 dsi
->endptr
= NULL_TREE
;
1467 dsi
->writable
= true;
1469 dsi
->dont_invalidate
= true;
1476 idx
= get_stridx (src
);
1478 srclen
= build_int_cst (size_type_node
, ~idx
);
1481 si
= get_strinfo (idx
);
1483 srclen
= get_string_length (si
);
1486 loc
= gimple_location (stmt
);
1487 dstlen
= dsi
->length
;
1488 endptr
= dsi
->endptr
;
1490 dsi
= unshare_strinfo (dsi
);
1491 dsi
->endptr
= NULL_TREE
;
1493 dsi
->writable
= true;
1495 if (srclen
!= NULL_TREE
)
1497 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1498 dsi
->length
, srclen
);
1499 adjust_related_strinfos (loc
, dsi
, srclen
);
1500 dsi
->dont_invalidate
= true;
1505 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1506 dsi
->dont_invalidate
= true;
1510 /* strcat src may not overlap dst, so src doesn't need to be
1511 invalidated either. */
1512 si
->dont_invalidate
= true;
1514 /* For now. Could remove the lhs from the call and add
1515 lhs = dst; afterwards. */
1523 case BUILT_IN_STRCAT
:
1524 if (srclen
!= NULL_TREE
)
1525 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1527 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1529 case BUILT_IN_STRCAT_CHK
:
1530 if (srclen
!= NULL_TREE
)
1531 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1533 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1534 objsz
= gimple_call_arg (stmt
, 2);
1540 if (fn
== NULL_TREE
)
1544 if (srclen
!= NULL_TREE
)
1546 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1547 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1549 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1550 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1551 build_int_cst (type
, 1));
1552 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1556 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1558 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1559 TREE_TYPE (dst
), unshare_expr (dst
),
1560 fold_convert_loc (loc
, sizetype
,
1561 unshare_expr (dstlen
)));
1562 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1564 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1566 fprintf (dump_file
, "Optimizing: ");
1567 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1569 if (srclen
!= NULL_TREE
)
1570 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1571 dst
, src
, len
, objsz
);
1573 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1577 stmt
= gsi_stmt (*gsi
);
1579 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1581 fprintf (dump_file
, "into: ");
1582 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1584 /* If srclen == NULL, note that current string length can be
1585 computed by transforming this strcpy into stpcpy. */
1586 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1588 adjust_last_stmt (dsi
, stmt
, true);
1589 if (srclen
!= NULL_TREE
)
1591 laststmt
.stmt
= stmt
;
1592 laststmt
.len
= srclen
;
1593 laststmt
.stridx
= dsi
->idx
;
1596 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1597 fprintf (dump_file
, "not possible.\n");
1600 /* Handle a POINTER_PLUS_EXPR statement.
1601 For p = "abcd" + 2; compute associated length, or if
1602 p = q + off is pointing to a '\0' character of a string, call
1603 zero_length_string on it. */
1606 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1608 gimple stmt
= gsi_stmt (*gsi
);
1609 tree lhs
= gimple_assign_lhs (stmt
), off
;
1610 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1618 tree off
= gimple_assign_rhs2 (stmt
);
1619 if (host_integerp (off
, 1)
1620 && (unsigned HOST_WIDE_INT
) tree_low_cst (off
, 1)
1621 <= (unsigned HOST_WIDE_INT
) ~idx
)
1622 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1623 = ~(~idx
- (int) tree_low_cst (off
, 1));
1627 si
= get_strinfo (idx
);
1628 if (si
== NULL
|| si
->length
== NULL_TREE
)
1631 off
= gimple_assign_rhs2 (stmt
);
1633 if (operand_equal_p (si
->length
, off
, 0))
1634 zsi
= zero_length_string (lhs
, si
);
1635 else if (TREE_CODE (off
) == SSA_NAME
)
1637 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1638 if (gimple_assign_single_p (def_stmt
)
1639 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1640 zsi
= zero_length_string (lhs
, si
);
1643 && si
->endptr
!= NULL_TREE
1644 && si
->endptr
!= lhs
1645 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1647 enum tree_code rhs_code
1648 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1649 ? SSA_NAME
: NOP_EXPR
;
1650 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
, NULL_TREE
);
1651 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1656 /* Handle a single character store. */
1659 handle_char_store (gimple_stmt_iterator
*gsi
)
1663 gimple stmt
= gsi_stmt (*gsi
);
1664 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1666 if (TREE_CODE (lhs
) == MEM_REF
1667 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1669 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1671 ssaname
= TREE_OPERAND (lhs
, 0);
1672 idx
= get_stridx (ssaname
);
1676 idx
= get_addr_stridx (lhs
);
1680 si
= get_strinfo (idx
);
1681 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1683 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1685 /* When storing '\0', the store can be removed
1686 if we know it has been stored in the current function. */
1687 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1689 unlink_stmt_vdef (stmt
);
1690 release_defs (stmt
);
1691 gsi_remove (gsi
, true);
1696 si
->writable
= true;
1702 /* Otherwise this statement overwrites the '\0' with
1703 something, if the previous stmt was a memcpy,
1704 its length may be decreased. */
1705 adjust_last_stmt (si
, stmt
, false);
1707 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1709 si
= unshare_strinfo (si
);
1710 si
->length
= build_int_cst (size_type_node
, 0);
1716 si
->writable
= true;
1717 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1718 si
->endptr
= ssaname
;
1719 si
->dont_invalidate
= true;
1721 /* If si->length is non-zero constant, we aren't overwriting '\0',
1722 and if we aren't storing '\0', we know that the length of the
1723 string and any other zero terminated string in memory remains
1724 the same. In that case we move to the next gimple statement and
1725 return to signal the caller that it shouldn't invalidate anything.
1727 This is benefical for cases like:
1732 strcpy (p, "foobar");
1733 size_t len = strlen (p); // This can be optimized into 6
1734 size_t len2 = strlen (q); // This has to be computed
1736 size_t len3 = strlen (p); // This can be optimized into 6
1737 size_t len4 = strlen (q); // This can be optimized into len2
1738 bar (len, len2, len3, len4);
1741 else if (si
!= NULL
&& si
->length
!= NULL_TREE
1742 && TREE_CODE (si
->length
) == INTEGER_CST
1743 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
1749 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1753 si
= zero_length_string (ssaname
, NULL
);
1755 si
->dont_invalidate
= true;
1759 int idx
= new_addr_stridx (lhs
);
1762 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1763 build_int_cst (size_type_node
, 0));
1764 set_strinfo (idx
, si
);
1765 si
->dont_invalidate
= true;
1769 si
->writable
= true;
1772 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
1773 && ssaname
== NULL_TREE
1774 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
1776 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
1777 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
1778 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
1780 int idx
= new_addr_stridx (lhs
);
1783 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1784 build_int_cst (size_type_node
, l
));
1785 set_strinfo (idx
, si
);
1786 si
->dont_invalidate
= true;
1791 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
1793 /* Allow adjust_last_stmt to remove it if the stored '\0'
1794 is immediately overwritten. */
1795 laststmt
.stmt
= stmt
;
1796 laststmt
.len
= build_int_cst (size_type_node
, 1);
1797 laststmt
.stridx
= si
->idx
;
1802 /* Attempt to optimize a single statement at *GSI using string length
1806 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
1808 gimple stmt
= gsi_stmt (*gsi
);
1810 if (is_gimple_call (stmt
))
1812 tree callee
= gimple_call_fndecl (stmt
);
1813 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
1814 switch (DECL_FUNCTION_CODE (callee
))
1816 case BUILT_IN_STRLEN
:
1817 handle_builtin_strlen (gsi
);
1819 case BUILT_IN_STRCHR
:
1820 handle_builtin_strchr (gsi
);
1822 case BUILT_IN_STRCPY
:
1823 case BUILT_IN_STRCPY_CHK
:
1824 case BUILT_IN_STPCPY
:
1825 case BUILT_IN_STPCPY_CHK
:
1826 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1828 case BUILT_IN_MEMCPY
:
1829 case BUILT_IN_MEMCPY_CHK
:
1830 case BUILT_IN_MEMPCPY
:
1831 case BUILT_IN_MEMPCPY_CHK
:
1832 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1834 case BUILT_IN_STRCAT
:
1835 case BUILT_IN_STRCAT_CHK
:
1836 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
1842 else if (is_gimple_assign (stmt
))
1844 tree lhs
= gimple_assign_lhs (stmt
);
1846 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
1848 if (gimple_assign_single_p (stmt
)
1849 || (gimple_assign_cast_p (stmt
)
1850 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
1852 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1853 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
1855 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
1856 handle_pointer_plus (gsi
);
1858 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
1860 tree type
= TREE_TYPE (lhs
);
1861 if (TREE_CODE (type
) == ARRAY_TYPE
)
1862 type
= TREE_TYPE (type
);
1863 if (TREE_CODE (type
) == INTEGER_TYPE
1864 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
1865 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
1867 if (! handle_char_store (gsi
))
1873 if (gimple_vdef (stmt
))
1874 maybe_invalidate (stmt
);
1878 /* Recursively call maybe_invalidate on stmts that might be executed
1879 in between dombb and current bb and that contain a vdef. Stop when
1880 *count stmts are inspected, or if the whole strinfo vector has
1881 been invalidated. */
1884 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
1886 unsigned int i
, n
= gimple_phi_num_args (phi
);
1888 for (i
= 0; i
< n
; i
++)
1890 tree vuse
= gimple_phi_arg_def (phi
, i
);
1891 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
1892 basic_block bb
= gimple_bb (stmt
);
1895 || !bitmap_set_bit (visited
, bb
->index
)
1896 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1900 if (gimple_code (stmt
) == GIMPLE_PHI
)
1902 do_invalidate (dombb
, stmt
, visited
, count
);
1909 if (!maybe_invalidate (stmt
))
1914 vuse
= gimple_vuse (stmt
);
1915 stmt
= SSA_NAME_DEF_STMT (vuse
);
1916 if (gimple_bb (stmt
) != bb
)
1918 bb
= gimple_bb (stmt
);
1921 || !bitmap_set_bit (visited
, bb
->index
)
1922 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1929 /* Callback for walk_dominator_tree. Attempt to optimize various
1930 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1933 strlen_enter_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
1936 gimple_stmt_iterator gsi
;
1937 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
1940 stridx_to_strinfo
= NULL
;
1943 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
1944 if (stridx_to_strinfo
)
1946 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1948 gimple phi
= gsi_stmt (gsi
);
1949 if (virtual_operand_p (gimple_phi_result (phi
)))
1951 bitmap visited
= BITMAP_ALLOC (NULL
);
1952 int count_vdef
= 100;
1953 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
1954 BITMAP_FREE (visited
);
1955 if (count_vdef
== 0)
1957 /* If there were too many vdefs in between immediate
1958 dominator and current bb, invalidate everything.
1959 If stridx_to_strinfo has been unshared, we need
1960 to free it, otherwise just set it to NULL. */
1961 if (!strinfo_shared ())
1967 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
1971 (*stridx_to_strinfo
)[i
] = NULL
;
1975 stridx_to_strinfo
= NULL
;
1983 /* If all PHI arguments have the same string index, the PHI result
1985 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1987 gimple phi
= gsi_stmt (gsi
);
1988 tree result
= gimple_phi_result (phi
);
1989 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
1991 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
1994 unsigned int i
, n
= gimple_phi_num_args (phi
);
1995 for (i
= 1; i
< n
; i
++)
1996 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
1999 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2004 /* Attempt to optimize individual statements. */
2005 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2006 if (strlen_optimize_stmt (&gsi
))
2009 bb
->aux
= stridx_to_strinfo
;
2010 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2011 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2014 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2015 owned by the current bb, clear bb->aux. */
2018 strlen_leave_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
2023 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2024 if (vec_safe_length (stridx_to_strinfo
)
2025 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2030 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2032 vec_free (stridx_to_strinfo
);
2038 /* Main entry point. */
2041 tree_ssa_strlen (void)
2043 struct dom_walk_data walk_data
;
2045 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2047 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
2048 sizeof (struct strinfo_struct
), 64);
2050 calculate_dominance_info (CDI_DOMINATORS
);
2052 /* String length optimization is implemented as a walk of the dominator
2053 tree and a forward walk of statements within each block. */
2054 walk_data
.dom_direction
= CDI_DOMINATORS
;
2055 walk_data
.initialize_block_local_data
= NULL
;
2056 walk_data
.before_dom_children
= strlen_enter_block
;
2057 walk_data
.after_dom_children
= strlen_leave_block
;
2058 walk_data
.block_local_data_size
= 0;
2059 walk_data
.global_data
= NULL
;
2061 /* Initialize the dominator walker. */
2062 init_walk_dominator_tree (&walk_data
);
2064 /* Recursively walk the dominator tree. */
2065 walk_dominator_tree (&walk_data
, ENTRY_BLOCK_PTR
);
2067 /* Finalize the dominator walker. */
2068 fini_walk_dominator_tree (&walk_data
);
2070 ssa_ver_to_stridx
.release ();
2071 free_alloc_pool (strinfo_pool
);
2072 if (decl_to_stridxlist_htab
.is_created ())
2074 obstack_free (&stridx_obstack
, NULL
);
2075 decl_to_stridxlist_htab
.dispose ();
2077 laststmt
.stmt
= NULL
;
2078 laststmt
.len
= NULL_TREE
;
2079 laststmt
.stridx
= 0;
2087 return flag_optimize_strlen
!= 0;
2092 const pass_data pass_data_strlen
=
2094 GIMPLE_PASS
, /* type */
2095 "strlen", /* name */
2096 OPTGROUP_NONE
, /* optinfo_flags */
2097 true, /* has_gate */
2098 true, /* has_execute */
2099 TV_TREE_STRLEN
, /* tv_id */
2100 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2101 0, /* properties_provided */
2102 0, /* properties_destroyed */
2103 0, /* todo_flags_start */
2104 TODO_verify_ssa
, /* todo_flags_finish */
2107 class pass_strlen
: public gimple_opt_pass
2110 pass_strlen(gcc::context
*ctxt
)
2111 : gimple_opt_pass(pass_data_strlen
, ctxt
)
2114 /* opt_pass methods: */
2115 bool gate () { return gate_strlen (); }
2116 unsigned int execute () { return tree_ssa_strlen (); }
2118 }; // class pass_strlen
2123 make_pass_strlen (gcc::context
*ctxt
)
2125 return new pass_strlen (ctxt
);