1 /* String length optimization
2 Copyright (C) 2011 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 "tree-flow.h"
25 #include "tree-pass.h"
27 #include "alloc-pool.h"
28 #include "tree-ssa-propagate.h"
29 #include "gimple-pretty-print.h"
33 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
34 is an index into strinfo vector, negative value stands for
35 string length of a string literal (~strlen). */
36 static VEC (int, heap
) *ssa_ver_to_stridx
;
38 /* Number of currently active string indexes plus one. */
39 static int max_stridx
;
41 /* String information record. */
42 typedef struct strinfo_struct
44 /* String length of this string. */
46 /* Any of the corresponding pointers for querying alias oracle. */
48 /* Statement for delayed length computation. */
50 /* Pointer to '\0' if known, if NULL, it can be computed as
53 /* Reference count. Any changes to strinfo entry possibly shared
54 with dominating basic blocks need unshare_strinfo first, except
55 for dont_invalidate which affects only the immediately next
58 /* Copy of index. get_strinfo (si->idx) should return si; */
60 /* These 3 fields are for chaining related string pointers together.
62 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
63 strcpy (c, d); e = c + dl;
64 strinfo(a) -> strinfo(c) -> strinfo(e)
65 All have ->first field equal to strinfo(a)->idx and are doubly
66 chained through prev/next fields. The later strinfos are required
67 to point into the same string with zero or more bytes after
68 the previous pointer and all bytes in between the two pointers
69 must be non-zero. Functions like strcpy or memcpy are supposed
70 to adjust all previous strinfo lengths, but not following strinfo
71 lengths (those are uncertain, usually invalidated during
72 maybe_invalidate, except when the alias oracle knows better).
73 Functions like strcat on the other side adjust the whole
74 related strinfo chain.
75 They are updated lazily, so to use the chain the same first fields
76 and si->prev->next == si->idx needs to be verified. */
80 /* A flag whether the string is known to be written in the current
83 /* A flag for the next maybe_invalidate that this strinfo shouldn't
84 be invalidated. Always cleared by maybe_invalidate. */
88 DEF_VEC_ALLOC_P(strinfo
,heap
);
90 /* Pool for allocating strinfo_struct entries. */
91 static alloc_pool strinfo_pool
;
93 /* Vector mapping positive string indexes to strinfo, for the
94 current basic block. The first pointer in the vector is special,
95 it is either NULL, meaning the vector isn't shared, or it is
96 a basic block pointer to the owner basic_block if shared.
97 If some other bb wants to modify the vector, the vector needs
98 to be unshared first, and only the owner bb is supposed to free it. */
99 static VEC(strinfo
, heap
) *stridx_to_strinfo
;
101 /* One OFFSET->IDX mapping. */
104 struct stridxlist
*next
;
105 HOST_WIDE_INT offset
;
109 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
110 struct decl_stridxlist_map
112 struct tree_map_base base
;
113 struct stridxlist list
;
116 /* Hash table for mapping decls to a chained list of offset -> idx
118 static htab_t decl_to_stridxlist_htab
;
120 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
121 static struct obstack stridx_obstack
;
123 /* Last memcpy statement if it could be adjusted if the trailing
124 '\0' written is immediately overwritten, or
125 *x = '\0' store that could be removed if it is immediately overwritten. */
126 struct laststmt_struct
133 /* Hash a from tree in a decl_stridxlist_map. */
136 decl_to_stridxlist_hash (const void *item
)
138 return DECL_UID (((const struct decl_stridxlist_map
*) item
)->base
.from
);
141 /* Helper function for get_stridx. */
144 get_addr_stridx (tree exp
)
147 struct decl_stridxlist_map ent
, *e
;
148 struct stridxlist
*list
;
151 if (decl_to_stridxlist_htab
== NULL
)
154 base
= get_addr_base_and_unit_offset (exp
, &off
);
155 if (base
== NULL
|| !DECL_P (base
))
158 ent
.base
.from
= base
;
159 e
= (struct decl_stridxlist_map
*)
160 htab_find_with_hash (decl_to_stridxlist_htab
, &ent
, DECL_UID (base
));
167 if (list
->offset
== off
)
175 /* Return string index for EXP. */
178 get_stridx (tree exp
)
182 if (TREE_CODE (exp
) == SSA_NAME
)
183 return VEC_index (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (exp
));
185 if (TREE_CODE (exp
) == ADDR_EXPR
)
187 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
192 s
= string_constant (exp
, &o
);
194 && (o
== NULL_TREE
|| host_integerp (o
, 0))
195 && TREE_STRING_LENGTH (s
) > 0)
197 HOST_WIDE_INT offset
= o
? tree_low_cst (o
, 0) : 0;
198 const char *p
= TREE_STRING_POINTER (s
);
199 int max
= TREE_STRING_LENGTH (s
) - 1;
201 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
202 return ~(int) strlen (p
+ offset
);
207 /* Return true if strinfo vector is shared with the immediate dominator. */
210 strinfo_shared (void)
212 return VEC_length (strinfo
, stridx_to_strinfo
)
213 && VEC_index (strinfo
, stridx_to_strinfo
, 0) != NULL
;
216 /* Unshare strinfo vector that is shared with the immediate dominator. */
219 unshare_strinfo_vec (void)
224 gcc_assert (strinfo_shared ());
225 stridx_to_strinfo
= VEC_copy (strinfo
, heap
, stridx_to_strinfo
);
226 for (i
= 1; VEC_iterate (strinfo
, stridx_to_strinfo
, i
, si
); ++i
)
229 VEC_replace (strinfo
, stridx_to_strinfo
, 0, NULL
);
232 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
233 Return a pointer to the location where the string index can
234 be stored (if 0) or is stored, or NULL if this can't be tracked. */
237 addr_stridxptr (tree exp
)
240 struct decl_stridxlist_map ent
;
241 struct stridxlist
*list
;
244 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
245 if (base
== NULL_TREE
|| !DECL_P (base
))
248 if (decl_to_stridxlist_htab
== NULL
)
250 decl_to_stridxlist_htab
251 = htab_create (64, decl_to_stridxlist_hash
, tree_map_base_eq
, NULL
);
252 gcc_obstack_init (&stridx_obstack
);
254 ent
.base
.from
= base
;
255 slot
= htab_find_slot_with_hash (decl_to_stridxlist_htab
, &ent
,
256 DECL_UID (base
), INSERT
);
260 list
= &((struct decl_stridxlist_map
*)*slot
)->list
;
261 for (i
= 0; i
< 16; i
++)
263 if (list
->offset
== off
)
265 if (list
->next
== NULL
)
270 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
275 struct decl_stridxlist_map
*e
276 = XOBNEW (&stridx_obstack
, struct decl_stridxlist_map
);
287 /* Create a new string index, or return 0 if reached limit. */
290 new_stridx (tree exp
)
293 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
295 if (TREE_CODE (exp
) == SSA_NAME
)
297 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
300 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (exp
), idx
);
303 if (TREE_CODE (exp
) == ADDR_EXPR
)
305 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
308 gcc_assert (*pidx
== 0);
309 *pidx
= max_stridx
++;
316 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
319 new_addr_stridx (tree exp
)
322 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
324 pidx
= addr_stridxptr (exp
);
327 gcc_assert (*pidx
== 0);
328 *pidx
= max_stridx
++;
334 /* Create a new strinfo. */
337 new_strinfo (tree ptr
, int idx
, tree length
)
339 strinfo si
= (strinfo
) pool_alloc (strinfo_pool
);
343 si
->endptr
= NULL_TREE
;
349 si
->writable
= false;
350 si
->dont_invalidate
= false;
354 /* Decrease strinfo refcount and free it if not referenced anymore. */
357 free_strinfo (strinfo si
)
359 if (si
&& --si
->refcount
== 0)
360 pool_free (strinfo_pool
, si
);
363 /* Return strinfo vector entry IDX. */
365 static inline strinfo
366 get_strinfo (int idx
)
368 if (VEC_length (strinfo
, stridx_to_strinfo
) <= (unsigned int) idx
)
370 return VEC_index (strinfo
, stridx_to_strinfo
, idx
);
373 /* Set strinfo in the vector entry IDX to SI. */
376 set_strinfo (int idx
, strinfo si
)
378 if (VEC_length (strinfo
, stridx_to_strinfo
) && VEC_index (strinfo
, stridx_to_strinfo
, 0))
379 unshare_strinfo_vec ();
380 if (VEC_length (strinfo
, stridx_to_strinfo
) <= (unsigned int) idx
)
381 VEC_safe_grow_cleared (strinfo
, heap
, stridx_to_strinfo
, idx
+ 1);
382 VEC_replace (strinfo
, stridx_to_strinfo
, idx
, si
);
385 /* Return string length, or NULL if it can't be computed. */
388 get_string_length (strinfo si
)
395 gimple stmt
= si
->stmt
, lenstmt
;
396 tree callee
, lhs
, fn
, tem
;
398 gimple_stmt_iterator gsi
;
400 gcc_assert (is_gimple_call (stmt
));
401 callee
= gimple_call_fndecl (stmt
);
402 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
403 lhs
= gimple_call_lhs (stmt
);
404 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
405 /* unshare_strinfo is intentionally not called here. The (delayed)
406 transformation of strcpy or strcat into stpcpy is done at the place
407 of the former strcpy/strcat call and so can affect all the strinfos
408 with the same stmt. If they were unshared before and transformation
409 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
410 just compute the right length. */
411 switch (DECL_FUNCTION_CODE (callee
))
413 case BUILT_IN_STRCAT
:
414 case BUILT_IN_STRCAT_CHK
:
415 gsi
= gsi_for_stmt (stmt
);
416 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
417 gcc_assert (lhs
== NULL_TREE
);
418 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
419 lenstmt
= gimple_build_call (fn
, 1, tem
);
420 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
421 gimple_call_set_lhs (lenstmt
, lhs
);
422 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
423 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
424 tem
= gimple_call_arg (stmt
, 0);
425 if (!ptrofftype_p (TREE_TYPE (lhs
)))
427 lhs
= convert_to_ptrofftype (lhs
);
428 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
429 true, GSI_SAME_STMT
);
432 = gimple_build_assign_with_ops
434 make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0)), NULL
),
436 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
437 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
440 case BUILT_IN_STRCPY
:
441 case BUILT_IN_STRCPY_CHK
:
442 if (gimple_call_num_args (stmt
) == 2)
443 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
445 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
446 gcc_assert (lhs
== NULL_TREE
);
447 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
449 fprintf (dump_file
, "Optimizing: ");
450 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
452 gimple_call_set_fndecl (stmt
, fn
);
453 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
454 gimple_call_set_lhs (stmt
, lhs
);
456 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
458 fprintf (dump_file
, "into: ");
459 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
462 case BUILT_IN_STPCPY
:
463 case BUILT_IN_STPCPY_CHK
:
464 gcc_assert (lhs
!= NULL_TREE
);
465 loc
= gimple_location (stmt
);
468 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
469 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
470 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
482 /* Invalidate string length information for strings whose length
483 might change due to stores in stmt. */
486 maybe_invalidate (gimple stmt
)
490 bool nonempty
= false;
492 for (i
= 1; VEC_iterate (strinfo
, stridx_to_strinfo
, i
, si
); ++i
)
495 if (!si
->dont_invalidate
)
498 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
499 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
501 set_strinfo (i
, NULL
);
506 si
->dont_invalidate
= false;
512 /* Unshare strinfo record SI, if it has recount > 1 or
513 if stridx_to_strinfo vector is shared with some other
517 unshare_strinfo (strinfo si
)
521 if (si
->refcount
== 1 && !strinfo_shared ())
524 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
525 nsi
->stmt
= si
->stmt
;
526 nsi
->endptr
= si
->endptr
;
527 nsi
->first
= si
->first
;
528 nsi
->prev
= si
->prev
;
529 nsi
->next
= si
->next
;
530 nsi
->writable
= si
->writable
;
531 set_strinfo (si
->idx
, nsi
);
536 /* Return first strinfo in the related strinfo chain
537 if all strinfos in between belong to the chain, otherwise
541 verify_related_strinfos (strinfo origsi
)
543 strinfo si
= origsi
, psi
;
545 if (origsi
->first
== 0)
547 for (; si
->prev
; si
= psi
)
549 if (si
->first
!= origsi
->first
)
551 psi
= get_strinfo (si
->prev
);
554 if (psi
->next
!= si
->idx
)
557 if (si
->idx
!= si
->first
)
562 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
563 to a zero-length string and if possible chain it to a related strinfo
564 chain whose part is or might be CHAINSI. */
567 zero_length_string (tree ptr
, strinfo chainsi
)
571 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
572 && get_stridx (ptr
) == 0);
574 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
578 si
= verify_related_strinfos (chainsi
);
582 for (; chainsi
->next
; chainsi
= si
)
584 if (chainsi
->endptr
== NULL_TREE
)
586 chainsi
= unshare_strinfo (chainsi
);
587 chainsi
->endptr
= ptr
;
589 si
= get_strinfo (chainsi
->next
);
591 || si
->first
!= chainsi
->first
592 || si
->prev
!= chainsi
->idx
)
595 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
596 if (chainsi
->endptr
== NULL_TREE
)
598 chainsi
= unshare_strinfo (chainsi
);
599 chainsi
->endptr
= ptr
;
601 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
605 chainsi
= unshare_strinfo (chainsi
);
608 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (ptr
),
613 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
615 chainsi
= unshare_strinfo (chainsi
);
621 idx
= new_stridx (ptr
);
624 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
625 set_strinfo (idx
, si
);
629 chainsi
= unshare_strinfo (chainsi
);
630 if (chainsi
->first
== 0)
631 chainsi
->first
= chainsi
->idx
;
633 if (chainsi
->endptr
== NULL_TREE
)
634 chainsi
->endptr
= ptr
;
635 si
->prev
= chainsi
->idx
;
636 si
->first
= chainsi
->first
;
637 si
->writable
= chainsi
->writable
;
642 /* For strinfo ORIGSI whose length has been just updated
643 update also related strinfo lengths (add ADJ to each,
644 but don't adjust ORIGSI). */
647 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
649 strinfo si
= verify_related_strinfos (origsi
);
662 si
= unshare_strinfo (si
);
665 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
666 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
667 TREE_TYPE (si
->length
), si
->length
,
670 else if (si
->stmt
!= NULL
)
671 /* Delayed length computation is unaffected. */
676 si
->endptr
= NULL_TREE
;
677 si
->dont_invalidate
= true;
681 nsi
= get_strinfo (si
->next
);
683 || nsi
->first
!= si
->first
684 || nsi
->prev
!= si
->idx
)
690 /* Find if there are other SSA_NAME pointers equal to PTR
691 for which we don't track their string lengths yet. If so, use
695 find_equal_ptrs (tree ptr
, int idx
)
697 if (TREE_CODE (ptr
) != SSA_NAME
)
701 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
702 if (!is_gimple_assign (stmt
))
704 ptr
= gimple_assign_rhs1 (stmt
);
705 switch (gimple_assign_rhs_code (stmt
))
710 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
712 if (TREE_CODE (ptr
) == SSA_NAME
)
714 if (TREE_CODE (ptr
) != ADDR_EXPR
)
719 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
720 if (pidx
!= NULL
&& *pidx
== 0)
728 /* We might find an endptr created in this pass. Grow the
729 vector in that case. */
730 if (VEC_length (int, ssa_ver_to_stridx
) <= SSA_NAME_VERSION (ptr
))
731 VEC_safe_grow_cleared (int, heap
, ssa_ver_to_stridx
, num_ssa_names
);
733 if (VEC_index (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (ptr
)) != 0)
735 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (ptr
), idx
);
739 /* If the last .MEM setter statement before STMT is
740 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
741 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
742 just memcpy (x, y, strlen (y)). SI must be the zero length
746 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
748 tree vuse
, callee
, len
;
749 struct laststmt_struct last
= laststmt
;
750 strinfo lastsi
, firstsi
;
752 laststmt
.stmt
= NULL
;
753 laststmt
.len
= NULL_TREE
;
756 if (last
.stmt
== NULL
)
759 vuse
= gimple_vuse (stmt
);
760 if (vuse
== NULL_TREE
761 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
762 || !has_single_use (vuse
))
765 gcc_assert (last
.stridx
> 0);
766 lastsi
= get_strinfo (last
.stridx
);
772 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
775 firstsi
= verify_related_strinfos (si
);
778 while (firstsi
!= lastsi
)
781 if (firstsi
->next
== 0)
783 nextsi
= get_strinfo (firstsi
->next
);
785 || nextsi
->prev
!= firstsi
->idx
786 || nextsi
->first
!= si
->first
)
794 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
798 if (is_gimple_assign (last
.stmt
))
800 gimple_stmt_iterator gsi
;
802 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
804 if (stmt_could_throw_p (last
.stmt
))
806 gsi
= gsi_for_stmt (last
.stmt
);
807 unlink_stmt_vdef (last
.stmt
);
808 release_defs (last
.stmt
);
809 gsi_remove (&gsi
, true);
813 if (!is_gimple_call (last
.stmt
))
815 callee
= gimple_call_fndecl (last
.stmt
);
816 if (callee
== NULL_TREE
|| DECL_BUILT_IN_CLASS (callee
) != BUILT_IN_NORMAL
)
819 switch (DECL_FUNCTION_CODE (callee
))
821 case BUILT_IN_MEMCPY
:
822 case BUILT_IN_MEMCPY_CHK
:
828 len
= gimple_call_arg (last
.stmt
, 2);
829 if (host_integerp (len
, 1))
831 if (!host_integerp (last
.len
, 1)
832 || integer_zerop (len
)
833 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
834 != (unsigned HOST_WIDE_INT
) tree_low_cst (last
.len
, 1) + 1)
836 /* Don't adjust the length if it is divisible by 4, it is more efficient
837 to store the extra '\0' in that case. */
838 if ((((unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)) & 3) == 0)
841 else if (TREE_CODE (len
) == SSA_NAME
)
843 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
844 if (!is_gimple_assign (def_stmt
)
845 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
846 || gimple_assign_rhs1 (def_stmt
) != last
.len
847 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
853 gimple_call_set_arg (last
.stmt
, 2, last
.len
);
854 update_stmt (last
.stmt
);
857 /* Handle a strlen call. If strlen of the argument is known, replace
858 the strlen call with the known value, otherwise remember that strlen
859 of the argument is stored in the lhs SSA_NAME. */
862 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
866 gimple stmt
= gsi_stmt (*gsi
);
867 tree lhs
= gimple_call_lhs (stmt
);
869 if (lhs
== NULL_TREE
)
872 src
= gimple_call_arg (stmt
, 0);
873 idx
= get_stridx (src
);
880 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
884 si
= get_strinfo (idx
);
886 rhs
= get_string_length (si
);
888 if (rhs
!= NULL_TREE
)
890 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
892 fprintf (dump_file
, "Optimizing: ");
893 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
895 rhs
= unshare_expr (rhs
);
896 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
897 rhs
= fold_convert_loc (gimple_location (stmt
),
898 TREE_TYPE (lhs
), rhs
);
899 if (!update_call_from_tree (gsi
, rhs
))
900 gimplify_and_update_call_from_tree (gsi
, rhs
);
901 stmt
= gsi_stmt (*gsi
);
903 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
905 fprintf (dump_file
, "into: ");
906 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
909 && TREE_CODE (si
->length
) != SSA_NAME
910 && TREE_CODE (si
->length
) != INTEGER_CST
911 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
913 si
= unshare_strinfo (si
);
919 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
922 idx
= new_stridx (src
);
923 else if (get_strinfo (idx
) != NULL
)
927 strinfo si
= new_strinfo (src
, idx
, lhs
);
928 set_strinfo (idx
, si
);
929 find_equal_ptrs (src
, idx
);
933 /* Handle a strchr call. If strlen of the first argument is known, replace
934 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
935 that lhs of the call is endptr and strlen of the argument is endptr - x. */
938 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
942 gimple stmt
= gsi_stmt (*gsi
);
943 tree lhs
= gimple_call_lhs (stmt
);
945 if (lhs
== NULL_TREE
)
948 if (!integer_zerop (gimple_call_arg (stmt
, 1)))
951 src
= gimple_call_arg (stmt
, 0);
952 idx
= get_stridx (src
);
959 rhs
= build_int_cst (size_type_node
, ~idx
);
963 si
= get_strinfo (idx
);
965 rhs
= get_string_length (si
);
967 if (rhs
!= NULL_TREE
)
969 location_t loc
= gimple_location (stmt
);
971 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
973 fprintf (dump_file
, "Optimizing: ");
974 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
976 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
978 rhs
= unshare_expr (si
->endptr
);
979 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
981 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
985 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
986 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
987 TREE_TYPE (src
), src
, rhs
);
988 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
990 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
992 if (!update_call_from_tree (gsi
, rhs
))
993 gimplify_and_update_call_from_tree (gsi
, rhs
);
994 stmt
= gsi_stmt (*gsi
);
996 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
998 fprintf (dump_file
, "into: ");
999 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1002 && si
->endptr
== NULL_TREE
1003 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1005 si
= unshare_strinfo (si
);
1008 zero_length_string (lhs
, si
);
1012 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1014 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1017 idx
= new_stridx (src
);
1018 else if (get_strinfo (idx
) != NULL
)
1020 zero_length_string (lhs
, NULL
);
1025 location_t loc
= gimple_location (stmt
);
1026 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1027 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1028 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1029 size_type_node
, lhsu
, srcu
);
1030 strinfo si
= new_strinfo (src
, idx
, length
);
1032 set_strinfo (idx
, si
);
1033 find_equal_ptrs (src
, idx
);
1034 zero_length_string (lhs
, si
);
1038 zero_length_string (lhs
, NULL
);
1041 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1042 If strlen of the second argument is known, strlen of the first argument
1043 is the same after this call. Furthermore, attempt to convert it to
1047 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1050 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1052 gimple stmt
= gsi_stmt (*gsi
);
1053 strinfo si
, dsi
, olddsi
, zsi
;
1056 src
= gimple_call_arg (stmt
, 1);
1057 dst
= gimple_call_arg (stmt
, 0);
1058 lhs
= gimple_call_lhs (stmt
);
1059 idx
= get_stridx (src
);
1062 si
= get_strinfo (idx
);
1064 didx
= get_stridx (dst
);
1068 olddsi
= get_strinfo (didx
);
1073 adjust_last_stmt (olddsi
, stmt
, false);
1077 srclen
= get_string_length (si
);
1079 srclen
= build_int_cst (size_type_node
, ~idx
);
1081 loc
= gimple_location (stmt
);
1082 if (srclen
== NULL_TREE
)
1085 case BUILT_IN_STRCPY
:
1086 case BUILT_IN_STRCPY_CHK
:
1087 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1090 case BUILT_IN_STPCPY
:
1091 case BUILT_IN_STPCPY_CHK
:
1092 if (lhs
== NULL_TREE
)
1096 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1097 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1098 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1108 didx
= new_stridx (dst
);
1114 oldlen
= olddsi
->length
;
1115 dsi
= unshare_strinfo (olddsi
);
1116 dsi
->length
= srclen
;
1117 /* Break the chain, so adjust_related_strinfo on later pointers in
1118 the chain won't adjust this one anymore. */
1121 dsi
->endptr
= NULL_TREE
;
1125 dsi
= new_strinfo (dst
, didx
, srclen
);
1126 set_strinfo (didx
, dsi
);
1127 find_equal_ptrs (dst
, didx
);
1129 dsi
->writable
= true;
1130 dsi
->dont_invalidate
= true;
1132 if (dsi
->length
== NULL_TREE
)
1136 /* If string length of src is unknown, use delayed length
1137 computation. If string lenth of dst will be needed, it
1138 can be computed by transforming this strcpy call into
1139 stpcpy and subtracting dst from the return value. */
1141 /* Look for earlier strings whose length could be determined if
1142 this strcpy is turned into an stpcpy. */
1144 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1146 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1148 /* When setting a stmt for delayed length computation
1149 prevent all strinfos through dsi from being
1151 chainsi
= unshare_strinfo (chainsi
);
1152 chainsi
->stmt
= stmt
;
1153 chainsi
->length
= NULL_TREE
;
1154 chainsi
->endptr
= NULL_TREE
;
1155 chainsi
->dont_invalidate
= true;
1164 tree adj
= NULL_TREE
;
1165 if (oldlen
== NULL_TREE
)
1167 else if (integer_zerop (oldlen
))
1169 else if (TREE_CODE (oldlen
) == INTEGER_CST
1170 || TREE_CODE (srclen
) == INTEGER_CST
)
1171 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1172 TREE_TYPE (srclen
), srclen
,
1173 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1175 if (adj
!= NULL_TREE
)
1176 adjust_related_strinfos (loc
, dsi
, adj
);
1180 /* strcpy src may not overlap dst, so src doesn't need to be
1181 invalidated either. */
1183 si
->dont_invalidate
= true;
1189 case BUILT_IN_STRCPY
:
1190 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1192 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
), didx
);
1194 case BUILT_IN_STRCPY_CHK
:
1195 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1197 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
), didx
);
1199 case BUILT_IN_STPCPY
:
1200 /* This would need adjustment of the lhs (subtract one),
1201 or detection that the trailing '\0' doesn't need to be
1202 written, if it will be immediately overwritten.
1203 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1207 zsi
= zero_length_string (lhs
, dsi
);
1210 case BUILT_IN_STPCPY_CHK
:
1211 /* This would need adjustment of the lhs (subtract one),
1212 or detection that the trailing '\0' doesn't need to be
1213 written, if it will be immediately overwritten.
1214 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1218 zsi
= zero_length_string (lhs
, dsi
);
1225 zsi
->dont_invalidate
= true;
1227 if (fn
== NULL_TREE
)
1230 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1231 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1233 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1234 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1235 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1237 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1239 fprintf (dump_file
, "Optimizing: ");
1240 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1242 if (gimple_call_num_args (stmt
) == 2)
1243 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1245 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1246 gimple_call_arg (stmt
, 2));
1249 stmt
= gsi_stmt (*gsi
);
1251 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1253 fprintf (dump_file
, "into: ");
1254 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1256 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1257 laststmt
.stmt
= stmt
;
1258 laststmt
.len
= srclen
;
1259 laststmt
.stridx
= dsi
->idx
;
1261 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1262 fprintf (dump_file
, "not possible.\n");
1265 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1266 If strlen of the second argument is known and length of the third argument
1267 is that plus one, strlen of the first argument is the same after this
1271 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1274 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1275 gimple stmt
= gsi_stmt (*gsi
);
1276 strinfo si
, dsi
, olddsi
;
1278 len
= gimple_call_arg (stmt
, 2);
1279 src
= gimple_call_arg (stmt
, 1);
1280 dst
= gimple_call_arg (stmt
, 0);
1281 idx
= get_stridx (src
);
1285 didx
= get_stridx (dst
);
1288 olddsi
= get_strinfo (didx
);
1293 && host_integerp (len
, 1)
1294 && !integer_zerop (len
))
1295 adjust_last_stmt (olddsi
, stmt
, false);
1301 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1302 si
= get_strinfo (idx
);
1303 if (si
== NULL
|| si
->length
== NULL_TREE
)
1305 if (TREE_CODE (len
) != SSA_NAME
)
1307 def_stmt
= SSA_NAME_DEF_STMT (len
);
1308 if (!is_gimple_assign (def_stmt
)
1309 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1310 || gimple_assign_rhs1 (def_stmt
) != si
->length
1311 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1317 /* Handle memcpy (x, "abcd", 5) or
1318 memcpy (x, "abc\0uvw", 7). */
1319 if (!host_integerp (len
, 1)
1320 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
1321 <= (unsigned HOST_WIDE_INT
) ~idx
)
1325 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1326 adjust_last_stmt (olddsi
, stmt
, false);
1330 didx
= new_stridx (dst
);
1335 newlen
= si
->length
;
1337 newlen
= build_int_cst (size_type_node
, ~idx
);
1341 dsi
= unshare_strinfo (olddsi
);
1342 oldlen
= olddsi
->length
;
1343 dsi
->length
= newlen
;
1344 /* Break the chain, so adjust_related_strinfo on later pointers in
1345 the chain won't adjust this one anymore. */
1348 dsi
->endptr
= NULL_TREE
;
1352 dsi
= new_strinfo (dst
, didx
, newlen
);
1353 set_strinfo (didx
, dsi
);
1354 find_equal_ptrs (dst
, didx
);
1356 dsi
->writable
= true;
1357 dsi
->dont_invalidate
= true;
1360 tree adj
= NULL_TREE
;
1361 location_t loc
= gimple_location (stmt
);
1362 if (oldlen
== NULL_TREE
)
1364 else if (integer_zerop (oldlen
))
1366 else if (TREE_CODE (oldlen
) == INTEGER_CST
1367 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1368 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1369 TREE_TYPE (dsi
->length
), dsi
->length
,
1370 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1372 if (adj
!= NULL_TREE
)
1373 adjust_related_strinfos (loc
, dsi
, adj
);
1377 /* memcpy src may not overlap dst, so src doesn't need to be
1378 invalidated either. */
1380 si
->dont_invalidate
= true;
1382 lhs
= gimple_call_lhs (stmt
);
1385 case BUILT_IN_MEMCPY
:
1386 case BUILT_IN_MEMCPY_CHK
:
1387 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1388 laststmt
.stmt
= stmt
;
1389 laststmt
.len
= dsi
->length
;
1390 laststmt
.stridx
= dsi
->idx
;
1392 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
), didx
);
1394 case BUILT_IN_MEMPCPY
:
1395 case BUILT_IN_MEMPCPY_CHK
:
1402 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1403 If strlen of the second argument is known, strlen of the first argument
1404 is increased by the length of the second argument. Furthermore, attempt
1405 to convert it to memcpy/strcpy if the length of the first argument
1409 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1412 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1414 gimple stmt
= gsi_stmt (*gsi
);
1418 src
= gimple_call_arg (stmt
, 1);
1419 dst
= gimple_call_arg (stmt
, 0);
1420 lhs
= gimple_call_lhs (stmt
);
1422 didx
= get_stridx (dst
);
1428 dsi
= get_strinfo (didx
);
1429 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1431 /* strcat (p, q) can be transformed into
1432 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1433 with length endptr - p if we need to compute the length
1434 later on. Don't do this transformation if we don't need
1436 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1440 didx
= new_stridx (dst
);
1446 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1447 set_strinfo (didx
, dsi
);
1448 find_equal_ptrs (dst
, didx
);
1452 dsi
= unshare_strinfo (dsi
);
1453 dsi
->length
= NULL_TREE
;
1455 dsi
->endptr
= NULL_TREE
;
1457 dsi
->writable
= true;
1459 dsi
->dont_invalidate
= true;
1466 idx
= get_stridx (src
);
1468 srclen
= build_int_cst (size_type_node
, ~idx
);
1471 si
= get_strinfo (idx
);
1473 srclen
= get_string_length (si
);
1476 loc
= gimple_location (stmt
);
1477 dstlen
= dsi
->length
;
1478 endptr
= dsi
->endptr
;
1480 dsi
= unshare_strinfo (dsi
);
1481 dsi
->endptr
= NULL_TREE
;
1483 dsi
->writable
= true;
1485 if (srclen
!= NULL_TREE
)
1487 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1488 dsi
->length
, srclen
);
1489 adjust_related_strinfos (loc
, dsi
, srclen
);
1490 dsi
->dont_invalidate
= true;
1495 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1496 dsi
->dont_invalidate
= true;
1500 /* strcat src may not overlap dst, so src doesn't need to be
1501 invalidated either. */
1502 si
->dont_invalidate
= true;
1504 /* For now. Could remove the lhs from the call and add
1505 lhs = dst; afterwards. */
1513 case BUILT_IN_STRCAT
:
1514 if (srclen
!= NULL_TREE
)
1515 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1517 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1519 case BUILT_IN_STRCAT_CHK
:
1520 if (srclen
!= NULL_TREE
)
1521 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1523 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1524 objsz
= gimple_call_arg (stmt
, 2);
1530 if (fn
== NULL_TREE
)
1534 if (srclen
!= NULL_TREE
)
1536 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1537 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1539 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1540 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1541 build_int_cst (type
, 1));
1542 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1546 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1548 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1549 TREE_TYPE (dst
), unshare_expr (dst
),
1550 fold_convert_loc (loc
, sizetype
,
1551 unshare_expr (dstlen
)));
1552 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1554 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1556 fprintf (dump_file
, "Optimizing: ");
1557 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1559 if (srclen
!= NULL_TREE
)
1560 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1561 dst
, src
, len
, objsz
);
1563 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1567 stmt
= gsi_stmt (*gsi
);
1569 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1571 fprintf (dump_file
, "into: ");
1572 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1574 /* If srclen == NULL, note that current string length can be
1575 computed by transforming this strcpy into stpcpy. */
1576 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1578 adjust_last_stmt (dsi
, stmt
, true);
1579 if (srclen
!= NULL_TREE
)
1581 laststmt
.stmt
= stmt
;
1582 laststmt
.len
= srclen
;
1583 laststmt
.stridx
= dsi
->idx
;
1586 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1587 fprintf (dump_file
, "not possible.\n");
1590 /* Handle a POINTER_PLUS_EXPR statement.
1591 For p = "abcd" + 2; compute associated length, or if
1592 p = q + off is pointing to a '\0' character of a string, call
1593 zero_length_string on it. */
1596 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1598 gimple stmt
= gsi_stmt (*gsi
);
1599 tree lhs
= gimple_assign_lhs (stmt
), off
;
1600 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1608 tree off
= gimple_assign_rhs2 (stmt
);
1609 if (host_integerp (off
, 1)
1610 && (unsigned HOST_WIDE_INT
) tree_low_cst (off
, 1)
1611 <= (unsigned HOST_WIDE_INT
) ~idx
)
1612 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
),
1613 ~(~idx
- (int) tree_low_cst (off
, 1)));
1617 si
= get_strinfo (idx
);
1618 if (si
== NULL
|| si
->length
== NULL_TREE
)
1621 off
= gimple_assign_rhs2 (stmt
);
1623 if (operand_equal_p (si
->length
, off
, 0))
1624 zsi
= zero_length_string (lhs
, si
);
1625 else if (TREE_CODE (off
) == SSA_NAME
)
1627 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1628 if (gimple_assign_single_p (def_stmt
)
1629 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1630 zsi
= zero_length_string (lhs
, si
);
1633 && si
->endptr
!= NULL_TREE
1634 && si
->endptr
!= lhs
1635 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1637 enum tree_code rhs_code
1638 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1639 ? SSA_NAME
: NOP_EXPR
;
1640 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
, NULL_TREE
);
1641 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1646 /* Handle a single character store. */
1649 handle_char_store (gimple_stmt_iterator
*gsi
)
1653 gimple stmt
= gsi_stmt (*gsi
);
1654 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1656 if (TREE_CODE (lhs
) == MEM_REF
1657 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1659 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1661 ssaname
= TREE_OPERAND (lhs
, 0);
1662 idx
= get_stridx (ssaname
);
1666 idx
= get_addr_stridx (lhs
);
1670 si
= get_strinfo (idx
);
1671 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1673 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1675 /* When storing '\0', the store can be removed
1676 if we know it has been stored in the current function. */
1677 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1679 unlink_stmt_vdef (stmt
);
1680 release_defs (stmt
);
1681 gsi_remove (gsi
, true);
1686 si
->writable
= true;
1687 si
->dont_invalidate
= true;
1691 /* Otherwise this statement overwrites the '\0' with
1692 something, if the previous stmt was a memcpy,
1693 its length may be decreased. */
1694 adjust_last_stmt (si
, stmt
, false);
1696 else if (si
!= NULL
)
1698 si
= unshare_strinfo (si
);
1699 si
->length
= build_int_cst (size_type_node
, 0);
1705 si
->writable
= true;
1706 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1707 si
->endptr
= ssaname
;
1708 si
->dont_invalidate
= true;
1711 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1715 si
= zero_length_string (ssaname
, NULL
);
1717 si
->dont_invalidate
= true;
1721 int idx
= new_addr_stridx (lhs
);
1724 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1725 build_int_cst (size_type_node
, 0));
1726 set_strinfo (idx
, si
);
1727 si
->dont_invalidate
= true;
1731 si
->writable
= true;
1734 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
1736 /* Allow adjust_last_stmt to remove it if the stored '\0'
1737 is immediately overwritten. */
1738 laststmt
.stmt
= stmt
;
1739 laststmt
.len
= build_int_cst (size_type_node
, 1);
1740 laststmt
.stridx
= si
->idx
;
1745 /* Attempt to optimize a single statement at *GSI using string length
1749 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
1751 gimple stmt
= gsi_stmt (*gsi
);
1753 if (is_gimple_call (stmt
))
1755 tree callee
= gimple_call_fndecl (stmt
);
1756 if (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
)
1757 switch (DECL_FUNCTION_CODE (callee
))
1759 case BUILT_IN_STRLEN
:
1760 handle_builtin_strlen (gsi
);
1762 case BUILT_IN_STRCHR
:
1763 handle_builtin_strchr (gsi
);
1765 case BUILT_IN_STRCPY
:
1766 case BUILT_IN_STRCPY_CHK
:
1767 case BUILT_IN_STPCPY
:
1768 case BUILT_IN_STPCPY_CHK
:
1769 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1771 case BUILT_IN_MEMCPY
:
1772 case BUILT_IN_MEMCPY_CHK
:
1773 case BUILT_IN_MEMPCPY
:
1774 case BUILT_IN_MEMPCPY_CHK
:
1775 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1777 case BUILT_IN_STRCAT
:
1778 case BUILT_IN_STRCAT_CHK
:
1779 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
1785 else if (is_gimple_assign (stmt
))
1787 tree lhs
= gimple_assign_lhs (stmt
);
1789 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
1791 if (gimple_assign_single_p (stmt
)
1792 || (gimple_assign_cast_p (stmt
)
1793 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
1795 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1796 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
),
1799 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
1800 handle_pointer_plus (gsi
);
1802 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
1804 tree type
= TREE_TYPE (lhs
);
1805 if (TREE_CODE (type
) == ARRAY_TYPE
)
1806 type
= TREE_TYPE (type
);
1807 if (TREE_CODE (type
) == INTEGER_TYPE
1808 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
1809 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
1811 if (! handle_char_store (gsi
))
1817 if (gimple_vdef (stmt
))
1818 maybe_invalidate (stmt
);
1822 /* Recursively call maybe_invalidate on stmts that might be executed
1823 in between dombb and current bb and that contain a vdef. Stop when
1824 *count stmts are inspected, or if the whole strinfo vector has
1825 been invalidated. */
1828 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
1830 unsigned int i
, n
= gimple_phi_num_args (phi
);
1832 for (i
= 0; i
< n
; i
++)
1834 tree vuse
= gimple_phi_arg_def (phi
, i
);
1835 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
1836 basic_block bb
= gimple_bb (stmt
);
1839 || !bitmap_set_bit (visited
, bb
->index
)
1840 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1844 if (gimple_code (stmt
) == GIMPLE_PHI
)
1846 do_invalidate (dombb
, stmt
, visited
, count
);
1853 if (!maybe_invalidate (stmt
))
1858 vuse
= gimple_vuse (stmt
);
1859 stmt
= SSA_NAME_DEF_STMT (vuse
);
1860 if (gimple_bb (stmt
) != bb
)
1862 bb
= gimple_bb (stmt
);
1865 || !bitmap_set_bit (visited
, bb
->index
)
1866 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1873 /* Callback for walk_dominator_tree. Attempt to optimize various
1874 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1877 strlen_enter_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
1880 gimple_stmt_iterator gsi
;
1881 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
1884 stridx_to_strinfo
= NULL
;
1887 stridx_to_strinfo
= (VEC(strinfo
, heap
) *) dombb
->aux
;
1888 if (stridx_to_strinfo
)
1890 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1892 gimple phi
= gsi_stmt (gsi
);
1893 if (virtual_operand_p (gimple_phi_result (phi
)))
1895 bitmap visited
= BITMAP_ALLOC (NULL
);
1896 int count_vdef
= 100;
1897 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
1898 BITMAP_FREE (visited
);
1905 /* If all PHI arguments have the same string index, the PHI result
1907 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1909 gimple phi
= gsi_stmt (gsi
);
1910 tree result
= gimple_phi_result (phi
);
1911 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
1913 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
1916 unsigned int i
, n
= gimple_phi_num_args (phi
);
1917 for (i
= 1; i
< n
; i
++)
1918 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
1921 VEC_replace (int, ssa_ver_to_stridx
,
1922 SSA_NAME_VERSION (result
), idx
);
1927 /* Attempt to optimize individual statements. */
1928 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
1929 if (strlen_optimize_stmt (&gsi
))
1932 bb
->aux
= stridx_to_strinfo
;
1933 if (VEC_length (strinfo
, stridx_to_strinfo
) && !strinfo_shared ())
1934 VEC_replace (strinfo
, stridx_to_strinfo
, 0, (strinfo
) bb
);
1937 /* Callback for walk_dominator_tree. Free strinfo vector if it is
1938 owned by the current bb, clear bb->aux. */
1941 strlen_leave_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
1946 stridx_to_strinfo
= (VEC(strinfo
, heap
) *) bb
->aux
;
1947 if (VEC_length (strinfo
, stridx_to_strinfo
)
1948 && VEC_index (strinfo
, stridx_to_strinfo
, 0) == (strinfo
) bb
)
1953 for (i
= 1; VEC_iterate (strinfo
, stridx_to_strinfo
, i
, si
); ++i
)
1955 VEC_free (strinfo
, heap
, stridx_to_strinfo
);
1961 /* Main entry point. */
1964 tree_ssa_strlen (void)
1966 struct dom_walk_data walk_data
;
1968 VEC_safe_grow_cleared (int, heap
, ssa_ver_to_stridx
, num_ssa_names
);
1970 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
1971 sizeof (struct strinfo_struct
), 64);
1973 calculate_dominance_info (CDI_DOMINATORS
);
1975 /* String length optimization is implemented as a walk of the dominator
1976 tree and a forward walk of statements within each block. */
1977 walk_data
.dom_direction
= CDI_DOMINATORS
;
1978 walk_data
.initialize_block_local_data
= NULL
;
1979 walk_data
.before_dom_children
= strlen_enter_block
;
1980 walk_data
.after_dom_children
= strlen_leave_block
;
1981 walk_data
.block_local_data_size
= 0;
1982 walk_data
.global_data
= NULL
;
1984 /* Initialize the dominator walker. */
1985 init_walk_dominator_tree (&walk_data
);
1987 /* Recursively walk the dominator tree. */
1988 walk_dominator_tree (&walk_data
, ENTRY_BLOCK_PTR
);
1990 /* Finalize the dominator walker. */
1991 fini_walk_dominator_tree (&walk_data
);
1993 VEC_free (int, heap
, ssa_ver_to_stridx
);
1994 free_alloc_pool (strinfo_pool
);
1995 if (decl_to_stridxlist_htab
)
1997 obstack_free (&stridx_obstack
, NULL
);
1998 htab_delete (decl_to_stridxlist_htab
);
1999 decl_to_stridxlist_htab
= NULL
;
2001 laststmt
.stmt
= NULL
;
2002 laststmt
.len
= NULL_TREE
;
2003 laststmt
.stridx
= 0;
2011 return flag_optimize_strlen
!= 0;
2014 struct gimple_opt_pass pass_strlen
=
2018 "strlen", /* name */
2019 gate_strlen
, /* gate */
2020 tree_ssa_strlen
, /* execute */
2023 0, /* static_pass_number */
2024 TV_TREE_STRLEN
, /* tv_id */
2025 PROP_cfg
| PROP_ssa
, /* properties_required */
2026 0, /* properties_provided */
2027 0, /* properties_destroyed */
2028 0, /* todo_flags_start */
2030 | TODO_verify_ssa
/* todo_flags_finish */