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
, lhs_var
, 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 lhs_var
= create_tmp_var (TREE_TYPE (TREE_TYPE (fn
)), NULL
);
419 add_referenced_var (lhs_var
);
420 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
421 lenstmt
= gimple_build_call (fn
, 1, tem
);
422 lhs
= make_ssa_name (lhs_var
, lenstmt
);
423 gimple_call_set_lhs (lenstmt
, lhs
);
424 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
425 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
426 lhs_var
= create_tmp_var (TREE_TYPE (gimple_call_arg (stmt
, 0)),
428 add_referenced_var (lhs_var
);
429 tem
= gimple_call_arg (stmt
, 0);
430 if (!ptrofftype_p (TREE_TYPE (lhs
)))
432 lhs
= convert_to_ptrofftype (lhs
);
433 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
434 true, GSI_SAME_STMT
);
437 = gimple_build_assign_with_ops (POINTER_PLUS_EXPR
,
438 make_ssa_name (lhs_var
, NULL
),
440 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
441 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
444 case BUILT_IN_STRCPY
:
445 case BUILT_IN_STRCPY_CHK
:
446 if (gimple_call_num_args (stmt
) == 2)
447 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
449 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
450 gcc_assert (lhs
== NULL_TREE
);
451 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
453 fprintf (dump_file
, "Optimizing: ");
454 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
456 gimple_call_set_fndecl (stmt
, fn
);
457 lhs_var
= create_tmp_var (TREE_TYPE (TREE_TYPE (fn
)), NULL
);
458 add_referenced_var (lhs_var
);
459 lhs
= make_ssa_name (lhs_var
, stmt
);
460 gimple_call_set_lhs (stmt
, lhs
);
462 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
464 fprintf (dump_file
, "into: ");
465 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
468 case BUILT_IN_STPCPY
:
469 case BUILT_IN_STPCPY_CHK
:
470 gcc_assert (lhs
!= NULL_TREE
);
471 loc
= gimple_location (stmt
);
474 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
475 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
476 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
488 /* Invalidate string length information for strings whose length
489 might change due to stores in stmt. */
492 maybe_invalidate (gimple stmt
)
496 bool nonempty
= false;
498 for (i
= 1; VEC_iterate (strinfo
, stridx_to_strinfo
, i
, si
); ++i
)
501 if (!si
->dont_invalidate
)
504 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
505 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
507 set_strinfo (i
, NULL
);
512 si
->dont_invalidate
= false;
518 /* Unshare strinfo record SI, if it has recount > 1 or
519 if stridx_to_strinfo vector is shared with some other
523 unshare_strinfo (strinfo si
)
527 if (si
->refcount
== 1 && !strinfo_shared ())
530 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
531 nsi
->stmt
= si
->stmt
;
532 nsi
->endptr
= si
->endptr
;
533 nsi
->first
= si
->first
;
534 nsi
->prev
= si
->prev
;
535 nsi
->next
= si
->next
;
536 nsi
->writable
= si
->writable
;
537 set_strinfo (si
->idx
, nsi
);
542 /* Return first strinfo in the related strinfo chain
543 if all strinfos in between belong to the chain, otherwise
547 verify_related_strinfos (strinfo origsi
)
549 strinfo si
= origsi
, psi
;
551 if (origsi
->first
== 0)
553 for (; si
->prev
; si
= psi
)
555 if (si
->first
!= origsi
->first
)
557 psi
= get_strinfo (si
->prev
);
560 if (psi
->next
!= si
->idx
)
563 if (si
->idx
!= si
->first
)
568 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
569 to a zero-length string and if possible chain it to a related strinfo
570 chain whose part is or might be CHAINSI. */
573 zero_length_string (tree ptr
, strinfo chainsi
)
577 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
578 && get_stridx (ptr
) == 0);
580 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
584 si
= verify_related_strinfos (chainsi
);
588 for (; chainsi
->next
; chainsi
= si
)
590 if (chainsi
->endptr
== NULL_TREE
)
592 chainsi
= unshare_strinfo (chainsi
);
593 chainsi
->endptr
= ptr
;
595 si
= get_strinfo (chainsi
->next
);
597 || si
->first
!= chainsi
->first
598 || si
->prev
!= chainsi
->idx
)
601 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
602 if (chainsi
->endptr
== NULL_TREE
)
604 chainsi
= unshare_strinfo (chainsi
);
605 chainsi
->endptr
= ptr
;
607 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
611 chainsi
= unshare_strinfo (chainsi
);
614 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (ptr
),
619 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
621 chainsi
= unshare_strinfo (chainsi
);
627 idx
= new_stridx (ptr
);
630 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
631 set_strinfo (idx
, si
);
635 chainsi
= unshare_strinfo (chainsi
);
636 if (chainsi
->first
== 0)
637 chainsi
->first
= chainsi
->idx
;
639 if (chainsi
->endptr
== NULL_TREE
)
640 chainsi
->endptr
= ptr
;
641 si
->prev
= chainsi
->idx
;
642 si
->first
= chainsi
->first
;
643 si
->writable
= chainsi
->writable
;
648 /* For strinfo ORIGSI whose length has been just updated
649 update also related strinfo lengths (add ADJ to each,
650 but don't adjust ORIGSI). */
653 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
655 strinfo si
= verify_related_strinfos (origsi
);
668 si
= unshare_strinfo (si
);
671 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
672 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
673 TREE_TYPE (si
->length
), si
->length
,
676 else if (si
->stmt
!= NULL
)
677 /* Delayed length computation is unaffected. */
682 si
->endptr
= NULL_TREE
;
683 si
->dont_invalidate
= true;
687 nsi
= get_strinfo (si
->next
);
689 || nsi
->first
!= si
->first
690 || nsi
->prev
!= si
->idx
)
696 /* Find if there are other SSA_NAME pointers equal to PTR
697 for which we don't track their string lengths yet. If so, use
701 find_equal_ptrs (tree ptr
, int idx
)
703 if (TREE_CODE (ptr
) != SSA_NAME
)
707 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
708 if (!is_gimple_assign (stmt
))
710 ptr
= gimple_assign_rhs1 (stmt
);
711 switch (gimple_assign_rhs_code (stmt
))
716 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
718 if (TREE_CODE (ptr
) == SSA_NAME
)
720 if (TREE_CODE (ptr
) != ADDR_EXPR
)
725 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
726 if (pidx
!= NULL
&& *pidx
== 0)
734 /* We might find an endptr created in this pass. Grow the
735 vector in that case. */
736 if (VEC_length (int, ssa_ver_to_stridx
) <= SSA_NAME_VERSION (ptr
))
737 VEC_safe_grow_cleared (int, heap
, ssa_ver_to_stridx
, num_ssa_names
);
739 if (VEC_index (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (ptr
)) != 0)
741 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (ptr
), idx
);
745 /* If the last .MEM setter statement before STMT is
746 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
747 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
748 just memcpy (x, y, strlen (y)). SI must be the zero length
752 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
754 tree vuse
, callee
, len
;
755 struct laststmt_struct last
= laststmt
;
756 strinfo lastsi
, firstsi
;
758 laststmt
.stmt
= NULL
;
759 laststmt
.len
= NULL_TREE
;
762 if (last
.stmt
== NULL
)
765 vuse
= gimple_vuse (stmt
);
766 if (vuse
== NULL_TREE
767 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
768 || !has_single_use (vuse
))
771 gcc_assert (last
.stridx
> 0);
772 lastsi
= get_strinfo (last
.stridx
);
778 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
781 firstsi
= verify_related_strinfos (si
);
784 while (firstsi
!= lastsi
)
787 if (firstsi
->next
== 0)
789 nextsi
= get_strinfo (firstsi
->next
);
791 || nextsi
->prev
!= firstsi
->idx
792 || nextsi
->first
!= si
->first
)
800 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
804 if (is_gimple_assign (last
.stmt
))
806 gimple_stmt_iterator gsi
;
808 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
810 if (stmt_could_throw_p (last
.stmt
))
812 gsi
= gsi_for_stmt (last
.stmt
);
813 unlink_stmt_vdef (last
.stmt
);
814 release_defs (last
.stmt
);
815 gsi_remove (&gsi
, true);
819 if (!is_gimple_call (last
.stmt
))
821 callee
= gimple_call_fndecl (last
.stmt
);
822 if (callee
== NULL_TREE
|| DECL_BUILT_IN_CLASS (callee
) != BUILT_IN_NORMAL
)
825 switch (DECL_FUNCTION_CODE (callee
))
827 case BUILT_IN_MEMCPY
:
828 case BUILT_IN_MEMCPY_CHK
:
834 len
= gimple_call_arg (last
.stmt
, 2);
835 if (host_integerp (len
, 1))
837 if (!host_integerp (last
.len
, 1)
838 || integer_zerop (len
)
839 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
840 != (unsigned HOST_WIDE_INT
) tree_low_cst (last
.len
, 1) + 1)
842 /* Don't adjust the length if it is divisible by 4, it is more efficient
843 to store the extra '\0' in that case. */
844 if ((((unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)) & 3) == 0)
847 else if (TREE_CODE (len
) == SSA_NAME
)
849 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
850 if (!is_gimple_assign (def_stmt
)
851 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
852 || gimple_assign_rhs1 (def_stmt
) != last
.len
853 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
859 gimple_call_set_arg (last
.stmt
, 2, last
.len
);
860 update_stmt (last
.stmt
);
863 /* Handle a strlen call. If strlen of the argument is known, replace
864 the strlen call with the known value, otherwise remember that strlen
865 of the argument is stored in the lhs SSA_NAME. */
868 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
872 gimple stmt
= gsi_stmt (*gsi
);
873 tree lhs
= gimple_call_lhs (stmt
);
875 if (lhs
== NULL_TREE
)
878 src
= gimple_call_arg (stmt
, 0);
879 idx
= get_stridx (src
);
886 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
890 si
= get_strinfo (idx
);
892 rhs
= get_string_length (si
);
894 if (rhs
!= NULL_TREE
)
896 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
898 fprintf (dump_file
, "Optimizing: ");
899 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
901 rhs
= unshare_expr (rhs
);
902 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
903 rhs
= fold_convert_loc (gimple_location (stmt
),
904 TREE_TYPE (lhs
), rhs
);
905 if (!update_call_from_tree (gsi
, rhs
))
906 gimplify_and_update_call_from_tree (gsi
, rhs
);
907 stmt
= gsi_stmt (*gsi
);
909 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
911 fprintf (dump_file
, "into: ");
912 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
915 && TREE_CODE (si
->length
) != SSA_NAME
916 && TREE_CODE (si
->length
) != INTEGER_CST
917 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
919 si
= unshare_strinfo (si
);
925 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
928 idx
= new_stridx (src
);
929 else if (get_strinfo (idx
) != NULL
)
933 strinfo si
= new_strinfo (src
, idx
, lhs
);
934 set_strinfo (idx
, si
);
935 find_equal_ptrs (src
, idx
);
939 /* Handle a strchr call. If strlen of the first argument is known, replace
940 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
941 that lhs of the call is endptr and strlen of the argument is endptr - x. */
944 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
948 gimple stmt
= gsi_stmt (*gsi
);
949 tree lhs
= gimple_call_lhs (stmt
);
951 if (lhs
== NULL_TREE
)
954 if (!integer_zerop (gimple_call_arg (stmt
, 1)))
957 src
= gimple_call_arg (stmt
, 0);
958 idx
= get_stridx (src
);
965 rhs
= build_int_cst (size_type_node
, ~idx
);
969 si
= get_strinfo (idx
);
971 rhs
= get_string_length (si
);
973 if (rhs
!= NULL_TREE
)
975 location_t loc
= gimple_location (stmt
);
977 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
979 fprintf (dump_file
, "Optimizing: ");
980 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
982 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
984 rhs
= unshare_expr (si
->endptr
);
985 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
987 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
991 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
992 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
993 TREE_TYPE (src
), src
, rhs
);
994 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
996 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
998 if (!update_call_from_tree (gsi
, rhs
))
999 gimplify_and_update_call_from_tree (gsi
, rhs
);
1000 stmt
= gsi_stmt (*gsi
);
1002 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1004 fprintf (dump_file
, "into: ");
1005 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1008 && si
->endptr
== NULL_TREE
1009 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1011 si
= unshare_strinfo (si
);
1014 zero_length_string (lhs
, si
);
1018 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1020 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1023 idx
= new_stridx (src
);
1024 else if (get_strinfo (idx
) != NULL
)
1026 zero_length_string (lhs
, NULL
);
1031 location_t loc
= gimple_location (stmt
);
1032 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1033 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1034 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1035 size_type_node
, lhsu
, srcu
);
1036 strinfo si
= new_strinfo (src
, idx
, length
);
1038 set_strinfo (idx
, si
);
1039 find_equal_ptrs (src
, idx
);
1040 zero_length_string (lhs
, si
);
1044 zero_length_string (lhs
, NULL
);
1047 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1048 If strlen of the second argument is known, strlen of the first argument
1049 is the same after this call. Furthermore, attempt to convert it to
1053 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1056 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1058 gimple stmt
= gsi_stmt (*gsi
);
1059 strinfo si
, dsi
, olddsi
, zsi
;
1062 src
= gimple_call_arg (stmt
, 1);
1063 dst
= gimple_call_arg (stmt
, 0);
1064 lhs
= gimple_call_lhs (stmt
);
1065 idx
= get_stridx (src
);
1068 si
= get_strinfo (idx
);
1070 didx
= get_stridx (dst
);
1074 olddsi
= get_strinfo (didx
);
1079 adjust_last_stmt (olddsi
, stmt
, false);
1083 srclen
= get_string_length (si
);
1085 srclen
= build_int_cst (size_type_node
, ~idx
);
1087 loc
= gimple_location (stmt
);
1088 if (srclen
== NULL_TREE
)
1091 case BUILT_IN_STRCPY
:
1092 case BUILT_IN_STRCPY_CHK
:
1093 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1096 case BUILT_IN_STPCPY
:
1097 case BUILT_IN_STPCPY_CHK
:
1098 if (lhs
== NULL_TREE
)
1102 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1103 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1104 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1114 didx
= new_stridx (dst
);
1120 oldlen
= olddsi
->length
;
1121 dsi
= unshare_strinfo (olddsi
);
1122 dsi
->length
= srclen
;
1123 /* Break the chain, so adjust_related_strinfo on later pointers in
1124 the chain won't adjust this one anymore. */
1127 dsi
->endptr
= NULL_TREE
;
1131 dsi
= new_strinfo (dst
, didx
, srclen
);
1132 set_strinfo (didx
, dsi
);
1133 find_equal_ptrs (dst
, didx
);
1135 dsi
->writable
= true;
1136 dsi
->dont_invalidate
= true;
1138 if (dsi
->length
== NULL_TREE
)
1142 /* If string length of src is unknown, use delayed length
1143 computation. If string lenth of dst will be needed, it
1144 can be computed by transforming this strcpy call into
1145 stpcpy and subtracting dst from the return value. */
1147 /* Look for earlier strings whose length could be determined if
1148 this strcpy is turned into an stpcpy. */
1150 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1152 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1154 /* When setting a stmt for delayed length computation
1155 prevent all strinfos through dsi from being
1157 chainsi
= unshare_strinfo (chainsi
);
1158 chainsi
->stmt
= stmt
;
1159 chainsi
->length
= NULL_TREE
;
1160 chainsi
->endptr
= NULL_TREE
;
1161 chainsi
->dont_invalidate
= true;
1170 tree adj
= NULL_TREE
;
1171 if (oldlen
== NULL_TREE
)
1173 else if (integer_zerop (oldlen
))
1175 else if (TREE_CODE (oldlen
) == INTEGER_CST
1176 || TREE_CODE (srclen
) == INTEGER_CST
)
1177 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1178 TREE_TYPE (srclen
), srclen
,
1179 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1181 if (adj
!= NULL_TREE
)
1182 adjust_related_strinfos (loc
, dsi
, adj
);
1186 /* strcpy src may not overlap dst, so src doesn't need to be
1187 invalidated either. */
1189 si
->dont_invalidate
= true;
1195 case BUILT_IN_STRCPY
:
1196 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1198 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
), didx
);
1200 case BUILT_IN_STRCPY_CHK
:
1201 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1203 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
), didx
);
1205 case BUILT_IN_STPCPY
:
1206 /* This would need adjustment of the lhs (subtract one),
1207 or detection that the trailing '\0' doesn't need to be
1208 written, if it will be immediately overwritten.
1209 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1213 zsi
= zero_length_string (lhs
, dsi
);
1216 case BUILT_IN_STPCPY_CHK
:
1217 /* This would need adjustment of the lhs (subtract one),
1218 or detection that the trailing '\0' doesn't need to be
1219 written, if it will be immediately overwritten.
1220 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1224 zsi
= zero_length_string (lhs
, dsi
);
1231 zsi
->dont_invalidate
= true;
1233 if (fn
== NULL_TREE
)
1236 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1237 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1239 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1240 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1241 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1243 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1245 fprintf (dump_file
, "Optimizing: ");
1246 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1248 if (gimple_call_num_args (stmt
) == 2)
1249 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1251 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1252 gimple_call_arg (stmt
, 2));
1255 stmt
= gsi_stmt (*gsi
);
1257 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1259 fprintf (dump_file
, "into: ");
1260 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1262 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1263 laststmt
.stmt
= stmt
;
1264 laststmt
.len
= srclen
;
1265 laststmt
.stridx
= dsi
->idx
;
1267 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1268 fprintf (dump_file
, "not possible.\n");
1271 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1272 If strlen of the second argument is known and length of the third argument
1273 is that plus one, strlen of the first argument is the same after this
1277 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1280 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1281 gimple stmt
= gsi_stmt (*gsi
);
1282 strinfo si
, dsi
, olddsi
;
1284 len
= gimple_call_arg (stmt
, 2);
1285 src
= gimple_call_arg (stmt
, 1);
1286 dst
= gimple_call_arg (stmt
, 0);
1287 idx
= get_stridx (src
);
1291 didx
= get_stridx (dst
);
1294 olddsi
= get_strinfo (didx
);
1299 && host_integerp (len
, 1)
1300 && !integer_zerop (len
))
1301 adjust_last_stmt (olddsi
, stmt
, false);
1307 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1308 si
= get_strinfo (idx
);
1309 if (si
== NULL
|| si
->length
== NULL_TREE
)
1311 if (TREE_CODE (len
) != SSA_NAME
)
1313 def_stmt
= SSA_NAME_DEF_STMT (len
);
1314 if (!is_gimple_assign (def_stmt
)
1315 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1316 || gimple_assign_rhs1 (def_stmt
) != si
->length
1317 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1323 /* Handle memcpy (x, "abcd", 5) or
1324 memcpy (x, "abc\0uvw", 7). */
1325 if (!host_integerp (len
, 1)
1326 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
1327 <= (unsigned HOST_WIDE_INT
) ~idx
)
1331 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1332 adjust_last_stmt (olddsi
, stmt
, false);
1336 didx
= new_stridx (dst
);
1341 newlen
= si
->length
;
1343 newlen
= build_int_cst (size_type_node
, ~idx
);
1347 dsi
= unshare_strinfo (olddsi
);
1348 oldlen
= olddsi
->length
;
1349 dsi
->length
= newlen
;
1350 /* Break the chain, so adjust_related_strinfo on later pointers in
1351 the chain won't adjust this one anymore. */
1354 dsi
->endptr
= NULL_TREE
;
1358 dsi
= new_strinfo (dst
, didx
, newlen
);
1359 set_strinfo (didx
, dsi
);
1360 find_equal_ptrs (dst
, didx
);
1362 dsi
->writable
= true;
1363 dsi
->dont_invalidate
= true;
1366 tree adj
= NULL_TREE
;
1367 location_t loc
= gimple_location (stmt
);
1368 if (oldlen
== NULL_TREE
)
1370 else if (integer_zerop (oldlen
))
1372 else if (TREE_CODE (oldlen
) == INTEGER_CST
1373 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1374 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1375 TREE_TYPE (dsi
->length
), dsi
->length
,
1376 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1378 if (adj
!= NULL_TREE
)
1379 adjust_related_strinfos (loc
, dsi
, adj
);
1383 /* memcpy src may not overlap dst, so src doesn't need to be
1384 invalidated either. */
1386 si
->dont_invalidate
= true;
1388 lhs
= gimple_call_lhs (stmt
);
1391 case BUILT_IN_MEMCPY
:
1392 case BUILT_IN_MEMCPY_CHK
:
1393 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1394 laststmt
.stmt
= stmt
;
1395 laststmt
.len
= dsi
->length
;
1396 laststmt
.stridx
= dsi
->idx
;
1398 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
), didx
);
1400 case BUILT_IN_MEMPCPY
:
1401 case BUILT_IN_MEMPCPY_CHK
:
1408 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1409 If strlen of the second argument is known, strlen of the first argument
1410 is increased by the length of the second argument. Furthermore, attempt
1411 to convert it to memcpy/strcpy if the length of the first argument
1415 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1418 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1420 gimple stmt
= gsi_stmt (*gsi
);
1424 src
= gimple_call_arg (stmt
, 1);
1425 dst
= gimple_call_arg (stmt
, 0);
1426 lhs
= gimple_call_lhs (stmt
);
1428 didx
= get_stridx (dst
);
1434 dsi
= get_strinfo (didx
);
1435 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1437 /* strcat (p, q) can be transformed into
1438 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1439 with length endptr - p if we need to compute the length
1440 later on. Don't do this transformation if we don't need
1442 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1446 didx
= new_stridx (dst
);
1452 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1453 set_strinfo (didx
, dsi
);
1454 find_equal_ptrs (dst
, didx
);
1458 dsi
= unshare_strinfo (dsi
);
1459 dsi
->length
= NULL_TREE
;
1461 dsi
->endptr
= NULL_TREE
;
1463 dsi
->writable
= true;
1465 dsi
->dont_invalidate
= true;
1472 idx
= get_stridx (src
);
1474 srclen
= build_int_cst (size_type_node
, ~idx
);
1477 si
= get_strinfo (idx
);
1479 srclen
= get_string_length (si
);
1482 loc
= gimple_location (stmt
);
1483 dstlen
= dsi
->length
;
1484 endptr
= dsi
->endptr
;
1486 dsi
= unshare_strinfo (dsi
);
1487 dsi
->endptr
= NULL_TREE
;
1489 dsi
->writable
= true;
1491 if (srclen
!= NULL_TREE
)
1493 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1494 dsi
->length
, srclen
);
1495 adjust_related_strinfos (loc
, dsi
, srclen
);
1496 dsi
->dont_invalidate
= true;
1501 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1502 dsi
->dont_invalidate
= true;
1506 /* strcat src may not overlap dst, so src doesn't need to be
1507 invalidated either. */
1508 si
->dont_invalidate
= true;
1510 /* For now. Could remove the lhs from the call and add
1511 lhs = dst; afterwards. */
1519 case BUILT_IN_STRCAT
:
1520 if (srclen
!= NULL_TREE
)
1521 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1523 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1525 case BUILT_IN_STRCAT_CHK
:
1526 if (srclen
!= NULL_TREE
)
1527 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1529 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1530 objsz
= gimple_call_arg (stmt
, 2);
1536 if (fn
== NULL_TREE
)
1540 if (srclen
!= NULL_TREE
)
1542 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1543 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1545 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1546 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1547 build_int_cst (type
, 1));
1548 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1552 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1554 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1555 TREE_TYPE (dst
), unshare_expr (dst
),
1556 fold_convert_loc (loc
, sizetype
,
1557 unshare_expr (dstlen
)));
1558 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1560 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1562 fprintf (dump_file
, "Optimizing: ");
1563 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1565 if (srclen
!= NULL_TREE
)
1566 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1567 dst
, src
, len
, objsz
);
1569 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1573 stmt
= gsi_stmt (*gsi
);
1575 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1577 fprintf (dump_file
, "into: ");
1578 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1580 /* If srclen == NULL, note that current string length can be
1581 computed by transforming this strcpy into stpcpy. */
1582 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1584 adjust_last_stmt (dsi
, stmt
, true);
1585 if (srclen
!= NULL_TREE
)
1587 laststmt
.stmt
= stmt
;
1588 laststmt
.len
= srclen
;
1589 laststmt
.stridx
= dsi
->idx
;
1592 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1593 fprintf (dump_file
, "not possible.\n");
1596 /* Handle a POINTER_PLUS_EXPR statement.
1597 For p = "abcd" + 2; compute associated length, or if
1598 p = q + off is pointing to a '\0' character of a string, call
1599 zero_length_string on it. */
1602 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1604 gimple stmt
= gsi_stmt (*gsi
);
1605 tree lhs
= gimple_assign_lhs (stmt
), off
;
1606 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1614 tree off
= gimple_assign_rhs2 (stmt
);
1615 if (host_integerp (off
, 1)
1616 && (unsigned HOST_WIDE_INT
) tree_low_cst (off
, 1)
1617 <= (unsigned HOST_WIDE_INT
) ~idx
)
1618 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
),
1619 ~(~idx
- (int) tree_low_cst (off
, 1)));
1623 si
= get_strinfo (idx
);
1624 if (si
== NULL
|| si
->length
== NULL_TREE
)
1627 off
= gimple_assign_rhs2 (stmt
);
1629 if (operand_equal_p (si
->length
, off
, 0))
1630 zsi
= zero_length_string (lhs
, si
);
1631 else if (TREE_CODE (off
) == SSA_NAME
)
1633 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1634 if (gimple_assign_single_p (def_stmt
)
1635 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1636 zsi
= zero_length_string (lhs
, si
);
1639 && si
->endptr
!= NULL_TREE
1640 && si
->endptr
!= lhs
1641 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1643 enum tree_code rhs_code
1644 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1645 ? SSA_NAME
: NOP_EXPR
;
1646 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
, NULL_TREE
);
1647 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1652 /* Handle a single character store. */
1655 handle_char_store (gimple_stmt_iterator
*gsi
)
1659 gimple stmt
= gsi_stmt (*gsi
);
1660 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1662 if (TREE_CODE (lhs
) == MEM_REF
1663 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1665 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1667 ssaname
= TREE_OPERAND (lhs
, 0);
1668 idx
= get_stridx (ssaname
);
1672 idx
= get_addr_stridx (lhs
);
1676 si
= get_strinfo (idx
);
1677 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1679 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1681 /* When storing '\0', the store can be removed
1682 if we know it has been stored in the current function. */
1683 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1685 unlink_stmt_vdef (stmt
);
1686 release_defs (stmt
);
1687 gsi_remove (gsi
, true);
1692 si
->writable
= true;
1693 si
->dont_invalidate
= true;
1697 /* Otherwise this statement overwrites the '\0' with
1698 something, if the previous stmt was a memcpy,
1699 its length may be decreased. */
1700 adjust_last_stmt (si
, stmt
, false);
1702 else if (si
!= NULL
)
1704 si
= unshare_strinfo (si
);
1705 si
->length
= build_int_cst (size_type_node
, 0);
1711 si
->writable
= true;
1712 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1713 si
->endptr
= ssaname
;
1714 si
->dont_invalidate
= true;
1717 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1721 si
= zero_length_string (ssaname
, NULL
);
1723 si
->dont_invalidate
= true;
1727 int idx
= new_addr_stridx (lhs
);
1730 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1731 build_int_cst (size_type_node
, 0));
1732 set_strinfo (idx
, si
);
1733 si
->dont_invalidate
= true;
1737 si
->writable
= true;
1740 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
1742 /* Allow adjust_last_stmt to remove it if the stored '\0'
1743 is immediately overwritten. */
1744 laststmt
.stmt
= stmt
;
1745 laststmt
.len
= build_int_cst (size_type_node
, 1);
1746 laststmt
.stridx
= si
->idx
;
1751 /* Attempt to optimize a single statement at *GSI using string length
1755 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
1757 gimple stmt
= gsi_stmt (*gsi
);
1759 if (is_gimple_call (stmt
))
1761 tree callee
= gimple_call_fndecl (stmt
);
1762 if (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
)
1763 switch (DECL_FUNCTION_CODE (callee
))
1765 case BUILT_IN_STRLEN
:
1766 handle_builtin_strlen (gsi
);
1768 case BUILT_IN_STRCHR
:
1769 handle_builtin_strchr (gsi
);
1771 case BUILT_IN_STRCPY
:
1772 case BUILT_IN_STRCPY_CHK
:
1773 case BUILT_IN_STPCPY
:
1774 case BUILT_IN_STPCPY_CHK
:
1775 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1777 case BUILT_IN_MEMCPY
:
1778 case BUILT_IN_MEMCPY_CHK
:
1779 case BUILT_IN_MEMPCPY
:
1780 case BUILT_IN_MEMPCPY_CHK
:
1781 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1783 case BUILT_IN_STRCAT
:
1784 case BUILT_IN_STRCAT_CHK
:
1785 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
1791 else if (is_gimple_assign (stmt
))
1793 tree lhs
= gimple_assign_lhs (stmt
);
1795 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
1797 if (gimple_assign_single_p (stmt
)
1798 || (gimple_assign_cast_p (stmt
)
1799 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
1801 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1802 VEC_replace (int, ssa_ver_to_stridx
, SSA_NAME_VERSION (lhs
),
1805 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
1806 handle_pointer_plus (gsi
);
1808 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
1810 tree type
= TREE_TYPE (lhs
);
1811 if (TREE_CODE (type
) == ARRAY_TYPE
)
1812 type
= TREE_TYPE (type
);
1813 if (TREE_CODE (type
) == INTEGER_TYPE
1814 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
1815 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
1817 if (! handle_char_store (gsi
))
1823 if (gimple_vdef (stmt
))
1824 maybe_invalidate (stmt
);
1828 /* Recursively call maybe_invalidate on stmts that might be executed
1829 in between dombb and current bb and that contain a vdef. Stop when
1830 *count stmts are inspected, or if the whole strinfo vector has
1831 been invalidated. */
1834 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
1836 unsigned int i
, n
= gimple_phi_num_args (phi
);
1838 for (i
= 0; i
< n
; i
++)
1840 tree vuse
= gimple_phi_arg_def (phi
, i
);
1841 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
1842 basic_block bb
= gimple_bb (stmt
);
1845 || !bitmap_set_bit (visited
, bb
->index
)
1846 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1850 if (gimple_code (stmt
) == GIMPLE_PHI
)
1852 do_invalidate (dombb
, stmt
, visited
, count
);
1859 if (!maybe_invalidate (stmt
))
1864 vuse
= gimple_vuse (stmt
);
1865 stmt
= SSA_NAME_DEF_STMT (vuse
);
1866 if (gimple_bb (stmt
) != bb
)
1868 bb
= gimple_bb (stmt
);
1871 || !bitmap_set_bit (visited
, bb
->index
)
1872 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1879 /* Callback for walk_dominator_tree. Attempt to optimize various
1880 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1883 strlen_enter_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
1886 gimple_stmt_iterator gsi
;
1887 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
1890 stridx_to_strinfo
= NULL
;
1893 stridx_to_strinfo
= (VEC(strinfo
, heap
) *) dombb
->aux
;
1894 if (stridx_to_strinfo
)
1896 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1898 gimple phi
= gsi_stmt (gsi
);
1899 if (!is_gimple_reg (gimple_phi_result (phi
)))
1901 bitmap visited
= BITMAP_ALLOC (NULL
);
1902 int count_vdef
= 100;
1903 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
1904 BITMAP_FREE (visited
);
1911 /* If all PHI arguments have the same string index, the PHI result
1913 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1915 gimple phi
= gsi_stmt (gsi
);
1916 tree result
= gimple_phi_result (phi
);
1917 if (is_gimple_reg (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
1919 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
1922 unsigned int i
, n
= gimple_phi_num_args (phi
);
1923 for (i
= 1; i
< n
; i
++)
1924 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
1927 VEC_replace (int, ssa_ver_to_stridx
,
1928 SSA_NAME_VERSION (result
), idx
);
1933 /* Attempt to optimize individual statements. */
1934 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
1935 if (strlen_optimize_stmt (&gsi
))
1938 bb
->aux
= stridx_to_strinfo
;
1939 if (VEC_length (strinfo
, stridx_to_strinfo
) && !strinfo_shared ())
1940 VEC_replace (strinfo
, stridx_to_strinfo
, 0, (strinfo
) bb
);
1943 /* Callback for walk_dominator_tree. Free strinfo vector if it is
1944 owned by the current bb, clear bb->aux. */
1947 strlen_leave_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
1952 stridx_to_strinfo
= (VEC(strinfo
, heap
) *) bb
->aux
;
1953 if (VEC_length (strinfo
, stridx_to_strinfo
)
1954 && VEC_index (strinfo
, stridx_to_strinfo
, 0) == (strinfo
) bb
)
1959 for (i
= 1; VEC_iterate (strinfo
, stridx_to_strinfo
, i
, si
); ++i
)
1961 VEC_free (strinfo
, heap
, stridx_to_strinfo
);
1967 /* Main entry point. */
1970 tree_ssa_strlen (void)
1972 struct dom_walk_data walk_data
;
1974 VEC_safe_grow_cleared (int, heap
, ssa_ver_to_stridx
, num_ssa_names
);
1976 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
1977 sizeof (struct strinfo_struct
), 64);
1979 calculate_dominance_info (CDI_DOMINATORS
);
1981 /* String length optimization is implemented as a walk of the dominator
1982 tree and a forward walk of statements within each block. */
1983 walk_data
.dom_direction
= CDI_DOMINATORS
;
1984 walk_data
.initialize_block_local_data
= NULL
;
1985 walk_data
.before_dom_children
= strlen_enter_block
;
1986 walk_data
.after_dom_children
= strlen_leave_block
;
1987 walk_data
.block_local_data_size
= 0;
1988 walk_data
.global_data
= NULL
;
1990 /* Initialize the dominator walker. */
1991 init_walk_dominator_tree (&walk_data
);
1993 /* Recursively walk the dominator tree. */
1994 walk_dominator_tree (&walk_data
, ENTRY_BLOCK_PTR
);
1996 /* Finalize the dominator walker. */
1997 fini_walk_dominator_tree (&walk_data
);
1999 VEC_free (int, heap
, ssa_ver_to_stridx
);
2000 free_alloc_pool (strinfo_pool
);
2001 if (decl_to_stridxlist_htab
)
2003 obstack_free (&stridx_obstack
, NULL
);
2004 htab_delete (decl_to_stridxlist_htab
);
2005 decl_to_stridxlist_htab
= NULL
;
2007 laststmt
.stmt
= NULL
;
2008 laststmt
.len
= NULL_TREE
;
2009 laststmt
.stridx
= 0;
2017 return flag_optimize_strlen
!= 0;
2020 struct gimple_opt_pass pass_strlen
=
2024 "strlen", /* name */
2025 gate_strlen
, /* gate */
2026 tree_ssa_strlen
, /* execute */
2029 0, /* static_pass_number */
2030 TV_TREE_STRLEN
, /* tv_id */
2031 PROP_cfg
| PROP_ssa
, /* properties_required */
2032 0, /* properties_provided */
2033 0, /* properties_destroyed */
2034 0, /* todo_flags_start */
2036 | TODO_verify_ssa
/* todo_flags_finish */