1 /* String length optimization
2 Copyright (C) 2011-2017 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"
28 #include "alloc-pool.h"
29 #include "tree-pass.h"
32 #include "gimple-pretty-print.h"
33 #include "fold-const.h"
34 #include "stor-layout.h"
35 #include "gimple-fold.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
43 #include "tree-ssa-propagate.h"
46 #include "tree-hash-traits.h"
49 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
50 is an index into strinfo vector, negative value stands for
51 string length of a string literal (~strlen). */
52 static vec
<int> ssa_ver_to_stridx
;
54 /* Number of currently active string indexes plus one. */
55 static int max_stridx
;
57 /* String information record. */
60 /* Number of leading characters that are known to be nonzero. This is
61 also the length of the string if FULL_STRING_P.
63 The values in a list of related string pointers must be consistent;
64 that is, if strinfo B comes X bytes after strinfo A, it must be
65 the case that A->nonzero_chars == X + B->nonzero_chars. */
67 /* Any of the corresponding pointers for querying alias oracle. */
69 /* This is used for two things:
71 - To record the statement that should be used for delayed length
72 computations. We maintain the invariant that all related strinfos
73 have delayed lengths or none do.
75 - To record the malloc or calloc call that produced this result. */
77 /* Pointer to '\0' if known, if NULL, it can be computed as
80 /* Reference count. Any changes to strinfo entry possibly shared
81 with dominating basic blocks need unshare_strinfo first, except
82 for dont_invalidate which affects only the immediately next
85 /* Copy of index. get_strinfo (si->idx) should return si; */
87 /* These 3 fields are for chaining related string pointers together.
89 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
90 strcpy (c, d); e = c + dl;
91 strinfo(a) -> strinfo(c) -> strinfo(e)
92 All have ->first field equal to strinfo(a)->idx and are doubly
93 chained through prev/next fields. The later strinfos are required
94 to point into the same string with zero or more bytes after
95 the previous pointer and all bytes in between the two pointers
96 must be non-zero. Functions like strcpy or memcpy are supposed
97 to adjust all previous strinfo lengths, but not following strinfo
98 lengths (those are uncertain, usually invalidated during
99 maybe_invalidate, except when the alias oracle knows better).
100 Functions like strcat on the other side adjust the whole
101 related strinfo chain.
102 They are updated lazily, so to use the chain the same first fields
103 and si->prev->next == si->idx needs to be verified. */
107 /* A flag whether the string is known to be written in the current
110 /* A flag for the next maybe_invalidate that this strinfo shouldn't
111 be invalidated. Always cleared by maybe_invalidate. */
112 bool dont_invalidate
;
113 /* True if the string is known to be nul-terminated after NONZERO_CHARS
114 characters. False is useful when detecting strings that are built
115 up via successive memcpys. */
119 /* Pool for allocating strinfo_struct entries. */
120 static object_allocator
<strinfo
> strinfo_pool ("strinfo pool");
122 /* Vector mapping positive string indexes to strinfo, for the
123 current basic block. The first pointer in the vector is special,
124 it is either NULL, meaning the vector isn't shared, or it is
125 a basic block pointer to the owner basic_block if shared.
126 If some other bb wants to modify the vector, the vector needs
127 to be unshared first, and only the owner bb is supposed to free it. */
128 static vec
<strinfo
*, va_heap
, vl_embed
> *stridx_to_strinfo
;
130 /* One OFFSET->IDX mapping. */
133 struct stridxlist
*next
;
134 HOST_WIDE_INT offset
;
138 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
139 struct decl_stridxlist_map
141 struct tree_map_base base
;
142 struct stridxlist list
;
145 /* Hash table for mapping decls to a chained list of offset -> idx
147 static hash_map
<tree_decl_hash
, stridxlist
> *decl_to_stridxlist_htab
;
149 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
150 static struct obstack stridx_obstack
;
152 /* Last memcpy statement if it could be adjusted if the trailing
153 '\0' written is immediately overwritten, or
154 *x = '\0' store that could be removed if it is immediately overwritten. */
155 struct laststmt_struct
162 static int get_stridx_plus_constant (strinfo
*, unsigned HOST_WIDE_INT
, tree
);
166 - 1 if SI is known to start with more than OFF nonzero characters.
168 - 0 if SI is known to start with OFF nonzero characters,
169 but is not known to start with more.
171 - -1 if SI might not start with OFF nonzero characters. */
174 compare_nonzero_chars (strinfo
*si
, unsigned HOST_WIDE_INT off
)
176 if (si
->nonzero_chars
177 && TREE_CODE (si
->nonzero_chars
) == INTEGER_CST
)
178 return compare_tree_int (si
->nonzero_chars
, off
);
183 /* Return true if SI is known to be a zero-length string. */
186 zero_length_string_p (strinfo
*si
)
188 return si
->full_string_p
&& integer_zerop (si
->nonzero_chars
);
191 /* Return strinfo vector entry IDX. */
193 static inline strinfo
*
194 get_strinfo (int idx
)
196 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
198 return (*stridx_to_strinfo
)[idx
];
201 /* Get the next strinfo in the chain after SI, or null if none. */
203 static inline strinfo
*
204 get_next_strinfo (strinfo
*si
)
208 strinfo
*nextsi
= get_strinfo (si
->next
);
209 if (nextsi
== NULL
|| nextsi
->first
!= si
->first
|| nextsi
->prev
!= si
->idx
)
214 /* Helper function for get_stridx. Return the strinfo index of the address
215 of EXP, which is available in PTR if nonnull. If OFFSET_OUT, it is
216 OK to return the index for some X <= &EXP and store &EXP - X in
220 get_addr_stridx (tree exp
, tree ptr
, unsigned HOST_WIDE_INT
*offset_out
)
223 struct stridxlist
*list
, *last
= NULL
;
226 if (!decl_to_stridxlist_htab
)
229 base
= get_addr_base_and_unit_offset (exp
, &off
);
230 if (base
== NULL
|| !DECL_P (base
))
233 list
= decl_to_stridxlist_htab
->get (base
);
239 if (list
->offset
== off
)
245 if (list
->offset
> off
)
252 if ((offset_out
|| ptr
) && last
&& last
->idx
> 0)
254 unsigned HOST_WIDE_INT rel_off
255 = (unsigned HOST_WIDE_INT
) off
- last
->offset
;
256 strinfo
*si
= get_strinfo (last
->idx
);
257 if (si
&& compare_nonzero_chars (si
, rel_off
) >= 0)
261 *offset_out
= rel_off
;
265 return get_stridx_plus_constant (si
, rel_off
, ptr
);
271 /* Return string index for EXP. */
274 get_stridx (tree exp
)
278 if (TREE_CODE (exp
) == SSA_NAME
)
280 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
281 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
284 HOST_WIDE_INT off
= 0;
285 for (i
= 0; i
< 5; i
++)
287 gimple
*def_stmt
= SSA_NAME_DEF_STMT (e
);
288 if (!is_gimple_assign (def_stmt
)
289 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
291 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
292 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
293 if (TREE_CODE (rhs1
) != SSA_NAME
294 || !tree_fits_shwi_p (rhs2
))
296 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
299 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
302 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
305 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
306 if (si
&& compare_nonzero_chars (si
, off
) >= 0)
307 return get_stridx_plus_constant (si
, off
, exp
);
314 if (TREE_CODE (exp
) == ADDR_EXPR
)
316 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0), exp
, NULL
);
321 s
= string_constant (exp
, &o
);
323 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
324 && TREE_STRING_LENGTH (s
) > 0)
326 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
327 const char *p
= TREE_STRING_POINTER (s
);
328 int max
= TREE_STRING_LENGTH (s
) - 1;
330 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
331 return ~(int) strlen (p
+ offset
);
336 /* Return true if strinfo vector is shared with the immediate dominator. */
339 strinfo_shared (void)
341 return vec_safe_length (stridx_to_strinfo
)
342 && (*stridx_to_strinfo
)[0] != NULL
;
345 /* Unshare strinfo vector that is shared with the immediate dominator. */
348 unshare_strinfo_vec (void)
353 gcc_assert (strinfo_shared ());
354 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
355 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
358 (*stridx_to_strinfo
)[0] = NULL
;
361 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
362 Return a pointer to the location where the string index can
363 be stored (if 0) or is stored, or NULL if this can't be tracked. */
366 addr_stridxptr (tree exp
)
370 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
371 if (base
== NULL_TREE
|| !DECL_P (base
))
374 if (!decl_to_stridxlist_htab
)
376 decl_to_stridxlist_htab
377 = new hash_map
<tree_decl_hash
, stridxlist
> (64);
378 gcc_obstack_init (&stridx_obstack
);
382 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
386 stridxlist
*before
= NULL
;
387 for (i
= 0; i
< 32; i
++)
389 if (list
->offset
== off
)
391 if (list
->offset
> off
&& before
== NULL
)
393 if (list
->next
== NULL
)
402 before
= XOBNEW (&stridx_obstack
, struct stridxlist
);
409 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
419 /* Create a new string index, or return 0 if reached limit. */
422 new_stridx (tree exp
)
425 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
427 if (TREE_CODE (exp
) == SSA_NAME
)
429 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
432 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
435 if (TREE_CODE (exp
) == ADDR_EXPR
)
437 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
440 gcc_assert (*pidx
== 0);
441 *pidx
= max_stridx
++;
448 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
451 new_addr_stridx (tree exp
)
454 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
456 pidx
= addr_stridxptr (exp
);
459 gcc_assert (*pidx
== 0);
460 *pidx
= max_stridx
++;
466 /* Create a new strinfo. */
469 new_strinfo (tree ptr
, int idx
, tree nonzero_chars
, bool full_string_p
)
471 strinfo
*si
= strinfo_pool
.allocate ();
472 si
->nonzero_chars
= nonzero_chars
;
475 si
->endptr
= NULL_TREE
;
481 si
->writable
= false;
482 si
->dont_invalidate
= false;
483 si
->full_string_p
= full_string_p
;
487 /* Decrease strinfo refcount and free it if not referenced anymore. */
490 free_strinfo (strinfo
*si
)
492 if (si
&& --si
->refcount
== 0)
493 strinfo_pool
.remove (si
);
496 /* Set strinfo in the vector entry IDX to SI. */
499 set_strinfo (int idx
, strinfo
*si
)
501 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
502 unshare_strinfo_vec ();
503 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
504 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
505 (*stridx_to_strinfo
)[idx
] = si
;
508 /* Return the first strinfo in the related strinfo chain
509 if all strinfos in between belong to the chain, otherwise NULL. */
512 verify_related_strinfos (strinfo
*origsi
)
514 strinfo
*si
= origsi
, *psi
;
516 if (origsi
->first
== 0)
518 for (; si
->prev
; si
= psi
)
520 if (si
->first
!= origsi
->first
)
522 psi
= get_strinfo (si
->prev
);
525 if (psi
->next
!= si
->idx
)
528 if (si
->idx
!= si
->first
)
533 /* Set SI's endptr to ENDPTR and compute its length based on SI->ptr.
534 Use LOC for folding. */
537 set_endptr_and_length (location_t loc
, strinfo
*si
, tree endptr
)
541 tree start_as_size
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
542 tree end_as_size
= fold_convert_loc (loc
, size_type_node
, endptr
);
543 si
->nonzero_chars
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
544 end_as_size
, start_as_size
);
545 si
->full_string_p
= true;
548 /* Return string length, or NULL if it can't be computed. */
551 get_string_length (strinfo
*si
)
553 if (si
->nonzero_chars
)
554 return si
->full_string_p
? si
->nonzero_chars
: NULL
;
558 gimple
*stmt
= si
->stmt
, *lenstmt
;
559 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
560 tree callee
, lhs
, fn
, tem
;
562 gimple_stmt_iterator gsi
;
564 gcc_assert (is_gimple_call (stmt
));
565 callee
= gimple_call_fndecl (stmt
);
566 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
567 lhs
= gimple_call_lhs (stmt
);
568 /* unshare_strinfo is intentionally not called here. The (delayed)
569 transformation of strcpy or strcat into stpcpy is done at the place
570 of the former strcpy/strcat call and so can affect all the strinfos
571 with the same stmt. If they were unshared before and transformation
572 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
573 just compute the right length. */
574 switch (DECL_FUNCTION_CODE (callee
))
576 case BUILT_IN_STRCAT
:
577 case BUILT_IN_STRCAT_CHK
:
578 case BUILT_IN_STRCAT_CHKP
:
579 case BUILT_IN_STRCAT_CHK_CHKP
:
580 gsi
= gsi_for_stmt (stmt
);
581 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
582 gcc_assert (lhs
== NULL_TREE
);
583 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
586 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
587 2, tem
, gimple_call_arg (stmt
, 1));
588 gimple_call_set_with_bounds (lenstmt
, true);
591 lenstmt
= gimple_build_call (fn
, 1, tem
);
592 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
593 gimple_call_set_lhs (lenstmt
, lhs
);
594 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
595 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
596 tem
= gimple_call_arg (stmt
, 0);
597 if (!ptrofftype_p (TREE_TYPE (lhs
)))
599 lhs
= convert_to_ptrofftype (lhs
);
600 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
601 true, GSI_SAME_STMT
);
603 lenstmt
= gimple_build_assign
604 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
605 POINTER_PLUS_EXPR
,tem
, lhs
);
606 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
607 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
610 case BUILT_IN_STRCPY
:
611 case BUILT_IN_STRCPY_CHK
:
612 case BUILT_IN_STRCPY_CHKP
:
613 case BUILT_IN_STRCPY_CHK_CHKP
:
614 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
615 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
616 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
618 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
620 fn
= chkp_maybe_create_clone (fn
)->decl
;
621 gcc_assert (lhs
== NULL_TREE
);
622 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
624 fprintf (dump_file
, "Optimizing: ");
625 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
627 gimple_call_set_fndecl (stmt
, fn
);
628 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
629 gimple_call_set_lhs (stmt
, lhs
);
631 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
633 fprintf (dump_file
, "into: ");
634 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
637 case BUILT_IN_STPCPY
:
638 case BUILT_IN_STPCPY_CHK
:
639 case BUILT_IN_STPCPY_CHKP
:
640 case BUILT_IN_STPCPY_CHK_CHKP
:
641 gcc_assert (lhs
!= NULL_TREE
);
642 loc
= gimple_location (stmt
);
643 set_endptr_and_length (loc
, si
, lhs
);
644 for (strinfo
*chainsi
= verify_related_strinfos (si
);
646 chainsi
= get_next_strinfo (chainsi
))
647 if (chainsi
->nonzero_chars
== NULL
)
648 set_endptr_and_length (loc
, chainsi
, lhs
);
650 case BUILT_IN_MALLOC
:
652 /* BUILT_IN_CALLOC always has si->nonzero_chars set. */
659 return si
->nonzero_chars
;
662 /* Invalidate string length information for strings whose length
663 might change due to stores in stmt. */
666 maybe_invalidate (gimple
*stmt
)
670 bool nonempty
= false;
672 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
675 if (!si
->dont_invalidate
)
678 /* Do not use si->nonzero_chars. */
679 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
680 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
682 set_strinfo (i
, NULL
);
687 si
->dont_invalidate
= false;
693 /* Unshare strinfo record SI, if it has refcount > 1 or
694 if stridx_to_strinfo vector is shared with some other
698 unshare_strinfo (strinfo
*si
)
702 if (si
->refcount
== 1 && !strinfo_shared ())
705 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->nonzero_chars
, si
->full_string_p
);
706 nsi
->stmt
= si
->stmt
;
707 nsi
->endptr
= si
->endptr
;
708 nsi
->first
= si
->first
;
709 nsi
->prev
= si
->prev
;
710 nsi
->next
= si
->next
;
711 nsi
->writable
= si
->writable
;
712 set_strinfo (si
->idx
, nsi
);
717 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
718 strinfo if there is any. Return it's idx, or 0 if no strinfo has
722 get_stridx_plus_constant (strinfo
*basesi
, unsigned HOST_WIDE_INT off
,
725 if (TREE_CODE (ptr
) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
728 if (compare_nonzero_chars (basesi
, off
) < 0
729 || !tree_fits_uhwi_p (basesi
->nonzero_chars
))
732 unsigned HOST_WIDE_INT nonzero_chars
733 = tree_to_uhwi (basesi
->nonzero_chars
) - off
;
734 strinfo
*si
= basesi
, *chainsi
;
735 if (si
->first
|| si
->prev
|| si
->next
)
736 si
= verify_related_strinfos (basesi
);
738 || si
->nonzero_chars
== NULL_TREE
739 || TREE_CODE (si
->nonzero_chars
) != INTEGER_CST
)
742 if (TREE_CODE (ptr
) == SSA_NAME
743 && ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
744 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
746 gcc_checking_assert (compare_tree_int (si
->nonzero_chars
, off
) != -1);
747 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
749 si
= get_next_strinfo (chainsi
);
751 || si
->nonzero_chars
== NULL_TREE
752 || TREE_CODE (si
->nonzero_chars
) != INTEGER_CST
)
754 int r
= compare_tree_int (si
->nonzero_chars
, nonzero_chars
);
759 if (TREE_CODE (ptr
) == SSA_NAME
)
760 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
763 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
764 if (pidx
!= NULL
&& *pidx
== 0)
773 int idx
= new_stridx (ptr
);
776 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, nonzero_chars
),
777 basesi
->full_string_p
);
778 set_strinfo (idx
, si
);
781 strinfo
*nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
782 si
->next
= nextsi
->idx
;
785 chainsi
= unshare_strinfo (chainsi
);
786 if (chainsi
->first
== 0)
787 chainsi
->first
= chainsi
->idx
;
789 if (chainsi
->endptr
== NULL_TREE
&& zero_length_string_p (si
))
790 chainsi
->endptr
= ptr
;
791 si
->endptr
= chainsi
->endptr
;
792 si
->prev
= chainsi
->idx
;
793 si
->first
= chainsi
->first
;
794 si
->writable
= chainsi
->writable
;
798 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
799 to a zero-length string and if possible chain it to a related strinfo
800 chain whose part is or might be CHAINSI. */
803 zero_length_string (tree ptr
, strinfo
*chainsi
)
807 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
808 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
809 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
810 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
812 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
816 si
= verify_related_strinfos (chainsi
);
821 /* We shouldn't mix delayed and non-delayed lengths. */
822 gcc_assert (si
->full_string_p
);
823 if (si
->endptr
== NULL_TREE
)
825 si
= unshare_strinfo (si
);
829 si
= get_next_strinfo (si
);
832 if (zero_length_string_p (chainsi
))
836 chainsi
= unshare_strinfo (chainsi
);
839 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
845 /* We shouldn't mix delayed and non-delayed lengths. */
846 gcc_assert (chainsi
->full_string_p
);
847 if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
849 chainsi
= unshare_strinfo (chainsi
);
856 idx
= new_stridx (ptr
);
859 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0), true);
860 set_strinfo (idx
, si
);
864 chainsi
= unshare_strinfo (chainsi
);
865 if (chainsi
->first
== 0)
866 chainsi
->first
= chainsi
->idx
;
868 if (chainsi
->endptr
== NULL_TREE
)
869 chainsi
->endptr
= ptr
;
870 si
->prev
= chainsi
->idx
;
871 si
->first
= chainsi
->first
;
872 si
->writable
= chainsi
->writable
;
877 /* For strinfo ORIGSI whose length has been just updated, adjust other
878 related strinfos so that they match the new ORIGSI. This involves:
880 - adding ADJ to the nonzero_chars fields
881 - copying full_string_p from the new ORIGSI. */
884 adjust_related_strinfos (location_t loc
, strinfo
*origsi
, tree adj
)
886 strinfo
*si
= verify_related_strinfos (origsi
);
899 si
= unshare_strinfo (si
);
900 /* We shouldn't see delayed lengths here; the caller must have
901 calculated the old length in order to calculate the
903 gcc_assert (si
->nonzero_chars
);
904 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->nonzero_chars
), adj
);
905 si
->nonzero_chars
= fold_build2_loc (loc
, PLUS_EXPR
,
906 TREE_TYPE (si
->nonzero_chars
),
907 si
->nonzero_chars
, tem
);
908 si
->full_string_p
= origsi
->full_string_p
;
910 si
->endptr
= NULL_TREE
;
911 si
->dont_invalidate
= true;
913 nsi
= get_next_strinfo (si
);
920 /* Find if there are other SSA_NAME pointers equal to PTR
921 for which we don't track their string lengths yet. If so, use
925 find_equal_ptrs (tree ptr
, int idx
)
927 if (TREE_CODE (ptr
) != SSA_NAME
)
931 gimple
*stmt
= SSA_NAME_DEF_STMT (ptr
);
932 if (!is_gimple_assign (stmt
))
934 ptr
= gimple_assign_rhs1 (stmt
);
935 switch (gimple_assign_rhs_code (stmt
))
940 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
942 if (TREE_CODE (ptr
) == SSA_NAME
)
944 if (TREE_CODE (ptr
) != ADDR_EXPR
)
949 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
950 if (pidx
!= NULL
&& *pidx
== 0)
958 /* We might find an endptr created in this pass. Grow the
959 vector in that case. */
960 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
961 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
963 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
965 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
969 /* Return true if STMT is a call to a builtin function with the right
970 arguments and attributes that should be considered for optimization
974 valid_builtin_call (gimple
*stmt
)
976 if (!gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
979 tree callee
= gimple_call_fndecl (stmt
);
980 switch (DECL_FUNCTION_CODE (callee
))
982 case BUILT_IN_MEMCMP
:
983 case BUILT_IN_MEMCMP_EQ
:
984 case BUILT_IN_STRCHR
:
985 case BUILT_IN_STRCHR_CHKP
:
986 case BUILT_IN_STRLEN
:
987 case BUILT_IN_STRLEN_CHKP
:
988 /* The above functions should be pure. Punt if they aren't. */
989 if (gimple_vdef (stmt
) || gimple_vuse (stmt
) == NULL_TREE
)
993 case BUILT_IN_CALLOC
:
994 case BUILT_IN_MALLOC
:
995 case BUILT_IN_MEMCPY
:
996 case BUILT_IN_MEMCPY_CHK
:
997 case BUILT_IN_MEMCPY_CHKP
:
998 case BUILT_IN_MEMCPY_CHK_CHKP
:
999 case BUILT_IN_MEMPCPY
:
1000 case BUILT_IN_MEMPCPY_CHK
:
1001 case BUILT_IN_MEMPCPY_CHKP
:
1002 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1003 case BUILT_IN_MEMSET
:
1004 case BUILT_IN_STPCPY
:
1005 case BUILT_IN_STPCPY_CHK
:
1006 case BUILT_IN_STPCPY_CHKP
:
1007 case BUILT_IN_STPCPY_CHK_CHKP
:
1008 case BUILT_IN_STRCAT
:
1009 case BUILT_IN_STRCAT_CHK
:
1010 case BUILT_IN_STRCAT_CHKP
:
1011 case BUILT_IN_STRCAT_CHK_CHKP
:
1012 case BUILT_IN_STRCPY
:
1013 case BUILT_IN_STRCPY_CHK
:
1014 case BUILT_IN_STRCPY_CHKP
:
1015 case BUILT_IN_STRCPY_CHK_CHKP
:
1016 /* The above functions should be neither const nor pure. Punt if they
1018 if (gimple_vdef (stmt
) == NULL_TREE
|| gimple_vuse (stmt
) == NULL_TREE
)
1029 /* If the last .MEM setter statement before STMT is
1030 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
1031 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
1032 just memcpy (x, y, strlen (y)). SI must be the zero length
1036 adjust_last_stmt (strinfo
*si
, gimple
*stmt
, bool is_strcat
)
1038 tree vuse
, callee
, len
;
1039 struct laststmt_struct last
= laststmt
;
1040 strinfo
*lastsi
, *firstsi
;
1041 unsigned len_arg_no
= 2;
1043 laststmt
.stmt
= NULL
;
1044 laststmt
.len
= NULL_TREE
;
1045 laststmt
.stridx
= 0;
1047 if (last
.stmt
== NULL
)
1050 vuse
= gimple_vuse (stmt
);
1051 if (vuse
== NULL_TREE
1052 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
1053 || !has_single_use (vuse
))
1056 gcc_assert (last
.stridx
> 0);
1057 lastsi
= get_strinfo (last
.stridx
);
1063 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
1066 firstsi
= verify_related_strinfos (si
);
1067 if (firstsi
== NULL
)
1069 while (firstsi
!= lastsi
)
1071 firstsi
= get_next_strinfo (firstsi
);
1072 if (firstsi
== NULL
)
1077 if (!is_strcat
&& !zero_length_string_p (si
))
1080 if (is_gimple_assign (last
.stmt
))
1082 gimple_stmt_iterator gsi
;
1084 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
1086 if (stmt_could_throw_p (last
.stmt
))
1088 gsi
= gsi_for_stmt (last
.stmt
);
1089 unlink_stmt_vdef (last
.stmt
);
1090 release_defs (last
.stmt
);
1091 gsi_remove (&gsi
, true);
1095 if (!valid_builtin_call (last
.stmt
))
1098 callee
= gimple_call_fndecl (last
.stmt
);
1099 switch (DECL_FUNCTION_CODE (callee
))
1101 case BUILT_IN_MEMCPY
:
1102 case BUILT_IN_MEMCPY_CHK
:
1104 case BUILT_IN_MEMCPY_CHKP
:
1105 case BUILT_IN_MEMCPY_CHK_CHKP
:
1112 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
1113 if (tree_fits_uhwi_p (len
))
1115 if (!tree_fits_uhwi_p (last
.len
)
1116 || integer_zerop (len
)
1117 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
1119 /* Don't adjust the length if it is divisible by 4, it is more efficient
1120 to store the extra '\0' in that case. */
1121 if ((tree_to_uhwi (len
) & 3) == 0)
1124 else if (TREE_CODE (len
) == SSA_NAME
)
1126 gimple
*def_stmt
= SSA_NAME_DEF_STMT (len
);
1127 if (!is_gimple_assign (def_stmt
)
1128 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1129 || gimple_assign_rhs1 (def_stmt
) != last
.len
1130 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1136 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
1137 update_stmt (last
.stmt
);
1140 /* Handle a strlen call. If strlen of the argument is known, replace
1141 the strlen call with the known value, otherwise remember that strlen
1142 of the argument is stored in the lhs SSA_NAME. */
1145 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1149 gimple
*stmt
= gsi_stmt (*gsi
);
1150 tree lhs
= gimple_call_lhs (stmt
);
1152 if (lhs
== NULL_TREE
)
1155 src
= gimple_call_arg (stmt
, 0);
1156 idx
= get_stridx (src
);
1163 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1167 si
= get_strinfo (idx
);
1169 rhs
= get_string_length (si
);
1171 if (rhs
!= NULL_TREE
)
1173 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1175 fprintf (dump_file
, "Optimizing: ");
1176 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1178 rhs
= unshare_expr (rhs
);
1179 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1180 rhs
= fold_convert_loc (gimple_location (stmt
),
1181 TREE_TYPE (lhs
), rhs
);
1182 if (!update_call_from_tree (gsi
, rhs
))
1183 gimplify_and_update_call_from_tree (gsi
, rhs
);
1184 stmt
= gsi_stmt (*gsi
);
1186 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1188 fprintf (dump_file
, "into: ");
1189 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1192 && TREE_CODE (si
->nonzero_chars
) != SSA_NAME
1193 && TREE_CODE (si
->nonzero_chars
) != INTEGER_CST
1194 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1196 si
= unshare_strinfo (si
);
1197 si
->nonzero_chars
= lhs
;
1198 gcc_assert (si
->full_string_p
);
1203 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1206 idx
= new_stridx (src
);
1209 strinfo
*si
= get_strinfo (idx
);
1212 if (!si
->full_string_p
&& !si
->stmt
)
1214 /* Until now we only had a lower bound on the string length.
1215 Install LHS as the actual length. */
1216 si
= unshare_strinfo (si
);
1217 tree old
= si
->nonzero_chars
;
1218 si
->nonzero_chars
= lhs
;
1219 si
->full_string_p
= true;
1220 if (TREE_CODE (old
) == INTEGER_CST
)
1222 location_t loc
= gimple_location (stmt
);
1223 old
= fold_convert_loc (loc
, TREE_TYPE (lhs
), old
);
1224 tree adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1225 TREE_TYPE (lhs
), lhs
, old
);
1226 adjust_related_strinfos (loc
, si
, adj
);
1240 strinfo
*si
= new_strinfo (src
, idx
, lhs
, true);
1241 set_strinfo (idx
, si
);
1242 find_equal_ptrs (src
, idx
);
1246 /* Handle a strchr call. If strlen of the first argument is known, replace
1247 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1248 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1251 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1255 gimple
*stmt
= gsi_stmt (*gsi
);
1256 tree lhs
= gimple_call_lhs (stmt
);
1257 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1259 if (lhs
== NULL_TREE
)
1262 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1265 src
= gimple_call_arg (stmt
, 0);
1266 idx
= get_stridx (src
);
1273 rhs
= build_int_cst (size_type_node
, ~idx
);
1277 si
= get_strinfo (idx
);
1279 rhs
= get_string_length (si
);
1281 if (rhs
!= NULL_TREE
)
1283 location_t loc
= gimple_location (stmt
);
1285 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1287 fprintf (dump_file
, "Optimizing: ");
1288 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1290 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1292 rhs
= unshare_expr (si
->endptr
);
1293 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1295 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1299 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1300 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1301 TREE_TYPE (src
), src
, rhs
);
1302 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1304 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1306 if (!update_call_from_tree (gsi
, rhs
))
1307 gimplify_and_update_call_from_tree (gsi
, rhs
);
1308 stmt
= gsi_stmt (*gsi
);
1310 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1312 fprintf (dump_file
, "into: ");
1313 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1316 && si
->endptr
== NULL_TREE
1317 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1319 si
= unshare_strinfo (si
);
1322 zero_length_string (lhs
, si
);
1326 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1328 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1331 idx
= new_stridx (src
);
1332 else if (get_strinfo (idx
) != NULL
)
1334 zero_length_string (lhs
, NULL
);
1339 location_t loc
= gimple_location (stmt
);
1340 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1341 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1342 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1343 size_type_node
, lhsu
, srcu
);
1344 strinfo
*si
= new_strinfo (src
, idx
, length
, true);
1346 set_strinfo (idx
, si
);
1347 find_equal_ptrs (src
, idx
);
1348 zero_length_string (lhs
, si
);
1352 zero_length_string (lhs
, NULL
);
1355 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1356 If strlen of the second argument is known, strlen of the first argument
1357 is the same after this call. Furthermore, attempt to convert it to
1361 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1364 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1366 gimple
*stmt
= gsi_stmt (*gsi
);
1367 strinfo
*si
, *dsi
, *olddsi
, *zsi
;
1369 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1371 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1372 dst
= gimple_call_arg (stmt
, 0);
1373 lhs
= gimple_call_lhs (stmt
);
1374 idx
= get_stridx (src
);
1377 si
= get_strinfo (idx
);
1379 didx
= get_stridx (dst
);
1383 olddsi
= get_strinfo (didx
);
1388 adjust_last_stmt (olddsi
, stmt
, false);
1392 srclen
= get_string_length (si
);
1394 srclen
= build_int_cst (size_type_node
, ~idx
);
1396 loc
= gimple_location (stmt
);
1397 if (srclen
== NULL_TREE
)
1400 case BUILT_IN_STRCPY
:
1401 case BUILT_IN_STRCPY_CHK
:
1402 case BUILT_IN_STRCPY_CHKP
:
1403 case BUILT_IN_STRCPY_CHK_CHKP
:
1404 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1407 case BUILT_IN_STPCPY
:
1408 case BUILT_IN_STPCPY_CHK
:
1409 case BUILT_IN_STPCPY_CHKP
:
1410 case BUILT_IN_STPCPY_CHK_CHKP
:
1411 if (lhs
== NULL_TREE
)
1415 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1416 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1417 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1427 didx
= new_stridx (dst
);
1433 oldlen
= olddsi
->nonzero_chars
;
1434 dsi
= unshare_strinfo (olddsi
);
1435 dsi
->nonzero_chars
= srclen
;
1436 dsi
->full_string_p
= (srclen
!= NULL_TREE
);
1437 /* Break the chain, so adjust_related_strinfo on later pointers in
1438 the chain won't adjust this one anymore. */
1441 dsi
->endptr
= NULL_TREE
;
1445 dsi
= new_strinfo (dst
, didx
, srclen
, srclen
!= NULL_TREE
);
1446 set_strinfo (didx
, dsi
);
1447 find_equal_ptrs (dst
, didx
);
1449 dsi
->writable
= true;
1450 dsi
->dont_invalidate
= true;
1452 if (dsi
->nonzero_chars
== NULL_TREE
)
1456 /* If string length of src is unknown, use delayed length
1457 computation. If string lenth of dst will be needed, it
1458 can be computed by transforming this strcpy call into
1459 stpcpy and subtracting dst from the return value. */
1461 /* Look for earlier strings whose length could be determined if
1462 this strcpy is turned into an stpcpy. */
1464 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1466 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1468 /* When setting a stmt for delayed length computation
1469 prevent all strinfos through dsi from being
1471 chainsi
= unshare_strinfo (chainsi
);
1472 chainsi
->stmt
= stmt
;
1473 chainsi
->nonzero_chars
= NULL_TREE
;
1474 chainsi
->full_string_p
= false;
1475 chainsi
->endptr
= NULL_TREE
;
1476 chainsi
->dont_invalidate
= true;
1485 tree adj
= NULL_TREE
;
1486 if (oldlen
== NULL_TREE
)
1488 else if (integer_zerop (oldlen
))
1490 else if (TREE_CODE (oldlen
) == INTEGER_CST
1491 || TREE_CODE (srclen
) == INTEGER_CST
)
1492 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1493 TREE_TYPE (srclen
), srclen
,
1494 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1496 if (adj
!= NULL_TREE
)
1497 adjust_related_strinfos (loc
, dsi
, adj
);
1501 /* strcpy src may not overlap dst, so src doesn't need to be
1502 invalidated either. */
1504 si
->dont_invalidate
= true;
1510 case BUILT_IN_STRCPY
:
1511 case BUILT_IN_STRCPY_CHKP
:
1512 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1514 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1516 case BUILT_IN_STRCPY_CHK
:
1517 case BUILT_IN_STRCPY_CHK_CHKP
:
1518 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1520 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1522 case BUILT_IN_STPCPY
:
1523 case BUILT_IN_STPCPY_CHKP
:
1524 /* This would need adjustment of the lhs (subtract one),
1525 or detection that the trailing '\0' doesn't need to be
1526 written, if it will be immediately overwritten.
1527 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1531 zsi
= zero_length_string (lhs
, dsi
);
1534 case BUILT_IN_STPCPY_CHK
:
1535 case BUILT_IN_STPCPY_CHK_CHKP
:
1536 /* This would need adjustment of the lhs (subtract one),
1537 or detection that the trailing '\0' doesn't need to be
1538 written, if it will be immediately overwritten.
1539 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1543 zsi
= zero_length_string (lhs
, dsi
);
1550 zsi
->dont_invalidate
= true;
1552 if (fn
== NULL_TREE
)
1555 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1556 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1558 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1559 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1560 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1562 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1564 fprintf (dump_file
, "Optimizing: ");
1565 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1569 fn
= chkp_maybe_create_clone (fn
)->decl
;
1570 if (gimple_call_num_args (stmt
) == 4)
1571 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1572 gimple_call_arg (stmt
, 1),
1574 gimple_call_arg (stmt
, 3),
1577 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1578 gimple_call_arg (stmt
, 1),
1580 gimple_call_arg (stmt
, 3),
1582 gimple_call_arg (stmt
, 4));
1585 if (gimple_call_num_args (stmt
) == 2)
1586 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1588 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1589 gimple_call_arg (stmt
, 2));
1592 stmt
= gsi_stmt (*gsi
);
1593 gimple_call_set_with_bounds (stmt
, with_bounds
);
1595 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1597 fprintf (dump_file
, "into: ");
1598 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1600 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1601 laststmt
.stmt
= stmt
;
1602 laststmt
.len
= srclen
;
1603 laststmt
.stridx
= dsi
->idx
;
1605 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1606 fprintf (dump_file
, "not possible.\n");
1609 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1610 If strlen of the second argument is known and length of the third argument
1611 is that plus one, strlen of the first argument is the same after this
1615 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1618 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1619 gimple
*stmt
= gsi_stmt (*gsi
);
1620 strinfo
*si
, *dsi
, *olddsi
;
1621 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1623 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1624 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1625 dst
= gimple_call_arg (stmt
, 0);
1626 idx
= get_stridx (src
);
1630 didx
= get_stridx (dst
);
1633 olddsi
= get_strinfo (didx
);
1638 && tree_fits_uhwi_p (len
)
1639 && !integer_zerop (len
))
1640 adjust_last_stmt (olddsi
, stmt
, false);
1647 /* Handle memcpy (x, y, l) where l's relationship with strlen (y)
1649 si
= get_strinfo (idx
);
1650 if (si
== NULL
|| si
->nonzero_chars
== NULL_TREE
)
1652 if (TREE_CODE (len
) == INTEGER_CST
1653 && TREE_CODE (si
->nonzero_chars
) == INTEGER_CST
)
1655 if (tree_int_cst_le (len
, si
->nonzero_chars
))
1657 /* Copying LEN nonzero characters, where LEN is constant. */
1659 full_string_p
= false;
1663 /* Copying the whole of the analyzed part of SI. */
1664 newlen
= si
->nonzero_chars
;
1665 full_string_p
= si
->full_string_p
;
1670 if (!si
->full_string_p
)
1672 if (TREE_CODE (len
) != SSA_NAME
)
1674 def_stmt
= SSA_NAME_DEF_STMT (len
);
1675 if (!is_gimple_assign (def_stmt
)
1676 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1677 || gimple_assign_rhs1 (def_stmt
) != si
->nonzero_chars
1678 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1680 /* Copying variable-length string SI (and no more). */
1681 newlen
= si
->nonzero_chars
;
1682 full_string_p
= true;
1688 /* Handle memcpy (x, "abcd", 5) or
1689 memcpy (x, "abc\0uvw", 7). */
1690 if (!tree_fits_uhwi_p (len
))
1693 unsigned HOST_WIDE_INT clen
= tree_to_uhwi (len
);
1694 unsigned HOST_WIDE_INT nonzero_chars
= ~idx
;
1695 newlen
= build_int_cst (size_type_node
, MIN (nonzero_chars
, clen
));
1696 full_string_p
= clen
> nonzero_chars
;
1699 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1700 adjust_last_stmt (olddsi
, stmt
, false);
1704 didx
= new_stridx (dst
);
1711 dsi
= unshare_strinfo (olddsi
);
1712 oldlen
= olddsi
->nonzero_chars
;
1713 dsi
->nonzero_chars
= newlen
;
1714 dsi
->full_string_p
= full_string_p
;
1715 /* Break the chain, so adjust_related_strinfo on later pointers in
1716 the chain won't adjust this one anymore. */
1719 dsi
->endptr
= NULL_TREE
;
1723 dsi
= new_strinfo (dst
, didx
, newlen
, full_string_p
);
1724 set_strinfo (didx
, dsi
);
1725 find_equal_ptrs (dst
, didx
);
1727 dsi
->writable
= true;
1728 dsi
->dont_invalidate
= true;
1731 tree adj
= NULL_TREE
;
1732 location_t loc
= gimple_location (stmt
);
1733 if (oldlen
== NULL_TREE
)
1735 else if (integer_zerop (oldlen
))
1737 else if (TREE_CODE (oldlen
) == INTEGER_CST
1738 || TREE_CODE (newlen
) == INTEGER_CST
)
1739 adj
= fold_build2_loc (loc
, MINUS_EXPR
, TREE_TYPE (newlen
), newlen
,
1740 fold_convert_loc (loc
, TREE_TYPE (newlen
),
1742 if (adj
!= NULL_TREE
)
1743 adjust_related_strinfos (loc
, dsi
, adj
);
1747 /* memcpy src may not overlap dst, so src doesn't need to be
1748 invalidated either. */
1750 si
->dont_invalidate
= true;
1754 lhs
= gimple_call_lhs (stmt
);
1757 case BUILT_IN_MEMCPY
:
1758 case BUILT_IN_MEMCPY_CHK
:
1759 case BUILT_IN_MEMCPY_CHKP
:
1760 case BUILT_IN_MEMCPY_CHK_CHKP
:
1761 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1762 laststmt
.stmt
= stmt
;
1763 laststmt
.len
= dsi
->nonzero_chars
;
1764 laststmt
.stridx
= dsi
->idx
;
1766 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1768 case BUILT_IN_MEMPCPY
:
1769 case BUILT_IN_MEMPCPY_CHK
:
1770 case BUILT_IN_MEMPCPY_CHKP
:
1771 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1779 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1780 If strlen of the second argument is known, strlen of the first argument
1781 is increased by the length of the second argument. Furthermore, attempt
1782 to convert it to memcpy/strcpy if the length of the first argument
1786 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1789 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1791 gimple
*stmt
= gsi_stmt (*gsi
);
1794 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1796 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1797 dst
= gimple_call_arg (stmt
, 0);
1798 lhs
= gimple_call_lhs (stmt
);
1800 didx
= get_stridx (dst
);
1806 dsi
= get_strinfo (didx
);
1807 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1809 /* strcat (p, q) can be transformed into
1810 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1811 with length endptr - p if we need to compute the length
1812 later on. Don't do this transformation if we don't need
1814 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1818 didx
= new_stridx (dst
);
1824 dsi
= new_strinfo (dst
, didx
, NULL_TREE
, false);
1825 set_strinfo (didx
, dsi
);
1826 find_equal_ptrs (dst
, didx
);
1830 dsi
= unshare_strinfo (dsi
);
1831 dsi
->nonzero_chars
= NULL_TREE
;
1832 dsi
->full_string_p
= false;
1834 dsi
->endptr
= NULL_TREE
;
1836 dsi
->writable
= true;
1838 dsi
->dont_invalidate
= true;
1845 idx
= get_stridx (src
);
1847 srclen
= build_int_cst (size_type_node
, ~idx
);
1850 si
= get_strinfo (idx
);
1852 srclen
= get_string_length (si
);
1855 loc
= gimple_location (stmt
);
1856 dstlen
= dsi
->nonzero_chars
;
1857 endptr
= dsi
->endptr
;
1859 dsi
= unshare_strinfo (dsi
);
1860 dsi
->endptr
= NULL_TREE
;
1862 dsi
->writable
= true;
1864 if (srclen
!= NULL_TREE
)
1866 dsi
->nonzero_chars
= fold_build2_loc (loc
, PLUS_EXPR
,
1867 TREE_TYPE (dsi
->nonzero_chars
),
1868 dsi
->nonzero_chars
, srclen
);
1869 gcc_assert (dsi
->full_string_p
);
1870 adjust_related_strinfos (loc
, dsi
, srclen
);
1871 dsi
->dont_invalidate
= true;
1875 dsi
->nonzero_chars
= NULL
;
1876 dsi
->full_string_p
= false;
1877 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1878 dsi
->dont_invalidate
= true;
1882 /* strcat src may not overlap dst, so src doesn't need to be
1883 invalidated either. */
1884 si
->dont_invalidate
= true;
1886 /* For now. Could remove the lhs from the call and add
1887 lhs = dst; afterwards. */
1895 case BUILT_IN_STRCAT
:
1896 case BUILT_IN_STRCAT_CHKP
:
1897 if (srclen
!= NULL_TREE
)
1898 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1900 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1902 case BUILT_IN_STRCAT_CHK
:
1903 case BUILT_IN_STRCAT_CHK_CHKP
:
1904 if (srclen
!= NULL_TREE
)
1905 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1907 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1908 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1914 if (fn
== NULL_TREE
)
1918 if (srclen
!= NULL_TREE
)
1920 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1921 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1923 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1924 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1925 build_int_cst (type
, 1));
1926 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1930 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1932 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1933 TREE_TYPE (dst
), unshare_expr (dst
),
1934 fold_convert_loc (loc
, sizetype
,
1935 unshare_expr (dstlen
)));
1936 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1938 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1940 fprintf (dump_file
, "Optimizing: ");
1941 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1945 fn
= chkp_maybe_create_clone (fn
)->decl
;
1946 if (srclen
!= NULL_TREE
)
1947 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1949 gimple_call_arg (stmt
, 1),
1951 gimple_call_arg (stmt
, 3),
1954 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1956 gimple_call_arg (stmt
, 1),
1958 gimple_call_arg (stmt
, 3),
1962 if (srclen
!= NULL_TREE
)
1963 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1964 dst
, src
, len
, objsz
);
1966 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1970 stmt
= gsi_stmt (*gsi
);
1971 gimple_call_set_with_bounds (stmt
, with_bounds
);
1973 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1975 fprintf (dump_file
, "into: ");
1976 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1978 /* If srclen == NULL, note that current string length can be
1979 computed by transforming this strcpy into stpcpy. */
1980 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1982 adjust_last_stmt (dsi
, stmt
, true);
1983 if (srclen
!= NULL_TREE
)
1985 laststmt
.stmt
= stmt
;
1986 laststmt
.len
= srclen
;
1987 laststmt
.stridx
= dsi
->idx
;
1990 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1991 fprintf (dump_file
, "not possible.\n");
1994 /* Handle a call to malloc or calloc. */
1997 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1999 gimple
*stmt
= gsi_stmt (*gsi
);
2000 tree lhs
= gimple_call_lhs (stmt
);
2001 if (lhs
== NULL_TREE
)
2004 gcc_assert (get_stridx (lhs
) == 0);
2005 int idx
= new_stridx (lhs
);
2006 tree length
= NULL_TREE
;
2007 if (bcode
== BUILT_IN_CALLOC
)
2008 length
= build_int_cst (size_type_node
, 0);
2009 strinfo
*si
= new_strinfo (lhs
, idx
, length
, length
!= NULL_TREE
);
2010 if (bcode
== BUILT_IN_CALLOC
)
2012 set_strinfo (idx
, si
);
2013 si
->writable
= true;
2015 si
->dont_invalidate
= true;
2018 /* Handle a call to memset.
2019 After a call to calloc, memset(,0,) is unnecessary.
2020 memset(malloc(n),0,n) is calloc(n,1). */
2023 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
2025 gimple
*stmt2
= gsi_stmt (*gsi
);
2026 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
2028 tree ptr
= gimple_call_arg (stmt2
, 0);
2029 int idx1
= get_stridx (ptr
);
2032 strinfo
*si1
= get_strinfo (idx1
);
2035 gimple
*stmt1
= si1
->stmt
;
2036 if (!stmt1
|| !is_gimple_call (stmt1
))
2038 tree callee1
= gimple_call_fndecl (stmt1
);
2039 if (!valid_builtin_call (stmt1
))
2041 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
2042 tree size
= gimple_call_arg (stmt2
, 2);
2043 if (code1
== BUILT_IN_CALLOC
)
2044 /* Not touching stmt1 */ ;
2045 else if (code1
== BUILT_IN_MALLOC
2046 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
2048 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
2049 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
2050 size
, build_one_cst (size_type_node
));
2051 si1
->nonzero_chars
= build_int_cst (size_type_node
, 0);
2052 si1
->full_string_p
= true;
2053 si1
->stmt
= gsi_stmt (gsi1
);
2057 tree lhs
= gimple_call_lhs (stmt2
);
2058 unlink_stmt_vdef (stmt2
);
2061 gimple
*assign
= gimple_build_assign (lhs
, ptr
);
2062 gsi_replace (gsi
, assign
, false);
2066 gsi_remove (gsi
, true);
2067 release_defs (stmt2
);
2073 /* Handle a call to memcmp. We try to handle small comparisons by
2074 converting them to load and compare, and replacing the call to memcmp
2075 with a __builtin_memcmp_eq call where possible. */
2078 handle_builtin_memcmp (gimple_stmt_iterator
*gsi
)
2080 gcall
*stmt2
= as_a
<gcall
*> (gsi_stmt (*gsi
));
2081 tree res
= gimple_call_lhs (stmt2
);
2082 tree arg1
= gimple_call_arg (stmt2
, 0);
2083 tree arg2
= gimple_call_arg (stmt2
, 1);
2084 tree len
= gimple_call_arg (stmt2
, 2);
2085 unsigned HOST_WIDE_INT leni
;
2086 use_operand_p use_p
;
2087 imm_use_iterator iter
;
2092 FOR_EACH_IMM_USE_FAST (use_p
, iter
, res
)
2094 gimple
*ustmt
= USE_STMT (use_p
);
2096 if (is_gimple_debug (ustmt
))
2098 if (gimple_code (ustmt
) == GIMPLE_ASSIGN
)
2100 gassign
*asgn
= as_a
<gassign
*> (ustmt
);
2101 tree_code code
= gimple_assign_rhs_code (asgn
);
2102 if ((code
!= EQ_EXPR
&& code
!= NE_EXPR
)
2103 || !integer_zerop (gimple_assign_rhs2 (asgn
)))
2106 else if (gimple_code (ustmt
) == GIMPLE_COND
)
2108 tree_code code
= gimple_cond_code (ustmt
);
2109 if ((code
!= EQ_EXPR
&& code
!= NE_EXPR
)
2110 || !integer_zerop (gimple_cond_rhs (ustmt
)))
2117 if (tree_fits_uhwi_p (len
)
2118 && (leni
= tree_to_uhwi (len
)) <= GET_MODE_SIZE (word_mode
)
2119 && pow2p_hwi (leni
))
2121 leni
*= CHAR_TYPE_SIZE
;
2122 unsigned align1
= get_pointer_alignment (arg1
);
2123 unsigned align2
= get_pointer_alignment (arg2
);
2124 unsigned align
= MIN (align1
, align2
);
2125 machine_mode mode
= mode_for_size (leni
, MODE_INT
, 1);
2127 && (align
>= leni
|| !SLOW_UNALIGNED_ACCESS (mode
, align
)))
2129 location_t loc
= gimple_location (stmt2
);
2131 type
= build_nonstandard_integer_type (leni
, 1);
2132 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type
)) == leni
);
2133 tree ptrtype
= build_pointer_type_for_mode (char_type_node
,
2135 off
= build_int_cst (ptrtype
, 0);
2136 arg1
= build2_loc (loc
, MEM_REF
, type
, arg1
, off
);
2137 arg2
= build2_loc (loc
, MEM_REF
, type
, arg2
, off
);
2138 tree tem1
= fold_const_aggregate_ref (arg1
);
2141 tree tem2
= fold_const_aggregate_ref (arg2
);
2144 res
= fold_convert_loc (loc
, TREE_TYPE (res
),
2145 fold_build2_loc (loc
, NE_EXPR
,
2148 gimplify_and_update_call_from_tree (gsi
, res
);
2153 gimple_call_set_fndecl (stmt2
, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ
));
2157 /* Handle a POINTER_PLUS_EXPR statement.
2158 For p = "abcd" + 2; compute associated length, or if
2159 p = q + off is pointing to a '\0' character of a string, call
2160 zero_length_string on it. */
2163 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
2165 gimple
*stmt
= gsi_stmt (*gsi
);
2166 tree lhs
= gimple_assign_lhs (stmt
), off
;
2167 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2175 tree off
= gimple_assign_rhs2 (stmt
);
2176 if (tree_fits_uhwi_p (off
)
2177 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
2178 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
2179 = ~(~idx
- (int) tree_to_uhwi (off
));
2183 si
= get_strinfo (idx
);
2184 if (si
== NULL
|| si
->nonzero_chars
== NULL_TREE
)
2187 off
= gimple_assign_rhs2 (stmt
);
2189 if (si
->full_string_p
&& operand_equal_p (si
->nonzero_chars
, off
, 0))
2190 zsi
= zero_length_string (lhs
, si
);
2191 else if (TREE_CODE (off
) == SSA_NAME
)
2193 gimple
*def_stmt
= SSA_NAME_DEF_STMT (off
);
2194 if (gimple_assign_single_p (def_stmt
)
2195 && si
->full_string_p
2196 && operand_equal_p (si
->nonzero_chars
,
2197 gimple_assign_rhs1 (def_stmt
), 0))
2198 zsi
= zero_length_string (lhs
, si
);
2201 && si
->endptr
!= NULL_TREE
2202 && si
->endptr
!= lhs
2203 && TREE_CODE (si
->endptr
) == SSA_NAME
)
2205 enum tree_code rhs_code
2206 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
2207 ? SSA_NAME
: NOP_EXPR
;
2208 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
2209 gcc_assert (gsi_stmt (*gsi
) == stmt
);
2214 /* Handle a single character store. */
2217 handle_char_store (gimple_stmt_iterator
*gsi
)
2221 gimple
*stmt
= gsi_stmt (*gsi
);
2222 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
2223 tree rhs
= gimple_assign_rhs1 (stmt
);
2224 unsigned HOST_WIDE_INT offset
= 0;
2226 if (TREE_CODE (lhs
) == MEM_REF
2227 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
2229 tree mem_offset
= TREE_OPERAND (lhs
, 1);
2230 if (tree_fits_uhwi_p (mem_offset
))
2232 /* Get the strinfo for the base, and use it if it starts with at
2233 least OFFSET nonzero characters. This is trivially true if
2235 offset
= tree_to_uhwi (mem_offset
);
2236 idx
= get_stridx (TREE_OPERAND (lhs
, 0));
2238 si
= get_strinfo (idx
);
2240 ssaname
= TREE_OPERAND (lhs
, 0);
2241 else if (si
== NULL
|| compare_nonzero_chars (si
, offset
) < 0)
2247 idx
= get_addr_stridx (lhs
, NULL_TREE
, &offset
);
2249 si
= get_strinfo (idx
);
2252 bool storing_zero_p
= initializer_zerop (rhs
);
2253 bool storing_nonzero_p
= (!storing_zero_p
2254 && TREE_CODE (rhs
) == INTEGER_CST
2255 && integer_nonzerop (rhs
));
2259 int cmp
= compare_nonzero_chars (si
, offset
);
2260 gcc_assert (offset
== 0 || cmp
>= 0);
2261 if (storing_zero_p
&& cmp
== 0 && si
->full_string_p
)
2263 /* When overwriting a '\0' with a '\0', the store can be removed
2264 if we know it has been stored in the current function. */
2265 if (!stmt_could_throw_p (stmt
) && si
->writable
)
2267 unlink_stmt_vdef (stmt
);
2268 release_defs (stmt
);
2269 gsi_remove (gsi
, true);
2274 si
->writable
= true;
2279 /* If si->nonzero_chars > OFFSET, we aren't overwriting '\0',
2280 and if we aren't storing '\0', we know that the length of the
2281 string and any other zero terminated string in memory remains
2282 the same. In that case we move to the next gimple statement and
2283 return to signal the caller that it shouldn't invalidate anything.
2285 This is benefical for cases like:
2290 strcpy (p, "foobar");
2291 size_t len = strlen (p); // This can be optimized into 6
2292 size_t len2 = strlen (q); // This has to be computed
2294 size_t len3 = strlen (p); // This can be optimized into 6
2295 size_t len4 = strlen (q); // This can be optimized into len2
2296 bar (len, len2, len3, len4);
2299 else if (storing_nonzero_p
&& cmp
> 0)
2304 else if (storing_zero_p
|| storing_nonzero_p
|| (offset
!= 0 && cmp
> 0))
2306 /* When storing_nonzero_p, we know that the string now starts
2307 with OFFSET + 1 nonzero characters, but don't know whether
2308 there's a following nul terminator.
2310 When storing_zero_p, we know that the string is now OFFSET
2313 Otherwise, we're storing an unknown value at offset OFFSET,
2314 so need to clip the nonzero_chars to OFFSET. */
2315 location_t loc
= gimple_location (stmt
);
2316 tree oldlen
= si
->nonzero_chars
;
2317 if (cmp
== 0 && si
->full_string_p
)
2318 /* We're overwriting the nul terminator with a nonzero or
2319 unknown character. If the previous stmt was a memcpy,
2320 its length may be decreased. */
2321 adjust_last_stmt (si
, stmt
, false);
2322 si
= unshare_strinfo (si
);
2323 if (storing_nonzero_p
)
2324 si
->nonzero_chars
= build_int_cst (size_type_node
, offset
+ 1);
2326 si
->nonzero_chars
= build_int_cst (size_type_node
, offset
);
2327 si
->full_string_p
= storing_zero_p
;
2330 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2331 si
->endptr
= ssaname
;
2336 si
->writable
= true;
2337 si
->dont_invalidate
= true;
2340 tree adj
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
2341 si
->nonzero_chars
, oldlen
);
2342 adjust_related_strinfos (loc
, si
, adj
);
2348 else if (idx
== 0 && (storing_zero_p
|| storing_nonzero_p
))
2351 idx
= new_stridx (ssaname
);
2353 idx
= new_addr_stridx (lhs
);
2356 tree ptr
= (ssaname
? ssaname
: build_fold_addr_expr (lhs
));
2357 tree len
= storing_nonzero_p
? size_one_node
: size_zero_node
;
2358 si
= new_strinfo (ptr
, idx
, len
, storing_zero_p
);
2359 set_strinfo (idx
, si
);
2362 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2363 si
->endptr
= ssaname
;
2364 si
->dont_invalidate
= true;
2365 si
->writable
= true;
2369 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2370 && ssaname
== NULL_TREE
2371 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2373 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2374 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2375 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2377 int idx
= new_addr_stridx (lhs
);
2380 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2381 build_int_cst (size_type_node
, l
), true);
2382 set_strinfo (idx
, si
);
2383 si
->dont_invalidate
= true;
2388 if (si
!= NULL
&& offset
== 0 && storing_zero_p
)
2390 /* Allow adjust_last_stmt to remove it if the stored '\0'
2391 is immediately overwritten. */
2392 laststmt
.stmt
= stmt
;
2393 laststmt
.len
= build_int_cst (size_type_node
, 1);
2394 laststmt
.stridx
= si
->idx
;
2399 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0. */
2402 fold_strstr_to_strncmp (tree rhs1
, tree rhs2
, gimple
*stmt
)
2404 if (TREE_CODE (rhs1
) != SSA_NAME
2405 || TREE_CODE (rhs2
) != SSA_NAME
)
2408 gimple
*call_stmt
= NULL
;
2409 for (int pass
= 0; pass
< 2; pass
++)
2411 gimple
*g
= SSA_NAME_DEF_STMT (rhs1
);
2412 if (gimple_call_builtin_p (g
, BUILT_IN_STRSTR
)
2413 && has_single_use (rhs1
)
2414 && gimple_call_arg (g
, 0) == rhs2
)
2419 std::swap (rhs1
, rhs2
);
2424 tree arg0
= gimple_call_arg (call_stmt
, 0);
2428 tree arg1
= gimple_call_arg (call_stmt
, 1);
2429 tree arg1_len
= NULL_TREE
;
2430 int idx
= get_stridx (arg1
);
2435 arg1_len
= build_int_cst (size_type_node
, ~idx
);
2438 strinfo
*si
= get_strinfo (idx
);
2440 arg1_len
= get_string_length (si
);
2444 if (arg1_len
!= NULL_TREE
)
2446 gimple_stmt_iterator gsi
= gsi_for_stmt (call_stmt
);
2447 tree strncmp_decl
= builtin_decl_explicit (BUILT_IN_STRNCMP
);
2448 gcall
*strncmp_call
= gimple_build_call (strncmp_decl
, 3,
2449 arg0
, arg1
, arg1_len
);
2450 tree strncmp_lhs
= make_ssa_name (integer_type_node
);
2451 gimple_set_vuse (strncmp_call
, gimple_vuse (call_stmt
));
2452 gimple_call_set_lhs (strncmp_call
, strncmp_lhs
);
2453 gsi_remove (&gsi
, true);
2454 gsi_insert_before (&gsi
, strncmp_call
, GSI_SAME_STMT
);
2455 tree zero
= build_zero_cst (TREE_TYPE (strncmp_lhs
));
2457 if (is_gimple_assign (stmt
))
2459 if (gimple_assign_rhs_code (stmt
) == COND_EXPR
)
2461 tree cond
= gimple_assign_rhs1 (stmt
);
2462 TREE_OPERAND (cond
, 0) = strncmp_lhs
;
2463 TREE_OPERAND (cond
, 1) = zero
;
2467 gimple_assign_set_rhs1 (stmt
, strncmp_lhs
);
2468 gimple_assign_set_rhs2 (stmt
, zero
);
2473 gcond
*cond
= as_a
<gcond
*> (stmt
);
2474 gimple_cond_set_lhs (cond
, strncmp_lhs
);
2475 gimple_cond_set_rhs (cond
, zero
);
2483 /* Attempt to optimize a single statement at *GSI using string length
2487 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2489 gimple
*stmt
= gsi_stmt (*gsi
);
2491 if (is_gimple_call (stmt
))
2493 tree callee
= gimple_call_fndecl (stmt
);
2494 if (valid_builtin_call (stmt
))
2495 switch (DECL_FUNCTION_CODE (callee
))
2497 case BUILT_IN_STRLEN
:
2498 case BUILT_IN_STRLEN_CHKP
:
2499 handle_builtin_strlen (gsi
);
2501 case BUILT_IN_STRCHR
:
2502 case BUILT_IN_STRCHR_CHKP
:
2503 handle_builtin_strchr (gsi
);
2505 case BUILT_IN_STRCPY
:
2506 case BUILT_IN_STRCPY_CHK
:
2507 case BUILT_IN_STPCPY
:
2508 case BUILT_IN_STPCPY_CHK
:
2509 case BUILT_IN_STRCPY_CHKP
:
2510 case BUILT_IN_STRCPY_CHK_CHKP
:
2511 case BUILT_IN_STPCPY_CHKP
:
2512 case BUILT_IN_STPCPY_CHK_CHKP
:
2513 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2515 case BUILT_IN_MEMCPY
:
2516 case BUILT_IN_MEMCPY_CHK
:
2517 case BUILT_IN_MEMPCPY
:
2518 case BUILT_IN_MEMPCPY_CHK
:
2519 case BUILT_IN_MEMCPY_CHKP
:
2520 case BUILT_IN_MEMCPY_CHK_CHKP
:
2521 case BUILT_IN_MEMPCPY_CHKP
:
2522 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2523 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2525 case BUILT_IN_STRCAT
:
2526 case BUILT_IN_STRCAT_CHK
:
2527 case BUILT_IN_STRCAT_CHKP
:
2528 case BUILT_IN_STRCAT_CHK_CHKP
:
2529 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2531 case BUILT_IN_MALLOC
:
2532 case BUILT_IN_CALLOC
:
2533 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2535 case BUILT_IN_MEMSET
:
2536 if (!handle_builtin_memset (gsi
))
2539 case BUILT_IN_MEMCMP
:
2540 if (!handle_builtin_memcmp (gsi
))
2547 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2549 tree lhs
= gimple_assign_lhs (stmt
);
2551 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2553 if (gimple_assign_single_p (stmt
)
2554 || (gimple_assign_cast_p (stmt
)
2555 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2557 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2558 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2560 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2561 handle_pointer_plus (gsi
);
2563 else if (TREE_CODE (lhs
) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (lhs
)))
2565 enum tree_code code
= gimple_assign_rhs_code (stmt
);
2566 if (code
== COND_EXPR
)
2568 tree cond
= gimple_assign_rhs1 (stmt
);
2569 enum tree_code cond_code
= TREE_CODE (cond
);
2571 if (cond_code
== EQ_EXPR
|| cond_code
== NE_EXPR
)
2572 fold_strstr_to_strncmp (TREE_OPERAND (cond
, 0),
2573 TREE_OPERAND (cond
, 1), stmt
);
2575 else if (code
== EQ_EXPR
|| code
== NE_EXPR
)
2576 fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt
),
2577 gimple_assign_rhs2 (stmt
), stmt
);
2579 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2581 tree type
= TREE_TYPE (lhs
);
2582 if (TREE_CODE (type
) == ARRAY_TYPE
)
2583 type
= TREE_TYPE (type
);
2584 if (TREE_CODE (type
) == INTEGER_TYPE
2585 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2586 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2588 if (! handle_char_store (gsi
))
2593 else if (gcond
*cond
= dyn_cast
<gcond
*> (stmt
))
2595 enum tree_code code
= gimple_cond_code (cond
);
2596 if (code
== EQ_EXPR
|| code
== NE_EXPR
)
2597 fold_strstr_to_strncmp (gimple_cond_lhs (stmt
),
2598 gimple_cond_rhs (stmt
), stmt
);
2601 if (gimple_vdef (stmt
))
2602 maybe_invalidate (stmt
);
2606 /* Recursively call maybe_invalidate on stmts that might be executed
2607 in between dombb and current bb and that contain a vdef. Stop when
2608 *count stmts are inspected, or if the whole strinfo vector has
2609 been invalidated. */
2612 do_invalidate (basic_block dombb
, gimple
*phi
, bitmap visited
, int *count
)
2614 unsigned int i
, n
= gimple_phi_num_args (phi
);
2616 for (i
= 0; i
< n
; i
++)
2618 tree vuse
= gimple_phi_arg_def (phi
, i
);
2619 gimple
*stmt
= SSA_NAME_DEF_STMT (vuse
);
2620 basic_block bb
= gimple_bb (stmt
);
2623 || !bitmap_set_bit (visited
, bb
->index
)
2624 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2628 if (gimple_code (stmt
) == GIMPLE_PHI
)
2630 do_invalidate (dombb
, stmt
, visited
, count
);
2637 if (!maybe_invalidate (stmt
))
2642 vuse
= gimple_vuse (stmt
);
2643 stmt
= SSA_NAME_DEF_STMT (vuse
);
2644 if (gimple_bb (stmt
) != bb
)
2646 bb
= gimple_bb (stmt
);
2649 || !bitmap_set_bit (visited
, bb
->index
)
2650 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2657 class strlen_dom_walker
: public dom_walker
2660 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2662 virtual edge
before_dom_children (basic_block
);
2663 virtual void after_dom_children (basic_block
);
2666 /* Callback for walk_dominator_tree. Attempt to optimize various
2667 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */
2670 strlen_dom_walker::before_dom_children (basic_block bb
)
2672 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2675 stridx_to_strinfo
= NULL
;
2678 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) dombb
->aux
);
2679 if (stridx_to_strinfo
)
2681 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2684 gphi
*phi
= gsi
.phi ();
2685 if (virtual_operand_p (gimple_phi_result (phi
)))
2687 bitmap visited
= BITMAP_ALLOC (NULL
);
2688 int count_vdef
= 100;
2689 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2690 BITMAP_FREE (visited
);
2691 if (count_vdef
== 0)
2693 /* If there were too many vdefs in between immediate
2694 dominator and current bb, invalidate everything.
2695 If stridx_to_strinfo has been unshared, we need
2696 to free it, otherwise just set it to NULL. */
2697 if (!strinfo_shared ())
2703 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2707 (*stridx_to_strinfo
)[i
] = NULL
;
2711 stridx_to_strinfo
= NULL
;
2719 /* If all PHI arguments have the same string index, the PHI result
2721 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2724 gphi
*phi
= gsi
.phi ();
2725 tree result
= gimple_phi_result (phi
);
2726 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2728 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2731 unsigned int i
, n
= gimple_phi_num_args (phi
);
2732 for (i
= 1; i
< n
; i
++)
2733 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2736 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2741 /* Attempt to optimize individual statements. */
2742 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2743 if (strlen_optimize_stmt (&gsi
))
2746 bb
->aux
= stridx_to_strinfo
;
2747 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2748 (*stridx_to_strinfo
)[0] = (strinfo
*) bb
;
2752 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2753 owned by the current bb, clear bb->aux. */
2756 strlen_dom_walker::after_dom_children (basic_block bb
)
2760 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) bb
->aux
);
2761 if (vec_safe_length (stridx_to_strinfo
)
2762 && (*stridx_to_strinfo
)[0] == (strinfo
*) bb
)
2767 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2769 vec_free (stridx_to_strinfo
);
2775 /* Main entry point. */
2779 const pass_data pass_data_strlen
=
2781 GIMPLE_PASS
, /* type */
2782 "strlen", /* name */
2783 OPTGROUP_NONE
, /* optinfo_flags */
2784 TV_TREE_STRLEN
, /* tv_id */
2785 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2786 0, /* properties_provided */
2787 0, /* properties_destroyed */
2788 0, /* todo_flags_start */
2789 0, /* todo_flags_finish */
2792 class pass_strlen
: public gimple_opt_pass
2795 pass_strlen (gcc::context
*ctxt
)
2796 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2799 /* opt_pass methods: */
2800 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2801 virtual unsigned int execute (function
*);
2803 }; // class pass_strlen
2806 pass_strlen::execute (function
*fun
)
2808 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2811 calculate_dominance_info (CDI_DOMINATORS
);
2813 /* String length optimization is implemented as a walk of the dominator
2814 tree and a forward walk of statements within each block. */
2815 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2817 ssa_ver_to_stridx
.release ();
2818 strinfo_pool
.release ();
2819 if (decl_to_stridxlist_htab
)
2821 obstack_free (&stridx_obstack
, NULL
);
2822 delete decl_to_stridxlist_htab
;
2823 decl_to_stridxlist_htab
= NULL
;
2825 laststmt
.stmt
= NULL
;
2826 laststmt
.len
= NULL_TREE
;
2827 laststmt
.stridx
= 0;
2835 make_pass_strlen (gcc::context
*ctxt
)
2837 return new pass_strlen (ctxt
);