1 /* String length optimization
2 Copyright (C) 2011-2014 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"
25 #include "stor-layout.h"
26 #include "hash-table.h"
35 #include "hard-reg-set.h"
38 #include "dominance.h"
40 #include "basic-block.h"
41 #include "tree-ssa-alias.h"
42 #include "internal-fn.h"
43 #include "gimple-fold.h"
45 #include "gimple-expr.h"
49 #include "gimple-iterator.h"
50 #include "gimplify-me.h"
51 #include "gimple-ssa.h"
52 #include "tree-phinodes.h"
53 #include "ssa-iterators.h"
54 #include "stringpool.h"
55 #include "tree-ssanames.h"
58 #include "tree-pass.h"
60 #include "alloc-pool.h"
61 #include "tree-ssa-propagate.h"
62 #include "gimple-pretty-print.h"
65 #include "plugin-api.h"
70 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
71 is an index into strinfo vector, negative value stands for
72 string length of a string literal (~strlen). */
73 static vec
<int> ssa_ver_to_stridx
;
75 /* Number of currently active string indexes plus one. */
76 static int max_stridx
;
78 /* String information record. */
79 typedef struct strinfo_struct
81 /* String length of this string. */
83 /* Any of the corresponding pointers for querying alias oracle. */
85 /* Statement for delayed length computation. */
87 /* Pointer to '\0' if known, if NULL, it can be computed as
90 /* Reference count. Any changes to strinfo entry possibly shared
91 with dominating basic blocks need unshare_strinfo first, except
92 for dont_invalidate which affects only the immediately next
95 /* Copy of index. get_strinfo (si->idx) should return si; */
97 /* These 3 fields are for chaining related string pointers together.
99 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
100 strcpy (c, d); e = c + dl;
101 strinfo(a) -> strinfo(c) -> strinfo(e)
102 All have ->first field equal to strinfo(a)->idx and are doubly
103 chained through prev/next fields. The later strinfos are required
104 to point into the same string with zero or more bytes after
105 the previous pointer and all bytes in between the two pointers
106 must be non-zero. Functions like strcpy or memcpy are supposed
107 to adjust all previous strinfo lengths, but not following strinfo
108 lengths (those are uncertain, usually invalidated during
109 maybe_invalidate, except when the alias oracle knows better).
110 Functions like strcat on the other side adjust the whole
111 related strinfo chain.
112 They are updated lazily, so to use the chain the same first fields
113 and si->prev->next == si->idx needs to be verified. */
117 /* A flag whether the string is known to be written in the current
120 /* A flag for the next maybe_invalidate that this strinfo shouldn't
121 be invalidated. Always cleared by maybe_invalidate. */
122 bool dont_invalidate
;
125 /* Pool for allocating strinfo_struct entries. */
126 static alloc_pool strinfo_pool
;
128 /* Vector mapping positive string indexes to strinfo, for the
129 current basic block. The first pointer in the vector is special,
130 it is either NULL, meaning the vector isn't shared, or it is
131 a basic block pointer to the owner basic_block if shared.
132 If some other bb wants to modify the vector, the vector needs
133 to be unshared first, and only the owner bb is supposed to free it. */
134 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
136 /* One OFFSET->IDX mapping. */
139 struct stridxlist
*next
;
140 HOST_WIDE_INT offset
;
144 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
145 struct decl_stridxlist_map
147 struct tree_map_base base
;
148 struct stridxlist list
;
151 /* stridxlist hashtable helpers. */
153 struct stridxlist_hash_traits
: default_hashmap_traits
155 static inline hashval_t
hash (tree
);
158 /* Hash a from tree in a decl_stridxlist_map. */
161 stridxlist_hash_traits::hash (tree item
)
163 return DECL_UID (item
);
166 /* Hash table for mapping decls to a chained list of offset -> idx
168 static hash_map
<tree
, stridxlist
, stridxlist_hash_traits
>
169 *decl_to_stridxlist_htab
;
171 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
172 static struct obstack stridx_obstack
;
174 /* Last memcpy statement if it could be adjusted if the trailing
175 '\0' written is immediately overwritten, or
176 *x = '\0' store that could be removed if it is immediately overwritten. */
177 struct laststmt_struct
184 /* Helper function for get_stridx. */
187 get_addr_stridx (tree exp
)
190 struct stridxlist
*list
;
193 if (!decl_to_stridxlist_htab
)
196 base
= get_addr_base_and_unit_offset (exp
, &off
);
197 if (base
== NULL
|| !DECL_P (base
))
200 list
= decl_to_stridxlist_htab
->get (base
);
206 if (list
->offset
== off
)
214 /* Return string index for EXP. */
217 get_stridx (tree exp
)
221 if (TREE_CODE (exp
) == SSA_NAME
)
222 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
224 if (TREE_CODE (exp
) == ADDR_EXPR
)
226 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
231 s
= string_constant (exp
, &o
);
233 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
234 && TREE_STRING_LENGTH (s
) > 0)
236 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
237 const char *p
= TREE_STRING_POINTER (s
);
238 int max
= TREE_STRING_LENGTH (s
) - 1;
240 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
241 return ~(int) strlen (p
+ offset
);
246 /* Return true if strinfo vector is shared with the immediate dominator. */
249 strinfo_shared (void)
251 return vec_safe_length (stridx_to_strinfo
)
252 && (*stridx_to_strinfo
)[0] != NULL
;
255 /* Unshare strinfo vector that is shared with the immediate dominator. */
258 unshare_strinfo_vec (void)
263 gcc_assert (strinfo_shared ());
264 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
265 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
268 (*stridx_to_strinfo
)[0] = NULL
;
271 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
272 Return a pointer to the location where the string index can
273 be stored (if 0) or is stored, or NULL if this can't be tracked. */
276 addr_stridxptr (tree exp
)
280 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
281 if (base
== NULL_TREE
|| !DECL_P (base
))
284 if (!decl_to_stridxlist_htab
)
286 decl_to_stridxlist_htab
287 = new hash_map
<tree
, stridxlist
, stridxlist_hash_traits
> (64);
288 gcc_obstack_init (&stridx_obstack
);
292 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
296 for (i
= 0; i
< 16; i
++)
298 if (list
->offset
== off
)
300 if (list
->next
== NULL
)
305 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
315 /* Create a new string index, or return 0 if reached limit. */
318 new_stridx (tree exp
)
321 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
323 if (TREE_CODE (exp
) == SSA_NAME
)
325 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
328 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
331 if (TREE_CODE (exp
) == ADDR_EXPR
)
333 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
336 gcc_assert (*pidx
== 0);
337 *pidx
= max_stridx
++;
344 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
347 new_addr_stridx (tree exp
)
350 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
352 pidx
= addr_stridxptr (exp
);
355 gcc_assert (*pidx
== 0);
356 *pidx
= max_stridx
++;
362 /* Create a new strinfo. */
365 new_strinfo (tree ptr
, int idx
, tree length
)
367 strinfo si
= (strinfo
) pool_alloc (strinfo_pool
);
371 si
->endptr
= NULL_TREE
;
377 si
->writable
= false;
378 si
->dont_invalidate
= false;
382 /* Decrease strinfo refcount and free it if not referenced anymore. */
385 free_strinfo (strinfo si
)
387 if (si
&& --si
->refcount
== 0)
388 pool_free (strinfo_pool
, si
);
391 /* Return strinfo vector entry IDX. */
393 static inline strinfo
394 get_strinfo (int idx
)
396 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
398 return (*stridx_to_strinfo
)[idx
];
401 /* Set strinfo in the vector entry IDX to SI. */
404 set_strinfo (int idx
, strinfo si
)
406 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
407 unshare_strinfo_vec ();
408 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
409 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
410 (*stridx_to_strinfo
)[idx
] = si
;
413 /* Return string length, or NULL if it can't be computed. */
416 get_string_length (strinfo si
)
423 gimple stmt
= si
->stmt
, lenstmt
;
424 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
425 tree callee
, lhs
, fn
, tem
;
427 gimple_stmt_iterator gsi
;
429 gcc_assert (is_gimple_call (stmt
));
430 callee
= gimple_call_fndecl (stmt
);
431 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
432 lhs
= gimple_call_lhs (stmt
);
433 /* unshare_strinfo is intentionally not called here. The (delayed)
434 transformation of strcpy or strcat into stpcpy is done at the place
435 of the former strcpy/strcat call and so can affect all the strinfos
436 with the same stmt. If they were unshared before and transformation
437 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
438 just compute the right length. */
439 switch (DECL_FUNCTION_CODE (callee
))
441 case BUILT_IN_STRCAT
:
442 case BUILT_IN_STRCAT_CHK
:
443 case BUILT_IN_STRCAT_CHKP
:
444 case BUILT_IN_STRCAT_CHK_CHKP
:
445 gsi
= gsi_for_stmt (stmt
);
446 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
447 gcc_assert (lhs
== NULL_TREE
);
448 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
451 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
452 2, tem
, gimple_call_arg (stmt
, 1));
453 gimple_call_set_with_bounds (lenstmt
, true);
456 lenstmt
= gimple_build_call (fn
, 1, tem
);
457 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
458 gimple_call_set_lhs (lenstmt
, lhs
);
459 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
460 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
461 tem
= gimple_call_arg (stmt
, 0);
462 if (!ptrofftype_p (TREE_TYPE (lhs
)))
464 lhs
= convert_to_ptrofftype (lhs
);
465 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
466 true, GSI_SAME_STMT
);
468 lenstmt
= gimple_build_assign
469 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
470 POINTER_PLUS_EXPR
,tem
, lhs
);
471 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
472 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
475 case BUILT_IN_STRCPY
:
476 case BUILT_IN_STRCPY_CHK
:
477 case BUILT_IN_STRCPY_CHKP
:
478 case BUILT_IN_STRCPY_CHK_CHKP
:
479 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
480 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
481 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
483 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
485 fn
= chkp_maybe_create_clone (fn
)->decl
;
486 gcc_assert (lhs
== NULL_TREE
);
487 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
489 fprintf (dump_file
, "Optimizing: ");
490 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
492 gimple_call_set_fndecl (stmt
, fn
);
493 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
494 gimple_call_set_lhs (stmt
, lhs
);
496 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
498 fprintf (dump_file
, "into: ");
499 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
502 case BUILT_IN_STPCPY
:
503 case BUILT_IN_STPCPY_CHK
:
504 case BUILT_IN_STPCPY_CHKP
:
505 case BUILT_IN_STPCPY_CHK_CHKP
:
506 gcc_assert (lhs
!= NULL_TREE
);
507 loc
= gimple_location (stmt
);
510 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
511 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
512 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
515 case BUILT_IN_MALLOC
:
517 /* BUILT_IN_CALLOC always has si->length set. */
527 /* Invalidate string length information for strings whose length
528 might change due to stores in stmt. */
531 maybe_invalidate (gimple stmt
)
535 bool nonempty
= false;
537 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
540 if (!si
->dont_invalidate
)
543 /* Do not use si->length. */
544 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
545 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
547 set_strinfo (i
, NULL
);
552 si
->dont_invalidate
= false;
558 /* Unshare strinfo record SI, if it has recount > 1 or
559 if stridx_to_strinfo vector is shared with some other
563 unshare_strinfo (strinfo si
)
567 if (si
->refcount
== 1 && !strinfo_shared ())
570 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
571 nsi
->stmt
= si
->stmt
;
572 nsi
->endptr
= si
->endptr
;
573 nsi
->first
= si
->first
;
574 nsi
->prev
= si
->prev
;
575 nsi
->next
= si
->next
;
576 nsi
->writable
= si
->writable
;
577 set_strinfo (si
->idx
, nsi
);
582 /* Return first strinfo in the related strinfo chain
583 if all strinfos in between belong to the chain, otherwise
587 verify_related_strinfos (strinfo origsi
)
589 strinfo si
= origsi
, psi
;
591 if (origsi
->first
== 0)
593 for (; si
->prev
; si
= psi
)
595 if (si
->first
!= origsi
->first
)
597 psi
= get_strinfo (si
->prev
);
600 if (psi
->next
!= si
->idx
)
603 if (si
->idx
!= si
->first
)
608 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
609 to a zero-length string and if possible chain it to a related strinfo
610 chain whose part is or might be CHAINSI. */
613 zero_length_string (tree ptr
, strinfo chainsi
)
617 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
618 && get_stridx (ptr
) == 0);
620 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
624 si
= verify_related_strinfos (chainsi
);
628 for (; chainsi
->next
; chainsi
= si
)
630 if (chainsi
->endptr
== NULL_TREE
)
632 chainsi
= unshare_strinfo (chainsi
);
633 chainsi
->endptr
= ptr
;
635 si
= get_strinfo (chainsi
->next
);
637 || si
->first
!= chainsi
->first
638 || si
->prev
!= chainsi
->idx
)
641 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
642 if (chainsi
->endptr
== NULL_TREE
)
644 chainsi
= unshare_strinfo (chainsi
);
645 chainsi
->endptr
= ptr
;
647 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
651 chainsi
= unshare_strinfo (chainsi
);
654 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
658 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
660 chainsi
= unshare_strinfo (chainsi
);
666 idx
= new_stridx (ptr
);
669 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
670 set_strinfo (idx
, si
);
674 chainsi
= unshare_strinfo (chainsi
);
675 if (chainsi
->first
== 0)
676 chainsi
->first
= chainsi
->idx
;
678 if (chainsi
->endptr
== NULL_TREE
)
679 chainsi
->endptr
= ptr
;
680 si
->prev
= chainsi
->idx
;
681 si
->first
= chainsi
->first
;
682 si
->writable
= chainsi
->writable
;
687 /* For strinfo ORIGSI whose length has been just updated
688 update also related strinfo lengths (add ADJ to each,
689 but don't adjust ORIGSI). */
692 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
694 strinfo si
= verify_related_strinfos (origsi
);
707 si
= unshare_strinfo (si
);
710 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
711 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
712 TREE_TYPE (si
->length
), si
->length
,
715 else if (si
->stmt
!= NULL
)
716 /* Delayed length computation is unaffected. */
721 si
->endptr
= NULL_TREE
;
722 si
->dont_invalidate
= true;
726 nsi
= get_strinfo (si
->next
);
728 || nsi
->first
!= si
->first
729 || nsi
->prev
!= si
->idx
)
735 /* Find if there are other SSA_NAME pointers equal to PTR
736 for which we don't track their string lengths yet. If so, use
740 find_equal_ptrs (tree ptr
, int idx
)
742 if (TREE_CODE (ptr
) != SSA_NAME
)
746 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
747 if (!is_gimple_assign (stmt
))
749 ptr
= gimple_assign_rhs1 (stmt
);
750 switch (gimple_assign_rhs_code (stmt
))
755 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
757 if (TREE_CODE (ptr
) == SSA_NAME
)
759 if (TREE_CODE (ptr
) != ADDR_EXPR
)
764 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
765 if (pidx
!= NULL
&& *pidx
== 0)
773 /* We might find an endptr created in this pass. Grow the
774 vector in that case. */
775 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
776 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
778 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
780 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
784 /* If the last .MEM setter statement before STMT is
785 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
786 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
787 just memcpy (x, y, strlen (y)). SI must be the zero length
791 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
793 tree vuse
, callee
, len
;
794 struct laststmt_struct last
= laststmt
;
795 strinfo lastsi
, firstsi
;
796 unsigned len_arg_no
= 2;
798 laststmt
.stmt
= NULL
;
799 laststmt
.len
= NULL_TREE
;
802 if (last
.stmt
== NULL
)
805 vuse
= gimple_vuse (stmt
);
806 if (vuse
== NULL_TREE
807 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
808 || !has_single_use (vuse
))
811 gcc_assert (last
.stridx
> 0);
812 lastsi
= get_strinfo (last
.stridx
);
818 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
821 firstsi
= verify_related_strinfos (si
);
824 while (firstsi
!= lastsi
)
827 if (firstsi
->next
== 0)
829 nextsi
= get_strinfo (firstsi
->next
);
831 || nextsi
->prev
!= firstsi
->idx
832 || nextsi
->first
!= si
->first
)
840 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
844 if (is_gimple_assign (last
.stmt
))
846 gimple_stmt_iterator gsi
;
848 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
850 if (stmt_could_throw_p (last
.stmt
))
852 gsi
= gsi_for_stmt (last
.stmt
);
853 unlink_stmt_vdef (last
.stmt
);
854 release_defs (last
.stmt
);
855 gsi_remove (&gsi
, true);
859 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
862 callee
= gimple_call_fndecl (last
.stmt
);
863 switch (DECL_FUNCTION_CODE (callee
))
865 case BUILT_IN_MEMCPY
:
866 case BUILT_IN_MEMCPY_CHK
:
868 case BUILT_IN_MEMCPY_CHKP
:
869 case BUILT_IN_MEMCPY_CHK_CHKP
:
876 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
877 if (tree_fits_uhwi_p (len
))
879 if (!tree_fits_uhwi_p (last
.len
)
880 || integer_zerop (len
)
881 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
883 /* Don't adjust the length if it is divisible by 4, it is more efficient
884 to store the extra '\0' in that case. */
885 if ((tree_to_uhwi (len
) & 3) == 0)
888 else if (TREE_CODE (len
) == SSA_NAME
)
890 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
891 if (!is_gimple_assign (def_stmt
)
892 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
893 || gimple_assign_rhs1 (def_stmt
) != last
.len
894 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
900 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
901 update_stmt (last
.stmt
);
904 /* Handle a strlen call. If strlen of the argument is known, replace
905 the strlen call with the known value, otherwise remember that strlen
906 of the argument is stored in the lhs SSA_NAME. */
909 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
913 gimple stmt
= gsi_stmt (*gsi
);
914 tree lhs
= gimple_call_lhs (stmt
);
916 if (lhs
== NULL_TREE
)
919 src
= gimple_call_arg (stmt
, 0);
920 idx
= get_stridx (src
);
927 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
931 si
= get_strinfo (idx
);
933 rhs
= get_string_length (si
);
935 if (rhs
!= NULL_TREE
)
937 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
939 fprintf (dump_file
, "Optimizing: ");
940 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
942 rhs
= unshare_expr (rhs
);
943 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
944 rhs
= fold_convert_loc (gimple_location (stmt
),
945 TREE_TYPE (lhs
), rhs
);
946 if (!update_call_from_tree (gsi
, rhs
))
947 gimplify_and_update_call_from_tree (gsi
, rhs
);
948 stmt
= gsi_stmt (*gsi
);
950 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
952 fprintf (dump_file
, "into: ");
953 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
956 && TREE_CODE (si
->length
) != SSA_NAME
957 && TREE_CODE (si
->length
) != INTEGER_CST
958 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
960 si
= unshare_strinfo (si
);
966 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
969 idx
= new_stridx (src
);
970 else if (get_strinfo (idx
) != NULL
)
974 strinfo si
= new_strinfo (src
, idx
, lhs
);
975 set_strinfo (idx
, si
);
976 find_equal_ptrs (src
, idx
);
980 /* Handle a strchr call. If strlen of the first argument is known, replace
981 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
982 that lhs of the call is endptr and strlen of the argument is endptr - x. */
985 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
989 gimple stmt
= gsi_stmt (*gsi
);
990 tree lhs
= gimple_call_lhs (stmt
);
991 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
993 if (lhs
== NULL_TREE
)
996 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
999 src
= gimple_call_arg (stmt
, 0);
1000 idx
= get_stridx (src
);
1007 rhs
= build_int_cst (size_type_node
, ~idx
);
1011 si
= get_strinfo (idx
);
1013 rhs
= get_string_length (si
);
1015 if (rhs
!= NULL_TREE
)
1017 location_t loc
= gimple_location (stmt
);
1019 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1021 fprintf (dump_file
, "Optimizing: ");
1022 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1024 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1026 rhs
= unshare_expr (si
->endptr
);
1027 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1029 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1033 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1034 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1035 TREE_TYPE (src
), src
, rhs
);
1036 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1038 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1040 if (!update_call_from_tree (gsi
, rhs
))
1041 gimplify_and_update_call_from_tree (gsi
, rhs
);
1042 stmt
= gsi_stmt (*gsi
);
1044 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1046 fprintf (dump_file
, "into: ");
1047 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1050 && si
->endptr
== NULL_TREE
1051 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1053 si
= unshare_strinfo (si
);
1056 zero_length_string (lhs
, si
);
1060 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1062 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1065 idx
= new_stridx (src
);
1066 else if (get_strinfo (idx
) != NULL
)
1068 zero_length_string (lhs
, NULL
);
1073 location_t loc
= gimple_location (stmt
);
1074 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1075 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1076 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1077 size_type_node
, lhsu
, srcu
);
1078 strinfo si
= new_strinfo (src
, idx
, length
);
1080 set_strinfo (idx
, si
);
1081 find_equal_ptrs (src
, idx
);
1082 zero_length_string (lhs
, si
);
1086 zero_length_string (lhs
, NULL
);
1089 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1090 If strlen of the second argument is known, strlen of the first argument
1091 is the same after this call. Furthermore, attempt to convert it to
1095 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1098 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1100 gimple stmt
= gsi_stmt (*gsi
);
1101 strinfo si
, dsi
, olddsi
, zsi
;
1103 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1105 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1106 dst
= gimple_call_arg (stmt
, 0);
1107 lhs
= gimple_call_lhs (stmt
);
1108 idx
= get_stridx (src
);
1111 si
= get_strinfo (idx
);
1113 didx
= get_stridx (dst
);
1117 olddsi
= get_strinfo (didx
);
1122 adjust_last_stmt (olddsi
, stmt
, false);
1126 srclen
= get_string_length (si
);
1128 srclen
= build_int_cst (size_type_node
, ~idx
);
1130 loc
= gimple_location (stmt
);
1131 if (srclen
== NULL_TREE
)
1134 case BUILT_IN_STRCPY
:
1135 case BUILT_IN_STRCPY_CHK
:
1136 case BUILT_IN_STRCPY_CHKP
:
1137 case BUILT_IN_STRCPY_CHK_CHKP
:
1138 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1141 case BUILT_IN_STPCPY
:
1142 case BUILT_IN_STPCPY_CHK
:
1143 case BUILT_IN_STPCPY_CHKP
:
1144 case BUILT_IN_STPCPY_CHK_CHKP
:
1145 if (lhs
== NULL_TREE
)
1149 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1150 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1151 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1161 didx
= new_stridx (dst
);
1167 oldlen
= olddsi
->length
;
1168 dsi
= unshare_strinfo (olddsi
);
1169 dsi
->length
= srclen
;
1170 /* Break the chain, so adjust_related_strinfo on later pointers in
1171 the chain won't adjust this one anymore. */
1174 dsi
->endptr
= NULL_TREE
;
1178 dsi
= new_strinfo (dst
, didx
, srclen
);
1179 set_strinfo (didx
, dsi
);
1180 find_equal_ptrs (dst
, didx
);
1182 dsi
->writable
= true;
1183 dsi
->dont_invalidate
= true;
1185 if (dsi
->length
== NULL_TREE
)
1189 /* If string length of src is unknown, use delayed length
1190 computation. If string lenth of dst will be needed, it
1191 can be computed by transforming this strcpy call into
1192 stpcpy and subtracting dst from the return value. */
1194 /* Look for earlier strings whose length could be determined if
1195 this strcpy is turned into an stpcpy. */
1197 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1199 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1201 /* When setting a stmt for delayed length computation
1202 prevent all strinfos through dsi from being
1204 chainsi
= unshare_strinfo (chainsi
);
1205 chainsi
->stmt
= stmt
;
1206 chainsi
->length
= NULL_TREE
;
1207 chainsi
->endptr
= NULL_TREE
;
1208 chainsi
->dont_invalidate
= true;
1217 tree adj
= NULL_TREE
;
1218 if (oldlen
== NULL_TREE
)
1220 else if (integer_zerop (oldlen
))
1222 else if (TREE_CODE (oldlen
) == INTEGER_CST
1223 || TREE_CODE (srclen
) == INTEGER_CST
)
1224 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1225 TREE_TYPE (srclen
), srclen
,
1226 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1228 if (adj
!= NULL_TREE
)
1229 adjust_related_strinfos (loc
, dsi
, adj
);
1233 /* strcpy src may not overlap dst, so src doesn't need to be
1234 invalidated either. */
1236 si
->dont_invalidate
= true;
1242 case BUILT_IN_STRCPY
:
1243 case BUILT_IN_STRCPY_CHKP
:
1244 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1246 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1248 case BUILT_IN_STRCPY_CHK
:
1249 case BUILT_IN_STRCPY_CHK_CHKP
:
1250 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1252 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1254 case BUILT_IN_STPCPY
:
1255 case BUILT_IN_STPCPY_CHKP
:
1256 /* This would need adjustment of the lhs (subtract one),
1257 or detection that the trailing '\0' doesn't need to be
1258 written, if it will be immediately overwritten.
1259 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1263 zsi
= zero_length_string (lhs
, dsi
);
1266 case BUILT_IN_STPCPY_CHK
:
1267 case BUILT_IN_STPCPY_CHK_CHKP
:
1268 /* This would need adjustment of the lhs (subtract one),
1269 or detection that the trailing '\0' doesn't need to be
1270 written, if it will be immediately overwritten.
1271 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1275 zsi
= zero_length_string (lhs
, dsi
);
1282 zsi
->dont_invalidate
= true;
1284 if (fn
== NULL_TREE
)
1287 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1288 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1290 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1291 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1292 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1294 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1296 fprintf (dump_file
, "Optimizing: ");
1297 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1301 fn
= chkp_maybe_create_clone (fn
)->decl
;
1302 if (gimple_call_num_args (stmt
) == 4)
1303 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1304 gimple_call_arg (stmt
, 1),
1306 gimple_call_arg (stmt
, 3),
1309 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1310 gimple_call_arg (stmt
, 1),
1312 gimple_call_arg (stmt
, 3),
1314 gimple_call_arg (stmt
, 4));
1317 if (gimple_call_num_args (stmt
) == 2)
1318 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1320 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1321 gimple_call_arg (stmt
, 2));
1324 stmt
= gsi_stmt (*gsi
);
1325 gimple_call_set_with_bounds (stmt
, with_bounds
);
1327 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1329 fprintf (dump_file
, "into: ");
1330 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1332 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1333 laststmt
.stmt
= stmt
;
1334 laststmt
.len
= srclen
;
1335 laststmt
.stridx
= dsi
->idx
;
1337 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1338 fprintf (dump_file
, "not possible.\n");
1341 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1342 If strlen of the second argument is known and length of the third argument
1343 is that plus one, strlen of the first argument is the same after this
1347 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1350 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1351 gimple stmt
= gsi_stmt (*gsi
);
1352 strinfo si
, dsi
, olddsi
;
1353 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1355 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1356 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1357 dst
= gimple_call_arg (stmt
, 0);
1358 idx
= get_stridx (src
);
1362 didx
= get_stridx (dst
);
1365 olddsi
= get_strinfo (didx
);
1370 && tree_fits_uhwi_p (len
)
1371 && !integer_zerop (len
))
1372 adjust_last_stmt (olddsi
, stmt
, false);
1378 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1379 si
= get_strinfo (idx
);
1380 if (si
== NULL
|| si
->length
== NULL_TREE
)
1382 if (TREE_CODE (len
) != SSA_NAME
)
1384 def_stmt
= SSA_NAME_DEF_STMT (len
);
1385 if (!is_gimple_assign (def_stmt
)
1386 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1387 || gimple_assign_rhs1 (def_stmt
) != si
->length
1388 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1394 /* Handle memcpy (x, "abcd", 5) or
1395 memcpy (x, "abc\0uvw", 7). */
1396 if (!tree_fits_uhwi_p (len
)
1397 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1401 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1402 adjust_last_stmt (olddsi
, stmt
, false);
1406 didx
= new_stridx (dst
);
1411 newlen
= si
->length
;
1413 newlen
= build_int_cst (size_type_node
, ~idx
);
1417 dsi
= unshare_strinfo (olddsi
);
1418 oldlen
= olddsi
->length
;
1419 dsi
->length
= newlen
;
1420 /* Break the chain, so adjust_related_strinfo on later pointers in
1421 the chain won't adjust this one anymore. */
1424 dsi
->endptr
= NULL_TREE
;
1428 dsi
= new_strinfo (dst
, didx
, newlen
);
1429 set_strinfo (didx
, dsi
);
1430 find_equal_ptrs (dst
, didx
);
1432 dsi
->writable
= true;
1433 dsi
->dont_invalidate
= true;
1436 tree adj
= NULL_TREE
;
1437 location_t loc
= gimple_location (stmt
);
1438 if (oldlen
== NULL_TREE
)
1440 else if (integer_zerop (oldlen
))
1442 else if (TREE_CODE (oldlen
) == INTEGER_CST
1443 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1444 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1445 TREE_TYPE (dsi
->length
), dsi
->length
,
1446 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1448 if (adj
!= NULL_TREE
)
1449 adjust_related_strinfos (loc
, dsi
, adj
);
1453 /* memcpy src may not overlap dst, so src doesn't need to be
1454 invalidated either. */
1456 si
->dont_invalidate
= true;
1458 lhs
= gimple_call_lhs (stmt
);
1461 case BUILT_IN_MEMCPY
:
1462 case BUILT_IN_MEMCPY_CHK
:
1463 case BUILT_IN_MEMCPY_CHKP
:
1464 case BUILT_IN_MEMCPY_CHK_CHKP
:
1465 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1466 laststmt
.stmt
= stmt
;
1467 laststmt
.len
= dsi
->length
;
1468 laststmt
.stridx
= dsi
->idx
;
1470 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1472 case BUILT_IN_MEMPCPY
:
1473 case BUILT_IN_MEMPCPY_CHK
:
1474 case BUILT_IN_MEMPCPY_CHKP
:
1475 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1482 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1483 If strlen of the second argument is known, strlen of the first argument
1484 is increased by the length of the second argument. Furthermore, attempt
1485 to convert it to memcpy/strcpy if the length of the first argument
1489 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1492 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1494 gimple stmt
= gsi_stmt (*gsi
);
1497 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1499 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1500 dst
= gimple_call_arg (stmt
, 0);
1501 lhs
= gimple_call_lhs (stmt
);
1503 didx
= get_stridx (dst
);
1509 dsi
= get_strinfo (didx
);
1510 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1512 /* strcat (p, q) can be transformed into
1513 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1514 with length endptr - p if we need to compute the length
1515 later on. Don't do this transformation if we don't need
1517 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1521 didx
= new_stridx (dst
);
1527 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1528 set_strinfo (didx
, dsi
);
1529 find_equal_ptrs (dst
, didx
);
1533 dsi
= unshare_strinfo (dsi
);
1534 dsi
->length
= NULL_TREE
;
1536 dsi
->endptr
= NULL_TREE
;
1538 dsi
->writable
= true;
1540 dsi
->dont_invalidate
= true;
1547 idx
= get_stridx (src
);
1549 srclen
= build_int_cst (size_type_node
, ~idx
);
1552 si
= get_strinfo (idx
);
1554 srclen
= get_string_length (si
);
1557 loc
= gimple_location (stmt
);
1558 dstlen
= dsi
->length
;
1559 endptr
= dsi
->endptr
;
1561 dsi
= unshare_strinfo (dsi
);
1562 dsi
->endptr
= NULL_TREE
;
1564 dsi
->writable
= true;
1566 if (srclen
!= NULL_TREE
)
1568 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1569 dsi
->length
, srclen
);
1570 adjust_related_strinfos (loc
, dsi
, srclen
);
1571 dsi
->dont_invalidate
= true;
1576 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1577 dsi
->dont_invalidate
= true;
1581 /* strcat src may not overlap dst, so src doesn't need to be
1582 invalidated either. */
1583 si
->dont_invalidate
= true;
1585 /* For now. Could remove the lhs from the call and add
1586 lhs = dst; afterwards. */
1594 case BUILT_IN_STRCAT
:
1595 case BUILT_IN_STRCAT_CHKP
:
1596 if (srclen
!= NULL_TREE
)
1597 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1599 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1601 case BUILT_IN_STRCAT_CHK
:
1602 case BUILT_IN_STRCAT_CHK_CHKP
:
1603 if (srclen
!= NULL_TREE
)
1604 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1606 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1607 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1613 if (fn
== NULL_TREE
)
1617 if (srclen
!= NULL_TREE
)
1619 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1620 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1622 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1623 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1624 build_int_cst (type
, 1));
1625 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1629 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1631 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1632 TREE_TYPE (dst
), unshare_expr (dst
),
1633 fold_convert_loc (loc
, sizetype
,
1634 unshare_expr (dstlen
)));
1635 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1637 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1639 fprintf (dump_file
, "Optimizing: ");
1640 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1644 fn
= chkp_maybe_create_clone (fn
)->decl
;
1645 if (srclen
!= NULL_TREE
)
1646 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1648 gimple_call_arg (stmt
, 1),
1650 gimple_call_arg (stmt
, 3),
1653 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1655 gimple_call_arg (stmt
, 1),
1657 gimple_call_arg (stmt
, 3),
1661 if (srclen
!= NULL_TREE
)
1662 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1663 dst
, src
, len
, objsz
);
1665 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1669 stmt
= gsi_stmt (*gsi
);
1670 gimple_call_set_with_bounds (stmt
, with_bounds
);
1672 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1674 fprintf (dump_file
, "into: ");
1675 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1677 /* If srclen == NULL, note that current string length can be
1678 computed by transforming this strcpy into stpcpy. */
1679 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1681 adjust_last_stmt (dsi
, stmt
, true);
1682 if (srclen
!= NULL_TREE
)
1684 laststmt
.stmt
= stmt
;
1685 laststmt
.len
= srclen
;
1686 laststmt
.stridx
= dsi
->idx
;
1689 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1690 fprintf (dump_file
, "not possible.\n");
1693 /* Handle a call to malloc or calloc. */
1696 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1698 gimple stmt
= gsi_stmt (*gsi
);
1699 tree lhs
= gimple_call_lhs (stmt
);
1700 gcc_assert (get_stridx (lhs
) == 0);
1701 int idx
= new_stridx (lhs
);
1702 tree length
= NULL_TREE
;
1703 if (bcode
== BUILT_IN_CALLOC
)
1704 length
= build_int_cst (size_type_node
, 0);
1705 strinfo si
= new_strinfo (lhs
, idx
, length
);
1706 if (bcode
== BUILT_IN_CALLOC
)
1708 set_strinfo (idx
, si
);
1709 si
->writable
= true;
1711 si
->dont_invalidate
= true;
1714 /* Handle a call to memset.
1715 After a call to calloc, memset(,0,) is unnecessary.
1716 memset(malloc(n),0,n) is calloc(n,1). */
1719 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1721 gimple stmt2
= gsi_stmt (*gsi
);
1722 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1724 tree ptr
= gimple_call_arg (stmt2
, 0);
1725 int idx1
= get_stridx (ptr
);
1728 strinfo si1
= get_strinfo (idx1
);
1731 gimple stmt1
= si1
->stmt
;
1732 if (!stmt1
|| !is_gimple_call (stmt1
))
1734 tree callee1
= gimple_call_fndecl (stmt1
);
1735 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1737 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1738 tree size
= gimple_call_arg (stmt2
, 2);
1739 if (code1
== BUILT_IN_CALLOC
)
1740 /* Not touching stmt1 */ ;
1741 else if (code1
== BUILT_IN_MALLOC
1742 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1744 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1745 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1746 size
, build_one_cst (size_type_node
));
1747 si1
->length
= build_int_cst (size_type_node
, 0);
1748 si1
->stmt
= gsi_stmt (gsi1
);
1752 tree lhs
= gimple_call_lhs (stmt2
);
1753 unlink_stmt_vdef (stmt2
);
1756 gimple assign
= gimple_build_assign (lhs
, ptr
);
1757 gsi_replace (gsi
, assign
, false);
1761 gsi_remove (gsi
, true);
1762 release_defs (stmt2
);
1768 /* Handle a POINTER_PLUS_EXPR statement.
1769 For p = "abcd" + 2; compute associated length, or if
1770 p = q + off is pointing to a '\0' character of a string, call
1771 zero_length_string on it. */
1774 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1776 gimple stmt
= gsi_stmt (*gsi
);
1777 tree lhs
= gimple_assign_lhs (stmt
), off
;
1778 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1786 tree off
= gimple_assign_rhs2 (stmt
);
1787 if (tree_fits_uhwi_p (off
)
1788 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1789 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1790 = ~(~idx
- (int) tree_to_uhwi (off
));
1794 si
= get_strinfo (idx
);
1795 if (si
== NULL
|| si
->length
== NULL_TREE
)
1798 off
= gimple_assign_rhs2 (stmt
);
1800 if (operand_equal_p (si
->length
, off
, 0))
1801 zsi
= zero_length_string (lhs
, si
);
1802 else if (TREE_CODE (off
) == SSA_NAME
)
1804 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1805 if (gimple_assign_single_p (def_stmt
)
1806 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1807 zsi
= zero_length_string (lhs
, si
);
1810 && si
->endptr
!= NULL_TREE
1811 && si
->endptr
!= lhs
1812 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1814 enum tree_code rhs_code
1815 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1816 ? SSA_NAME
: NOP_EXPR
;
1817 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1818 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1823 /* Handle a single character store. */
1826 handle_char_store (gimple_stmt_iterator
*gsi
)
1830 gimple stmt
= gsi_stmt (*gsi
);
1831 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1833 if (TREE_CODE (lhs
) == MEM_REF
1834 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1836 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1838 ssaname
= TREE_OPERAND (lhs
, 0);
1839 idx
= get_stridx (ssaname
);
1843 idx
= get_addr_stridx (lhs
);
1847 si
= get_strinfo (idx
);
1848 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1850 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1852 /* When storing '\0', the store can be removed
1853 if we know it has been stored in the current function. */
1854 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1856 unlink_stmt_vdef (stmt
);
1857 release_defs (stmt
);
1858 gsi_remove (gsi
, true);
1863 si
->writable
= true;
1869 /* Otherwise this statement overwrites the '\0' with
1870 something, if the previous stmt was a memcpy,
1871 its length may be decreased. */
1872 adjust_last_stmt (si
, stmt
, false);
1874 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1876 si
= unshare_strinfo (si
);
1877 si
->length
= build_int_cst (size_type_node
, 0);
1883 si
->writable
= true;
1884 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1885 si
->endptr
= ssaname
;
1886 si
->dont_invalidate
= true;
1888 /* If si->length is non-zero constant, we aren't overwriting '\0',
1889 and if we aren't storing '\0', we know that the length of the
1890 string and any other zero terminated string in memory remains
1891 the same. In that case we move to the next gimple statement and
1892 return to signal the caller that it shouldn't invalidate anything.
1894 This is benefical for cases like:
1899 strcpy (p, "foobar");
1900 size_t len = strlen (p); // This can be optimized into 6
1901 size_t len2 = strlen (q); // This has to be computed
1903 size_t len3 = strlen (p); // This can be optimized into 6
1904 size_t len4 = strlen (q); // This can be optimized into len2
1905 bar (len, len2, len3, len4);
1908 else if (si
!= NULL
&& si
->length
!= NULL_TREE
1909 && TREE_CODE (si
->length
) == INTEGER_CST
1910 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
1916 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1920 si
= zero_length_string (ssaname
, NULL
);
1922 si
->dont_invalidate
= true;
1926 int idx
= new_addr_stridx (lhs
);
1929 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1930 build_int_cst (size_type_node
, 0));
1931 set_strinfo (idx
, si
);
1932 si
->dont_invalidate
= true;
1936 si
->writable
= true;
1939 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
1940 && ssaname
== NULL_TREE
1941 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
1943 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
1944 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
1945 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
1947 int idx
= new_addr_stridx (lhs
);
1950 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
1951 build_int_cst (size_type_node
, l
));
1952 set_strinfo (idx
, si
);
1953 si
->dont_invalidate
= true;
1958 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
1960 /* Allow adjust_last_stmt to remove it if the stored '\0'
1961 is immediately overwritten. */
1962 laststmt
.stmt
= stmt
;
1963 laststmt
.len
= build_int_cst (size_type_node
, 1);
1964 laststmt
.stridx
= si
->idx
;
1969 /* Attempt to optimize a single statement at *GSI using string length
1973 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
1975 gimple stmt
= gsi_stmt (*gsi
);
1977 if (is_gimple_call (stmt
))
1979 tree callee
= gimple_call_fndecl (stmt
);
1980 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
1981 switch (DECL_FUNCTION_CODE (callee
))
1983 case BUILT_IN_STRLEN
:
1984 case BUILT_IN_STRLEN_CHKP
:
1985 handle_builtin_strlen (gsi
);
1987 case BUILT_IN_STRCHR
:
1988 case BUILT_IN_STRCHR_CHKP
:
1989 handle_builtin_strchr (gsi
);
1991 case BUILT_IN_STRCPY
:
1992 case BUILT_IN_STRCPY_CHK
:
1993 case BUILT_IN_STPCPY
:
1994 case BUILT_IN_STPCPY_CHK
:
1995 case BUILT_IN_STRCPY_CHKP
:
1996 case BUILT_IN_STRCPY_CHK_CHKP
:
1997 case BUILT_IN_STPCPY_CHKP
:
1998 case BUILT_IN_STPCPY_CHK_CHKP
:
1999 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2001 case BUILT_IN_MEMCPY
:
2002 case BUILT_IN_MEMCPY_CHK
:
2003 case BUILT_IN_MEMPCPY
:
2004 case BUILT_IN_MEMPCPY_CHK
:
2005 case BUILT_IN_MEMCPY_CHKP
:
2006 case BUILT_IN_MEMCPY_CHK_CHKP
:
2007 case BUILT_IN_MEMPCPY_CHKP
:
2008 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2009 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2011 case BUILT_IN_STRCAT
:
2012 case BUILT_IN_STRCAT_CHK
:
2013 case BUILT_IN_STRCAT_CHKP
:
2014 case BUILT_IN_STRCAT_CHK_CHKP
:
2015 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2017 case BUILT_IN_MALLOC
:
2018 case BUILT_IN_CALLOC
:
2019 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2021 case BUILT_IN_MEMSET
:
2022 if (!handle_builtin_memset (gsi
))
2029 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2031 tree lhs
= gimple_assign_lhs (stmt
);
2033 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2035 if (gimple_assign_single_p (stmt
)
2036 || (gimple_assign_cast_p (stmt
)
2037 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2039 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2040 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2042 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2043 handle_pointer_plus (gsi
);
2045 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2047 tree type
= TREE_TYPE (lhs
);
2048 if (TREE_CODE (type
) == ARRAY_TYPE
)
2049 type
= TREE_TYPE (type
);
2050 if (TREE_CODE (type
) == INTEGER_TYPE
2051 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2052 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2054 if (! handle_char_store (gsi
))
2060 if (gimple_vdef (stmt
))
2061 maybe_invalidate (stmt
);
2065 /* Recursively call maybe_invalidate on stmts that might be executed
2066 in between dombb and current bb and that contain a vdef. Stop when
2067 *count stmts are inspected, or if the whole strinfo vector has
2068 been invalidated. */
2071 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
2073 unsigned int i
, n
= gimple_phi_num_args (phi
);
2075 for (i
= 0; i
< n
; i
++)
2077 tree vuse
= gimple_phi_arg_def (phi
, i
);
2078 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
2079 basic_block bb
= gimple_bb (stmt
);
2082 || !bitmap_set_bit (visited
, bb
->index
)
2083 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2087 if (gimple_code (stmt
) == GIMPLE_PHI
)
2089 do_invalidate (dombb
, stmt
, visited
, count
);
2096 if (!maybe_invalidate (stmt
))
2101 vuse
= gimple_vuse (stmt
);
2102 stmt
= SSA_NAME_DEF_STMT (vuse
);
2103 if (gimple_bb (stmt
) != bb
)
2105 bb
= gimple_bb (stmt
);
2108 || !bitmap_set_bit (visited
, bb
->index
)
2109 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2116 class strlen_dom_walker
: public dom_walker
2119 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2121 virtual void before_dom_children (basic_block
);
2122 virtual void after_dom_children (basic_block
);
2125 /* Callback for walk_dominator_tree. Attempt to optimize various
2126 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2129 strlen_dom_walker::before_dom_children (basic_block bb
)
2131 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2134 stridx_to_strinfo
= NULL
;
2137 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
2138 if (stridx_to_strinfo
)
2140 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2143 gphi
*phi
= gsi
.phi ();
2144 if (virtual_operand_p (gimple_phi_result (phi
)))
2146 bitmap visited
= BITMAP_ALLOC (NULL
);
2147 int count_vdef
= 100;
2148 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2149 BITMAP_FREE (visited
);
2150 if (count_vdef
== 0)
2152 /* If there were too many vdefs in between immediate
2153 dominator and current bb, invalidate everything.
2154 If stridx_to_strinfo has been unshared, we need
2155 to free it, otherwise just set it to NULL. */
2156 if (!strinfo_shared ())
2162 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2166 (*stridx_to_strinfo
)[i
] = NULL
;
2170 stridx_to_strinfo
= NULL
;
2178 /* If all PHI arguments have the same string index, the PHI result
2180 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2183 gphi
*phi
= gsi
.phi ();
2184 tree result
= gimple_phi_result (phi
);
2185 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2187 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2190 unsigned int i
, n
= gimple_phi_num_args (phi
);
2191 for (i
= 1; i
< n
; i
++)
2192 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2195 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2200 /* Attempt to optimize individual statements. */
2201 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2202 if (strlen_optimize_stmt (&gsi
))
2205 bb
->aux
= stridx_to_strinfo
;
2206 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2207 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2210 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2211 owned by the current bb, clear bb->aux. */
2214 strlen_dom_walker::after_dom_children (basic_block bb
)
2218 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2219 if (vec_safe_length (stridx_to_strinfo
)
2220 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2225 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2227 vec_free (stridx_to_strinfo
);
2233 /* Main entry point. */
2237 const pass_data pass_data_strlen
=
2239 GIMPLE_PASS
, /* type */
2240 "strlen", /* name */
2241 OPTGROUP_NONE
, /* optinfo_flags */
2242 TV_TREE_STRLEN
, /* tv_id */
2243 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2244 0, /* properties_provided */
2245 0, /* properties_destroyed */
2246 0, /* todo_flags_start */
2247 0, /* todo_flags_finish */
2250 class pass_strlen
: public gimple_opt_pass
2253 pass_strlen (gcc::context
*ctxt
)
2254 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2257 /* opt_pass methods: */
2258 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2259 virtual unsigned int execute (function
*);
2261 }; // class pass_strlen
2264 pass_strlen::execute (function
*fun
)
2266 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2268 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
2269 sizeof (struct strinfo_struct
), 64);
2271 calculate_dominance_info (CDI_DOMINATORS
);
2273 /* String length optimization is implemented as a walk of the dominator
2274 tree and a forward walk of statements within each block. */
2275 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2277 ssa_ver_to_stridx
.release ();
2278 free_alloc_pool (strinfo_pool
);
2279 if (decl_to_stridxlist_htab
)
2281 obstack_free (&stridx_obstack
, NULL
);
2282 delete decl_to_stridxlist_htab
;
2283 decl_to_stridxlist_htab
= NULL
;
2285 laststmt
.stmt
= NULL
;
2286 laststmt
.len
= NULL_TREE
;
2287 laststmt
.stridx
= 0;
2295 make_pass_strlen (gcc::context
*ctxt
)
2297 return new pass_strlen (ctxt
);