1 /* String length optimization
2 Copyright (C) 2011-2013 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
24 #include "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> 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 /* Pool for allocating strinfo_struct entries. */
89 static alloc_pool strinfo_pool
;
91 /* Vector mapping positive string indexes to strinfo, for the
92 current basic block. The first pointer in the vector is special,
93 it is either NULL, meaning the vector isn't shared, or it is
94 a basic block pointer to the owner basic_block if shared.
95 If some other bb wants to modify the vector, the vector needs
96 to be unshared first, and only the owner bb is supposed to free it. */
97 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
99 /* One OFFSET->IDX mapping. */
102 struct stridxlist
*next
;
103 HOST_WIDE_INT offset
;
107 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
108 struct decl_stridxlist_map
110 struct tree_map_base base
;
111 struct stridxlist list
;
114 /* Hash table for mapping decls to a chained list of offset -> idx
116 static htab_t decl_to_stridxlist_htab
;
118 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
119 static struct obstack stridx_obstack
;
121 /* Last memcpy statement if it could be adjusted if the trailing
122 '\0' written is immediately overwritten, or
123 *x = '\0' store that could be removed if it is immediately overwritten. */
124 struct laststmt_struct
131 /* Hash a from tree in a decl_stridxlist_map. */
134 decl_to_stridxlist_hash (const void *item
)
136 return DECL_UID (((const struct decl_stridxlist_map
*) item
)->base
.from
);
139 /* Helper function for get_stridx. */
142 get_addr_stridx (tree exp
)
145 struct decl_stridxlist_map ent
, *e
;
146 struct stridxlist
*list
;
149 if (decl_to_stridxlist_htab
== NULL
)
152 base
= get_addr_base_and_unit_offset (exp
, &off
);
153 if (base
== NULL
|| !DECL_P (base
))
156 ent
.base
.from
= base
;
157 e
= (struct decl_stridxlist_map
*)
158 htab_find_with_hash (decl_to_stridxlist_htab
, &ent
, DECL_UID (base
));
165 if (list
->offset
== off
)
173 /* Return string index for EXP. */
176 get_stridx (tree exp
)
180 if (TREE_CODE (exp
) == SSA_NAME
)
181 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
183 if (TREE_CODE (exp
) == ADDR_EXPR
)
185 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
190 s
= string_constant (exp
, &o
);
192 && (o
== NULL_TREE
|| host_integerp (o
, 0))
193 && TREE_STRING_LENGTH (s
) > 0)
195 HOST_WIDE_INT offset
= o
? tree_low_cst (o
, 0) : 0;
196 const char *p
= TREE_STRING_POINTER (s
);
197 int max
= TREE_STRING_LENGTH (s
) - 1;
199 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
200 return ~(int) strlen (p
+ offset
);
205 /* Return true if strinfo vector is shared with the immediate dominator. */
208 strinfo_shared (void)
210 return vec_safe_length (stridx_to_strinfo
)
211 && (*stridx_to_strinfo
)[0] != NULL
;
214 /* Unshare strinfo vector that is shared with the immediate dominator. */
217 unshare_strinfo_vec (void)
222 gcc_assert (strinfo_shared ());
223 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
224 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
227 (*stridx_to_strinfo
)[0] = NULL
;
230 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
231 Return a pointer to the location where the string index can
232 be stored (if 0) or is stored, or NULL if this can't be tracked. */
235 addr_stridxptr (tree exp
)
238 struct decl_stridxlist_map ent
;
239 struct stridxlist
*list
;
242 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
243 if (base
== NULL_TREE
|| !DECL_P (base
))
246 if (decl_to_stridxlist_htab
== NULL
)
248 decl_to_stridxlist_htab
249 = htab_create (64, decl_to_stridxlist_hash
, tree_map_base_eq
, NULL
);
250 gcc_obstack_init (&stridx_obstack
);
252 ent
.base
.from
= base
;
253 slot
= htab_find_slot_with_hash (decl_to_stridxlist_htab
, &ent
,
254 DECL_UID (base
), INSERT
);
258 list
= &((struct decl_stridxlist_map
*)*slot
)->list
;
259 for (i
= 0; i
< 16; i
++)
261 if (list
->offset
== off
)
263 if (list
->next
== NULL
)
268 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
273 struct decl_stridxlist_map
*e
274 = XOBNEW (&stridx_obstack
, struct decl_stridxlist_map
);
285 /* Create a new string index, or return 0 if reached limit. */
288 new_stridx (tree exp
)
291 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
293 if (TREE_CODE (exp
) == SSA_NAME
)
295 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
298 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
301 if (TREE_CODE (exp
) == ADDR_EXPR
)
303 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
306 gcc_assert (*pidx
== 0);
307 *pidx
= max_stridx
++;
314 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
317 new_addr_stridx (tree exp
)
320 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
322 pidx
= addr_stridxptr (exp
);
325 gcc_assert (*pidx
== 0);
326 *pidx
= max_stridx
++;
332 /* Create a new strinfo. */
335 new_strinfo (tree ptr
, int idx
, tree length
)
337 strinfo si
= (strinfo
) pool_alloc (strinfo_pool
);
341 si
->endptr
= NULL_TREE
;
347 si
->writable
= false;
348 si
->dont_invalidate
= false;
352 /* Decrease strinfo refcount and free it if not referenced anymore. */
355 free_strinfo (strinfo si
)
357 if (si
&& --si
->refcount
== 0)
358 pool_free (strinfo_pool
, si
);
361 /* Return strinfo vector entry IDX. */
363 static inline strinfo
364 get_strinfo (int idx
)
366 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
368 return (*stridx_to_strinfo
)[idx
];
371 /* Set strinfo in the vector entry IDX to SI. */
374 set_strinfo (int idx
, strinfo si
)
376 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
377 unshare_strinfo_vec ();
378 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
379 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
380 (*stridx_to_strinfo
)[idx
] = si
;
383 /* Return string length, or NULL if it can't be computed. */
386 get_string_length (strinfo si
)
393 gimple stmt
= si
->stmt
, lenstmt
;
394 tree callee
, lhs
, fn
, tem
;
396 gimple_stmt_iterator gsi
;
398 gcc_assert (is_gimple_call (stmt
));
399 callee
= gimple_call_fndecl (stmt
);
400 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
401 lhs
= gimple_call_lhs (stmt
);
402 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
403 /* unshare_strinfo is intentionally not called here. The (delayed)
404 transformation of strcpy or strcat into stpcpy is done at the place
405 of the former strcpy/strcat call and so can affect all the strinfos
406 with the same stmt. If they were unshared before and transformation
407 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
408 just compute the right length. */
409 switch (DECL_FUNCTION_CODE (callee
))
411 case BUILT_IN_STRCAT
:
412 case BUILT_IN_STRCAT_CHK
:
413 gsi
= gsi_for_stmt (stmt
);
414 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
415 gcc_assert (lhs
== NULL_TREE
);
416 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
417 lenstmt
= gimple_build_call (fn
, 1, tem
);
418 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
419 gimple_call_set_lhs (lenstmt
, lhs
);
420 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
421 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
422 tem
= gimple_call_arg (stmt
, 0);
423 if (!ptrofftype_p (TREE_TYPE (lhs
)))
425 lhs
= convert_to_ptrofftype (lhs
);
426 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
427 true, GSI_SAME_STMT
);
430 = gimple_build_assign_with_ops
432 make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0)), NULL
),
434 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
435 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
438 case BUILT_IN_STRCPY
:
439 case BUILT_IN_STRCPY_CHK
:
440 if (gimple_call_num_args (stmt
) == 2)
441 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
443 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
444 gcc_assert (lhs
== NULL_TREE
);
445 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
447 fprintf (dump_file
, "Optimizing: ");
448 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
450 gimple_call_set_fndecl (stmt
, fn
);
451 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
452 gimple_call_set_lhs (stmt
, lhs
);
454 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
456 fprintf (dump_file
, "into: ");
457 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
460 case BUILT_IN_STPCPY
:
461 case BUILT_IN_STPCPY_CHK
:
462 gcc_assert (lhs
!= NULL_TREE
);
463 loc
= gimple_location (stmt
);
466 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
467 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
468 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
480 /* Invalidate string length information for strings whose length
481 might change due to stores in stmt. */
484 maybe_invalidate (gimple stmt
)
488 bool nonempty
= false;
490 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
493 if (!si
->dont_invalidate
)
496 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
497 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
499 set_strinfo (i
, NULL
);
504 si
->dont_invalidate
= false;
510 /* Unshare strinfo record SI, if it has recount > 1 or
511 if stridx_to_strinfo vector is shared with some other
515 unshare_strinfo (strinfo si
)
519 if (si
->refcount
== 1 && !strinfo_shared ())
522 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
523 nsi
->stmt
= si
->stmt
;
524 nsi
->endptr
= si
->endptr
;
525 nsi
->first
= si
->first
;
526 nsi
->prev
= si
->prev
;
527 nsi
->next
= si
->next
;
528 nsi
->writable
= si
->writable
;
529 set_strinfo (si
->idx
, nsi
);
534 /* Return first strinfo in the related strinfo chain
535 if all strinfos in between belong to the chain, otherwise
539 verify_related_strinfos (strinfo origsi
)
541 strinfo si
= origsi
, psi
;
543 if (origsi
->first
== 0)
545 for (; si
->prev
; si
= psi
)
547 if (si
->first
!= origsi
->first
)
549 psi
= get_strinfo (si
->prev
);
552 if (psi
->next
!= si
->idx
)
555 if (si
->idx
!= si
->first
)
560 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
561 to a zero-length string and if possible chain it to a related strinfo
562 chain whose part is or might be CHAINSI. */
565 zero_length_string (tree ptr
, strinfo chainsi
)
569 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
570 && get_stridx (ptr
) == 0);
572 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
576 si
= verify_related_strinfos (chainsi
);
580 for (; chainsi
->next
; chainsi
= si
)
582 if (chainsi
->endptr
== NULL_TREE
)
584 chainsi
= unshare_strinfo (chainsi
);
585 chainsi
->endptr
= ptr
;
587 si
= get_strinfo (chainsi
->next
);
589 || si
->first
!= chainsi
->first
590 || si
->prev
!= chainsi
->idx
)
593 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
594 if (chainsi
->endptr
== NULL_TREE
)
596 chainsi
= unshare_strinfo (chainsi
);
597 chainsi
->endptr
= ptr
;
599 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
603 chainsi
= unshare_strinfo (chainsi
);
606 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
610 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
612 chainsi
= unshare_strinfo (chainsi
);
618 idx
= new_stridx (ptr
);
621 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
622 set_strinfo (idx
, si
);
626 chainsi
= unshare_strinfo (chainsi
);
627 if (chainsi
->first
== 0)
628 chainsi
->first
= chainsi
->idx
;
630 if (chainsi
->endptr
== NULL_TREE
)
631 chainsi
->endptr
= ptr
;
632 si
->prev
= chainsi
->idx
;
633 si
->first
= chainsi
->first
;
634 si
->writable
= chainsi
->writable
;
639 /* For strinfo ORIGSI whose length has been just updated
640 update also related strinfo lengths (add ADJ to each,
641 but don't adjust ORIGSI). */
644 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
646 strinfo si
= verify_related_strinfos (origsi
);
659 si
= unshare_strinfo (si
);
662 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
663 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
664 TREE_TYPE (si
->length
), si
->length
,
667 else if (si
->stmt
!= NULL
)
668 /* Delayed length computation is unaffected. */
673 si
->endptr
= NULL_TREE
;
674 si
->dont_invalidate
= true;
678 nsi
= get_strinfo (si
->next
);
680 || nsi
->first
!= si
->first
681 || nsi
->prev
!= si
->idx
)
687 /* Find if there are other SSA_NAME pointers equal to PTR
688 for which we don't track their string lengths yet. If so, use
692 find_equal_ptrs (tree ptr
, int idx
)
694 if (TREE_CODE (ptr
) != SSA_NAME
)
698 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
699 if (!is_gimple_assign (stmt
))
701 ptr
= gimple_assign_rhs1 (stmt
);
702 switch (gimple_assign_rhs_code (stmt
))
707 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
709 if (TREE_CODE (ptr
) == SSA_NAME
)
711 if (TREE_CODE (ptr
) != ADDR_EXPR
)
716 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
717 if (pidx
!= NULL
&& *pidx
== 0)
725 /* We might find an endptr created in this pass. Grow the
726 vector in that case. */
727 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
728 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
730 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
732 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
736 /* If the last .MEM setter statement before STMT is
737 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
738 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
739 just memcpy (x, y, strlen (y)). SI must be the zero length
743 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
745 tree vuse
, callee
, len
;
746 struct laststmt_struct last
= laststmt
;
747 strinfo lastsi
, firstsi
;
749 laststmt
.stmt
= NULL
;
750 laststmt
.len
= NULL_TREE
;
753 if (last
.stmt
== NULL
)
756 vuse
= gimple_vuse (stmt
);
757 if (vuse
== NULL_TREE
758 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
759 || !has_single_use (vuse
))
762 gcc_assert (last
.stridx
> 0);
763 lastsi
= get_strinfo (last
.stridx
);
769 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
772 firstsi
= verify_related_strinfos (si
);
775 while (firstsi
!= lastsi
)
778 if (firstsi
->next
== 0)
780 nextsi
= get_strinfo (firstsi
->next
);
782 || nextsi
->prev
!= firstsi
->idx
783 || nextsi
->first
!= si
->first
)
791 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
795 if (is_gimple_assign (last
.stmt
))
797 gimple_stmt_iterator gsi
;
799 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
801 if (stmt_could_throw_p (last
.stmt
))
803 gsi
= gsi_for_stmt (last
.stmt
);
804 unlink_stmt_vdef (last
.stmt
);
805 release_defs (last
.stmt
);
806 gsi_remove (&gsi
, true);
810 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
813 callee
= gimple_call_fndecl (last
.stmt
);
814 switch (DECL_FUNCTION_CODE (callee
))
816 case BUILT_IN_MEMCPY
:
817 case BUILT_IN_MEMCPY_CHK
:
823 len
= gimple_call_arg (last
.stmt
, 2);
824 if (host_integerp (len
, 1))
826 if (!host_integerp (last
.len
, 1)
827 || integer_zerop (len
)
828 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
829 != (unsigned HOST_WIDE_INT
) tree_low_cst (last
.len
, 1) + 1)
831 /* Don't adjust the length if it is divisible by 4, it is more efficient
832 to store the extra '\0' in that case. */
833 if ((((unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)) & 3) == 0)
836 else if (TREE_CODE (len
) == SSA_NAME
)
838 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
839 if (!is_gimple_assign (def_stmt
)
840 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
841 || gimple_assign_rhs1 (def_stmt
) != last
.len
842 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
848 gimple_call_set_arg (last
.stmt
, 2, last
.len
);
849 update_stmt (last
.stmt
);
852 /* Handle a strlen call. If strlen of the argument is known, replace
853 the strlen call with the known value, otherwise remember that strlen
854 of the argument is stored in the lhs SSA_NAME. */
857 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
861 gimple stmt
= gsi_stmt (*gsi
);
862 tree lhs
= gimple_call_lhs (stmt
);
864 if (lhs
== NULL_TREE
)
867 src
= gimple_call_arg (stmt
, 0);
868 idx
= get_stridx (src
);
875 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
879 si
= get_strinfo (idx
);
881 rhs
= get_string_length (si
);
883 if (rhs
!= NULL_TREE
)
885 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
887 fprintf (dump_file
, "Optimizing: ");
888 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
890 rhs
= unshare_expr (rhs
);
891 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
892 rhs
= fold_convert_loc (gimple_location (stmt
),
893 TREE_TYPE (lhs
), rhs
);
894 if (!update_call_from_tree (gsi
, rhs
))
895 gimplify_and_update_call_from_tree (gsi
, rhs
);
896 stmt
= gsi_stmt (*gsi
);
898 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
900 fprintf (dump_file
, "into: ");
901 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
904 && TREE_CODE (si
->length
) != SSA_NAME
905 && TREE_CODE (si
->length
) != INTEGER_CST
906 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
908 si
= unshare_strinfo (si
);
914 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
917 idx
= new_stridx (src
);
918 else if (get_strinfo (idx
) != NULL
)
922 strinfo si
= new_strinfo (src
, idx
, lhs
);
923 set_strinfo (idx
, si
);
924 find_equal_ptrs (src
, idx
);
928 /* Handle a strchr call. If strlen of the first argument is known, replace
929 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
930 that lhs of the call is endptr and strlen of the argument is endptr - x. */
933 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
937 gimple stmt
= gsi_stmt (*gsi
);
938 tree lhs
= gimple_call_lhs (stmt
);
940 if (lhs
== NULL_TREE
)
943 if (!integer_zerop (gimple_call_arg (stmt
, 1)))
946 src
= gimple_call_arg (stmt
, 0);
947 idx
= get_stridx (src
);
954 rhs
= build_int_cst (size_type_node
, ~idx
);
958 si
= get_strinfo (idx
);
960 rhs
= get_string_length (si
);
962 if (rhs
!= NULL_TREE
)
964 location_t loc
= gimple_location (stmt
);
966 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
968 fprintf (dump_file
, "Optimizing: ");
969 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
971 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
973 rhs
= unshare_expr (si
->endptr
);
974 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
976 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
980 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
981 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
982 TREE_TYPE (src
), src
, rhs
);
983 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
985 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
987 if (!update_call_from_tree (gsi
, rhs
))
988 gimplify_and_update_call_from_tree (gsi
, rhs
);
989 stmt
= gsi_stmt (*gsi
);
991 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
993 fprintf (dump_file
, "into: ");
994 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
997 && si
->endptr
== NULL_TREE
998 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1000 si
= unshare_strinfo (si
);
1003 zero_length_string (lhs
, si
);
1007 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1009 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1012 idx
= new_stridx (src
);
1013 else if (get_strinfo (idx
) != NULL
)
1015 zero_length_string (lhs
, NULL
);
1020 location_t loc
= gimple_location (stmt
);
1021 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1022 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1023 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1024 size_type_node
, lhsu
, srcu
);
1025 strinfo si
= new_strinfo (src
, idx
, length
);
1027 set_strinfo (idx
, si
);
1028 find_equal_ptrs (src
, idx
);
1029 zero_length_string (lhs
, si
);
1033 zero_length_string (lhs
, NULL
);
1036 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1037 If strlen of the second argument is known, strlen of the first argument
1038 is the same after this call. Furthermore, attempt to convert it to
1042 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1045 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1047 gimple stmt
= gsi_stmt (*gsi
);
1048 strinfo si
, dsi
, olddsi
, zsi
;
1051 src
= gimple_call_arg (stmt
, 1);
1052 dst
= gimple_call_arg (stmt
, 0);
1053 lhs
= gimple_call_lhs (stmt
);
1054 idx
= get_stridx (src
);
1057 si
= get_strinfo (idx
);
1059 didx
= get_stridx (dst
);
1063 olddsi
= get_strinfo (didx
);
1068 adjust_last_stmt (olddsi
, stmt
, false);
1072 srclen
= get_string_length (si
);
1074 srclen
= build_int_cst (size_type_node
, ~idx
);
1076 loc
= gimple_location (stmt
);
1077 if (srclen
== NULL_TREE
)
1080 case BUILT_IN_STRCPY
:
1081 case BUILT_IN_STRCPY_CHK
:
1082 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1085 case BUILT_IN_STPCPY
:
1086 case BUILT_IN_STPCPY_CHK
:
1087 if (lhs
== NULL_TREE
)
1091 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1092 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1093 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1103 didx
= new_stridx (dst
);
1109 oldlen
= olddsi
->length
;
1110 dsi
= unshare_strinfo (olddsi
);
1111 dsi
->length
= srclen
;
1112 /* Break the chain, so adjust_related_strinfo on later pointers in
1113 the chain won't adjust this one anymore. */
1116 dsi
->endptr
= NULL_TREE
;
1120 dsi
= new_strinfo (dst
, didx
, srclen
);
1121 set_strinfo (didx
, dsi
);
1122 find_equal_ptrs (dst
, didx
);
1124 dsi
->writable
= true;
1125 dsi
->dont_invalidate
= true;
1127 if (dsi
->length
== NULL_TREE
)
1131 /* If string length of src is unknown, use delayed length
1132 computation. If string lenth of dst will be needed, it
1133 can be computed by transforming this strcpy call into
1134 stpcpy and subtracting dst from the return value. */
1136 /* Look for earlier strings whose length could be determined if
1137 this strcpy is turned into an stpcpy. */
1139 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1141 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1143 /* When setting a stmt for delayed length computation
1144 prevent all strinfos through dsi from being
1146 chainsi
= unshare_strinfo (chainsi
);
1147 chainsi
->stmt
= stmt
;
1148 chainsi
->length
= NULL_TREE
;
1149 chainsi
->endptr
= NULL_TREE
;
1150 chainsi
->dont_invalidate
= true;
1159 tree adj
= NULL_TREE
;
1160 if (oldlen
== NULL_TREE
)
1162 else if (integer_zerop (oldlen
))
1164 else if (TREE_CODE (oldlen
) == INTEGER_CST
1165 || TREE_CODE (srclen
) == INTEGER_CST
)
1166 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1167 TREE_TYPE (srclen
), srclen
,
1168 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1170 if (adj
!= NULL_TREE
)
1171 adjust_related_strinfos (loc
, dsi
, adj
);
1175 /* strcpy src may not overlap dst, so src doesn't need to be
1176 invalidated either. */
1178 si
->dont_invalidate
= true;
1184 case BUILT_IN_STRCPY
:
1185 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1187 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1189 case BUILT_IN_STRCPY_CHK
:
1190 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1192 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1194 case BUILT_IN_STPCPY
:
1195 /* This would need adjustment of the lhs (subtract one),
1196 or detection that the trailing '\0' doesn't need to be
1197 written, if it will be immediately overwritten.
1198 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1202 zsi
= zero_length_string (lhs
, dsi
);
1205 case BUILT_IN_STPCPY_CHK
:
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_CHK); */
1213 zsi
= zero_length_string (lhs
, dsi
);
1220 zsi
->dont_invalidate
= true;
1222 if (fn
== NULL_TREE
)
1225 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1226 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1228 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1229 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1230 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1232 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1234 fprintf (dump_file
, "Optimizing: ");
1235 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1237 if (gimple_call_num_args (stmt
) == 2)
1238 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1240 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1241 gimple_call_arg (stmt
, 2));
1244 stmt
= gsi_stmt (*gsi
);
1246 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1248 fprintf (dump_file
, "into: ");
1249 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1251 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1252 laststmt
.stmt
= stmt
;
1253 laststmt
.len
= srclen
;
1254 laststmt
.stridx
= dsi
->idx
;
1256 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1257 fprintf (dump_file
, "not possible.\n");
1260 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1261 If strlen of the second argument is known and length of the third argument
1262 is that plus one, strlen of the first argument is the same after this
1266 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1269 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1270 gimple stmt
= gsi_stmt (*gsi
);
1271 strinfo si
, dsi
, olddsi
;
1273 len
= gimple_call_arg (stmt
, 2);
1274 src
= gimple_call_arg (stmt
, 1);
1275 dst
= gimple_call_arg (stmt
, 0);
1276 idx
= get_stridx (src
);
1280 didx
= get_stridx (dst
);
1283 olddsi
= get_strinfo (didx
);
1288 && host_integerp (len
, 1)
1289 && !integer_zerop (len
))
1290 adjust_last_stmt (olddsi
, stmt
, false);
1296 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1297 si
= get_strinfo (idx
);
1298 if (si
== NULL
|| si
->length
== NULL_TREE
)
1300 if (TREE_CODE (len
) != SSA_NAME
)
1302 def_stmt
= SSA_NAME_DEF_STMT (len
);
1303 if (!is_gimple_assign (def_stmt
)
1304 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1305 || gimple_assign_rhs1 (def_stmt
) != si
->length
1306 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1312 /* Handle memcpy (x, "abcd", 5) or
1313 memcpy (x, "abc\0uvw", 7). */
1314 if (!host_integerp (len
, 1)
1315 || (unsigned HOST_WIDE_INT
) tree_low_cst (len
, 1)
1316 <= (unsigned HOST_WIDE_INT
) ~idx
)
1320 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1321 adjust_last_stmt (olddsi
, stmt
, false);
1325 didx
= new_stridx (dst
);
1330 newlen
= si
->length
;
1332 newlen
= build_int_cst (size_type_node
, ~idx
);
1336 dsi
= unshare_strinfo (olddsi
);
1337 oldlen
= olddsi
->length
;
1338 dsi
->length
= newlen
;
1339 /* Break the chain, so adjust_related_strinfo on later pointers in
1340 the chain won't adjust this one anymore. */
1343 dsi
->endptr
= NULL_TREE
;
1347 dsi
= new_strinfo (dst
, didx
, newlen
);
1348 set_strinfo (didx
, dsi
);
1349 find_equal_ptrs (dst
, didx
);
1351 dsi
->writable
= true;
1352 dsi
->dont_invalidate
= true;
1355 tree adj
= NULL_TREE
;
1356 location_t loc
= gimple_location (stmt
);
1357 if (oldlen
== NULL_TREE
)
1359 else if (integer_zerop (oldlen
))
1361 else if (TREE_CODE (oldlen
) == INTEGER_CST
1362 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1363 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1364 TREE_TYPE (dsi
->length
), dsi
->length
,
1365 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1367 if (adj
!= NULL_TREE
)
1368 adjust_related_strinfos (loc
, dsi
, adj
);
1372 /* memcpy src may not overlap dst, so src doesn't need to be
1373 invalidated either. */
1375 si
->dont_invalidate
= true;
1377 lhs
= gimple_call_lhs (stmt
);
1380 case BUILT_IN_MEMCPY
:
1381 case BUILT_IN_MEMCPY_CHK
:
1382 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1383 laststmt
.stmt
= stmt
;
1384 laststmt
.len
= dsi
->length
;
1385 laststmt
.stridx
= dsi
->idx
;
1387 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1389 case BUILT_IN_MEMPCPY
:
1390 case BUILT_IN_MEMPCPY_CHK
:
1397 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1398 If strlen of the second argument is known, strlen of the first argument
1399 is increased by the length of the second argument. Furthermore, attempt
1400 to convert it to memcpy/strcpy if the length of the first argument
1404 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1407 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1409 gimple stmt
= gsi_stmt (*gsi
);
1413 src
= gimple_call_arg (stmt
, 1);
1414 dst
= gimple_call_arg (stmt
, 0);
1415 lhs
= gimple_call_lhs (stmt
);
1417 didx
= get_stridx (dst
);
1423 dsi
= get_strinfo (didx
);
1424 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1426 /* strcat (p, q) can be transformed into
1427 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1428 with length endptr - p if we need to compute the length
1429 later on. Don't do this transformation if we don't need
1431 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1435 didx
= new_stridx (dst
);
1441 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1442 set_strinfo (didx
, dsi
);
1443 find_equal_ptrs (dst
, didx
);
1447 dsi
= unshare_strinfo (dsi
);
1448 dsi
->length
= NULL_TREE
;
1450 dsi
->endptr
= NULL_TREE
;
1452 dsi
->writable
= true;
1454 dsi
->dont_invalidate
= true;
1461 idx
= get_stridx (src
);
1463 srclen
= build_int_cst (size_type_node
, ~idx
);
1466 si
= get_strinfo (idx
);
1468 srclen
= get_string_length (si
);
1471 loc
= gimple_location (stmt
);
1472 dstlen
= dsi
->length
;
1473 endptr
= dsi
->endptr
;
1475 dsi
= unshare_strinfo (dsi
);
1476 dsi
->endptr
= NULL_TREE
;
1478 dsi
->writable
= true;
1480 if (srclen
!= NULL_TREE
)
1482 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1483 dsi
->length
, srclen
);
1484 adjust_related_strinfos (loc
, dsi
, srclen
);
1485 dsi
->dont_invalidate
= true;
1490 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1491 dsi
->dont_invalidate
= true;
1495 /* strcat src may not overlap dst, so src doesn't need to be
1496 invalidated either. */
1497 si
->dont_invalidate
= true;
1499 /* For now. Could remove the lhs from the call and add
1500 lhs = dst; afterwards. */
1508 case BUILT_IN_STRCAT
:
1509 if (srclen
!= NULL_TREE
)
1510 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1512 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1514 case BUILT_IN_STRCAT_CHK
:
1515 if (srclen
!= NULL_TREE
)
1516 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1518 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1519 objsz
= gimple_call_arg (stmt
, 2);
1525 if (fn
== NULL_TREE
)
1529 if (srclen
!= NULL_TREE
)
1531 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1532 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1534 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1535 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1536 build_int_cst (type
, 1));
1537 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1541 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1543 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1544 TREE_TYPE (dst
), unshare_expr (dst
),
1545 fold_convert_loc (loc
, sizetype
,
1546 unshare_expr (dstlen
)));
1547 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1549 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1551 fprintf (dump_file
, "Optimizing: ");
1552 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1554 if (srclen
!= NULL_TREE
)
1555 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1556 dst
, src
, len
, objsz
);
1558 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1562 stmt
= gsi_stmt (*gsi
);
1564 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1566 fprintf (dump_file
, "into: ");
1567 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1569 /* If srclen == NULL, note that current string length can be
1570 computed by transforming this strcpy into stpcpy. */
1571 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1573 adjust_last_stmt (dsi
, stmt
, true);
1574 if (srclen
!= NULL_TREE
)
1576 laststmt
.stmt
= stmt
;
1577 laststmt
.len
= srclen
;
1578 laststmt
.stridx
= dsi
->idx
;
1581 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1582 fprintf (dump_file
, "not possible.\n");
1585 /* Handle a POINTER_PLUS_EXPR statement.
1586 For p = "abcd" + 2; compute associated length, or if
1587 p = q + off is pointing to a '\0' character of a string, call
1588 zero_length_string on it. */
1591 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1593 gimple stmt
= gsi_stmt (*gsi
);
1594 tree lhs
= gimple_assign_lhs (stmt
), off
;
1595 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1603 tree off
= gimple_assign_rhs2 (stmt
);
1604 if (host_integerp (off
, 1)
1605 && (unsigned HOST_WIDE_INT
) tree_low_cst (off
, 1)
1606 <= (unsigned HOST_WIDE_INT
) ~idx
)
1607 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1608 = ~(~idx
- (int) tree_low_cst (off
, 1));
1612 si
= get_strinfo (idx
);
1613 if (si
== NULL
|| si
->length
== NULL_TREE
)
1616 off
= gimple_assign_rhs2 (stmt
);
1618 if (operand_equal_p (si
->length
, off
, 0))
1619 zsi
= zero_length_string (lhs
, si
);
1620 else if (TREE_CODE (off
) == SSA_NAME
)
1622 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1623 if (gimple_assign_single_p (def_stmt
)
1624 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1625 zsi
= zero_length_string (lhs
, si
);
1628 && si
->endptr
!= NULL_TREE
1629 && si
->endptr
!= lhs
1630 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1632 enum tree_code rhs_code
1633 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1634 ? SSA_NAME
: NOP_EXPR
;
1635 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
, NULL_TREE
);
1636 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1641 /* Handle a single character store. */
1644 handle_char_store (gimple_stmt_iterator
*gsi
)
1648 gimple stmt
= gsi_stmt (*gsi
);
1649 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1651 if (TREE_CODE (lhs
) == MEM_REF
1652 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1654 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1656 ssaname
= TREE_OPERAND (lhs
, 0);
1657 idx
= get_stridx (ssaname
);
1661 idx
= get_addr_stridx (lhs
);
1665 si
= get_strinfo (idx
);
1666 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1668 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1670 /* When storing '\0', the store can be removed
1671 if we know it has been stored in the current function. */
1672 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1674 unlink_stmt_vdef (stmt
);
1675 release_defs (stmt
);
1676 gsi_remove (gsi
, true);
1681 si
->writable
= true;
1682 si
->dont_invalidate
= true;
1686 /* Otherwise this statement overwrites the '\0' with
1687 something, if the previous stmt was a memcpy,
1688 its length may be decreased. */
1689 adjust_last_stmt (si
, stmt
, false);
1691 else if (si
!= NULL
)
1693 si
= unshare_strinfo (si
);
1694 si
->length
= build_int_cst (size_type_node
, 0);
1700 si
->writable
= true;
1701 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1702 si
->endptr
= ssaname
;
1703 si
->dont_invalidate
= true;
1706 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1710 si
= zero_length_string (ssaname
, NULL
);
1712 si
->dont_invalidate
= true;
1716 int idx
= new_addr_stridx (lhs
);
1719 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1720 build_int_cst (size_type_node
, 0));
1721 set_strinfo (idx
, si
);
1722 si
->dont_invalidate
= true;
1726 si
->writable
= true;
1729 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
1731 /* Allow adjust_last_stmt to remove it if the stored '\0'
1732 is immediately overwritten. */
1733 laststmt
.stmt
= stmt
;
1734 laststmt
.len
= build_int_cst (size_type_node
, 1);
1735 laststmt
.stridx
= si
->idx
;
1740 /* Attempt to optimize a single statement at *GSI using string length
1744 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
1746 gimple stmt
= gsi_stmt (*gsi
);
1748 if (is_gimple_call (stmt
))
1750 tree callee
= gimple_call_fndecl (stmt
);
1751 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
1752 switch (DECL_FUNCTION_CODE (callee
))
1754 case BUILT_IN_STRLEN
:
1755 handle_builtin_strlen (gsi
);
1757 case BUILT_IN_STRCHR
:
1758 handle_builtin_strchr (gsi
);
1760 case BUILT_IN_STRCPY
:
1761 case BUILT_IN_STRCPY_CHK
:
1762 case BUILT_IN_STPCPY
:
1763 case BUILT_IN_STPCPY_CHK
:
1764 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1766 case BUILT_IN_MEMCPY
:
1767 case BUILT_IN_MEMCPY_CHK
:
1768 case BUILT_IN_MEMPCPY
:
1769 case BUILT_IN_MEMPCPY_CHK
:
1770 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
1772 case BUILT_IN_STRCAT
:
1773 case BUILT_IN_STRCAT_CHK
:
1774 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
1780 else if (is_gimple_assign (stmt
))
1782 tree lhs
= gimple_assign_lhs (stmt
);
1784 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
1786 if (gimple_assign_single_p (stmt
)
1787 || (gimple_assign_cast_p (stmt
)
1788 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
1790 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1791 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
1793 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
1794 handle_pointer_plus (gsi
);
1796 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
1798 tree type
= TREE_TYPE (lhs
);
1799 if (TREE_CODE (type
) == ARRAY_TYPE
)
1800 type
= TREE_TYPE (type
);
1801 if (TREE_CODE (type
) == INTEGER_TYPE
1802 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
1803 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
1805 if (! handle_char_store (gsi
))
1811 if (gimple_vdef (stmt
))
1812 maybe_invalidate (stmt
);
1816 /* Recursively call maybe_invalidate on stmts that might be executed
1817 in between dombb and current bb and that contain a vdef. Stop when
1818 *count stmts are inspected, or if the whole strinfo vector has
1819 been invalidated. */
1822 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
1824 unsigned int i
, n
= gimple_phi_num_args (phi
);
1826 for (i
= 0; i
< n
; i
++)
1828 tree vuse
= gimple_phi_arg_def (phi
, i
);
1829 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
1830 basic_block bb
= gimple_bb (stmt
);
1833 || !bitmap_set_bit (visited
, bb
->index
)
1834 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1838 if (gimple_code (stmt
) == GIMPLE_PHI
)
1840 do_invalidate (dombb
, stmt
, visited
, count
);
1847 if (!maybe_invalidate (stmt
))
1852 vuse
= gimple_vuse (stmt
);
1853 stmt
= SSA_NAME_DEF_STMT (vuse
);
1854 if (gimple_bb (stmt
) != bb
)
1856 bb
= gimple_bb (stmt
);
1859 || !bitmap_set_bit (visited
, bb
->index
)
1860 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
1867 /* Callback for walk_dominator_tree. Attempt to optimize various
1868 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
1871 strlen_enter_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
1874 gimple_stmt_iterator gsi
;
1875 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
1878 stridx_to_strinfo
= NULL
;
1881 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
1882 if (stridx_to_strinfo
)
1884 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1886 gimple phi
= gsi_stmt (gsi
);
1887 if (virtual_operand_p (gimple_phi_result (phi
)))
1889 bitmap visited
= BITMAP_ALLOC (NULL
);
1890 int count_vdef
= 100;
1891 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
1892 BITMAP_FREE (visited
);
1899 /* If all PHI arguments have the same string index, the PHI result
1901 for (gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
); gsi_next (&gsi
))
1903 gimple phi
= gsi_stmt (gsi
);
1904 tree result
= gimple_phi_result (phi
);
1905 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
1907 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
1910 unsigned int i
, n
= gimple_phi_num_args (phi
);
1911 for (i
= 1; i
< n
; i
++)
1912 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
1915 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
1920 /* Attempt to optimize individual statements. */
1921 for (gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
1922 if (strlen_optimize_stmt (&gsi
))
1925 bb
->aux
= stridx_to_strinfo
;
1926 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
1927 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
1930 /* Callback for walk_dominator_tree. Free strinfo vector if it is
1931 owned by the current bb, clear bb->aux. */
1934 strlen_leave_block (struct dom_walk_data
*walk_data ATTRIBUTE_UNUSED
,
1939 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
1940 if (vec_safe_length (stridx_to_strinfo
)
1941 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
1946 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
1948 vec_free (stridx_to_strinfo
);
1954 /* Main entry point. */
1957 tree_ssa_strlen (void)
1959 struct dom_walk_data walk_data
;
1961 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
1963 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
1964 sizeof (struct strinfo_struct
), 64);
1966 calculate_dominance_info (CDI_DOMINATORS
);
1968 /* String length optimization is implemented as a walk of the dominator
1969 tree and a forward walk of statements within each block. */
1970 walk_data
.dom_direction
= CDI_DOMINATORS
;
1971 walk_data
.initialize_block_local_data
= NULL
;
1972 walk_data
.before_dom_children
= strlen_enter_block
;
1973 walk_data
.after_dom_children
= strlen_leave_block
;
1974 walk_data
.block_local_data_size
= 0;
1975 walk_data
.global_data
= NULL
;
1977 /* Initialize the dominator walker. */
1978 init_walk_dominator_tree (&walk_data
);
1980 /* Recursively walk the dominator tree. */
1981 walk_dominator_tree (&walk_data
, ENTRY_BLOCK_PTR
);
1983 /* Finalize the dominator walker. */
1984 fini_walk_dominator_tree (&walk_data
);
1986 ssa_ver_to_stridx
.release ();
1987 free_alloc_pool (strinfo_pool
);
1988 if (decl_to_stridxlist_htab
)
1990 obstack_free (&stridx_obstack
, NULL
);
1991 htab_delete (decl_to_stridxlist_htab
);
1992 decl_to_stridxlist_htab
= NULL
;
1994 laststmt
.stmt
= NULL
;
1995 laststmt
.len
= NULL_TREE
;
1996 laststmt
.stridx
= 0;
2004 return flag_optimize_strlen
!= 0;
2007 struct gimple_opt_pass pass_strlen
=
2011 "strlen", /* name */
2012 OPTGROUP_NONE
, /* optinfo_flags */
2013 gate_strlen
, /* gate */
2014 tree_ssa_strlen
, /* execute */
2017 0, /* static_pass_number */
2018 TV_TREE_STRLEN
, /* tv_id */
2019 PROP_cfg
| PROP_ssa
, /* properties_required */
2020 0, /* properties_provided */
2021 0, /* properties_destroyed */
2022 0, /* todo_flags_start */
2024 | TODO_verify_ssa
/* todo_flags_finish */