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 /* If the last .MEM setter statement before STMT is
863 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
864 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
865 just memcpy (x, y, strlen (y)). SI must be the zero length
869 adjust_last_stmt (strinfo
*si
, gimple
*stmt
, bool is_strcat
)
871 tree vuse
, callee
, len
;
872 struct laststmt_struct last
= laststmt
;
873 strinfo
*lastsi
, *firstsi
;
874 unsigned len_arg_no
= 2;
876 laststmt
.stmt
= NULL
;
877 laststmt
.len
= NULL_TREE
;
880 if (last
.stmt
== NULL
)
883 vuse
= gimple_vuse (stmt
);
884 if (vuse
== NULL_TREE
885 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
886 || !has_single_use (vuse
))
889 gcc_assert (last
.stridx
> 0);
890 lastsi
= get_strinfo (last
.stridx
);
896 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
899 firstsi
= verify_related_strinfos (si
);
902 while (firstsi
!= lastsi
)
905 if (firstsi
->next
== 0)
907 nextsi
= get_strinfo (firstsi
->next
);
909 || nextsi
->prev
!= firstsi
->idx
910 || nextsi
->first
!= si
->first
)
918 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
922 if (is_gimple_assign (last
.stmt
))
924 gimple_stmt_iterator gsi
;
926 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
928 if (stmt_could_throw_p (last
.stmt
))
930 gsi
= gsi_for_stmt (last
.stmt
);
931 unlink_stmt_vdef (last
.stmt
);
932 release_defs (last
.stmt
);
933 gsi_remove (&gsi
, true);
937 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
940 callee
= gimple_call_fndecl (last
.stmt
);
941 switch (DECL_FUNCTION_CODE (callee
))
943 case BUILT_IN_MEMCPY
:
944 case BUILT_IN_MEMCPY_CHK
:
946 case BUILT_IN_MEMCPY_CHKP
:
947 case BUILT_IN_MEMCPY_CHK_CHKP
:
954 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
955 if (tree_fits_uhwi_p (len
))
957 if (!tree_fits_uhwi_p (last
.len
)
958 || integer_zerop (len
)
959 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
961 /* Don't adjust the length if it is divisible by 4, it is more efficient
962 to store the extra '\0' in that case. */
963 if ((tree_to_uhwi (len
) & 3) == 0)
966 else if (TREE_CODE (len
) == SSA_NAME
)
968 gimple
*def_stmt
= SSA_NAME_DEF_STMT (len
);
969 if (!is_gimple_assign (def_stmt
)
970 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
971 || gimple_assign_rhs1 (def_stmt
) != last
.len
972 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
978 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
979 update_stmt (last
.stmt
);
982 /* Handle a strlen call. If strlen of the argument is known, replace
983 the strlen call with the known value, otherwise remember that strlen
984 of the argument is stored in the lhs SSA_NAME. */
987 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
991 gimple
*stmt
= gsi_stmt (*gsi
);
992 tree lhs
= gimple_call_lhs (stmt
);
994 if (lhs
== NULL_TREE
)
997 src
= gimple_call_arg (stmt
, 0);
998 idx
= get_stridx (src
);
1005 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1009 si
= get_strinfo (idx
);
1011 rhs
= get_string_length (si
);
1013 if (rhs
!= NULL_TREE
)
1015 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1017 fprintf (dump_file
, "Optimizing: ");
1018 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1020 rhs
= unshare_expr (rhs
);
1021 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1022 rhs
= fold_convert_loc (gimple_location (stmt
),
1023 TREE_TYPE (lhs
), rhs
);
1024 if (!update_call_from_tree (gsi
, rhs
))
1025 gimplify_and_update_call_from_tree (gsi
, rhs
);
1026 stmt
= gsi_stmt (*gsi
);
1028 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1030 fprintf (dump_file
, "into: ");
1031 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1034 && TREE_CODE (si
->length
) != SSA_NAME
1035 && TREE_CODE (si
->length
) != INTEGER_CST
1036 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1038 si
= unshare_strinfo (si
);
1044 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1047 idx
= new_stridx (src
);
1048 else if (get_strinfo (idx
) != NULL
)
1052 strinfo
*si
= new_strinfo (src
, idx
, lhs
);
1053 set_strinfo (idx
, si
);
1054 find_equal_ptrs (src
, idx
);
1058 /* Handle a strchr call. If strlen of the first argument is known, replace
1059 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1060 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1063 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1067 gimple
*stmt
= gsi_stmt (*gsi
);
1068 tree lhs
= gimple_call_lhs (stmt
);
1069 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1071 if (lhs
== NULL_TREE
)
1074 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1077 src
= gimple_call_arg (stmt
, 0);
1078 idx
= get_stridx (src
);
1085 rhs
= build_int_cst (size_type_node
, ~idx
);
1089 si
= get_strinfo (idx
);
1091 rhs
= get_string_length (si
);
1093 if (rhs
!= NULL_TREE
)
1095 location_t loc
= gimple_location (stmt
);
1097 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1099 fprintf (dump_file
, "Optimizing: ");
1100 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1102 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1104 rhs
= unshare_expr (si
->endptr
);
1105 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1107 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1111 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1112 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1113 TREE_TYPE (src
), src
, rhs
);
1114 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1116 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1118 if (!update_call_from_tree (gsi
, rhs
))
1119 gimplify_and_update_call_from_tree (gsi
, rhs
);
1120 stmt
= gsi_stmt (*gsi
);
1122 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1124 fprintf (dump_file
, "into: ");
1125 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1128 && si
->endptr
== NULL_TREE
1129 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1131 si
= unshare_strinfo (si
);
1134 zero_length_string (lhs
, si
);
1138 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1140 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1143 idx
= new_stridx (src
);
1144 else if (get_strinfo (idx
) != NULL
)
1146 zero_length_string (lhs
, NULL
);
1151 location_t loc
= gimple_location (stmt
);
1152 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1153 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1154 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1155 size_type_node
, lhsu
, srcu
);
1156 strinfo
*si
= new_strinfo (src
, idx
, length
);
1158 set_strinfo (idx
, si
);
1159 find_equal_ptrs (src
, idx
);
1160 zero_length_string (lhs
, si
);
1164 zero_length_string (lhs
, NULL
);
1167 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1168 If strlen of the second argument is known, strlen of the first argument
1169 is the same after this call. Furthermore, attempt to convert it to
1173 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1176 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1178 gimple
*stmt
= gsi_stmt (*gsi
);
1179 strinfo
*si
, *dsi
, *olddsi
, *zsi
;
1181 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1183 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1184 dst
= gimple_call_arg (stmt
, 0);
1185 lhs
= gimple_call_lhs (stmt
);
1186 idx
= get_stridx (src
);
1189 si
= get_strinfo (idx
);
1191 didx
= get_stridx (dst
);
1195 olddsi
= get_strinfo (didx
);
1200 adjust_last_stmt (olddsi
, stmt
, false);
1204 srclen
= get_string_length (si
);
1206 srclen
= build_int_cst (size_type_node
, ~idx
);
1208 loc
= gimple_location (stmt
);
1209 if (srclen
== NULL_TREE
)
1212 case BUILT_IN_STRCPY
:
1213 case BUILT_IN_STRCPY_CHK
:
1214 case BUILT_IN_STRCPY_CHKP
:
1215 case BUILT_IN_STRCPY_CHK_CHKP
:
1216 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1219 case BUILT_IN_STPCPY
:
1220 case BUILT_IN_STPCPY_CHK
:
1221 case BUILT_IN_STPCPY_CHKP
:
1222 case BUILT_IN_STPCPY_CHK_CHKP
:
1223 if (lhs
== NULL_TREE
)
1227 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1228 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1229 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1239 didx
= new_stridx (dst
);
1245 oldlen
= olddsi
->length
;
1246 dsi
= unshare_strinfo (olddsi
);
1247 dsi
->length
= srclen
;
1248 /* Break the chain, so adjust_related_strinfo on later pointers in
1249 the chain won't adjust this one anymore. */
1252 dsi
->endptr
= NULL_TREE
;
1256 dsi
= new_strinfo (dst
, didx
, srclen
);
1257 set_strinfo (didx
, dsi
);
1258 find_equal_ptrs (dst
, didx
);
1260 dsi
->writable
= true;
1261 dsi
->dont_invalidate
= true;
1263 if (dsi
->length
== NULL_TREE
)
1267 /* If string length of src is unknown, use delayed length
1268 computation. If string lenth of dst will be needed, it
1269 can be computed by transforming this strcpy call into
1270 stpcpy and subtracting dst from the return value. */
1272 /* Look for earlier strings whose length could be determined if
1273 this strcpy is turned into an stpcpy. */
1275 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1277 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1279 /* When setting a stmt for delayed length computation
1280 prevent all strinfos through dsi from being
1282 chainsi
= unshare_strinfo (chainsi
);
1283 chainsi
->stmt
= stmt
;
1284 chainsi
->length
= NULL_TREE
;
1285 chainsi
->endptr
= NULL_TREE
;
1286 chainsi
->dont_invalidate
= true;
1295 tree adj
= NULL_TREE
;
1296 if (oldlen
== NULL_TREE
)
1298 else if (integer_zerop (oldlen
))
1300 else if (TREE_CODE (oldlen
) == INTEGER_CST
1301 || TREE_CODE (srclen
) == INTEGER_CST
)
1302 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1303 TREE_TYPE (srclen
), srclen
,
1304 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1306 if (adj
!= NULL_TREE
)
1307 adjust_related_strinfos (loc
, dsi
, adj
);
1311 /* strcpy src may not overlap dst, so src doesn't need to be
1312 invalidated either. */
1314 si
->dont_invalidate
= true;
1320 case BUILT_IN_STRCPY
:
1321 case BUILT_IN_STRCPY_CHKP
:
1322 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1324 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1326 case BUILT_IN_STRCPY_CHK
:
1327 case BUILT_IN_STRCPY_CHK_CHKP
:
1328 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1330 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1332 case BUILT_IN_STPCPY
:
1333 case BUILT_IN_STPCPY_CHKP
:
1334 /* This would need adjustment of the lhs (subtract one),
1335 or detection that the trailing '\0' doesn't need to be
1336 written, if it will be immediately overwritten.
1337 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1341 zsi
= zero_length_string (lhs
, dsi
);
1344 case BUILT_IN_STPCPY_CHK
:
1345 case BUILT_IN_STPCPY_CHK_CHKP
:
1346 /* This would need adjustment of the lhs (subtract one),
1347 or detection that the trailing '\0' doesn't need to be
1348 written, if it will be immediately overwritten.
1349 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1353 zsi
= zero_length_string (lhs
, dsi
);
1360 zsi
->dont_invalidate
= true;
1362 if (fn
== NULL_TREE
)
1365 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1366 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1368 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1369 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1370 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1372 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1374 fprintf (dump_file
, "Optimizing: ");
1375 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1379 fn
= chkp_maybe_create_clone (fn
)->decl
;
1380 if (gimple_call_num_args (stmt
) == 4)
1381 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1382 gimple_call_arg (stmt
, 1),
1384 gimple_call_arg (stmt
, 3),
1387 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1388 gimple_call_arg (stmt
, 1),
1390 gimple_call_arg (stmt
, 3),
1392 gimple_call_arg (stmt
, 4));
1395 if (gimple_call_num_args (stmt
) == 2)
1396 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1398 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1399 gimple_call_arg (stmt
, 2));
1402 stmt
= gsi_stmt (*gsi
);
1403 gimple_call_set_with_bounds (stmt
, with_bounds
);
1405 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1407 fprintf (dump_file
, "into: ");
1408 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1410 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1411 laststmt
.stmt
= stmt
;
1412 laststmt
.len
= srclen
;
1413 laststmt
.stridx
= dsi
->idx
;
1415 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1416 fprintf (dump_file
, "not possible.\n");
1419 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1420 If strlen of the second argument is known and length of the third argument
1421 is that plus one, strlen of the first argument is the same after this
1425 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1428 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1429 gimple
*stmt
= gsi_stmt (*gsi
);
1430 strinfo
*si
, *dsi
, *olddsi
;
1431 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1433 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1434 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1435 dst
= gimple_call_arg (stmt
, 0);
1436 idx
= get_stridx (src
);
1440 didx
= get_stridx (dst
);
1443 olddsi
= get_strinfo (didx
);
1448 && tree_fits_uhwi_p (len
)
1449 && !integer_zerop (len
))
1450 adjust_last_stmt (olddsi
, stmt
, false);
1456 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1457 si
= get_strinfo (idx
);
1458 if (si
== NULL
|| si
->length
== NULL_TREE
)
1460 if (TREE_CODE (len
) != SSA_NAME
)
1462 def_stmt
= SSA_NAME_DEF_STMT (len
);
1463 if (!is_gimple_assign (def_stmt
)
1464 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1465 || gimple_assign_rhs1 (def_stmt
) != si
->length
1466 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1472 /* Handle memcpy (x, "abcd", 5) or
1473 memcpy (x, "abc\0uvw", 7). */
1474 if (!tree_fits_uhwi_p (len
)
1475 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1479 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1480 adjust_last_stmt (olddsi
, stmt
, false);
1484 didx
= new_stridx (dst
);
1489 newlen
= si
->length
;
1491 newlen
= build_int_cst (size_type_node
, ~idx
);
1495 dsi
= unshare_strinfo (olddsi
);
1496 oldlen
= olddsi
->length
;
1497 dsi
->length
= newlen
;
1498 /* Break the chain, so adjust_related_strinfo on later pointers in
1499 the chain won't adjust this one anymore. */
1502 dsi
->endptr
= NULL_TREE
;
1506 dsi
= new_strinfo (dst
, didx
, newlen
);
1507 set_strinfo (didx
, dsi
);
1508 find_equal_ptrs (dst
, didx
);
1510 dsi
->writable
= true;
1511 dsi
->dont_invalidate
= true;
1514 tree adj
= NULL_TREE
;
1515 location_t loc
= gimple_location (stmt
);
1516 if (oldlen
== NULL_TREE
)
1518 else if (integer_zerop (oldlen
))
1520 else if (TREE_CODE (oldlen
) == INTEGER_CST
1521 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1522 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1523 TREE_TYPE (dsi
->length
), dsi
->length
,
1524 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1526 if (adj
!= NULL_TREE
)
1527 adjust_related_strinfos (loc
, dsi
, adj
);
1531 /* memcpy src may not overlap dst, so src doesn't need to be
1532 invalidated either. */
1534 si
->dont_invalidate
= true;
1536 lhs
= gimple_call_lhs (stmt
);
1539 case BUILT_IN_MEMCPY
:
1540 case BUILT_IN_MEMCPY_CHK
:
1541 case BUILT_IN_MEMCPY_CHKP
:
1542 case BUILT_IN_MEMCPY_CHK_CHKP
:
1543 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1544 laststmt
.stmt
= stmt
;
1545 laststmt
.len
= dsi
->length
;
1546 laststmt
.stridx
= dsi
->idx
;
1548 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1550 case BUILT_IN_MEMPCPY
:
1551 case BUILT_IN_MEMPCPY_CHK
:
1552 case BUILT_IN_MEMPCPY_CHKP
:
1553 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1560 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1561 If strlen of the second argument is known, strlen of the first argument
1562 is increased by the length of the second argument. Furthermore, attempt
1563 to convert it to memcpy/strcpy if the length of the first argument
1567 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1570 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1572 gimple
*stmt
= gsi_stmt (*gsi
);
1575 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1577 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1578 dst
= gimple_call_arg (stmt
, 0);
1579 lhs
= gimple_call_lhs (stmt
);
1581 didx
= get_stridx (dst
);
1587 dsi
= get_strinfo (didx
);
1588 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1590 /* strcat (p, q) can be transformed into
1591 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1592 with length endptr - p if we need to compute the length
1593 later on. Don't do this transformation if we don't need
1595 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1599 didx
= new_stridx (dst
);
1605 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1606 set_strinfo (didx
, dsi
);
1607 find_equal_ptrs (dst
, didx
);
1611 dsi
= unshare_strinfo (dsi
);
1612 dsi
->length
= NULL_TREE
;
1614 dsi
->endptr
= NULL_TREE
;
1616 dsi
->writable
= true;
1618 dsi
->dont_invalidate
= true;
1625 idx
= get_stridx (src
);
1627 srclen
= build_int_cst (size_type_node
, ~idx
);
1630 si
= get_strinfo (idx
);
1632 srclen
= get_string_length (si
);
1635 loc
= gimple_location (stmt
);
1636 dstlen
= dsi
->length
;
1637 endptr
= dsi
->endptr
;
1639 dsi
= unshare_strinfo (dsi
);
1640 dsi
->endptr
= NULL_TREE
;
1642 dsi
->writable
= true;
1644 if (srclen
!= NULL_TREE
)
1646 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1647 dsi
->length
, srclen
);
1648 adjust_related_strinfos (loc
, dsi
, srclen
);
1649 dsi
->dont_invalidate
= true;
1654 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1655 dsi
->dont_invalidate
= true;
1659 /* strcat src may not overlap dst, so src doesn't need to be
1660 invalidated either. */
1661 si
->dont_invalidate
= true;
1663 /* For now. Could remove the lhs from the call and add
1664 lhs = dst; afterwards. */
1672 case BUILT_IN_STRCAT
:
1673 case BUILT_IN_STRCAT_CHKP
:
1674 if (srclen
!= NULL_TREE
)
1675 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1677 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1679 case BUILT_IN_STRCAT_CHK
:
1680 case BUILT_IN_STRCAT_CHK_CHKP
:
1681 if (srclen
!= NULL_TREE
)
1682 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1684 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1685 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1691 if (fn
== NULL_TREE
)
1695 if (srclen
!= NULL_TREE
)
1697 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1698 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1700 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1701 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1702 build_int_cst (type
, 1));
1703 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1707 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1709 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1710 TREE_TYPE (dst
), unshare_expr (dst
),
1711 fold_convert_loc (loc
, sizetype
,
1712 unshare_expr (dstlen
)));
1713 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1715 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1717 fprintf (dump_file
, "Optimizing: ");
1718 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1722 fn
= chkp_maybe_create_clone (fn
)->decl
;
1723 if (srclen
!= NULL_TREE
)
1724 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1726 gimple_call_arg (stmt
, 1),
1728 gimple_call_arg (stmt
, 3),
1731 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1733 gimple_call_arg (stmt
, 1),
1735 gimple_call_arg (stmt
, 3),
1739 if (srclen
!= NULL_TREE
)
1740 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1741 dst
, src
, len
, objsz
);
1743 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1747 stmt
= gsi_stmt (*gsi
);
1748 gimple_call_set_with_bounds (stmt
, with_bounds
);
1750 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1752 fprintf (dump_file
, "into: ");
1753 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1755 /* If srclen == NULL, note that current string length can be
1756 computed by transforming this strcpy into stpcpy. */
1757 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1759 adjust_last_stmt (dsi
, stmt
, true);
1760 if (srclen
!= NULL_TREE
)
1762 laststmt
.stmt
= stmt
;
1763 laststmt
.len
= srclen
;
1764 laststmt
.stridx
= dsi
->idx
;
1767 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1768 fprintf (dump_file
, "not possible.\n");
1771 /* Handle a call to malloc or calloc. */
1774 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1776 gimple
*stmt
= gsi_stmt (*gsi
);
1777 tree lhs
= gimple_call_lhs (stmt
);
1778 gcc_assert (get_stridx (lhs
) == 0);
1779 int idx
= new_stridx (lhs
);
1780 tree length
= NULL_TREE
;
1781 if (bcode
== BUILT_IN_CALLOC
)
1782 length
= build_int_cst (size_type_node
, 0);
1783 strinfo
*si
= new_strinfo (lhs
, idx
, length
);
1784 if (bcode
== BUILT_IN_CALLOC
)
1786 set_strinfo (idx
, si
);
1787 si
->writable
= true;
1789 si
->dont_invalidate
= true;
1792 /* Handle a call to memset.
1793 After a call to calloc, memset(,0,) is unnecessary.
1794 memset(malloc(n),0,n) is calloc(n,1). */
1797 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1799 gimple
*stmt2
= gsi_stmt (*gsi
);
1800 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1802 tree ptr
= gimple_call_arg (stmt2
, 0);
1803 int idx1
= get_stridx (ptr
);
1806 strinfo
*si1
= get_strinfo (idx1
);
1809 gimple
*stmt1
= si1
->stmt
;
1810 if (!stmt1
|| !is_gimple_call (stmt1
))
1812 tree callee1
= gimple_call_fndecl (stmt1
);
1813 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1815 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1816 tree size
= gimple_call_arg (stmt2
, 2);
1817 if (code1
== BUILT_IN_CALLOC
)
1818 /* Not touching stmt1 */ ;
1819 else if (code1
== BUILT_IN_MALLOC
1820 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1822 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1823 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1824 size
, build_one_cst (size_type_node
));
1825 si1
->length
= build_int_cst (size_type_node
, 0);
1826 si1
->stmt
= gsi_stmt (gsi1
);
1830 tree lhs
= gimple_call_lhs (stmt2
);
1831 unlink_stmt_vdef (stmt2
);
1834 gimple
*assign
= gimple_build_assign (lhs
, ptr
);
1835 gsi_replace (gsi
, assign
, false);
1839 gsi_remove (gsi
, true);
1840 release_defs (stmt2
);
1846 /* Handle a POINTER_PLUS_EXPR statement.
1847 For p = "abcd" + 2; compute associated length, or if
1848 p = q + off is pointing to a '\0' character of a string, call
1849 zero_length_string on it. */
1852 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1854 gimple
*stmt
= gsi_stmt (*gsi
);
1855 tree lhs
= gimple_assign_lhs (stmt
), off
;
1856 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1864 tree off
= gimple_assign_rhs2 (stmt
);
1865 if (tree_fits_uhwi_p (off
)
1866 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1867 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1868 = ~(~idx
- (int) tree_to_uhwi (off
));
1872 si
= get_strinfo (idx
);
1873 if (si
== NULL
|| si
->length
== NULL_TREE
)
1876 off
= gimple_assign_rhs2 (stmt
);
1878 if (operand_equal_p (si
->length
, off
, 0))
1879 zsi
= zero_length_string (lhs
, si
);
1880 else if (TREE_CODE (off
) == SSA_NAME
)
1882 gimple
*def_stmt
= SSA_NAME_DEF_STMT (off
);
1883 if (gimple_assign_single_p (def_stmt
)
1884 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1885 zsi
= zero_length_string (lhs
, si
);
1888 && si
->endptr
!= NULL_TREE
1889 && si
->endptr
!= lhs
1890 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1892 enum tree_code rhs_code
1893 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1894 ? SSA_NAME
: NOP_EXPR
;
1895 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1896 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1901 /* Handle a single character store. */
1904 handle_char_store (gimple_stmt_iterator
*gsi
)
1908 gimple
*stmt
= gsi_stmt (*gsi
);
1909 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1911 if (TREE_CODE (lhs
) == MEM_REF
1912 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1914 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1916 ssaname
= TREE_OPERAND (lhs
, 0);
1917 idx
= get_stridx (ssaname
);
1921 idx
= get_addr_stridx (lhs
);
1925 si
= get_strinfo (idx
);
1926 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1928 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1930 /* When storing '\0', the store can be removed
1931 if we know it has been stored in the current function. */
1932 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1934 unlink_stmt_vdef (stmt
);
1935 release_defs (stmt
);
1936 gsi_remove (gsi
, true);
1941 si
->writable
= true;
1947 /* Otherwise this statement overwrites the '\0' with
1948 something, if the previous stmt was a memcpy,
1949 its length may be decreased. */
1950 adjust_last_stmt (si
, stmt
, false);
1952 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1954 si
= unshare_strinfo (si
);
1955 si
->length
= build_int_cst (size_type_node
, 0);
1961 si
->writable
= true;
1962 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1963 si
->endptr
= ssaname
;
1964 si
->dont_invalidate
= true;
1966 /* If si->length is non-zero constant, we aren't overwriting '\0',
1967 and if we aren't storing '\0', we know that the length of the
1968 string and any other zero terminated string in memory remains
1969 the same. In that case we move to the next gimple statement and
1970 return to signal the caller that it shouldn't invalidate anything.
1972 This is benefical for cases like:
1977 strcpy (p, "foobar");
1978 size_t len = strlen (p); // This can be optimized into 6
1979 size_t len2 = strlen (q); // This has to be computed
1981 size_t len3 = strlen (p); // This can be optimized into 6
1982 size_t len4 = strlen (q); // This can be optimized into len2
1983 bar (len, len2, len3, len4);
1986 else if (si
!= NULL
&& si
->length
!= NULL_TREE
1987 && TREE_CODE (si
->length
) == INTEGER_CST
1988 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
1994 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
1998 si
= zero_length_string (ssaname
, NULL
);
2000 si
->dont_invalidate
= true;
2004 int idx
= new_addr_stridx (lhs
);
2007 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2008 build_int_cst (size_type_node
, 0));
2009 set_strinfo (idx
, si
);
2010 si
->dont_invalidate
= true;
2014 si
->writable
= true;
2017 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2018 && ssaname
== NULL_TREE
2019 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2021 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2022 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2023 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2025 int idx
= new_addr_stridx (lhs
);
2028 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2029 build_int_cst (size_type_node
, l
));
2030 set_strinfo (idx
, si
);
2031 si
->dont_invalidate
= true;
2036 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2038 /* Allow adjust_last_stmt to remove it if the stored '\0'
2039 is immediately overwritten. */
2040 laststmt
.stmt
= stmt
;
2041 laststmt
.len
= build_int_cst (size_type_node
, 1);
2042 laststmt
.stridx
= si
->idx
;
2047 /* Attempt to optimize a single statement at *GSI using string length
2051 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2053 gimple
*stmt
= gsi_stmt (*gsi
);
2055 if (is_gimple_call (stmt
))
2057 tree callee
= gimple_call_fndecl (stmt
);
2058 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2059 switch (DECL_FUNCTION_CODE (callee
))
2061 case BUILT_IN_STRLEN
:
2062 case BUILT_IN_STRLEN_CHKP
:
2063 handle_builtin_strlen (gsi
);
2065 case BUILT_IN_STRCHR
:
2066 case BUILT_IN_STRCHR_CHKP
:
2067 handle_builtin_strchr (gsi
);
2069 case BUILT_IN_STRCPY
:
2070 case BUILT_IN_STRCPY_CHK
:
2071 case BUILT_IN_STPCPY
:
2072 case BUILT_IN_STPCPY_CHK
:
2073 case BUILT_IN_STRCPY_CHKP
:
2074 case BUILT_IN_STRCPY_CHK_CHKP
:
2075 case BUILT_IN_STPCPY_CHKP
:
2076 case BUILT_IN_STPCPY_CHK_CHKP
:
2077 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2079 case BUILT_IN_MEMCPY
:
2080 case BUILT_IN_MEMCPY_CHK
:
2081 case BUILT_IN_MEMPCPY
:
2082 case BUILT_IN_MEMPCPY_CHK
:
2083 case BUILT_IN_MEMCPY_CHKP
:
2084 case BUILT_IN_MEMCPY_CHK_CHKP
:
2085 case BUILT_IN_MEMPCPY_CHKP
:
2086 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2087 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2089 case BUILT_IN_STRCAT
:
2090 case BUILT_IN_STRCAT_CHK
:
2091 case BUILT_IN_STRCAT_CHKP
:
2092 case BUILT_IN_STRCAT_CHK_CHKP
:
2093 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2095 case BUILT_IN_MALLOC
:
2096 case BUILT_IN_CALLOC
:
2097 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2099 case BUILT_IN_MEMSET
:
2100 if (!handle_builtin_memset (gsi
))
2107 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2109 tree lhs
= gimple_assign_lhs (stmt
);
2111 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2113 if (gimple_assign_single_p (stmt
)
2114 || (gimple_assign_cast_p (stmt
)
2115 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2117 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2118 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2120 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2121 handle_pointer_plus (gsi
);
2123 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2125 tree type
= TREE_TYPE (lhs
);
2126 if (TREE_CODE (type
) == ARRAY_TYPE
)
2127 type
= TREE_TYPE (type
);
2128 if (TREE_CODE (type
) == INTEGER_TYPE
2129 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2130 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2132 if (! handle_char_store (gsi
))
2138 if (gimple_vdef (stmt
))
2139 maybe_invalidate (stmt
);
2143 /* Recursively call maybe_invalidate on stmts that might be executed
2144 in between dombb and current bb and that contain a vdef. Stop when
2145 *count stmts are inspected, or if the whole strinfo vector has
2146 been invalidated. */
2149 do_invalidate (basic_block dombb
, gimple
*phi
, bitmap visited
, int *count
)
2151 unsigned int i
, n
= gimple_phi_num_args (phi
);
2153 for (i
= 0; i
< n
; i
++)
2155 tree vuse
= gimple_phi_arg_def (phi
, i
);
2156 gimple
*stmt
= SSA_NAME_DEF_STMT (vuse
);
2157 basic_block bb
= gimple_bb (stmt
);
2160 || !bitmap_set_bit (visited
, bb
->index
)
2161 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2165 if (gimple_code (stmt
) == GIMPLE_PHI
)
2167 do_invalidate (dombb
, stmt
, visited
, count
);
2174 if (!maybe_invalidate (stmt
))
2179 vuse
= gimple_vuse (stmt
);
2180 stmt
= SSA_NAME_DEF_STMT (vuse
);
2181 if (gimple_bb (stmt
) != bb
)
2183 bb
= gimple_bb (stmt
);
2186 || !bitmap_set_bit (visited
, bb
->index
)
2187 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2194 class strlen_dom_walker
: public dom_walker
2197 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2199 virtual edge
before_dom_children (basic_block
);
2200 virtual void after_dom_children (basic_block
);
2203 /* Callback for walk_dominator_tree. Attempt to optimize various
2204 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2207 strlen_dom_walker::before_dom_children (basic_block bb
)
2209 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2212 stridx_to_strinfo
= NULL
;
2215 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) dombb
->aux
);
2216 if (stridx_to_strinfo
)
2218 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2221 gphi
*phi
= gsi
.phi ();
2222 if (virtual_operand_p (gimple_phi_result (phi
)))
2224 bitmap visited
= BITMAP_ALLOC (NULL
);
2225 int count_vdef
= 100;
2226 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2227 BITMAP_FREE (visited
);
2228 if (count_vdef
== 0)
2230 /* If there were too many vdefs in between immediate
2231 dominator and current bb, invalidate everything.
2232 If stridx_to_strinfo has been unshared, we need
2233 to free it, otherwise just set it to NULL. */
2234 if (!strinfo_shared ())
2240 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2244 (*stridx_to_strinfo
)[i
] = NULL
;
2248 stridx_to_strinfo
= NULL
;
2256 /* If all PHI arguments have the same string index, the PHI result
2258 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2261 gphi
*phi
= gsi
.phi ();
2262 tree result
= gimple_phi_result (phi
);
2263 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2265 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2268 unsigned int i
, n
= gimple_phi_num_args (phi
);
2269 for (i
= 1; i
< n
; i
++)
2270 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2273 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2278 /* Attempt to optimize individual statements. */
2279 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2280 if (strlen_optimize_stmt (&gsi
))
2283 bb
->aux
= stridx_to_strinfo
;
2284 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2285 (*stridx_to_strinfo
)[0] = (strinfo
*) bb
;
2289 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2290 owned by the current bb, clear bb->aux. */
2293 strlen_dom_walker::after_dom_children (basic_block bb
)
2297 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) bb
->aux
);
2298 if (vec_safe_length (stridx_to_strinfo
)
2299 && (*stridx_to_strinfo
)[0] == (strinfo
*) bb
)
2304 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2306 vec_free (stridx_to_strinfo
);
2312 /* Main entry point. */
2316 const pass_data pass_data_strlen
=
2318 GIMPLE_PASS
, /* type */
2319 "strlen", /* name */
2320 OPTGROUP_NONE
, /* optinfo_flags */
2321 TV_TREE_STRLEN
, /* tv_id */
2322 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2323 0, /* properties_provided */
2324 0, /* properties_destroyed */
2325 0, /* todo_flags_start */
2326 0, /* todo_flags_finish */
2329 class pass_strlen
: public gimple_opt_pass
2332 pass_strlen (gcc::context
*ctxt
)
2333 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2336 /* opt_pass methods: */
2337 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2338 virtual unsigned int execute (function
*);
2340 }; // class pass_strlen
2343 pass_strlen::execute (function
*fun
)
2345 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2348 calculate_dominance_info (CDI_DOMINATORS
);
2350 /* String length optimization is implemented as a walk of the dominator
2351 tree and a forward walk of statements within each block. */
2352 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2354 ssa_ver_to_stridx
.release ();
2355 strinfo_pool
.release ();
2356 if (decl_to_stridxlist_htab
)
2358 obstack_free (&stridx_obstack
, NULL
);
2359 delete decl_to_stridxlist_htab
;
2360 decl_to_stridxlist_htab
= NULL
;
2362 laststmt
.stmt
= NULL
;
2363 laststmt
.len
= NULL_TREE
;
2364 laststmt
.stridx
= 0;
2372 make_pass_strlen (gcc::context
*ctxt
)
2374 return new pass_strlen (ctxt
);