1 /* String length optimization
2 Copyright (C) 2011-2016 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"
48 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
49 is an index into strinfo vector, negative value stands for
50 string length of a string literal (~strlen). */
51 static vec
<int> ssa_ver_to_stridx
;
53 /* Number of currently active string indexes plus one. */
54 static int max_stridx
;
56 /* String information record. */
59 /* String length of this string. */
61 /* Any of the corresponding pointers for querying alias oracle. */
63 /* Statement for delayed length computation. */
65 /* Pointer to '\0' if known, if NULL, it can be computed as
68 /* Reference count. Any changes to strinfo entry possibly shared
69 with dominating basic blocks need unshare_strinfo first, except
70 for dont_invalidate which affects only the immediately next
73 /* Copy of index. get_strinfo (si->idx) should return si; */
75 /* These 3 fields are for chaining related string pointers together.
77 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
78 strcpy (c, d); e = c + dl;
79 strinfo(a) -> strinfo(c) -> strinfo(e)
80 All have ->first field equal to strinfo(a)->idx and are doubly
81 chained through prev/next fields. The later strinfos are required
82 to point into the same string with zero or more bytes after
83 the previous pointer and all bytes in between the two pointers
84 must be non-zero. Functions like strcpy or memcpy are supposed
85 to adjust all previous strinfo lengths, but not following strinfo
86 lengths (those are uncertain, usually invalidated during
87 maybe_invalidate, except when the alias oracle knows better).
88 Functions like strcat on the other side adjust the whole
89 related strinfo chain.
90 They are updated lazily, so to use the chain the same first fields
91 and si->prev->next == si->idx needs to be verified. */
95 /* A flag whether the string is known to be written in the current
98 /* A flag for the next maybe_invalidate that this strinfo shouldn't
99 be invalidated. Always cleared by maybe_invalidate. */
100 bool dont_invalidate
;
103 /* Pool for allocating strinfo_struct entries. */
104 static object_allocator
<strinfo
> strinfo_pool ("strinfo pool");
106 /* Vector mapping positive string indexes to strinfo, for the
107 current basic block. The first pointer in the vector is special,
108 it is either NULL, meaning the vector isn't shared, or it is
109 a basic block pointer to the owner basic_block if shared.
110 If some other bb wants to modify the vector, the vector needs
111 to be unshared first, and only the owner bb is supposed to free it. */
112 static vec
<strinfo
*, va_heap
, vl_embed
> *stridx_to_strinfo
;
114 /* One OFFSET->IDX mapping. */
117 struct stridxlist
*next
;
118 HOST_WIDE_INT offset
;
122 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
123 struct decl_stridxlist_map
125 struct tree_map_base base
;
126 struct stridxlist list
;
129 /* Hash table for mapping decls to a chained list of offset -> idx
131 static hash_map
<tree_decl_hash
, stridxlist
> *decl_to_stridxlist_htab
;
133 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
134 static struct obstack stridx_obstack
;
136 /* Last memcpy statement if it could be adjusted if the trailing
137 '\0' written is immediately overwritten, or
138 *x = '\0' store that could be removed if it is immediately overwritten. */
139 struct laststmt_struct
146 static int get_stridx_plus_constant (strinfo
*, HOST_WIDE_INT
, tree
);
148 /* Return strinfo vector entry IDX. */
150 static inline strinfo
*
151 get_strinfo (int idx
)
153 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
155 return (*stridx_to_strinfo
)[idx
];
158 /* Helper function for get_stridx. */
161 get_addr_stridx (tree exp
)
164 struct stridxlist
*list
;
167 if (!decl_to_stridxlist_htab
)
170 base
= get_addr_base_and_unit_offset (exp
, &off
);
171 if (base
== NULL
|| !DECL_P (base
))
174 list
= decl_to_stridxlist_htab
->get (base
);
180 if (list
->offset
== off
)
188 /* Return string index for EXP. */
191 get_stridx (tree exp
)
195 if (TREE_CODE (exp
) == SSA_NAME
)
197 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
198 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
201 HOST_WIDE_INT off
= 0;
202 for (i
= 0; i
< 5; i
++)
204 gimple
*def_stmt
= SSA_NAME_DEF_STMT (e
);
205 if (!is_gimple_assign (def_stmt
)
206 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
208 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
209 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
210 if (TREE_CODE (rhs1
) != SSA_NAME
211 || !tree_fits_shwi_p (rhs2
))
213 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
216 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
219 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
222 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
225 && TREE_CODE (si
->length
) == INTEGER_CST
226 && compare_tree_int (si
->length
, off
) != -1)
227 return get_stridx_plus_constant (si
, off
, exp
);
234 if (TREE_CODE (exp
) == ADDR_EXPR
)
236 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
241 s
= string_constant (exp
, &o
);
243 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
244 && TREE_STRING_LENGTH (s
) > 0)
246 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
247 const char *p
= TREE_STRING_POINTER (s
);
248 int max
= TREE_STRING_LENGTH (s
) - 1;
250 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
251 return ~(int) strlen (p
+ offset
);
256 /* Return true if strinfo vector is shared with the immediate dominator. */
259 strinfo_shared (void)
261 return vec_safe_length (stridx_to_strinfo
)
262 && (*stridx_to_strinfo
)[0] != NULL
;
265 /* Unshare strinfo vector that is shared with the immediate dominator. */
268 unshare_strinfo_vec (void)
273 gcc_assert (strinfo_shared ());
274 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
275 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
278 (*stridx_to_strinfo
)[0] = NULL
;
281 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
282 Return a pointer to the location where the string index can
283 be stored (if 0) or is stored, or NULL if this can't be tracked. */
286 addr_stridxptr (tree exp
)
290 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
291 if (base
== NULL_TREE
|| !DECL_P (base
))
294 if (!decl_to_stridxlist_htab
)
296 decl_to_stridxlist_htab
297 = new hash_map
<tree_decl_hash
, stridxlist
> (64);
298 gcc_obstack_init (&stridx_obstack
);
302 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
306 for (i
= 0; i
< 16; i
++)
308 if (list
->offset
== off
)
310 if (list
->next
== NULL
)
315 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
325 /* Create a new string index, or return 0 if reached limit. */
328 new_stridx (tree exp
)
331 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
333 if (TREE_CODE (exp
) == SSA_NAME
)
335 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
338 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
341 if (TREE_CODE (exp
) == ADDR_EXPR
)
343 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
346 gcc_assert (*pidx
== 0);
347 *pidx
= max_stridx
++;
354 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
357 new_addr_stridx (tree exp
)
360 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
362 pidx
= addr_stridxptr (exp
);
365 gcc_assert (*pidx
== 0);
366 *pidx
= max_stridx
++;
372 /* Create a new strinfo. */
375 new_strinfo (tree ptr
, int idx
, tree length
)
377 strinfo
*si
= strinfo_pool
.allocate ();
381 si
->endptr
= NULL_TREE
;
387 si
->writable
= false;
388 si
->dont_invalidate
= false;
392 /* Decrease strinfo refcount and free it if not referenced anymore. */
395 free_strinfo (strinfo
*si
)
397 if (si
&& --si
->refcount
== 0)
398 strinfo_pool
.remove (si
);
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 refcount > 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 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
609 strinfo if there is any. Return it's idx, or 0 if no strinfo has
613 get_stridx_plus_constant (strinfo
*basesi
, HOST_WIDE_INT off
, tree ptr
)
615 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
617 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
620 if (basesi
->length
== NULL_TREE
621 || TREE_CODE (basesi
->length
) != INTEGER_CST
622 || compare_tree_int (basesi
->length
, off
) == -1
623 || !tree_fits_shwi_p (basesi
->length
))
626 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
627 strinfo
*si
= basesi
, *chainsi
;
628 if (si
->first
|| si
->prev
|| si
->next
)
629 si
= verify_related_strinfos (basesi
);
631 || si
->length
== NULL_TREE
632 || TREE_CODE (si
->length
) != INTEGER_CST
)
635 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
636 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
638 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
639 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
641 si
= get_strinfo (chainsi
->next
);
643 || si
->first
!= chainsi
->first
644 || si
->prev
!= chainsi
->idx
645 || si
->length
== NULL_TREE
646 || TREE_CODE (si
->length
) != INTEGER_CST
)
648 int r
= compare_tree_int (si
->length
, len
);
653 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
660 int idx
= new_stridx (ptr
);
663 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
664 set_strinfo (idx
, si
);
667 strinfo
*nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
668 si
->next
= nextsi
->idx
;
671 chainsi
= unshare_strinfo (chainsi
);
672 if (chainsi
->first
== 0)
673 chainsi
->first
= chainsi
->idx
;
675 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
676 chainsi
->endptr
= ptr
;
677 si
->endptr
= chainsi
->endptr
;
678 si
->prev
= chainsi
->idx
;
679 si
->first
= chainsi
->first
;
680 si
->writable
= chainsi
->writable
;
684 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
685 to a zero-length string and if possible chain it to a related strinfo
686 chain whose part is or might be CHAINSI. */
689 zero_length_string (tree ptr
, strinfo
*chainsi
)
693 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
694 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
695 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
696 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
698 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
702 si
= verify_related_strinfos (chainsi
);
706 for (; chainsi
->next
; chainsi
= si
)
708 if (chainsi
->endptr
== NULL_TREE
)
710 chainsi
= unshare_strinfo (chainsi
);
711 chainsi
->endptr
= ptr
;
713 si
= get_strinfo (chainsi
->next
);
715 || si
->first
!= chainsi
->first
716 || si
->prev
!= chainsi
->idx
)
719 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
720 if (chainsi
->endptr
== NULL_TREE
)
722 chainsi
= unshare_strinfo (chainsi
);
723 chainsi
->endptr
= ptr
;
725 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
729 chainsi
= unshare_strinfo (chainsi
);
732 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
736 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
738 chainsi
= unshare_strinfo (chainsi
);
744 idx
= new_stridx (ptr
);
747 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
748 set_strinfo (idx
, si
);
752 chainsi
= unshare_strinfo (chainsi
);
753 if (chainsi
->first
== 0)
754 chainsi
->first
= chainsi
->idx
;
756 if (chainsi
->endptr
== NULL_TREE
)
757 chainsi
->endptr
= ptr
;
758 si
->prev
= chainsi
->idx
;
759 si
->first
= chainsi
->first
;
760 si
->writable
= chainsi
->writable
;
765 /* For strinfo ORIGSI whose length has been just updated
766 update also related strinfo lengths (add ADJ to each,
767 but don't adjust ORIGSI). */
770 adjust_related_strinfos (location_t loc
, strinfo
*origsi
, tree adj
)
772 strinfo
*si
= verify_related_strinfos (origsi
);
785 si
= unshare_strinfo (si
);
788 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
789 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
790 TREE_TYPE (si
->length
), si
->length
,
793 else if (si
->stmt
!= NULL
)
794 /* Delayed length computation is unaffected. */
799 si
->endptr
= NULL_TREE
;
800 si
->dont_invalidate
= true;
804 nsi
= get_strinfo (si
->next
);
806 || nsi
->first
!= si
->first
807 || nsi
->prev
!= si
->idx
)
813 /* Find if there are other SSA_NAME pointers equal to PTR
814 for which we don't track their string lengths yet. If so, use
818 find_equal_ptrs (tree ptr
, int idx
)
820 if (TREE_CODE (ptr
) != SSA_NAME
)
824 gimple
*stmt
= SSA_NAME_DEF_STMT (ptr
);
825 if (!is_gimple_assign (stmt
))
827 ptr
= gimple_assign_rhs1 (stmt
);
828 switch (gimple_assign_rhs_code (stmt
))
833 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
835 if (TREE_CODE (ptr
) == SSA_NAME
)
837 if (TREE_CODE (ptr
) != ADDR_EXPR
)
842 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
843 if (pidx
!= NULL
&& *pidx
== 0)
851 /* We might find an endptr created in this pass. Grow the
852 vector in that case. */
853 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
854 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
856 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
858 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
862 /* Return true if STMT is a call to a builtin function with the right
863 arguments and attributes that should be considered for optimization
867 valid_builtin_call (gimple
*stmt
)
869 if (!gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
872 tree callee
= gimple_call_fndecl (stmt
);
873 switch (DECL_FUNCTION_CODE (callee
))
875 case BUILT_IN_MEMCMP
:
876 case BUILT_IN_STRCHR
:
877 case BUILT_IN_STRCHR_CHKP
:
878 case BUILT_IN_STRLEN
:
879 case BUILT_IN_STRLEN_CHKP
:
880 /* The above functions should be pure. Punt if they aren't. */
881 if (gimple_vdef (stmt
) || gimple_vuse (stmt
) == NULL_TREE
)
885 case BUILT_IN_CALLOC
:
886 case BUILT_IN_MALLOC
:
887 case BUILT_IN_MEMCPY
:
888 case BUILT_IN_MEMCPY_CHK
:
889 case BUILT_IN_MEMCPY_CHKP
:
890 case BUILT_IN_MEMCPY_CHK_CHKP
:
891 case BUILT_IN_MEMPCPY
:
892 case BUILT_IN_MEMPCPY_CHK
:
893 case BUILT_IN_MEMPCPY_CHKP
:
894 case BUILT_IN_MEMPCPY_CHK_CHKP
:
895 case BUILT_IN_MEMSET
:
896 case BUILT_IN_STPCPY
:
897 case BUILT_IN_STPCPY_CHK
:
898 case BUILT_IN_STPCPY_CHKP
:
899 case BUILT_IN_STPCPY_CHK_CHKP
:
900 case BUILT_IN_STRCAT
:
901 case BUILT_IN_STRCAT_CHK
:
902 case BUILT_IN_STRCAT_CHKP
:
903 case BUILT_IN_STRCAT_CHK_CHKP
:
904 case BUILT_IN_STRCPY
:
905 case BUILT_IN_STRCPY_CHK
:
906 case BUILT_IN_STRCPY_CHKP
:
907 case BUILT_IN_STRCPY_CHK_CHKP
:
908 /* The above functions should be neither const nor pure. Punt if they
910 if (gimple_vdef (stmt
) == NULL_TREE
|| gimple_vuse (stmt
) == NULL_TREE
)
921 /* If the last .MEM setter statement before STMT is
922 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
923 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
924 just memcpy (x, y, strlen (y)). SI must be the zero length
928 adjust_last_stmt (strinfo
*si
, gimple
*stmt
, bool is_strcat
)
930 tree vuse
, callee
, len
;
931 struct laststmt_struct last
= laststmt
;
932 strinfo
*lastsi
, *firstsi
;
933 unsigned len_arg_no
= 2;
935 laststmt
.stmt
= NULL
;
936 laststmt
.len
= NULL_TREE
;
939 if (last
.stmt
== NULL
)
942 vuse
= gimple_vuse (stmt
);
943 if (vuse
== NULL_TREE
944 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
945 || !has_single_use (vuse
))
948 gcc_assert (last
.stridx
> 0);
949 lastsi
= get_strinfo (last
.stridx
);
955 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
958 firstsi
= verify_related_strinfos (si
);
961 while (firstsi
!= lastsi
)
964 if (firstsi
->next
== 0)
966 nextsi
= get_strinfo (firstsi
->next
);
968 || nextsi
->prev
!= firstsi
->idx
969 || nextsi
->first
!= si
->first
)
977 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
981 if (is_gimple_assign (last
.stmt
))
983 gimple_stmt_iterator gsi
;
985 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
987 if (stmt_could_throw_p (last
.stmt
))
989 gsi
= gsi_for_stmt (last
.stmt
);
990 unlink_stmt_vdef (last
.stmt
);
991 release_defs (last
.stmt
);
992 gsi_remove (&gsi
, true);
996 if (!valid_builtin_call (last
.stmt
))
999 callee
= gimple_call_fndecl (last
.stmt
);
1000 switch (DECL_FUNCTION_CODE (callee
))
1002 case BUILT_IN_MEMCPY
:
1003 case BUILT_IN_MEMCPY_CHK
:
1005 case BUILT_IN_MEMCPY_CHKP
:
1006 case BUILT_IN_MEMCPY_CHK_CHKP
:
1013 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
1014 if (tree_fits_uhwi_p (len
))
1016 if (!tree_fits_uhwi_p (last
.len
)
1017 || integer_zerop (len
)
1018 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
1020 /* Don't adjust the length if it is divisible by 4, it is more efficient
1021 to store the extra '\0' in that case. */
1022 if ((tree_to_uhwi (len
) & 3) == 0)
1025 else if (TREE_CODE (len
) == SSA_NAME
)
1027 gimple
*def_stmt
= SSA_NAME_DEF_STMT (len
);
1028 if (!is_gimple_assign (def_stmt
)
1029 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1030 || gimple_assign_rhs1 (def_stmt
) != last
.len
1031 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1037 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
1038 update_stmt (last
.stmt
);
1041 /* Handle a strlen call. If strlen of the argument is known, replace
1042 the strlen call with the known value, otherwise remember that strlen
1043 of the argument is stored in the lhs SSA_NAME. */
1046 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1050 gimple
*stmt
= gsi_stmt (*gsi
);
1051 tree lhs
= gimple_call_lhs (stmt
);
1053 if (lhs
== NULL_TREE
)
1056 src
= gimple_call_arg (stmt
, 0);
1057 idx
= get_stridx (src
);
1064 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1068 si
= get_strinfo (idx
);
1070 rhs
= get_string_length (si
);
1072 if (rhs
!= NULL_TREE
)
1074 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1076 fprintf (dump_file
, "Optimizing: ");
1077 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1079 rhs
= unshare_expr (rhs
);
1080 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1081 rhs
= fold_convert_loc (gimple_location (stmt
),
1082 TREE_TYPE (lhs
), rhs
);
1083 if (!update_call_from_tree (gsi
, rhs
))
1084 gimplify_and_update_call_from_tree (gsi
, rhs
);
1085 stmt
= gsi_stmt (*gsi
);
1087 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1089 fprintf (dump_file
, "into: ");
1090 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1093 && TREE_CODE (si
->length
) != SSA_NAME
1094 && TREE_CODE (si
->length
) != INTEGER_CST
1095 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1097 si
= unshare_strinfo (si
);
1103 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1106 idx
= new_stridx (src
);
1107 else if (get_strinfo (idx
) != NULL
)
1111 strinfo
*si
= new_strinfo (src
, idx
, lhs
);
1112 set_strinfo (idx
, si
);
1113 find_equal_ptrs (src
, idx
);
1117 /* Handle a strchr call. If strlen of the first argument is known, replace
1118 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1119 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1122 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1126 gimple
*stmt
= gsi_stmt (*gsi
);
1127 tree lhs
= gimple_call_lhs (stmt
);
1128 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1130 if (lhs
== NULL_TREE
)
1133 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1136 src
= gimple_call_arg (stmt
, 0);
1137 idx
= get_stridx (src
);
1144 rhs
= build_int_cst (size_type_node
, ~idx
);
1148 si
= get_strinfo (idx
);
1150 rhs
= get_string_length (si
);
1152 if (rhs
!= NULL_TREE
)
1154 location_t loc
= gimple_location (stmt
);
1156 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1158 fprintf (dump_file
, "Optimizing: ");
1159 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1161 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1163 rhs
= unshare_expr (si
->endptr
);
1164 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1166 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1170 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1171 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1172 TREE_TYPE (src
), src
, rhs
);
1173 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1175 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1177 if (!update_call_from_tree (gsi
, rhs
))
1178 gimplify_and_update_call_from_tree (gsi
, rhs
);
1179 stmt
= gsi_stmt (*gsi
);
1181 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1183 fprintf (dump_file
, "into: ");
1184 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1187 && si
->endptr
== NULL_TREE
1188 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1190 si
= unshare_strinfo (si
);
1193 zero_length_string (lhs
, si
);
1197 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1199 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1202 idx
= new_stridx (src
);
1203 else if (get_strinfo (idx
) != NULL
)
1205 zero_length_string (lhs
, NULL
);
1210 location_t loc
= gimple_location (stmt
);
1211 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1212 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1213 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1214 size_type_node
, lhsu
, srcu
);
1215 strinfo
*si
= new_strinfo (src
, idx
, length
);
1217 set_strinfo (idx
, si
);
1218 find_equal_ptrs (src
, idx
);
1219 zero_length_string (lhs
, si
);
1223 zero_length_string (lhs
, NULL
);
1226 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1227 If strlen of the second argument is known, strlen of the first argument
1228 is the same after this call. Furthermore, attempt to convert it to
1232 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1235 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1237 gimple
*stmt
= gsi_stmt (*gsi
);
1238 strinfo
*si
, *dsi
, *olddsi
, *zsi
;
1240 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1242 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1243 dst
= gimple_call_arg (stmt
, 0);
1244 lhs
= gimple_call_lhs (stmt
);
1245 idx
= get_stridx (src
);
1248 si
= get_strinfo (idx
);
1250 didx
= get_stridx (dst
);
1254 olddsi
= get_strinfo (didx
);
1259 adjust_last_stmt (olddsi
, stmt
, false);
1263 srclen
= get_string_length (si
);
1265 srclen
= build_int_cst (size_type_node
, ~idx
);
1267 loc
= gimple_location (stmt
);
1268 if (srclen
== NULL_TREE
)
1271 case BUILT_IN_STRCPY
:
1272 case BUILT_IN_STRCPY_CHK
:
1273 case BUILT_IN_STRCPY_CHKP
:
1274 case BUILT_IN_STRCPY_CHK_CHKP
:
1275 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1278 case BUILT_IN_STPCPY
:
1279 case BUILT_IN_STPCPY_CHK
:
1280 case BUILT_IN_STPCPY_CHKP
:
1281 case BUILT_IN_STPCPY_CHK_CHKP
:
1282 if (lhs
== NULL_TREE
)
1286 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1287 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1288 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1298 didx
= new_stridx (dst
);
1304 oldlen
= olddsi
->length
;
1305 dsi
= unshare_strinfo (olddsi
);
1306 dsi
->length
= srclen
;
1307 /* Break the chain, so adjust_related_strinfo on later pointers in
1308 the chain won't adjust this one anymore. */
1311 dsi
->endptr
= NULL_TREE
;
1315 dsi
= new_strinfo (dst
, didx
, srclen
);
1316 set_strinfo (didx
, dsi
);
1317 find_equal_ptrs (dst
, didx
);
1319 dsi
->writable
= true;
1320 dsi
->dont_invalidate
= true;
1322 if (dsi
->length
== NULL_TREE
)
1326 /* If string length of src is unknown, use delayed length
1327 computation. If string lenth of dst will be needed, it
1328 can be computed by transforming this strcpy call into
1329 stpcpy and subtracting dst from the return value. */
1331 /* Look for earlier strings whose length could be determined if
1332 this strcpy is turned into an stpcpy. */
1334 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1336 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1338 /* When setting a stmt for delayed length computation
1339 prevent all strinfos through dsi from being
1341 chainsi
= unshare_strinfo (chainsi
);
1342 chainsi
->stmt
= stmt
;
1343 chainsi
->length
= NULL_TREE
;
1344 chainsi
->endptr
= NULL_TREE
;
1345 chainsi
->dont_invalidate
= true;
1354 tree adj
= NULL_TREE
;
1355 if (oldlen
== NULL_TREE
)
1357 else if (integer_zerop (oldlen
))
1359 else if (TREE_CODE (oldlen
) == INTEGER_CST
1360 || TREE_CODE (srclen
) == INTEGER_CST
)
1361 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1362 TREE_TYPE (srclen
), srclen
,
1363 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1365 if (adj
!= NULL_TREE
)
1366 adjust_related_strinfos (loc
, dsi
, adj
);
1370 /* strcpy src may not overlap dst, so src doesn't need to be
1371 invalidated either. */
1373 si
->dont_invalidate
= true;
1379 case BUILT_IN_STRCPY
:
1380 case BUILT_IN_STRCPY_CHKP
:
1381 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1383 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1385 case BUILT_IN_STRCPY_CHK
:
1386 case BUILT_IN_STRCPY_CHK_CHKP
:
1387 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1389 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1391 case BUILT_IN_STPCPY
:
1392 case BUILT_IN_STPCPY_CHKP
:
1393 /* This would need adjustment of the lhs (subtract one),
1394 or detection that the trailing '\0' doesn't need to be
1395 written, if it will be immediately overwritten.
1396 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1400 zsi
= zero_length_string (lhs
, dsi
);
1403 case BUILT_IN_STPCPY_CHK
:
1404 case BUILT_IN_STPCPY_CHK_CHKP
:
1405 /* This would need adjustment of the lhs (subtract one),
1406 or detection that the trailing '\0' doesn't need to be
1407 written, if it will be immediately overwritten.
1408 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1412 zsi
= zero_length_string (lhs
, dsi
);
1419 zsi
->dont_invalidate
= true;
1421 if (fn
== NULL_TREE
)
1424 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1425 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1427 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1428 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1429 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1431 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1433 fprintf (dump_file
, "Optimizing: ");
1434 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1438 fn
= chkp_maybe_create_clone (fn
)->decl
;
1439 if (gimple_call_num_args (stmt
) == 4)
1440 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1441 gimple_call_arg (stmt
, 1),
1443 gimple_call_arg (stmt
, 3),
1446 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1447 gimple_call_arg (stmt
, 1),
1449 gimple_call_arg (stmt
, 3),
1451 gimple_call_arg (stmt
, 4));
1454 if (gimple_call_num_args (stmt
) == 2)
1455 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1457 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1458 gimple_call_arg (stmt
, 2));
1461 stmt
= gsi_stmt (*gsi
);
1462 gimple_call_set_with_bounds (stmt
, with_bounds
);
1464 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1466 fprintf (dump_file
, "into: ");
1467 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1469 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1470 laststmt
.stmt
= stmt
;
1471 laststmt
.len
= srclen
;
1472 laststmt
.stridx
= dsi
->idx
;
1474 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1475 fprintf (dump_file
, "not possible.\n");
1478 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1479 If strlen of the second argument is known and length of the third argument
1480 is that plus one, strlen of the first argument is the same after this
1484 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1487 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1488 gimple
*stmt
= gsi_stmt (*gsi
);
1489 strinfo
*si
, *dsi
, *olddsi
;
1490 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1492 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1493 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1494 dst
= gimple_call_arg (stmt
, 0);
1495 idx
= get_stridx (src
);
1499 didx
= get_stridx (dst
);
1502 olddsi
= get_strinfo (didx
);
1507 && tree_fits_uhwi_p (len
)
1508 && !integer_zerop (len
))
1509 adjust_last_stmt (olddsi
, stmt
, false);
1515 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1516 si
= get_strinfo (idx
);
1517 if (si
== NULL
|| si
->length
== NULL_TREE
)
1519 if (TREE_CODE (len
) != SSA_NAME
)
1521 def_stmt
= SSA_NAME_DEF_STMT (len
);
1522 if (!is_gimple_assign (def_stmt
)
1523 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1524 || gimple_assign_rhs1 (def_stmt
) != si
->length
1525 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1531 /* Handle memcpy (x, "abcd", 5) or
1532 memcpy (x, "abc\0uvw", 7). */
1533 if (!tree_fits_uhwi_p (len
)
1534 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1538 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1539 adjust_last_stmt (olddsi
, stmt
, false);
1543 didx
= new_stridx (dst
);
1548 newlen
= si
->length
;
1550 newlen
= build_int_cst (size_type_node
, ~idx
);
1554 dsi
= unshare_strinfo (olddsi
);
1555 oldlen
= olddsi
->length
;
1556 dsi
->length
= newlen
;
1557 /* Break the chain, so adjust_related_strinfo on later pointers in
1558 the chain won't adjust this one anymore. */
1561 dsi
->endptr
= NULL_TREE
;
1565 dsi
= new_strinfo (dst
, didx
, newlen
);
1566 set_strinfo (didx
, dsi
);
1567 find_equal_ptrs (dst
, didx
);
1569 dsi
->writable
= true;
1570 dsi
->dont_invalidate
= true;
1573 tree adj
= NULL_TREE
;
1574 location_t loc
= gimple_location (stmt
);
1575 if (oldlen
== NULL_TREE
)
1577 else if (integer_zerop (oldlen
))
1579 else if (TREE_CODE (oldlen
) == INTEGER_CST
1580 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1581 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1582 TREE_TYPE (dsi
->length
), dsi
->length
,
1583 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1585 if (adj
!= NULL_TREE
)
1586 adjust_related_strinfos (loc
, dsi
, adj
);
1590 /* memcpy src may not overlap dst, so src doesn't need to be
1591 invalidated either. */
1593 si
->dont_invalidate
= true;
1595 lhs
= gimple_call_lhs (stmt
);
1598 case BUILT_IN_MEMCPY
:
1599 case BUILT_IN_MEMCPY_CHK
:
1600 case BUILT_IN_MEMCPY_CHKP
:
1601 case BUILT_IN_MEMCPY_CHK_CHKP
:
1602 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1603 laststmt
.stmt
= stmt
;
1604 laststmt
.len
= dsi
->length
;
1605 laststmt
.stridx
= dsi
->idx
;
1607 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1609 case BUILT_IN_MEMPCPY
:
1610 case BUILT_IN_MEMPCPY_CHK
:
1611 case BUILT_IN_MEMPCPY_CHKP
:
1612 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1619 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1620 If strlen of the second argument is known, strlen of the first argument
1621 is increased by the length of the second argument. Furthermore, attempt
1622 to convert it to memcpy/strcpy if the length of the first argument
1626 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1629 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1631 gimple
*stmt
= gsi_stmt (*gsi
);
1634 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1636 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1637 dst
= gimple_call_arg (stmt
, 0);
1638 lhs
= gimple_call_lhs (stmt
);
1640 didx
= get_stridx (dst
);
1646 dsi
= get_strinfo (didx
);
1647 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1649 /* strcat (p, q) can be transformed into
1650 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1651 with length endptr - p if we need to compute the length
1652 later on. Don't do this transformation if we don't need
1654 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1658 didx
= new_stridx (dst
);
1664 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1665 set_strinfo (didx
, dsi
);
1666 find_equal_ptrs (dst
, didx
);
1670 dsi
= unshare_strinfo (dsi
);
1671 dsi
->length
= NULL_TREE
;
1673 dsi
->endptr
= NULL_TREE
;
1675 dsi
->writable
= true;
1677 dsi
->dont_invalidate
= true;
1684 idx
= get_stridx (src
);
1686 srclen
= build_int_cst (size_type_node
, ~idx
);
1689 si
= get_strinfo (idx
);
1691 srclen
= get_string_length (si
);
1694 loc
= gimple_location (stmt
);
1695 dstlen
= dsi
->length
;
1696 endptr
= dsi
->endptr
;
1698 dsi
= unshare_strinfo (dsi
);
1699 dsi
->endptr
= NULL_TREE
;
1701 dsi
->writable
= true;
1703 if (srclen
!= NULL_TREE
)
1705 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1706 dsi
->length
, srclen
);
1707 adjust_related_strinfos (loc
, dsi
, srclen
);
1708 dsi
->dont_invalidate
= true;
1713 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1714 dsi
->dont_invalidate
= true;
1718 /* strcat src may not overlap dst, so src doesn't need to be
1719 invalidated either. */
1720 si
->dont_invalidate
= true;
1722 /* For now. Could remove the lhs from the call and add
1723 lhs = dst; afterwards. */
1731 case BUILT_IN_STRCAT
:
1732 case BUILT_IN_STRCAT_CHKP
:
1733 if (srclen
!= NULL_TREE
)
1734 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1736 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1738 case BUILT_IN_STRCAT_CHK
:
1739 case BUILT_IN_STRCAT_CHK_CHKP
:
1740 if (srclen
!= NULL_TREE
)
1741 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1743 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1744 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1750 if (fn
== NULL_TREE
)
1754 if (srclen
!= NULL_TREE
)
1756 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1757 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1759 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1760 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1761 build_int_cst (type
, 1));
1762 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1766 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1768 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1769 TREE_TYPE (dst
), unshare_expr (dst
),
1770 fold_convert_loc (loc
, sizetype
,
1771 unshare_expr (dstlen
)));
1772 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1774 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1776 fprintf (dump_file
, "Optimizing: ");
1777 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1781 fn
= chkp_maybe_create_clone (fn
)->decl
;
1782 if (srclen
!= NULL_TREE
)
1783 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1785 gimple_call_arg (stmt
, 1),
1787 gimple_call_arg (stmt
, 3),
1790 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1792 gimple_call_arg (stmt
, 1),
1794 gimple_call_arg (stmt
, 3),
1798 if (srclen
!= NULL_TREE
)
1799 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1800 dst
, src
, len
, objsz
);
1802 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1806 stmt
= gsi_stmt (*gsi
);
1807 gimple_call_set_with_bounds (stmt
, with_bounds
);
1809 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1811 fprintf (dump_file
, "into: ");
1812 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1814 /* If srclen == NULL, note that current string length can be
1815 computed by transforming this strcpy into stpcpy. */
1816 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1818 adjust_last_stmt (dsi
, stmt
, true);
1819 if (srclen
!= NULL_TREE
)
1821 laststmt
.stmt
= stmt
;
1822 laststmt
.len
= srclen
;
1823 laststmt
.stridx
= dsi
->idx
;
1826 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1827 fprintf (dump_file
, "not possible.\n");
1830 /* Handle a call to malloc or calloc. */
1833 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1835 gimple
*stmt
= gsi_stmt (*gsi
);
1836 tree lhs
= gimple_call_lhs (stmt
);
1837 gcc_assert (get_stridx (lhs
) == 0);
1838 int idx
= new_stridx (lhs
);
1839 tree length
= NULL_TREE
;
1840 if (bcode
== BUILT_IN_CALLOC
)
1841 length
= build_int_cst (size_type_node
, 0);
1842 strinfo
*si
= new_strinfo (lhs
, idx
, length
);
1843 if (bcode
== BUILT_IN_CALLOC
)
1845 set_strinfo (idx
, si
);
1846 si
->writable
= true;
1848 si
->dont_invalidate
= true;
1851 /* Handle a call to memset.
1852 After a call to calloc, memset(,0,) is unnecessary.
1853 memset(malloc(n),0,n) is calloc(n,1). */
1856 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1858 gimple
*stmt2
= gsi_stmt (*gsi
);
1859 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1861 tree ptr
= gimple_call_arg (stmt2
, 0);
1862 int idx1
= get_stridx (ptr
);
1865 strinfo
*si1
= get_strinfo (idx1
);
1868 gimple
*stmt1
= si1
->stmt
;
1869 if (!stmt1
|| !is_gimple_call (stmt1
))
1871 tree callee1
= gimple_call_fndecl (stmt1
);
1872 if (!valid_builtin_call (stmt1
))
1874 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1875 tree size
= gimple_call_arg (stmt2
, 2);
1876 if (code1
== BUILT_IN_CALLOC
)
1877 /* Not touching stmt1 */ ;
1878 else if (code1
== BUILT_IN_MALLOC
1879 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1881 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1882 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1883 size
, build_one_cst (size_type_node
));
1884 si1
->length
= build_int_cst (size_type_node
, 0);
1885 si1
->stmt
= gsi_stmt (gsi1
);
1889 tree lhs
= gimple_call_lhs (stmt2
);
1890 unlink_stmt_vdef (stmt2
);
1893 gimple
*assign
= gimple_build_assign (lhs
, ptr
);
1894 gsi_replace (gsi
, assign
, false);
1898 gsi_remove (gsi
, true);
1899 release_defs (stmt2
);
1905 /* Handle a POINTER_PLUS_EXPR statement.
1906 For p = "abcd" + 2; compute associated length, or if
1907 p = q + off is pointing to a '\0' character of a string, call
1908 zero_length_string on it. */
1911 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1913 gimple
*stmt
= gsi_stmt (*gsi
);
1914 tree lhs
= gimple_assign_lhs (stmt
), off
;
1915 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1923 tree off
= gimple_assign_rhs2 (stmt
);
1924 if (tree_fits_uhwi_p (off
)
1925 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1926 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1927 = ~(~idx
- (int) tree_to_uhwi (off
));
1931 si
= get_strinfo (idx
);
1932 if (si
== NULL
|| si
->length
== NULL_TREE
)
1935 off
= gimple_assign_rhs2 (stmt
);
1937 if (operand_equal_p (si
->length
, off
, 0))
1938 zsi
= zero_length_string (lhs
, si
);
1939 else if (TREE_CODE (off
) == SSA_NAME
)
1941 gimple
*def_stmt
= SSA_NAME_DEF_STMT (off
);
1942 if (gimple_assign_single_p (def_stmt
)
1943 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1944 zsi
= zero_length_string (lhs
, si
);
1947 && si
->endptr
!= NULL_TREE
1948 && si
->endptr
!= lhs
1949 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1951 enum tree_code rhs_code
1952 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1953 ? SSA_NAME
: NOP_EXPR
;
1954 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1955 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1960 /* Handle a single character store. */
1963 handle_char_store (gimple_stmt_iterator
*gsi
)
1967 gimple
*stmt
= gsi_stmt (*gsi
);
1968 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1970 if (TREE_CODE (lhs
) == MEM_REF
1971 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1973 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1975 ssaname
= TREE_OPERAND (lhs
, 0);
1976 idx
= get_stridx (ssaname
);
1980 idx
= get_addr_stridx (lhs
);
1984 si
= get_strinfo (idx
);
1985 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1987 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1989 /* When storing '\0', the store can be removed
1990 if we know it has been stored in the current function. */
1991 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1993 unlink_stmt_vdef (stmt
);
1994 release_defs (stmt
);
1995 gsi_remove (gsi
, true);
2000 si
->writable
= true;
2006 /* Otherwise this statement overwrites the '\0' with
2007 something, if the previous stmt was a memcpy,
2008 its length may be decreased. */
2009 adjust_last_stmt (si
, stmt
, false);
2011 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
2013 si
= unshare_strinfo (si
);
2014 si
->length
= build_int_cst (size_type_node
, 0);
2020 si
->writable
= true;
2021 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2022 si
->endptr
= ssaname
;
2023 si
->dont_invalidate
= true;
2025 /* If si->length is non-zero constant, we aren't overwriting '\0',
2026 and if we aren't storing '\0', we know that the length of the
2027 string and any other zero terminated string in memory remains
2028 the same. In that case we move to the next gimple statement and
2029 return to signal the caller that it shouldn't invalidate anything.
2031 This is benefical for cases like:
2036 strcpy (p, "foobar");
2037 size_t len = strlen (p); // This can be optimized into 6
2038 size_t len2 = strlen (q); // This has to be computed
2040 size_t len3 = strlen (p); // This can be optimized into 6
2041 size_t len4 = strlen (q); // This can be optimized into len2
2042 bar (len, len2, len3, len4);
2045 else if (si
!= NULL
&& si
->length
!= NULL_TREE
2046 && TREE_CODE (si
->length
) == INTEGER_CST
2047 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2053 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2057 si
= zero_length_string (ssaname
, NULL
);
2059 si
->dont_invalidate
= true;
2063 int idx
= new_addr_stridx (lhs
);
2066 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2067 build_int_cst (size_type_node
, 0));
2068 set_strinfo (idx
, si
);
2069 si
->dont_invalidate
= true;
2073 si
->writable
= true;
2076 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2077 && ssaname
== NULL_TREE
2078 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2080 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2081 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2082 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2084 int idx
= new_addr_stridx (lhs
);
2087 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2088 build_int_cst (size_type_node
, l
));
2089 set_strinfo (idx
, si
);
2090 si
->dont_invalidate
= true;
2095 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2097 /* Allow adjust_last_stmt to remove it if the stored '\0'
2098 is immediately overwritten. */
2099 laststmt
.stmt
= stmt
;
2100 laststmt
.len
= build_int_cst (size_type_node
, 1);
2101 laststmt
.stridx
= si
->idx
;
2106 /* Attempt to optimize a single statement at *GSI using string length
2110 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2112 gimple
*stmt
= gsi_stmt (*gsi
);
2114 if (is_gimple_call (stmt
))
2116 tree callee
= gimple_call_fndecl (stmt
);
2117 if (valid_builtin_call (stmt
))
2118 switch (DECL_FUNCTION_CODE (callee
))
2120 case BUILT_IN_STRLEN
:
2121 case BUILT_IN_STRLEN_CHKP
:
2122 handle_builtin_strlen (gsi
);
2124 case BUILT_IN_STRCHR
:
2125 case BUILT_IN_STRCHR_CHKP
:
2126 handle_builtin_strchr (gsi
);
2128 case BUILT_IN_STRCPY
:
2129 case BUILT_IN_STRCPY_CHK
:
2130 case BUILT_IN_STPCPY
:
2131 case BUILT_IN_STPCPY_CHK
:
2132 case BUILT_IN_STRCPY_CHKP
:
2133 case BUILT_IN_STRCPY_CHK_CHKP
:
2134 case BUILT_IN_STPCPY_CHKP
:
2135 case BUILT_IN_STPCPY_CHK_CHKP
:
2136 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2138 case BUILT_IN_MEMCPY
:
2139 case BUILT_IN_MEMCPY_CHK
:
2140 case BUILT_IN_MEMPCPY
:
2141 case BUILT_IN_MEMPCPY_CHK
:
2142 case BUILT_IN_MEMCPY_CHKP
:
2143 case BUILT_IN_MEMCPY_CHK_CHKP
:
2144 case BUILT_IN_MEMPCPY_CHKP
:
2145 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2146 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2148 case BUILT_IN_STRCAT
:
2149 case BUILT_IN_STRCAT_CHK
:
2150 case BUILT_IN_STRCAT_CHKP
:
2151 case BUILT_IN_STRCAT_CHK_CHKP
:
2152 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2154 case BUILT_IN_MALLOC
:
2155 case BUILT_IN_CALLOC
:
2156 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2158 case BUILT_IN_MEMSET
:
2159 if (!handle_builtin_memset (gsi
))
2166 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2168 tree lhs
= gimple_assign_lhs (stmt
);
2170 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2172 if (gimple_assign_single_p (stmt
)
2173 || (gimple_assign_cast_p (stmt
)
2174 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2176 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2177 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2179 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2180 handle_pointer_plus (gsi
);
2182 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2184 tree type
= TREE_TYPE (lhs
);
2185 if (TREE_CODE (type
) == ARRAY_TYPE
)
2186 type
= TREE_TYPE (type
);
2187 if (TREE_CODE (type
) == INTEGER_TYPE
2188 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2189 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2191 if (! handle_char_store (gsi
))
2197 if (gimple_vdef (stmt
))
2198 maybe_invalidate (stmt
);
2202 /* Recursively call maybe_invalidate on stmts that might be executed
2203 in between dombb and current bb and that contain a vdef. Stop when
2204 *count stmts are inspected, or if the whole strinfo vector has
2205 been invalidated. */
2208 do_invalidate (basic_block dombb
, gimple
*phi
, bitmap visited
, int *count
)
2210 unsigned int i
, n
= gimple_phi_num_args (phi
);
2212 for (i
= 0; i
< n
; i
++)
2214 tree vuse
= gimple_phi_arg_def (phi
, i
);
2215 gimple
*stmt
= SSA_NAME_DEF_STMT (vuse
);
2216 basic_block bb
= gimple_bb (stmt
);
2219 || !bitmap_set_bit (visited
, bb
->index
)
2220 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2224 if (gimple_code (stmt
) == GIMPLE_PHI
)
2226 do_invalidate (dombb
, stmt
, visited
, count
);
2233 if (!maybe_invalidate (stmt
))
2238 vuse
= gimple_vuse (stmt
);
2239 stmt
= SSA_NAME_DEF_STMT (vuse
);
2240 if (gimple_bb (stmt
) != bb
)
2242 bb
= gimple_bb (stmt
);
2245 || !bitmap_set_bit (visited
, bb
->index
)
2246 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2253 class strlen_dom_walker
: public dom_walker
2256 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2258 virtual edge
before_dom_children (basic_block
);
2259 virtual void after_dom_children (basic_block
);
2262 /* Callback for walk_dominator_tree. Attempt to optimize various
2263 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2266 strlen_dom_walker::before_dom_children (basic_block bb
)
2268 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2271 stridx_to_strinfo
= NULL
;
2274 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) dombb
->aux
);
2275 if (stridx_to_strinfo
)
2277 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2280 gphi
*phi
= gsi
.phi ();
2281 if (virtual_operand_p (gimple_phi_result (phi
)))
2283 bitmap visited
= BITMAP_ALLOC (NULL
);
2284 int count_vdef
= 100;
2285 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2286 BITMAP_FREE (visited
);
2287 if (count_vdef
== 0)
2289 /* If there were too many vdefs in between immediate
2290 dominator and current bb, invalidate everything.
2291 If stridx_to_strinfo has been unshared, we need
2292 to free it, otherwise just set it to NULL. */
2293 if (!strinfo_shared ())
2299 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2303 (*stridx_to_strinfo
)[i
] = NULL
;
2307 stridx_to_strinfo
= NULL
;
2315 /* If all PHI arguments have the same string index, the PHI result
2317 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2320 gphi
*phi
= gsi
.phi ();
2321 tree result
= gimple_phi_result (phi
);
2322 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2324 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2327 unsigned int i
, n
= gimple_phi_num_args (phi
);
2328 for (i
= 1; i
< n
; i
++)
2329 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2332 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2337 /* Attempt to optimize individual statements. */
2338 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2339 if (strlen_optimize_stmt (&gsi
))
2342 bb
->aux
= stridx_to_strinfo
;
2343 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2344 (*stridx_to_strinfo
)[0] = (strinfo
*) bb
;
2348 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2349 owned by the current bb, clear bb->aux. */
2352 strlen_dom_walker::after_dom_children (basic_block bb
)
2356 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) bb
->aux
);
2357 if (vec_safe_length (stridx_to_strinfo
)
2358 && (*stridx_to_strinfo
)[0] == (strinfo
*) bb
)
2363 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2365 vec_free (stridx_to_strinfo
);
2371 /* Main entry point. */
2375 const pass_data pass_data_strlen
=
2377 GIMPLE_PASS
, /* type */
2378 "strlen", /* name */
2379 OPTGROUP_NONE
, /* optinfo_flags */
2380 TV_TREE_STRLEN
, /* tv_id */
2381 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2382 0, /* properties_provided */
2383 0, /* properties_destroyed */
2384 0, /* todo_flags_start */
2385 0, /* todo_flags_finish */
2388 class pass_strlen
: public gimple_opt_pass
2391 pass_strlen (gcc::context
*ctxt
)
2392 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2395 /* opt_pass methods: */
2396 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2397 virtual unsigned int execute (function
*);
2399 }; // class pass_strlen
2402 pass_strlen::execute (function
*fun
)
2404 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2407 calculate_dominance_info (CDI_DOMINATORS
);
2409 /* String length optimization is implemented as a walk of the dominator
2410 tree and a forward walk of statements within each block. */
2411 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2413 ssa_ver_to_stridx
.release ();
2414 strinfo_pool
.release ();
2415 if (decl_to_stridxlist_htab
)
2417 obstack_free (&stridx_obstack
, NULL
);
2418 delete decl_to_stridxlist_htab
;
2419 decl_to_stridxlist_htab
= NULL
;
2421 laststmt
.stmt
= NULL
;
2422 laststmt
.len
= NULL_TREE
;
2423 laststmt
.stridx
= 0;
2431 make_pass_strlen (gcc::context
*ctxt
)
2433 return new pass_strlen (ctxt
);