1 /* String length optimization
2 Copyright (C) 2011-2015 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 "insn-config.h"
35 #include "gimple-pretty-print.h"
37 #include "fold-const.h"
38 #include "stor-layout.h"
39 #include "internal-fn.h"
40 #include "gimple-fold.h"
43 #include "gimple-iterator.h"
44 #include "gimplify-me.h"
54 #include "tree-ssa-propagate.h"
57 #include "tree-hash-traits.h"
59 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
60 is an index into strinfo vector, negative value stands for
61 string length of a string literal (~strlen). */
62 static vec
<int> ssa_ver_to_stridx
;
64 /* Number of currently active string indexes plus one. */
65 static int max_stridx
;
67 /* String information record. */
70 /* String length of this string. */
72 /* Any of the corresponding pointers for querying alias oracle. */
74 /* Statement for delayed length computation. */
76 /* Pointer to '\0' if known, if NULL, it can be computed as
79 /* Reference count. Any changes to strinfo entry possibly shared
80 with dominating basic blocks need unshare_strinfo first, except
81 for dont_invalidate which affects only the immediately next
84 /* Copy of index. get_strinfo (si->idx) should return si; */
86 /* These 3 fields are for chaining related string pointers together.
88 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
89 strcpy (c, d); e = c + dl;
90 strinfo(a) -> strinfo(c) -> strinfo(e)
91 All have ->first field equal to strinfo(a)->idx and are doubly
92 chained through prev/next fields. The later strinfos are required
93 to point into the same string with zero or more bytes after
94 the previous pointer and all bytes in between the two pointers
95 must be non-zero. Functions like strcpy or memcpy are supposed
96 to adjust all previous strinfo lengths, but not following strinfo
97 lengths (those are uncertain, usually invalidated during
98 maybe_invalidate, except when the alias oracle knows better).
99 Functions like strcat on the other side adjust the whole
100 related strinfo chain.
101 They are updated lazily, so to use the chain the same first fields
102 and si->prev->next == si->idx needs to be verified. */
106 /* A flag whether the string is known to be written in the current
109 /* A flag for the next maybe_invalidate that this strinfo shouldn't
110 be invalidated. Always cleared by maybe_invalidate. */
111 bool dont_invalidate
;
114 /* Pool for allocating strinfo_struct entries. */
115 static object_allocator
<strinfo
> strinfo_pool ("strinfo pool");
117 /* Vector mapping positive string indexes to strinfo, for the
118 current basic block. The first pointer in the vector is special,
119 it is either NULL, meaning the vector isn't shared, or it is
120 a basic block pointer to the owner basic_block if shared.
121 If some other bb wants to modify the vector, the vector needs
122 to be unshared first, and only the owner bb is supposed to free it. */
123 static vec
<strinfo
*, va_heap
, vl_embed
> *stridx_to_strinfo
;
125 /* One OFFSET->IDX mapping. */
128 struct stridxlist
*next
;
129 HOST_WIDE_INT offset
;
133 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
134 struct decl_stridxlist_map
136 struct tree_map_base base
;
137 struct stridxlist list
;
140 /* Hash table for mapping decls to a chained list of offset -> idx
142 static hash_map
<tree_decl_hash
, stridxlist
> *decl_to_stridxlist_htab
;
144 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
145 static struct obstack stridx_obstack
;
147 /* Last memcpy statement if it could be adjusted if the trailing
148 '\0' written is immediately overwritten, or
149 *x = '\0' store that could be removed if it is immediately overwritten. */
150 struct laststmt_struct
157 static int get_stridx_plus_constant (strinfo
*, HOST_WIDE_INT
, tree
);
159 /* Return strinfo vector entry IDX. */
161 static inline strinfo
*
162 get_strinfo (int idx
)
164 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
166 return (*stridx_to_strinfo
)[idx
];
169 /* Helper function for get_stridx. */
172 get_addr_stridx (tree exp
)
175 struct stridxlist
*list
;
178 if (!decl_to_stridxlist_htab
)
181 base
= get_addr_base_and_unit_offset (exp
, &off
);
182 if (base
== NULL
|| !DECL_P (base
))
185 list
= decl_to_stridxlist_htab
->get (base
);
191 if (list
->offset
== off
)
199 /* Return string index for EXP. */
202 get_stridx (tree exp
)
206 if (TREE_CODE (exp
) == SSA_NAME
)
208 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
209 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
212 HOST_WIDE_INT off
= 0;
213 for (i
= 0; i
< 5; i
++)
215 gimple
*def_stmt
= SSA_NAME_DEF_STMT (e
);
216 if (!is_gimple_assign (def_stmt
)
217 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
219 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
220 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
221 if (TREE_CODE (rhs1
) != SSA_NAME
222 || !tree_fits_shwi_p (rhs2
))
224 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
227 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
230 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
233 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
236 && TREE_CODE (si
->length
) == INTEGER_CST
237 && compare_tree_int (si
->length
, off
) != -1)
238 return get_stridx_plus_constant (si
, off
, exp
);
245 if (TREE_CODE (exp
) == ADDR_EXPR
)
247 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
252 s
= string_constant (exp
, &o
);
254 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
255 && TREE_STRING_LENGTH (s
) > 0)
257 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
258 const char *p
= TREE_STRING_POINTER (s
);
259 int max
= TREE_STRING_LENGTH (s
) - 1;
261 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
262 return ~(int) strlen (p
+ offset
);
267 /* Return true if strinfo vector is shared with the immediate dominator. */
270 strinfo_shared (void)
272 return vec_safe_length (stridx_to_strinfo
)
273 && (*stridx_to_strinfo
)[0] != NULL
;
276 /* Unshare strinfo vector that is shared with the immediate dominator. */
279 unshare_strinfo_vec (void)
284 gcc_assert (strinfo_shared ());
285 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
286 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
289 (*stridx_to_strinfo
)[0] = NULL
;
292 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
293 Return a pointer to the location where the string index can
294 be stored (if 0) or is stored, or NULL if this can't be tracked. */
297 addr_stridxptr (tree exp
)
301 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
302 if (base
== NULL_TREE
|| !DECL_P (base
))
305 if (!decl_to_stridxlist_htab
)
307 decl_to_stridxlist_htab
308 = new hash_map
<tree_decl_hash
, stridxlist
> (64);
309 gcc_obstack_init (&stridx_obstack
);
313 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
317 for (i
= 0; i
< 16; i
++)
319 if (list
->offset
== off
)
321 if (list
->next
== NULL
)
326 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
336 /* Create a new string index, or return 0 if reached limit. */
339 new_stridx (tree exp
)
342 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
344 if (TREE_CODE (exp
) == SSA_NAME
)
346 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
349 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
352 if (TREE_CODE (exp
) == ADDR_EXPR
)
354 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
357 gcc_assert (*pidx
== 0);
358 *pidx
= max_stridx
++;
365 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
368 new_addr_stridx (tree exp
)
371 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
373 pidx
= addr_stridxptr (exp
);
376 gcc_assert (*pidx
== 0);
377 *pidx
= max_stridx
++;
383 /* Create a new strinfo. */
386 new_strinfo (tree ptr
, int idx
, tree length
)
388 strinfo
*si
= strinfo_pool
.allocate ();
392 si
->endptr
= NULL_TREE
;
398 si
->writable
= false;
399 si
->dont_invalidate
= false;
403 /* Decrease strinfo refcount and free it if not referenced anymore. */
406 free_strinfo (strinfo
*si
)
408 if (si
&& --si
->refcount
== 0)
409 strinfo_pool
.remove (si
);
412 /* Set strinfo in the vector entry IDX to SI. */
415 set_strinfo (int idx
, strinfo
*si
)
417 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
418 unshare_strinfo_vec ();
419 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
420 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
421 (*stridx_to_strinfo
)[idx
] = si
;
424 /* Return string length, or NULL if it can't be computed. */
427 get_string_length (strinfo
*si
)
434 gimple
*stmt
= si
->stmt
, *lenstmt
;
435 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
436 tree callee
, lhs
, fn
, tem
;
438 gimple_stmt_iterator gsi
;
440 gcc_assert (is_gimple_call (stmt
));
441 callee
= gimple_call_fndecl (stmt
);
442 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
443 lhs
= gimple_call_lhs (stmt
);
444 /* unshare_strinfo is intentionally not called here. The (delayed)
445 transformation of strcpy or strcat into stpcpy is done at the place
446 of the former strcpy/strcat call and so can affect all the strinfos
447 with the same stmt. If they were unshared before and transformation
448 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
449 just compute the right length. */
450 switch (DECL_FUNCTION_CODE (callee
))
452 case BUILT_IN_STRCAT
:
453 case BUILT_IN_STRCAT_CHK
:
454 case BUILT_IN_STRCAT_CHKP
:
455 case BUILT_IN_STRCAT_CHK_CHKP
:
456 gsi
= gsi_for_stmt (stmt
);
457 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
458 gcc_assert (lhs
== NULL_TREE
);
459 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
462 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
463 2, tem
, gimple_call_arg (stmt
, 1));
464 gimple_call_set_with_bounds (lenstmt
, true);
467 lenstmt
= gimple_build_call (fn
, 1, tem
);
468 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
469 gimple_call_set_lhs (lenstmt
, lhs
);
470 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
471 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
472 tem
= gimple_call_arg (stmt
, 0);
473 if (!ptrofftype_p (TREE_TYPE (lhs
)))
475 lhs
= convert_to_ptrofftype (lhs
);
476 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
477 true, GSI_SAME_STMT
);
479 lenstmt
= gimple_build_assign
480 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
481 POINTER_PLUS_EXPR
,tem
, lhs
);
482 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
483 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
486 case BUILT_IN_STRCPY
:
487 case BUILT_IN_STRCPY_CHK
:
488 case BUILT_IN_STRCPY_CHKP
:
489 case BUILT_IN_STRCPY_CHK_CHKP
:
490 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
491 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
492 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
494 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
496 fn
= chkp_maybe_create_clone (fn
)->decl
;
497 gcc_assert (lhs
== NULL_TREE
);
498 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
500 fprintf (dump_file
, "Optimizing: ");
501 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
503 gimple_call_set_fndecl (stmt
, fn
);
504 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
505 gimple_call_set_lhs (stmt
, lhs
);
507 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
509 fprintf (dump_file
, "into: ");
510 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
513 case BUILT_IN_STPCPY
:
514 case BUILT_IN_STPCPY_CHK
:
515 case BUILT_IN_STPCPY_CHKP
:
516 case BUILT_IN_STPCPY_CHK_CHKP
:
517 gcc_assert (lhs
!= NULL_TREE
);
518 loc
= gimple_location (stmt
);
521 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
522 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
523 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
526 case BUILT_IN_MALLOC
:
528 /* BUILT_IN_CALLOC always has si->length set. */
538 /* Invalidate string length information for strings whose length
539 might change due to stores in stmt. */
542 maybe_invalidate (gimple
*stmt
)
546 bool nonempty
= false;
548 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
551 if (!si
->dont_invalidate
)
554 /* Do not use si->length. */
555 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
556 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
558 set_strinfo (i
, NULL
);
563 si
->dont_invalidate
= false;
569 /* Unshare strinfo record SI, if it has refcount > 1 or
570 if stridx_to_strinfo vector is shared with some other
574 unshare_strinfo (strinfo
*si
)
578 if (si
->refcount
== 1 && !strinfo_shared ())
581 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
582 nsi
->stmt
= si
->stmt
;
583 nsi
->endptr
= si
->endptr
;
584 nsi
->first
= si
->first
;
585 nsi
->prev
= si
->prev
;
586 nsi
->next
= si
->next
;
587 nsi
->writable
= si
->writable
;
588 set_strinfo (si
->idx
, nsi
);
593 /* Return first strinfo in the related strinfo chain
594 if all strinfos in between belong to the chain, otherwise
598 verify_related_strinfos (strinfo
*origsi
)
600 strinfo
*si
= origsi
, *psi
;
602 if (origsi
->first
== 0)
604 for (; si
->prev
; si
= psi
)
606 if (si
->first
!= origsi
->first
)
608 psi
= get_strinfo (si
->prev
);
611 if (psi
->next
!= si
->idx
)
614 if (si
->idx
!= si
->first
)
619 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
620 strinfo if there is any. Return it's idx, or 0 if no strinfo has
624 get_stridx_plus_constant (strinfo
*basesi
, HOST_WIDE_INT off
, tree ptr
)
626 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
628 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
631 if (basesi
->length
== NULL_TREE
632 || TREE_CODE (basesi
->length
) != INTEGER_CST
633 || compare_tree_int (basesi
->length
, off
) == -1
634 || !tree_fits_shwi_p (basesi
->length
))
637 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
638 strinfo
*si
= basesi
, *chainsi
;
639 if (si
->first
|| si
->prev
|| si
->next
)
640 si
= verify_related_strinfos (basesi
);
642 || si
->length
== NULL_TREE
643 || TREE_CODE (si
->length
) != INTEGER_CST
)
646 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
647 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
649 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
650 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
652 si
= get_strinfo (chainsi
->next
);
654 || si
->first
!= chainsi
->first
655 || si
->prev
!= chainsi
->idx
656 || si
->length
== NULL_TREE
657 || TREE_CODE (si
->length
) != INTEGER_CST
)
659 int r
= compare_tree_int (si
->length
, len
);
664 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
671 int idx
= new_stridx (ptr
);
674 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
675 set_strinfo (idx
, si
);
678 strinfo
*nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
679 si
->next
= nextsi
->idx
;
682 chainsi
= unshare_strinfo (chainsi
);
683 if (chainsi
->first
== 0)
684 chainsi
->first
= chainsi
->idx
;
686 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
687 chainsi
->endptr
= ptr
;
688 si
->endptr
= chainsi
->endptr
;
689 si
->prev
= chainsi
->idx
;
690 si
->first
= chainsi
->first
;
691 si
->writable
= chainsi
->writable
;
695 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
696 to a zero-length string and if possible chain it to a related strinfo
697 chain whose part is or might be CHAINSI. */
700 zero_length_string (tree ptr
, strinfo
*chainsi
)
704 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
705 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
706 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
707 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
709 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
713 si
= verify_related_strinfos (chainsi
);
717 for (; chainsi
->next
; chainsi
= si
)
719 if (chainsi
->endptr
== NULL_TREE
)
721 chainsi
= unshare_strinfo (chainsi
);
722 chainsi
->endptr
= ptr
;
724 si
= get_strinfo (chainsi
->next
);
726 || si
->first
!= chainsi
->first
727 || si
->prev
!= chainsi
->idx
)
730 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
731 if (chainsi
->endptr
== NULL_TREE
)
733 chainsi
= unshare_strinfo (chainsi
);
734 chainsi
->endptr
= ptr
;
736 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
740 chainsi
= unshare_strinfo (chainsi
);
743 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
747 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
749 chainsi
= unshare_strinfo (chainsi
);
755 idx
= new_stridx (ptr
);
758 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
759 set_strinfo (idx
, si
);
763 chainsi
= unshare_strinfo (chainsi
);
764 if (chainsi
->first
== 0)
765 chainsi
->first
= chainsi
->idx
;
767 if (chainsi
->endptr
== NULL_TREE
)
768 chainsi
->endptr
= ptr
;
769 si
->prev
= chainsi
->idx
;
770 si
->first
= chainsi
->first
;
771 si
->writable
= chainsi
->writable
;
776 /* For strinfo ORIGSI whose length has been just updated
777 update also related strinfo lengths (add ADJ to each,
778 but don't adjust ORIGSI). */
781 adjust_related_strinfos (location_t loc
, strinfo
*origsi
, tree adj
)
783 strinfo
*si
= verify_related_strinfos (origsi
);
796 si
= unshare_strinfo (si
);
799 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
800 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
801 TREE_TYPE (si
->length
), si
->length
,
804 else if (si
->stmt
!= NULL
)
805 /* Delayed length computation is unaffected. */
810 si
->endptr
= NULL_TREE
;
811 si
->dont_invalidate
= true;
815 nsi
= get_strinfo (si
->next
);
817 || nsi
->first
!= si
->first
818 || nsi
->prev
!= si
->idx
)
824 /* Find if there are other SSA_NAME pointers equal to PTR
825 for which we don't track their string lengths yet. If so, use
829 find_equal_ptrs (tree ptr
, int idx
)
831 if (TREE_CODE (ptr
) != SSA_NAME
)
835 gimple
*stmt
= SSA_NAME_DEF_STMT (ptr
);
836 if (!is_gimple_assign (stmt
))
838 ptr
= gimple_assign_rhs1 (stmt
);
839 switch (gimple_assign_rhs_code (stmt
))
844 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
846 if (TREE_CODE (ptr
) == SSA_NAME
)
848 if (TREE_CODE (ptr
) != ADDR_EXPR
)
853 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
854 if (pidx
!= NULL
&& *pidx
== 0)
862 /* We might find an endptr created in this pass. Grow the
863 vector in that case. */
864 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
865 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
867 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
869 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
873 /* If the last .MEM setter statement before STMT is
874 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
875 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
876 just memcpy (x, y, strlen (y)). SI must be the zero length
880 adjust_last_stmt (strinfo
*si
, gimple
*stmt
, bool is_strcat
)
882 tree vuse
, callee
, len
;
883 struct laststmt_struct last
= laststmt
;
884 strinfo
*lastsi
, *firstsi
;
885 unsigned len_arg_no
= 2;
887 laststmt
.stmt
= NULL
;
888 laststmt
.len
= NULL_TREE
;
891 if (last
.stmt
== NULL
)
894 vuse
= gimple_vuse (stmt
);
895 if (vuse
== NULL_TREE
896 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
897 || !has_single_use (vuse
))
900 gcc_assert (last
.stridx
> 0);
901 lastsi
= get_strinfo (last
.stridx
);
907 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
910 firstsi
= verify_related_strinfos (si
);
913 while (firstsi
!= lastsi
)
916 if (firstsi
->next
== 0)
918 nextsi
= get_strinfo (firstsi
->next
);
920 || nextsi
->prev
!= firstsi
->idx
921 || nextsi
->first
!= si
->first
)
929 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
933 if (is_gimple_assign (last
.stmt
))
935 gimple_stmt_iterator gsi
;
937 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
939 if (stmt_could_throw_p (last
.stmt
))
941 gsi
= gsi_for_stmt (last
.stmt
);
942 unlink_stmt_vdef (last
.stmt
);
943 release_defs (last
.stmt
);
944 gsi_remove (&gsi
, true);
948 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
951 callee
= gimple_call_fndecl (last
.stmt
);
952 switch (DECL_FUNCTION_CODE (callee
))
954 case BUILT_IN_MEMCPY
:
955 case BUILT_IN_MEMCPY_CHK
:
957 case BUILT_IN_MEMCPY_CHKP
:
958 case BUILT_IN_MEMCPY_CHK_CHKP
:
965 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
966 if (tree_fits_uhwi_p (len
))
968 if (!tree_fits_uhwi_p (last
.len
)
969 || integer_zerop (len
)
970 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
972 /* Don't adjust the length if it is divisible by 4, it is more efficient
973 to store the extra '\0' in that case. */
974 if ((tree_to_uhwi (len
) & 3) == 0)
977 else if (TREE_CODE (len
) == SSA_NAME
)
979 gimple
*def_stmt
= SSA_NAME_DEF_STMT (len
);
980 if (!is_gimple_assign (def_stmt
)
981 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
982 || gimple_assign_rhs1 (def_stmt
) != last
.len
983 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
989 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
990 update_stmt (last
.stmt
);
993 /* Handle a strlen call. If strlen of the argument is known, replace
994 the strlen call with the known value, otherwise remember that strlen
995 of the argument is stored in the lhs SSA_NAME. */
998 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1002 gimple
*stmt
= gsi_stmt (*gsi
);
1003 tree lhs
= gimple_call_lhs (stmt
);
1005 if (lhs
== NULL_TREE
)
1008 src
= gimple_call_arg (stmt
, 0);
1009 idx
= get_stridx (src
);
1016 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1020 si
= get_strinfo (idx
);
1022 rhs
= get_string_length (si
);
1024 if (rhs
!= NULL_TREE
)
1026 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1028 fprintf (dump_file
, "Optimizing: ");
1029 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1031 rhs
= unshare_expr (rhs
);
1032 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1033 rhs
= fold_convert_loc (gimple_location (stmt
),
1034 TREE_TYPE (lhs
), rhs
);
1035 if (!update_call_from_tree (gsi
, rhs
))
1036 gimplify_and_update_call_from_tree (gsi
, rhs
);
1037 stmt
= gsi_stmt (*gsi
);
1039 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1041 fprintf (dump_file
, "into: ");
1042 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1045 && TREE_CODE (si
->length
) != SSA_NAME
1046 && TREE_CODE (si
->length
) != INTEGER_CST
1047 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1049 si
= unshare_strinfo (si
);
1055 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1058 idx
= new_stridx (src
);
1059 else if (get_strinfo (idx
) != NULL
)
1063 strinfo
*si
= new_strinfo (src
, idx
, lhs
);
1064 set_strinfo (idx
, si
);
1065 find_equal_ptrs (src
, idx
);
1069 /* Handle a strchr call. If strlen of the first argument is known, replace
1070 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1071 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1074 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1078 gimple
*stmt
= gsi_stmt (*gsi
);
1079 tree lhs
= gimple_call_lhs (stmt
);
1080 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1082 if (lhs
== NULL_TREE
)
1085 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1088 src
= gimple_call_arg (stmt
, 0);
1089 idx
= get_stridx (src
);
1096 rhs
= build_int_cst (size_type_node
, ~idx
);
1100 si
= get_strinfo (idx
);
1102 rhs
= get_string_length (si
);
1104 if (rhs
!= NULL_TREE
)
1106 location_t loc
= gimple_location (stmt
);
1108 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1110 fprintf (dump_file
, "Optimizing: ");
1111 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1113 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1115 rhs
= unshare_expr (si
->endptr
);
1116 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1118 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1122 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1123 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1124 TREE_TYPE (src
), src
, rhs
);
1125 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1127 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1129 if (!update_call_from_tree (gsi
, rhs
))
1130 gimplify_and_update_call_from_tree (gsi
, rhs
);
1131 stmt
= gsi_stmt (*gsi
);
1133 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1135 fprintf (dump_file
, "into: ");
1136 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1139 && si
->endptr
== NULL_TREE
1140 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1142 si
= unshare_strinfo (si
);
1145 zero_length_string (lhs
, si
);
1149 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1151 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1154 idx
= new_stridx (src
);
1155 else if (get_strinfo (idx
) != NULL
)
1157 zero_length_string (lhs
, NULL
);
1162 location_t loc
= gimple_location (stmt
);
1163 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1164 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1165 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1166 size_type_node
, lhsu
, srcu
);
1167 strinfo
*si
= new_strinfo (src
, idx
, length
);
1169 set_strinfo (idx
, si
);
1170 find_equal_ptrs (src
, idx
);
1171 zero_length_string (lhs
, si
);
1175 zero_length_string (lhs
, NULL
);
1178 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1179 If strlen of the second argument is known, strlen of the first argument
1180 is the same after this call. Furthermore, attempt to convert it to
1184 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1187 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1189 gimple
*stmt
= gsi_stmt (*gsi
);
1190 strinfo
*si
, *dsi
, *olddsi
, *zsi
;
1192 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1194 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1195 dst
= gimple_call_arg (stmt
, 0);
1196 lhs
= gimple_call_lhs (stmt
);
1197 idx
= get_stridx (src
);
1200 si
= get_strinfo (idx
);
1202 didx
= get_stridx (dst
);
1206 olddsi
= get_strinfo (didx
);
1211 adjust_last_stmt (olddsi
, stmt
, false);
1215 srclen
= get_string_length (si
);
1217 srclen
= build_int_cst (size_type_node
, ~idx
);
1219 loc
= gimple_location (stmt
);
1220 if (srclen
== NULL_TREE
)
1223 case BUILT_IN_STRCPY
:
1224 case BUILT_IN_STRCPY_CHK
:
1225 case BUILT_IN_STRCPY_CHKP
:
1226 case BUILT_IN_STRCPY_CHK_CHKP
:
1227 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1230 case BUILT_IN_STPCPY
:
1231 case BUILT_IN_STPCPY_CHK
:
1232 case BUILT_IN_STPCPY_CHKP
:
1233 case BUILT_IN_STPCPY_CHK_CHKP
:
1234 if (lhs
== NULL_TREE
)
1238 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1239 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1240 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1250 didx
= new_stridx (dst
);
1256 oldlen
= olddsi
->length
;
1257 dsi
= unshare_strinfo (olddsi
);
1258 dsi
->length
= srclen
;
1259 /* Break the chain, so adjust_related_strinfo on later pointers in
1260 the chain won't adjust this one anymore. */
1263 dsi
->endptr
= NULL_TREE
;
1267 dsi
= new_strinfo (dst
, didx
, srclen
);
1268 set_strinfo (didx
, dsi
);
1269 find_equal_ptrs (dst
, didx
);
1271 dsi
->writable
= true;
1272 dsi
->dont_invalidate
= true;
1274 if (dsi
->length
== NULL_TREE
)
1278 /* If string length of src is unknown, use delayed length
1279 computation. If string lenth of dst will be needed, it
1280 can be computed by transforming this strcpy call into
1281 stpcpy and subtracting dst from the return value. */
1283 /* Look for earlier strings whose length could be determined if
1284 this strcpy is turned into an stpcpy. */
1286 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1288 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1290 /* When setting a stmt for delayed length computation
1291 prevent all strinfos through dsi from being
1293 chainsi
= unshare_strinfo (chainsi
);
1294 chainsi
->stmt
= stmt
;
1295 chainsi
->length
= NULL_TREE
;
1296 chainsi
->endptr
= NULL_TREE
;
1297 chainsi
->dont_invalidate
= true;
1306 tree adj
= NULL_TREE
;
1307 if (oldlen
== NULL_TREE
)
1309 else if (integer_zerop (oldlen
))
1311 else if (TREE_CODE (oldlen
) == INTEGER_CST
1312 || TREE_CODE (srclen
) == INTEGER_CST
)
1313 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1314 TREE_TYPE (srclen
), srclen
,
1315 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1317 if (adj
!= NULL_TREE
)
1318 adjust_related_strinfos (loc
, dsi
, adj
);
1322 /* strcpy src may not overlap dst, so src doesn't need to be
1323 invalidated either. */
1325 si
->dont_invalidate
= true;
1331 case BUILT_IN_STRCPY
:
1332 case BUILT_IN_STRCPY_CHKP
:
1333 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1335 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1337 case BUILT_IN_STRCPY_CHK
:
1338 case BUILT_IN_STRCPY_CHK_CHKP
:
1339 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1341 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1343 case BUILT_IN_STPCPY
:
1344 case BUILT_IN_STPCPY_CHKP
:
1345 /* This would need adjustment of the lhs (subtract one),
1346 or detection that the trailing '\0' doesn't need to be
1347 written, if it will be immediately overwritten.
1348 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1352 zsi
= zero_length_string (lhs
, dsi
);
1355 case BUILT_IN_STPCPY_CHK
:
1356 case BUILT_IN_STPCPY_CHK_CHKP
:
1357 /* This would need adjustment of the lhs (subtract one),
1358 or detection that the trailing '\0' doesn't need to be
1359 written, if it will be immediately overwritten.
1360 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1364 zsi
= zero_length_string (lhs
, dsi
);
1371 zsi
->dont_invalidate
= true;
1373 if (fn
== NULL_TREE
)
1376 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1377 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1379 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1380 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1381 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1383 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1385 fprintf (dump_file
, "Optimizing: ");
1386 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1390 fn
= chkp_maybe_create_clone (fn
)->decl
;
1391 if (gimple_call_num_args (stmt
) == 4)
1392 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1393 gimple_call_arg (stmt
, 1),
1395 gimple_call_arg (stmt
, 3),
1398 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1399 gimple_call_arg (stmt
, 1),
1401 gimple_call_arg (stmt
, 3),
1403 gimple_call_arg (stmt
, 4));
1406 if (gimple_call_num_args (stmt
) == 2)
1407 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1409 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1410 gimple_call_arg (stmt
, 2));
1413 stmt
= gsi_stmt (*gsi
);
1414 gimple_call_set_with_bounds (stmt
, with_bounds
);
1416 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1418 fprintf (dump_file
, "into: ");
1419 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1421 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1422 laststmt
.stmt
= stmt
;
1423 laststmt
.len
= srclen
;
1424 laststmt
.stridx
= dsi
->idx
;
1426 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1427 fprintf (dump_file
, "not possible.\n");
1430 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1431 If strlen of the second argument is known and length of the third argument
1432 is that plus one, strlen of the first argument is the same after this
1436 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1439 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1440 gimple
*stmt
= gsi_stmt (*gsi
);
1441 strinfo
*si
, *dsi
, *olddsi
;
1442 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1444 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1445 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1446 dst
= gimple_call_arg (stmt
, 0);
1447 idx
= get_stridx (src
);
1451 didx
= get_stridx (dst
);
1454 olddsi
= get_strinfo (didx
);
1459 && tree_fits_uhwi_p (len
)
1460 && !integer_zerop (len
))
1461 adjust_last_stmt (olddsi
, stmt
, false);
1467 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1468 si
= get_strinfo (idx
);
1469 if (si
== NULL
|| si
->length
== NULL_TREE
)
1471 if (TREE_CODE (len
) != SSA_NAME
)
1473 def_stmt
= SSA_NAME_DEF_STMT (len
);
1474 if (!is_gimple_assign (def_stmt
)
1475 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1476 || gimple_assign_rhs1 (def_stmt
) != si
->length
1477 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1483 /* Handle memcpy (x, "abcd", 5) or
1484 memcpy (x, "abc\0uvw", 7). */
1485 if (!tree_fits_uhwi_p (len
)
1486 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1490 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1491 adjust_last_stmt (olddsi
, stmt
, false);
1495 didx
= new_stridx (dst
);
1500 newlen
= si
->length
;
1502 newlen
= build_int_cst (size_type_node
, ~idx
);
1506 dsi
= unshare_strinfo (olddsi
);
1507 oldlen
= olddsi
->length
;
1508 dsi
->length
= newlen
;
1509 /* Break the chain, so adjust_related_strinfo on later pointers in
1510 the chain won't adjust this one anymore. */
1513 dsi
->endptr
= NULL_TREE
;
1517 dsi
= new_strinfo (dst
, didx
, newlen
);
1518 set_strinfo (didx
, dsi
);
1519 find_equal_ptrs (dst
, didx
);
1521 dsi
->writable
= true;
1522 dsi
->dont_invalidate
= true;
1525 tree adj
= NULL_TREE
;
1526 location_t loc
= gimple_location (stmt
);
1527 if (oldlen
== NULL_TREE
)
1529 else if (integer_zerop (oldlen
))
1531 else if (TREE_CODE (oldlen
) == INTEGER_CST
1532 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1533 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1534 TREE_TYPE (dsi
->length
), dsi
->length
,
1535 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1537 if (adj
!= NULL_TREE
)
1538 adjust_related_strinfos (loc
, dsi
, adj
);
1542 /* memcpy src may not overlap dst, so src doesn't need to be
1543 invalidated either. */
1545 si
->dont_invalidate
= true;
1547 lhs
= gimple_call_lhs (stmt
);
1550 case BUILT_IN_MEMCPY
:
1551 case BUILT_IN_MEMCPY_CHK
:
1552 case BUILT_IN_MEMCPY_CHKP
:
1553 case BUILT_IN_MEMCPY_CHK_CHKP
:
1554 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1555 laststmt
.stmt
= stmt
;
1556 laststmt
.len
= dsi
->length
;
1557 laststmt
.stridx
= dsi
->idx
;
1559 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1561 case BUILT_IN_MEMPCPY
:
1562 case BUILT_IN_MEMPCPY_CHK
:
1563 case BUILT_IN_MEMPCPY_CHKP
:
1564 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1571 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1572 If strlen of the second argument is known, strlen of the first argument
1573 is increased by the length of the second argument. Furthermore, attempt
1574 to convert it to memcpy/strcpy if the length of the first argument
1578 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1581 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1583 gimple
*stmt
= gsi_stmt (*gsi
);
1586 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1588 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1589 dst
= gimple_call_arg (stmt
, 0);
1590 lhs
= gimple_call_lhs (stmt
);
1592 didx
= get_stridx (dst
);
1598 dsi
= get_strinfo (didx
);
1599 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1601 /* strcat (p, q) can be transformed into
1602 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1603 with length endptr - p if we need to compute the length
1604 later on. Don't do this transformation if we don't need
1606 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1610 didx
= new_stridx (dst
);
1616 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1617 set_strinfo (didx
, dsi
);
1618 find_equal_ptrs (dst
, didx
);
1622 dsi
= unshare_strinfo (dsi
);
1623 dsi
->length
= NULL_TREE
;
1625 dsi
->endptr
= NULL_TREE
;
1627 dsi
->writable
= true;
1629 dsi
->dont_invalidate
= true;
1636 idx
= get_stridx (src
);
1638 srclen
= build_int_cst (size_type_node
, ~idx
);
1641 si
= get_strinfo (idx
);
1643 srclen
= get_string_length (si
);
1646 loc
= gimple_location (stmt
);
1647 dstlen
= dsi
->length
;
1648 endptr
= dsi
->endptr
;
1650 dsi
= unshare_strinfo (dsi
);
1651 dsi
->endptr
= NULL_TREE
;
1653 dsi
->writable
= true;
1655 if (srclen
!= NULL_TREE
)
1657 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1658 dsi
->length
, srclen
);
1659 adjust_related_strinfos (loc
, dsi
, srclen
);
1660 dsi
->dont_invalidate
= true;
1665 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1666 dsi
->dont_invalidate
= true;
1670 /* strcat src may not overlap dst, so src doesn't need to be
1671 invalidated either. */
1672 si
->dont_invalidate
= true;
1674 /* For now. Could remove the lhs from the call and add
1675 lhs = dst; afterwards. */
1683 case BUILT_IN_STRCAT
:
1684 case BUILT_IN_STRCAT_CHKP
:
1685 if (srclen
!= NULL_TREE
)
1686 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1688 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1690 case BUILT_IN_STRCAT_CHK
:
1691 case BUILT_IN_STRCAT_CHK_CHKP
:
1692 if (srclen
!= NULL_TREE
)
1693 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1695 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1696 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1702 if (fn
== NULL_TREE
)
1706 if (srclen
!= NULL_TREE
)
1708 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1709 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1711 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1712 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1713 build_int_cst (type
, 1));
1714 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1718 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1720 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1721 TREE_TYPE (dst
), unshare_expr (dst
),
1722 fold_convert_loc (loc
, sizetype
,
1723 unshare_expr (dstlen
)));
1724 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1726 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1728 fprintf (dump_file
, "Optimizing: ");
1729 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1733 fn
= chkp_maybe_create_clone (fn
)->decl
;
1734 if (srclen
!= NULL_TREE
)
1735 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1737 gimple_call_arg (stmt
, 1),
1739 gimple_call_arg (stmt
, 3),
1742 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1744 gimple_call_arg (stmt
, 1),
1746 gimple_call_arg (stmt
, 3),
1750 if (srclen
!= NULL_TREE
)
1751 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1752 dst
, src
, len
, objsz
);
1754 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1758 stmt
= gsi_stmt (*gsi
);
1759 gimple_call_set_with_bounds (stmt
, with_bounds
);
1761 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1763 fprintf (dump_file
, "into: ");
1764 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1766 /* If srclen == NULL, note that current string length can be
1767 computed by transforming this strcpy into stpcpy. */
1768 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1770 adjust_last_stmt (dsi
, stmt
, true);
1771 if (srclen
!= NULL_TREE
)
1773 laststmt
.stmt
= stmt
;
1774 laststmt
.len
= srclen
;
1775 laststmt
.stridx
= dsi
->idx
;
1778 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1779 fprintf (dump_file
, "not possible.\n");
1782 /* Handle a call to malloc or calloc. */
1785 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1787 gimple
*stmt
= gsi_stmt (*gsi
);
1788 tree lhs
= gimple_call_lhs (stmt
);
1789 gcc_assert (get_stridx (lhs
) == 0);
1790 int idx
= new_stridx (lhs
);
1791 tree length
= NULL_TREE
;
1792 if (bcode
== BUILT_IN_CALLOC
)
1793 length
= build_int_cst (size_type_node
, 0);
1794 strinfo
*si
= new_strinfo (lhs
, idx
, length
);
1795 if (bcode
== BUILT_IN_CALLOC
)
1797 set_strinfo (idx
, si
);
1798 si
->writable
= true;
1800 si
->dont_invalidate
= true;
1803 /* Handle a call to memset.
1804 After a call to calloc, memset(,0,) is unnecessary.
1805 memset(malloc(n),0,n) is calloc(n,1). */
1808 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1810 gimple
*stmt2
= gsi_stmt (*gsi
);
1811 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1813 tree ptr
= gimple_call_arg (stmt2
, 0);
1814 int idx1
= get_stridx (ptr
);
1817 strinfo
*si1
= get_strinfo (idx1
);
1820 gimple
*stmt1
= si1
->stmt
;
1821 if (!stmt1
|| !is_gimple_call (stmt1
))
1823 tree callee1
= gimple_call_fndecl (stmt1
);
1824 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1826 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1827 tree size
= gimple_call_arg (stmt2
, 2);
1828 if (code1
== BUILT_IN_CALLOC
)
1829 /* Not touching stmt1 */ ;
1830 else if (code1
== BUILT_IN_MALLOC
1831 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1833 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1834 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1835 size
, build_one_cst (size_type_node
));
1836 si1
->length
= build_int_cst (size_type_node
, 0);
1837 si1
->stmt
= gsi_stmt (gsi1
);
1841 tree lhs
= gimple_call_lhs (stmt2
);
1842 unlink_stmt_vdef (stmt2
);
1845 gimple
*assign
= gimple_build_assign (lhs
, ptr
);
1846 gsi_replace (gsi
, assign
, false);
1850 gsi_remove (gsi
, true);
1851 release_defs (stmt2
);
1857 /* Handle a POINTER_PLUS_EXPR statement.
1858 For p = "abcd" + 2; compute associated length, or if
1859 p = q + off is pointing to a '\0' character of a string, call
1860 zero_length_string on it. */
1863 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1865 gimple
*stmt
= gsi_stmt (*gsi
);
1866 tree lhs
= gimple_assign_lhs (stmt
), off
;
1867 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1875 tree off
= gimple_assign_rhs2 (stmt
);
1876 if (tree_fits_uhwi_p (off
)
1877 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1878 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1879 = ~(~idx
- (int) tree_to_uhwi (off
));
1883 si
= get_strinfo (idx
);
1884 if (si
== NULL
|| si
->length
== NULL_TREE
)
1887 off
= gimple_assign_rhs2 (stmt
);
1889 if (operand_equal_p (si
->length
, off
, 0))
1890 zsi
= zero_length_string (lhs
, si
);
1891 else if (TREE_CODE (off
) == SSA_NAME
)
1893 gimple
*def_stmt
= SSA_NAME_DEF_STMT (off
);
1894 if (gimple_assign_single_p (def_stmt
)
1895 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1896 zsi
= zero_length_string (lhs
, si
);
1899 && si
->endptr
!= NULL_TREE
1900 && si
->endptr
!= lhs
1901 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1903 enum tree_code rhs_code
1904 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1905 ? SSA_NAME
: NOP_EXPR
;
1906 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1907 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1912 /* Handle a single character store. */
1915 handle_char_store (gimple_stmt_iterator
*gsi
)
1919 gimple
*stmt
= gsi_stmt (*gsi
);
1920 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1922 if (TREE_CODE (lhs
) == MEM_REF
1923 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1925 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1927 ssaname
= TREE_OPERAND (lhs
, 0);
1928 idx
= get_stridx (ssaname
);
1932 idx
= get_addr_stridx (lhs
);
1936 si
= get_strinfo (idx
);
1937 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1939 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1941 /* When storing '\0', the store can be removed
1942 if we know it has been stored in the current function. */
1943 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1945 unlink_stmt_vdef (stmt
);
1946 release_defs (stmt
);
1947 gsi_remove (gsi
, true);
1952 si
->writable
= true;
1958 /* Otherwise this statement overwrites the '\0' with
1959 something, if the previous stmt was a memcpy,
1960 its length may be decreased. */
1961 adjust_last_stmt (si
, stmt
, false);
1963 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1965 si
= unshare_strinfo (si
);
1966 si
->length
= build_int_cst (size_type_node
, 0);
1972 si
->writable
= true;
1973 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1974 si
->endptr
= ssaname
;
1975 si
->dont_invalidate
= true;
1977 /* If si->length is non-zero constant, we aren't overwriting '\0',
1978 and if we aren't storing '\0', we know that the length of the
1979 string and any other zero terminated string in memory remains
1980 the same. In that case we move to the next gimple statement and
1981 return to signal the caller that it shouldn't invalidate anything.
1983 This is benefical for cases like:
1988 strcpy (p, "foobar");
1989 size_t len = strlen (p); // This can be optimized into 6
1990 size_t len2 = strlen (q); // This has to be computed
1992 size_t len3 = strlen (p); // This can be optimized into 6
1993 size_t len4 = strlen (q); // This can be optimized into len2
1994 bar (len, len2, len3, len4);
1997 else if (si
!= NULL
&& si
->length
!= NULL_TREE
1998 && TREE_CODE (si
->length
) == INTEGER_CST
1999 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2005 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2009 si
= zero_length_string (ssaname
, NULL
);
2011 si
->dont_invalidate
= true;
2015 int idx
= new_addr_stridx (lhs
);
2018 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2019 build_int_cst (size_type_node
, 0));
2020 set_strinfo (idx
, si
);
2021 si
->dont_invalidate
= true;
2025 si
->writable
= true;
2028 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2029 && ssaname
== NULL_TREE
2030 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2032 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2033 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2034 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2036 int idx
= new_addr_stridx (lhs
);
2039 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2040 build_int_cst (size_type_node
, l
));
2041 set_strinfo (idx
, si
);
2042 si
->dont_invalidate
= true;
2047 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2049 /* Allow adjust_last_stmt to remove it if the stored '\0'
2050 is immediately overwritten. */
2051 laststmt
.stmt
= stmt
;
2052 laststmt
.len
= build_int_cst (size_type_node
, 1);
2053 laststmt
.stridx
= si
->idx
;
2058 /* Attempt to optimize a single statement at *GSI using string length
2062 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2064 gimple
*stmt
= gsi_stmt (*gsi
);
2066 if (is_gimple_call (stmt
))
2068 tree callee
= gimple_call_fndecl (stmt
);
2069 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2070 switch (DECL_FUNCTION_CODE (callee
))
2072 case BUILT_IN_STRLEN
:
2073 case BUILT_IN_STRLEN_CHKP
:
2074 handle_builtin_strlen (gsi
);
2076 case BUILT_IN_STRCHR
:
2077 case BUILT_IN_STRCHR_CHKP
:
2078 handle_builtin_strchr (gsi
);
2080 case BUILT_IN_STRCPY
:
2081 case BUILT_IN_STRCPY_CHK
:
2082 case BUILT_IN_STPCPY
:
2083 case BUILT_IN_STPCPY_CHK
:
2084 case BUILT_IN_STRCPY_CHKP
:
2085 case BUILT_IN_STRCPY_CHK_CHKP
:
2086 case BUILT_IN_STPCPY_CHKP
:
2087 case BUILT_IN_STPCPY_CHK_CHKP
:
2088 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2090 case BUILT_IN_MEMCPY
:
2091 case BUILT_IN_MEMCPY_CHK
:
2092 case BUILT_IN_MEMPCPY
:
2093 case BUILT_IN_MEMPCPY_CHK
:
2094 case BUILT_IN_MEMCPY_CHKP
:
2095 case BUILT_IN_MEMCPY_CHK_CHKP
:
2096 case BUILT_IN_MEMPCPY_CHKP
:
2097 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2098 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2100 case BUILT_IN_STRCAT
:
2101 case BUILT_IN_STRCAT_CHK
:
2102 case BUILT_IN_STRCAT_CHKP
:
2103 case BUILT_IN_STRCAT_CHK_CHKP
:
2104 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2106 case BUILT_IN_MALLOC
:
2107 case BUILT_IN_CALLOC
:
2108 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2110 case BUILT_IN_MEMSET
:
2111 if (!handle_builtin_memset (gsi
))
2118 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2120 tree lhs
= gimple_assign_lhs (stmt
);
2122 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2124 if (gimple_assign_single_p (stmt
)
2125 || (gimple_assign_cast_p (stmt
)
2126 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2128 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2129 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2131 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2132 handle_pointer_plus (gsi
);
2134 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2136 tree type
= TREE_TYPE (lhs
);
2137 if (TREE_CODE (type
) == ARRAY_TYPE
)
2138 type
= TREE_TYPE (type
);
2139 if (TREE_CODE (type
) == INTEGER_TYPE
2140 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2141 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2143 if (! handle_char_store (gsi
))
2149 if (gimple_vdef (stmt
))
2150 maybe_invalidate (stmt
);
2154 /* Recursively call maybe_invalidate on stmts that might be executed
2155 in between dombb and current bb and that contain a vdef. Stop when
2156 *count stmts are inspected, or if the whole strinfo vector has
2157 been invalidated. */
2160 do_invalidate (basic_block dombb
, gimple
*phi
, bitmap visited
, int *count
)
2162 unsigned int i
, n
= gimple_phi_num_args (phi
);
2164 for (i
= 0; i
< n
; i
++)
2166 tree vuse
= gimple_phi_arg_def (phi
, i
);
2167 gimple
*stmt
= SSA_NAME_DEF_STMT (vuse
);
2168 basic_block bb
= gimple_bb (stmt
);
2171 || !bitmap_set_bit (visited
, bb
->index
)
2172 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2176 if (gimple_code (stmt
) == GIMPLE_PHI
)
2178 do_invalidate (dombb
, stmt
, visited
, count
);
2185 if (!maybe_invalidate (stmt
))
2190 vuse
= gimple_vuse (stmt
);
2191 stmt
= SSA_NAME_DEF_STMT (vuse
);
2192 if (gimple_bb (stmt
) != bb
)
2194 bb
= gimple_bb (stmt
);
2197 || !bitmap_set_bit (visited
, bb
->index
)
2198 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2205 class strlen_dom_walker
: public dom_walker
2208 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2210 virtual void before_dom_children (basic_block
);
2211 virtual void after_dom_children (basic_block
);
2214 /* Callback for walk_dominator_tree. Attempt to optimize various
2215 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2218 strlen_dom_walker::before_dom_children (basic_block bb
)
2220 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2223 stridx_to_strinfo
= NULL
;
2226 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) dombb
->aux
);
2227 if (stridx_to_strinfo
)
2229 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2232 gphi
*phi
= gsi
.phi ();
2233 if (virtual_operand_p (gimple_phi_result (phi
)))
2235 bitmap visited
= BITMAP_ALLOC (NULL
);
2236 int count_vdef
= 100;
2237 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2238 BITMAP_FREE (visited
);
2239 if (count_vdef
== 0)
2241 /* If there were too many vdefs in between immediate
2242 dominator and current bb, invalidate everything.
2243 If stridx_to_strinfo has been unshared, we need
2244 to free it, otherwise just set it to NULL. */
2245 if (!strinfo_shared ())
2251 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2255 (*stridx_to_strinfo
)[i
] = NULL
;
2259 stridx_to_strinfo
= NULL
;
2267 /* If all PHI arguments have the same string index, the PHI result
2269 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2272 gphi
*phi
= gsi
.phi ();
2273 tree result
= gimple_phi_result (phi
);
2274 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2276 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2279 unsigned int i
, n
= gimple_phi_num_args (phi
);
2280 for (i
= 1; i
< n
; i
++)
2281 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2284 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2289 /* Attempt to optimize individual statements. */
2290 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2291 if (strlen_optimize_stmt (&gsi
))
2294 bb
->aux
= stridx_to_strinfo
;
2295 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2296 (*stridx_to_strinfo
)[0] = (strinfo
*) bb
;
2299 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2300 owned by the current bb, clear bb->aux. */
2303 strlen_dom_walker::after_dom_children (basic_block bb
)
2307 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) bb
->aux
);
2308 if (vec_safe_length (stridx_to_strinfo
)
2309 && (*stridx_to_strinfo
)[0] == (strinfo
*) bb
)
2314 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2316 vec_free (stridx_to_strinfo
);
2322 /* Main entry point. */
2326 const pass_data pass_data_strlen
=
2328 GIMPLE_PASS
, /* type */
2329 "strlen", /* name */
2330 OPTGROUP_NONE
, /* optinfo_flags */
2331 TV_TREE_STRLEN
, /* tv_id */
2332 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2333 0, /* properties_provided */
2334 0, /* properties_destroyed */
2335 0, /* todo_flags_start */
2336 0, /* todo_flags_finish */
2339 class pass_strlen
: public gimple_opt_pass
2342 pass_strlen (gcc::context
*ctxt
)
2343 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2346 /* opt_pass methods: */
2347 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2348 virtual unsigned int execute (function
*);
2350 }; // class pass_strlen
2353 pass_strlen::execute (function
*fun
)
2355 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2358 calculate_dominance_info (CDI_DOMINATORS
);
2360 /* String length optimization is implemented as a walk of the dominator
2361 tree and a forward walk of statements within each block. */
2362 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2364 ssa_ver_to_stridx
.release ();
2365 strinfo_pool
.release ();
2366 if (decl_to_stridxlist_htab
)
2368 obstack_free (&stridx_obstack
, NULL
);
2369 delete decl_to_stridxlist_htab
;
2370 decl_to_stridxlist_htab
= NULL
;
2372 laststmt
.stmt
= NULL
;
2373 laststmt
.len
= NULL_TREE
;
2374 laststmt
.stridx
= 0;
2382 make_pass_strlen (gcc::context
*ctxt
)
2384 return new pass_strlen (ctxt
);