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"
31 #include "fold-const.h"
32 #include "stor-layout.h"
33 #include "internal-fn.h"
34 #include "gimple-fold.h"
37 #include "gimple-iterator.h"
38 #include "gimplify-me.h"
40 #include "insn-config.h"
50 #include "tree-pass.h"
52 #include "alloc-pool.h"
53 #include "tree-ssa-propagate.h"
54 #include "gimple-pretty-print.h"
58 #include "tree-hash-traits.h"
60 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
61 is an index into strinfo vector, negative value stands for
62 string length of a string literal (~strlen). */
63 static vec
<int> ssa_ver_to_stridx
;
65 /* Number of currently active string indexes plus one. */
66 static int max_stridx
;
68 /* String information record. */
69 typedef struct strinfo_struct
71 /* String length of this string. */
73 /* Any of the corresponding pointers for querying alias oracle. */
75 /* Statement for delayed length computation. */
77 /* Pointer to '\0' if known, if NULL, it can be computed as
80 /* Reference count. Any changes to strinfo entry possibly shared
81 with dominating basic blocks need unshare_strinfo first, except
82 for dont_invalidate which affects only the immediately next
85 /* Copy of index. get_strinfo (si->idx) should return si; */
87 /* These 3 fields are for chaining related string pointers together.
89 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
90 strcpy (c, d); e = c + dl;
91 strinfo(a) -> strinfo(c) -> strinfo(e)
92 All have ->first field equal to strinfo(a)->idx and are doubly
93 chained through prev/next fields. The later strinfos are required
94 to point into the same string with zero or more bytes after
95 the previous pointer and all bytes in between the two pointers
96 must be non-zero. Functions like strcpy or memcpy are supposed
97 to adjust all previous strinfo lengths, but not following strinfo
98 lengths (those are uncertain, usually invalidated during
99 maybe_invalidate, except when the alias oracle knows better).
100 Functions like strcat on the other side adjust the whole
101 related strinfo chain.
102 They are updated lazily, so to use the chain the same first fields
103 and si->prev->next == si->idx needs to be verified. */
107 /* A flag whether the string is known to be written in the current
110 /* A flag for the next maybe_invalidate that this strinfo shouldn't
111 be invalidated. Always cleared by maybe_invalidate. */
112 bool dont_invalidate
;
115 /* Pool for allocating strinfo_struct entries. */
116 static object_allocator
<strinfo_struct
> strinfo_pool ("strinfo_struct pool",
119 /* Vector mapping positive string indexes to strinfo, for the
120 current basic block. The first pointer in the vector is special,
121 it is either NULL, meaning the vector isn't shared, or it is
122 a basic block pointer to the owner basic_block if shared.
123 If some other bb wants to modify the vector, the vector needs
124 to be unshared first, and only the owner bb is supposed to free it. */
125 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
127 /* One OFFSET->IDX mapping. */
130 struct stridxlist
*next
;
131 HOST_WIDE_INT offset
;
135 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
136 struct decl_stridxlist_map
138 struct tree_map_base base
;
139 struct stridxlist list
;
142 /* Hash table for mapping decls to a chained list of offset -> idx
144 static hash_map
<tree_decl_hash
, stridxlist
> *decl_to_stridxlist_htab
;
146 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
147 static struct obstack stridx_obstack
;
149 /* Last memcpy statement if it could be adjusted if the trailing
150 '\0' written is immediately overwritten, or
151 *x = '\0' store that could be removed if it is immediately overwritten. */
152 struct laststmt_struct
159 static int get_stridx_plus_constant (strinfo
, HOST_WIDE_INT
, tree
);
161 /* Return strinfo vector entry IDX. */
163 static inline strinfo
164 get_strinfo (int idx
)
166 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
168 return (*stridx_to_strinfo
)[idx
];
171 /* Helper function for get_stridx. */
174 get_addr_stridx (tree exp
)
177 struct stridxlist
*list
;
180 if (!decl_to_stridxlist_htab
)
183 base
= get_addr_base_and_unit_offset (exp
, &off
);
184 if (base
== NULL
|| !DECL_P (base
))
187 list
= decl_to_stridxlist_htab
->get (base
);
193 if (list
->offset
== off
)
201 /* Return string index for EXP. */
204 get_stridx (tree exp
)
208 if (TREE_CODE (exp
) == SSA_NAME
)
210 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
211 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
214 HOST_WIDE_INT off
= 0;
215 for (i
= 0; i
< 5; i
++)
217 gimple def_stmt
= SSA_NAME_DEF_STMT (e
);
218 if (!is_gimple_assign (def_stmt
)
219 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
221 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
222 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
223 if (TREE_CODE (rhs1
) != SSA_NAME
224 || !tree_fits_shwi_p (rhs2
))
226 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
229 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
232 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
235 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
238 && TREE_CODE (si
->length
) == INTEGER_CST
239 && compare_tree_int (si
->length
, off
) != -1)
240 return get_stridx_plus_constant (si
, off
, exp
);
247 if (TREE_CODE (exp
) == ADDR_EXPR
)
249 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
254 s
= string_constant (exp
, &o
);
256 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
257 && TREE_STRING_LENGTH (s
) > 0)
259 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
260 const char *p
= TREE_STRING_POINTER (s
);
261 int max
= TREE_STRING_LENGTH (s
) - 1;
263 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
264 return ~(int) strlen (p
+ offset
);
269 /* Return true if strinfo vector is shared with the immediate dominator. */
272 strinfo_shared (void)
274 return vec_safe_length (stridx_to_strinfo
)
275 && (*stridx_to_strinfo
)[0] != NULL
;
278 /* Unshare strinfo vector that is shared with the immediate dominator. */
281 unshare_strinfo_vec (void)
286 gcc_assert (strinfo_shared ());
287 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
288 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
291 (*stridx_to_strinfo
)[0] = NULL
;
294 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
295 Return a pointer to the location where the string index can
296 be stored (if 0) or is stored, or NULL if this can't be tracked. */
299 addr_stridxptr (tree exp
)
303 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
304 if (base
== NULL_TREE
|| !DECL_P (base
))
307 if (!decl_to_stridxlist_htab
)
309 decl_to_stridxlist_htab
310 = new hash_map
<tree_decl_hash
, stridxlist
> (64);
311 gcc_obstack_init (&stridx_obstack
);
315 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
319 for (i
= 0; i
< 16; i
++)
321 if (list
->offset
== off
)
323 if (list
->next
== NULL
)
328 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
338 /* Create a new string index, or return 0 if reached limit. */
341 new_stridx (tree exp
)
344 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
346 if (TREE_CODE (exp
) == SSA_NAME
)
348 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
351 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
354 if (TREE_CODE (exp
) == ADDR_EXPR
)
356 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
359 gcc_assert (*pidx
== 0);
360 *pidx
= max_stridx
++;
367 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
370 new_addr_stridx (tree exp
)
373 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
375 pidx
= addr_stridxptr (exp
);
378 gcc_assert (*pidx
== 0);
379 *pidx
= max_stridx
++;
385 /* Create a new strinfo. */
388 new_strinfo (tree ptr
, int idx
, tree length
)
390 strinfo si
= strinfo_pool
.allocate ();
394 si
->endptr
= NULL_TREE
;
400 si
->writable
= false;
401 si
->dont_invalidate
= false;
405 /* Decrease strinfo refcount and free it if not referenced anymore. */
408 free_strinfo (strinfo si
)
410 if (si
&& --si
->refcount
== 0)
411 strinfo_pool
.remove (si
);
414 /* Set strinfo in the vector entry IDX to SI. */
417 set_strinfo (int idx
, strinfo si
)
419 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
420 unshare_strinfo_vec ();
421 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
422 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
423 (*stridx_to_strinfo
)[idx
] = si
;
426 /* Return string length, or NULL if it can't be computed. */
429 get_string_length (strinfo si
)
436 gimple stmt
= si
->stmt
, lenstmt
;
437 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
438 tree callee
, lhs
, fn
, tem
;
440 gimple_stmt_iterator gsi
;
442 gcc_assert (is_gimple_call (stmt
));
443 callee
= gimple_call_fndecl (stmt
);
444 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
445 lhs
= gimple_call_lhs (stmt
);
446 /* unshare_strinfo is intentionally not called here. The (delayed)
447 transformation of strcpy or strcat into stpcpy is done at the place
448 of the former strcpy/strcat call and so can affect all the strinfos
449 with the same stmt. If they were unshared before and transformation
450 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
451 just compute the right length. */
452 switch (DECL_FUNCTION_CODE (callee
))
454 case BUILT_IN_STRCAT
:
455 case BUILT_IN_STRCAT_CHK
:
456 case BUILT_IN_STRCAT_CHKP
:
457 case BUILT_IN_STRCAT_CHK_CHKP
:
458 gsi
= gsi_for_stmt (stmt
);
459 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
460 gcc_assert (lhs
== NULL_TREE
);
461 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
464 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
465 2, tem
, gimple_call_arg (stmt
, 1));
466 gimple_call_set_with_bounds (lenstmt
, true);
469 lenstmt
= gimple_build_call (fn
, 1, tem
);
470 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
471 gimple_call_set_lhs (lenstmt
, lhs
);
472 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
473 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
474 tem
= gimple_call_arg (stmt
, 0);
475 if (!ptrofftype_p (TREE_TYPE (lhs
)))
477 lhs
= convert_to_ptrofftype (lhs
);
478 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
479 true, GSI_SAME_STMT
);
481 lenstmt
= gimple_build_assign
482 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
483 POINTER_PLUS_EXPR
,tem
, lhs
);
484 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
485 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
488 case BUILT_IN_STRCPY
:
489 case BUILT_IN_STRCPY_CHK
:
490 case BUILT_IN_STRCPY_CHKP
:
491 case BUILT_IN_STRCPY_CHK_CHKP
:
492 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
493 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
494 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
496 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
498 fn
= chkp_maybe_create_clone (fn
)->decl
;
499 gcc_assert (lhs
== NULL_TREE
);
500 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
502 fprintf (dump_file
, "Optimizing: ");
503 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
505 gimple_call_set_fndecl (stmt
, fn
);
506 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
507 gimple_call_set_lhs (stmt
, lhs
);
509 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
511 fprintf (dump_file
, "into: ");
512 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
515 case BUILT_IN_STPCPY
:
516 case BUILT_IN_STPCPY_CHK
:
517 case BUILT_IN_STPCPY_CHKP
:
518 case BUILT_IN_STPCPY_CHK_CHKP
:
519 gcc_assert (lhs
!= NULL_TREE
);
520 loc
= gimple_location (stmt
);
523 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
524 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
525 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
528 case BUILT_IN_MALLOC
:
530 /* BUILT_IN_CALLOC always has si->length set. */
540 /* Invalidate string length information for strings whose length
541 might change due to stores in stmt. */
544 maybe_invalidate (gimple stmt
)
548 bool nonempty
= false;
550 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
553 if (!si
->dont_invalidate
)
556 /* Do not use si->length. */
557 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
558 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
560 set_strinfo (i
, NULL
);
565 si
->dont_invalidate
= false;
571 /* Unshare strinfo record SI, if it has refcount > 1 or
572 if stridx_to_strinfo vector is shared with some other
576 unshare_strinfo (strinfo si
)
580 if (si
->refcount
== 1 && !strinfo_shared ())
583 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
584 nsi
->stmt
= si
->stmt
;
585 nsi
->endptr
= si
->endptr
;
586 nsi
->first
= si
->first
;
587 nsi
->prev
= si
->prev
;
588 nsi
->next
= si
->next
;
589 nsi
->writable
= si
->writable
;
590 set_strinfo (si
->idx
, nsi
);
595 /* Return first strinfo in the related strinfo chain
596 if all strinfos in between belong to the chain, otherwise
600 verify_related_strinfos (strinfo origsi
)
602 strinfo si
= origsi
, psi
;
604 if (origsi
->first
== 0)
606 for (; si
->prev
; si
= psi
)
608 if (si
->first
!= origsi
->first
)
610 psi
= get_strinfo (si
->prev
);
613 if (psi
->next
!= si
->idx
)
616 if (si
->idx
!= si
->first
)
621 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
622 strinfo if there is any. Return it's idx, or 0 if no strinfo has
626 get_stridx_plus_constant (strinfo basesi
, HOST_WIDE_INT off
, tree ptr
)
628 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
630 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
633 if (basesi
->length
== NULL_TREE
634 || TREE_CODE (basesi
->length
) != INTEGER_CST
635 || compare_tree_int (basesi
->length
, off
) == -1
636 || !tree_fits_shwi_p (basesi
->length
))
639 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
640 strinfo si
= basesi
, chainsi
;
641 if (si
->first
|| si
->prev
|| si
->next
)
642 si
= verify_related_strinfos (basesi
);
644 || si
->length
== NULL_TREE
645 || TREE_CODE (si
->length
) != INTEGER_CST
)
648 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
649 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
651 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
652 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
654 si
= get_strinfo (chainsi
->next
);
656 || si
->first
!= chainsi
->first
657 || si
->prev
!= chainsi
->idx
658 || si
->length
== NULL_TREE
659 || TREE_CODE (si
->length
) != INTEGER_CST
)
661 int r
= compare_tree_int (si
->length
, len
);
666 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
673 int idx
= new_stridx (ptr
);
676 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
677 set_strinfo (idx
, si
);
680 strinfo nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
681 si
->next
= nextsi
->idx
;
684 chainsi
= unshare_strinfo (chainsi
);
685 if (chainsi
->first
== 0)
686 chainsi
->first
= chainsi
->idx
;
688 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
689 chainsi
->endptr
= ptr
;
690 si
->endptr
= chainsi
->endptr
;
691 si
->prev
= chainsi
->idx
;
692 si
->first
= chainsi
->first
;
693 si
->writable
= chainsi
->writable
;
697 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
698 to a zero-length string and if possible chain it to a related strinfo
699 chain whose part is or might be CHAINSI. */
702 zero_length_string (tree ptr
, strinfo chainsi
)
706 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
707 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
708 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
709 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
711 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
715 si
= verify_related_strinfos (chainsi
);
719 for (; chainsi
->next
; chainsi
= si
)
721 if (chainsi
->endptr
== NULL_TREE
)
723 chainsi
= unshare_strinfo (chainsi
);
724 chainsi
->endptr
= ptr
;
726 si
= get_strinfo (chainsi
->next
);
728 || si
->first
!= chainsi
->first
729 || si
->prev
!= chainsi
->idx
)
732 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
733 if (chainsi
->endptr
== NULL_TREE
)
735 chainsi
= unshare_strinfo (chainsi
);
736 chainsi
->endptr
= ptr
;
738 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
742 chainsi
= unshare_strinfo (chainsi
);
745 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
749 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
751 chainsi
= unshare_strinfo (chainsi
);
757 idx
= new_stridx (ptr
);
760 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
761 set_strinfo (idx
, si
);
765 chainsi
= unshare_strinfo (chainsi
);
766 if (chainsi
->first
== 0)
767 chainsi
->first
= chainsi
->idx
;
769 if (chainsi
->endptr
== NULL_TREE
)
770 chainsi
->endptr
= ptr
;
771 si
->prev
= chainsi
->idx
;
772 si
->first
= chainsi
->first
;
773 si
->writable
= chainsi
->writable
;
778 /* For strinfo ORIGSI whose length has been just updated
779 update also related strinfo lengths (add ADJ to each,
780 but don't adjust ORIGSI). */
783 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
785 strinfo si
= verify_related_strinfos (origsi
);
798 si
= unshare_strinfo (si
);
801 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
802 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
803 TREE_TYPE (si
->length
), si
->length
,
806 else if (si
->stmt
!= NULL
)
807 /* Delayed length computation is unaffected. */
812 si
->endptr
= NULL_TREE
;
813 si
->dont_invalidate
= true;
817 nsi
= get_strinfo (si
->next
);
819 || nsi
->first
!= si
->first
820 || nsi
->prev
!= si
->idx
)
826 /* Find if there are other SSA_NAME pointers equal to PTR
827 for which we don't track their string lengths yet. If so, use
831 find_equal_ptrs (tree ptr
, int idx
)
833 if (TREE_CODE (ptr
) != SSA_NAME
)
837 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
838 if (!is_gimple_assign (stmt
))
840 ptr
= gimple_assign_rhs1 (stmt
);
841 switch (gimple_assign_rhs_code (stmt
))
846 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
848 if (TREE_CODE (ptr
) == SSA_NAME
)
850 if (TREE_CODE (ptr
) != ADDR_EXPR
)
855 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
856 if (pidx
!= NULL
&& *pidx
== 0)
864 /* We might find an endptr created in this pass. Grow the
865 vector in that case. */
866 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
867 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
869 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
871 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
875 /* If the last .MEM setter statement before STMT is
876 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
877 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
878 just memcpy (x, y, strlen (y)). SI must be the zero length
882 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
884 tree vuse
, callee
, len
;
885 struct laststmt_struct last
= laststmt
;
886 strinfo lastsi
, firstsi
;
887 unsigned len_arg_no
= 2;
889 laststmt
.stmt
= NULL
;
890 laststmt
.len
= NULL_TREE
;
893 if (last
.stmt
== NULL
)
896 vuse
= gimple_vuse (stmt
);
897 if (vuse
== NULL_TREE
898 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
899 || !has_single_use (vuse
))
902 gcc_assert (last
.stridx
> 0);
903 lastsi
= get_strinfo (last
.stridx
);
909 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
912 firstsi
= verify_related_strinfos (si
);
915 while (firstsi
!= lastsi
)
918 if (firstsi
->next
== 0)
920 nextsi
= get_strinfo (firstsi
->next
);
922 || nextsi
->prev
!= firstsi
->idx
923 || nextsi
->first
!= si
->first
)
931 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
935 if (is_gimple_assign (last
.stmt
))
937 gimple_stmt_iterator gsi
;
939 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
941 if (stmt_could_throw_p (last
.stmt
))
943 gsi
= gsi_for_stmt (last
.stmt
);
944 unlink_stmt_vdef (last
.stmt
);
945 release_defs (last
.stmt
);
946 gsi_remove (&gsi
, true);
950 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
953 callee
= gimple_call_fndecl (last
.stmt
);
954 switch (DECL_FUNCTION_CODE (callee
))
956 case BUILT_IN_MEMCPY
:
957 case BUILT_IN_MEMCPY_CHK
:
959 case BUILT_IN_MEMCPY_CHKP
:
960 case BUILT_IN_MEMCPY_CHK_CHKP
:
967 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
968 if (tree_fits_uhwi_p (len
))
970 if (!tree_fits_uhwi_p (last
.len
)
971 || integer_zerop (len
)
972 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
974 /* Don't adjust the length if it is divisible by 4, it is more efficient
975 to store the extra '\0' in that case. */
976 if ((tree_to_uhwi (len
) & 3) == 0)
979 else if (TREE_CODE (len
) == SSA_NAME
)
981 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
982 if (!is_gimple_assign (def_stmt
)
983 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
984 || gimple_assign_rhs1 (def_stmt
) != last
.len
985 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
991 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
992 update_stmt (last
.stmt
);
995 /* Handle a strlen call. If strlen of the argument is known, replace
996 the strlen call with the known value, otherwise remember that strlen
997 of the argument is stored in the lhs SSA_NAME. */
1000 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1004 gimple stmt
= gsi_stmt (*gsi
);
1005 tree lhs
= gimple_call_lhs (stmt
);
1007 if (lhs
== NULL_TREE
)
1010 src
= gimple_call_arg (stmt
, 0);
1011 idx
= get_stridx (src
);
1018 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1022 si
= get_strinfo (idx
);
1024 rhs
= get_string_length (si
);
1026 if (rhs
!= NULL_TREE
)
1028 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1030 fprintf (dump_file
, "Optimizing: ");
1031 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1033 rhs
= unshare_expr (rhs
);
1034 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1035 rhs
= fold_convert_loc (gimple_location (stmt
),
1036 TREE_TYPE (lhs
), rhs
);
1037 if (!update_call_from_tree (gsi
, rhs
))
1038 gimplify_and_update_call_from_tree (gsi
, rhs
);
1039 stmt
= gsi_stmt (*gsi
);
1041 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1043 fprintf (dump_file
, "into: ");
1044 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1047 && TREE_CODE (si
->length
) != SSA_NAME
1048 && TREE_CODE (si
->length
) != INTEGER_CST
1049 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1051 si
= unshare_strinfo (si
);
1057 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1060 idx
= new_stridx (src
);
1061 else if (get_strinfo (idx
) != NULL
)
1065 strinfo si
= new_strinfo (src
, idx
, lhs
);
1066 set_strinfo (idx
, si
);
1067 find_equal_ptrs (src
, idx
);
1071 /* Handle a strchr call. If strlen of the first argument is known, replace
1072 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1073 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1076 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1080 gimple stmt
= gsi_stmt (*gsi
);
1081 tree lhs
= gimple_call_lhs (stmt
);
1082 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1084 if (lhs
== NULL_TREE
)
1087 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1090 src
= gimple_call_arg (stmt
, 0);
1091 idx
= get_stridx (src
);
1098 rhs
= build_int_cst (size_type_node
, ~idx
);
1102 si
= get_strinfo (idx
);
1104 rhs
= get_string_length (si
);
1106 if (rhs
!= NULL_TREE
)
1108 location_t loc
= gimple_location (stmt
);
1110 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1112 fprintf (dump_file
, "Optimizing: ");
1113 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1115 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1117 rhs
= unshare_expr (si
->endptr
);
1118 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1120 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1124 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1125 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1126 TREE_TYPE (src
), src
, rhs
);
1127 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1129 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1131 if (!update_call_from_tree (gsi
, rhs
))
1132 gimplify_and_update_call_from_tree (gsi
, rhs
);
1133 stmt
= gsi_stmt (*gsi
);
1135 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1137 fprintf (dump_file
, "into: ");
1138 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1141 && si
->endptr
== NULL_TREE
1142 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1144 si
= unshare_strinfo (si
);
1147 zero_length_string (lhs
, si
);
1151 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1153 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1156 idx
= new_stridx (src
);
1157 else if (get_strinfo (idx
) != NULL
)
1159 zero_length_string (lhs
, NULL
);
1164 location_t loc
= gimple_location (stmt
);
1165 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1166 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1167 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1168 size_type_node
, lhsu
, srcu
);
1169 strinfo si
= new_strinfo (src
, idx
, length
);
1171 set_strinfo (idx
, si
);
1172 find_equal_ptrs (src
, idx
);
1173 zero_length_string (lhs
, si
);
1177 zero_length_string (lhs
, NULL
);
1180 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1181 If strlen of the second argument is known, strlen of the first argument
1182 is the same after this call. Furthermore, attempt to convert it to
1186 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1189 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1191 gimple stmt
= gsi_stmt (*gsi
);
1192 strinfo si
, dsi
, olddsi
, zsi
;
1194 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1196 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1197 dst
= gimple_call_arg (stmt
, 0);
1198 lhs
= gimple_call_lhs (stmt
);
1199 idx
= get_stridx (src
);
1202 si
= get_strinfo (idx
);
1204 didx
= get_stridx (dst
);
1208 olddsi
= get_strinfo (didx
);
1213 adjust_last_stmt (olddsi
, stmt
, false);
1217 srclen
= get_string_length (si
);
1219 srclen
= build_int_cst (size_type_node
, ~idx
);
1221 loc
= gimple_location (stmt
);
1222 if (srclen
== NULL_TREE
)
1225 case BUILT_IN_STRCPY
:
1226 case BUILT_IN_STRCPY_CHK
:
1227 case BUILT_IN_STRCPY_CHKP
:
1228 case BUILT_IN_STRCPY_CHK_CHKP
:
1229 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1232 case BUILT_IN_STPCPY
:
1233 case BUILT_IN_STPCPY_CHK
:
1234 case BUILT_IN_STPCPY_CHKP
:
1235 case BUILT_IN_STPCPY_CHK_CHKP
:
1236 if (lhs
== NULL_TREE
)
1240 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1241 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1242 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1252 didx
= new_stridx (dst
);
1258 oldlen
= olddsi
->length
;
1259 dsi
= unshare_strinfo (olddsi
);
1260 dsi
->length
= srclen
;
1261 /* Break the chain, so adjust_related_strinfo on later pointers in
1262 the chain won't adjust this one anymore. */
1265 dsi
->endptr
= NULL_TREE
;
1269 dsi
= new_strinfo (dst
, didx
, srclen
);
1270 set_strinfo (didx
, dsi
);
1271 find_equal_ptrs (dst
, didx
);
1273 dsi
->writable
= true;
1274 dsi
->dont_invalidate
= true;
1276 if (dsi
->length
== NULL_TREE
)
1280 /* If string length of src is unknown, use delayed length
1281 computation. If string lenth of dst will be needed, it
1282 can be computed by transforming this strcpy call into
1283 stpcpy and subtracting dst from the return value. */
1285 /* Look for earlier strings whose length could be determined if
1286 this strcpy is turned into an stpcpy. */
1288 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1290 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1292 /* When setting a stmt for delayed length computation
1293 prevent all strinfos through dsi from being
1295 chainsi
= unshare_strinfo (chainsi
);
1296 chainsi
->stmt
= stmt
;
1297 chainsi
->length
= NULL_TREE
;
1298 chainsi
->endptr
= NULL_TREE
;
1299 chainsi
->dont_invalidate
= true;
1308 tree adj
= NULL_TREE
;
1309 if (oldlen
== NULL_TREE
)
1311 else if (integer_zerop (oldlen
))
1313 else if (TREE_CODE (oldlen
) == INTEGER_CST
1314 || TREE_CODE (srclen
) == INTEGER_CST
)
1315 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1316 TREE_TYPE (srclen
), srclen
,
1317 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1319 if (adj
!= NULL_TREE
)
1320 adjust_related_strinfos (loc
, dsi
, adj
);
1324 /* strcpy src may not overlap dst, so src doesn't need to be
1325 invalidated either. */
1327 si
->dont_invalidate
= true;
1333 case BUILT_IN_STRCPY
:
1334 case BUILT_IN_STRCPY_CHKP
:
1335 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1337 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1339 case BUILT_IN_STRCPY_CHK
:
1340 case BUILT_IN_STRCPY_CHK_CHKP
:
1341 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1343 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1345 case BUILT_IN_STPCPY
:
1346 case BUILT_IN_STPCPY_CHKP
:
1347 /* This would need adjustment of the lhs (subtract one),
1348 or detection that the trailing '\0' doesn't need to be
1349 written, if it will be immediately overwritten.
1350 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1354 zsi
= zero_length_string (lhs
, dsi
);
1357 case BUILT_IN_STPCPY_CHK
:
1358 case BUILT_IN_STPCPY_CHK_CHKP
:
1359 /* This would need adjustment of the lhs (subtract one),
1360 or detection that the trailing '\0' doesn't need to be
1361 written, if it will be immediately overwritten.
1362 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1366 zsi
= zero_length_string (lhs
, dsi
);
1373 zsi
->dont_invalidate
= true;
1375 if (fn
== NULL_TREE
)
1378 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1379 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1381 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1382 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1383 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1385 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1387 fprintf (dump_file
, "Optimizing: ");
1388 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1392 fn
= chkp_maybe_create_clone (fn
)->decl
;
1393 if (gimple_call_num_args (stmt
) == 4)
1394 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1395 gimple_call_arg (stmt
, 1),
1397 gimple_call_arg (stmt
, 3),
1400 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1401 gimple_call_arg (stmt
, 1),
1403 gimple_call_arg (stmt
, 3),
1405 gimple_call_arg (stmt
, 4));
1408 if (gimple_call_num_args (stmt
) == 2)
1409 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1411 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1412 gimple_call_arg (stmt
, 2));
1415 stmt
= gsi_stmt (*gsi
);
1416 gimple_call_set_with_bounds (stmt
, with_bounds
);
1418 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1420 fprintf (dump_file
, "into: ");
1421 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1423 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1424 laststmt
.stmt
= stmt
;
1425 laststmt
.len
= srclen
;
1426 laststmt
.stridx
= dsi
->idx
;
1428 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1429 fprintf (dump_file
, "not possible.\n");
1432 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1433 If strlen of the second argument is known and length of the third argument
1434 is that plus one, strlen of the first argument is the same after this
1438 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1441 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1442 gimple stmt
= gsi_stmt (*gsi
);
1443 strinfo si
, dsi
, olddsi
;
1444 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1446 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1447 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1448 dst
= gimple_call_arg (stmt
, 0);
1449 idx
= get_stridx (src
);
1453 didx
= get_stridx (dst
);
1456 olddsi
= get_strinfo (didx
);
1461 && tree_fits_uhwi_p (len
)
1462 && !integer_zerop (len
))
1463 adjust_last_stmt (olddsi
, stmt
, false);
1469 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1470 si
= get_strinfo (idx
);
1471 if (si
== NULL
|| si
->length
== NULL_TREE
)
1473 if (TREE_CODE (len
) != SSA_NAME
)
1475 def_stmt
= SSA_NAME_DEF_STMT (len
);
1476 if (!is_gimple_assign (def_stmt
)
1477 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1478 || gimple_assign_rhs1 (def_stmt
) != si
->length
1479 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1485 /* Handle memcpy (x, "abcd", 5) or
1486 memcpy (x, "abc\0uvw", 7). */
1487 if (!tree_fits_uhwi_p (len
)
1488 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1492 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1493 adjust_last_stmt (olddsi
, stmt
, false);
1497 didx
= new_stridx (dst
);
1502 newlen
= si
->length
;
1504 newlen
= build_int_cst (size_type_node
, ~idx
);
1508 dsi
= unshare_strinfo (olddsi
);
1509 oldlen
= olddsi
->length
;
1510 dsi
->length
= newlen
;
1511 /* Break the chain, so adjust_related_strinfo on later pointers in
1512 the chain won't adjust this one anymore. */
1515 dsi
->endptr
= NULL_TREE
;
1519 dsi
= new_strinfo (dst
, didx
, newlen
);
1520 set_strinfo (didx
, dsi
);
1521 find_equal_ptrs (dst
, didx
);
1523 dsi
->writable
= true;
1524 dsi
->dont_invalidate
= true;
1527 tree adj
= NULL_TREE
;
1528 location_t loc
= gimple_location (stmt
);
1529 if (oldlen
== NULL_TREE
)
1531 else if (integer_zerop (oldlen
))
1533 else if (TREE_CODE (oldlen
) == INTEGER_CST
1534 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1535 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1536 TREE_TYPE (dsi
->length
), dsi
->length
,
1537 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1539 if (adj
!= NULL_TREE
)
1540 adjust_related_strinfos (loc
, dsi
, adj
);
1544 /* memcpy src may not overlap dst, so src doesn't need to be
1545 invalidated either. */
1547 si
->dont_invalidate
= true;
1549 lhs
= gimple_call_lhs (stmt
);
1552 case BUILT_IN_MEMCPY
:
1553 case BUILT_IN_MEMCPY_CHK
:
1554 case BUILT_IN_MEMCPY_CHKP
:
1555 case BUILT_IN_MEMCPY_CHK_CHKP
:
1556 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1557 laststmt
.stmt
= stmt
;
1558 laststmt
.len
= dsi
->length
;
1559 laststmt
.stridx
= dsi
->idx
;
1561 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1563 case BUILT_IN_MEMPCPY
:
1564 case BUILT_IN_MEMPCPY_CHK
:
1565 case BUILT_IN_MEMPCPY_CHKP
:
1566 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1573 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1574 If strlen of the second argument is known, strlen of the first argument
1575 is increased by the length of the second argument. Furthermore, attempt
1576 to convert it to memcpy/strcpy if the length of the first argument
1580 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1583 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1585 gimple stmt
= gsi_stmt (*gsi
);
1588 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1590 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1591 dst
= gimple_call_arg (stmt
, 0);
1592 lhs
= gimple_call_lhs (stmt
);
1594 didx
= get_stridx (dst
);
1600 dsi
= get_strinfo (didx
);
1601 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1603 /* strcat (p, q) can be transformed into
1604 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1605 with length endptr - p if we need to compute the length
1606 later on. Don't do this transformation if we don't need
1608 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1612 didx
= new_stridx (dst
);
1618 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1619 set_strinfo (didx
, dsi
);
1620 find_equal_ptrs (dst
, didx
);
1624 dsi
= unshare_strinfo (dsi
);
1625 dsi
->length
= NULL_TREE
;
1627 dsi
->endptr
= NULL_TREE
;
1629 dsi
->writable
= true;
1631 dsi
->dont_invalidate
= true;
1638 idx
= get_stridx (src
);
1640 srclen
= build_int_cst (size_type_node
, ~idx
);
1643 si
= get_strinfo (idx
);
1645 srclen
= get_string_length (si
);
1648 loc
= gimple_location (stmt
);
1649 dstlen
= dsi
->length
;
1650 endptr
= dsi
->endptr
;
1652 dsi
= unshare_strinfo (dsi
);
1653 dsi
->endptr
= NULL_TREE
;
1655 dsi
->writable
= true;
1657 if (srclen
!= NULL_TREE
)
1659 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1660 dsi
->length
, srclen
);
1661 adjust_related_strinfos (loc
, dsi
, srclen
);
1662 dsi
->dont_invalidate
= true;
1667 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1668 dsi
->dont_invalidate
= true;
1672 /* strcat src may not overlap dst, so src doesn't need to be
1673 invalidated either. */
1674 si
->dont_invalidate
= true;
1676 /* For now. Could remove the lhs from the call and add
1677 lhs = dst; afterwards. */
1685 case BUILT_IN_STRCAT
:
1686 case BUILT_IN_STRCAT_CHKP
:
1687 if (srclen
!= NULL_TREE
)
1688 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1690 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1692 case BUILT_IN_STRCAT_CHK
:
1693 case BUILT_IN_STRCAT_CHK_CHKP
:
1694 if (srclen
!= NULL_TREE
)
1695 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1697 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1698 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1704 if (fn
== NULL_TREE
)
1708 if (srclen
!= NULL_TREE
)
1710 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1711 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1713 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1714 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1715 build_int_cst (type
, 1));
1716 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1720 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1722 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1723 TREE_TYPE (dst
), unshare_expr (dst
),
1724 fold_convert_loc (loc
, sizetype
,
1725 unshare_expr (dstlen
)));
1726 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1728 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1730 fprintf (dump_file
, "Optimizing: ");
1731 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1735 fn
= chkp_maybe_create_clone (fn
)->decl
;
1736 if (srclen
!= NULL_TREE
)
1737 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1739 gimple_call_arg (stmt
, 1),
1741 gimple_call_arg (stmt
, 3),
1744 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1746 gimple_call_arg (stmt
, 1),
1748 gimple_call_arg (stmt
, 3),
1752 if (srclen
!= NULL_TREE
)
1753 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1754 dst
, src
, len
, objsz
);
1756 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1760 stmt
= gsi_stmt (*gsi
);
1761 gimple_call_set_with_bounds (stmt
, with_bounds
);
1763 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1765 fprintf (dump_file
, "into: ");
1766 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1768 /* If srclen == NULL, note that current string length can be
1769 computed by transforming this strcpy into stpcpy. */
1770 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1772 adjust_last_stmt (dsi
, stmt
, true);
1773 if (srclen
!= NULL_TREE
)
1775 laststmt
.stmt
= stmt
;
1776 laststmt
.len
= srclen
;
1777 laststmt
.stridx
= dsi
->idx
;
1780 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1781 fprintf (dump_file
, "not possible.\n");
1784 /* Handle a call to malloc or calloc. */
1787 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1789 gimple stmt
= gsi_stmt (*gsi
);
1790 tree lhs
= gimple_call_lhs (stmt
);
1791 gcc_assert (get_stridx (lhs
) == 0);
1792 int idx
= new_stridx (lhs
);
1793 tree length
= NULL_TREE
;
1794 if (bcode
== BUILT_IN_CALLOC
)
1795 length
= build_int_cst (size_type_node
, 0);
1796 strinfo si
= new_strinfo (lhs
, idx
, length
);
1797 if (bcode
== BUILT_IN_CALLOC
)
1799 set_strinfo (idx
, si
);
1800 si
->writable
= true;
1802 si
->dont_invalidate
= true;
1805 /* Handle a call to memset.
1806 After a call to calloc, memset(,0,) is unnecessary.
1807 memset(malloc(n),0,n) is calloc(n,1). */
1810 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1812 gimple stmt2
= gsi_stmt (*gsi
);
1813 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1815 tree ptr
= gimple_call_arg (stmt2
, 0);
1816 int idx1
= get_stridx (ptr
);
1819 strinfo si1
= get_strinfo (idx1
);
1822 gimple stmt1
= si1
->stmt
;
1823 if (!stmt1
|| !is_gimple_call (stmt1
))
1825 tree callee1
= gimple_call_fndecl (stmt1
);
1826 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1828 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1829 tree size
= gimple_call_arg (stmt2
, 2);
1830 if (code1
== BUILT_IN_CALLOC
)
1831 /* Not touching stmt1 */ ;
1832 else if (code1
== BUILT_IN_MALLOC
1833 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1835 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1836 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1837 size
, build_one_cst (size_type_node
));
1838 si1
->length
= build_int_cst (size_type_node
, 0);
1839 si1
->stmt
= gsi_stmt (gsi1
);
1843 tree lhs
= gimple_call_lhs (stmt2
);
1844 unlink_stmt_vdef (stmt2
);
1847 gimple assign
= gimple_build_assign (lhs
, ptr
);
1848 gsi_replace (gsi
, assign
, false);
1852 gsi_remove (gsi
, true);
1853 release_defs (stmt2
);
1859 /* Handle a POINTER_PLUS_EXPR statement.
1860 For p = "abcd" + 2; compute associated length, or if
1861 p = q + off is pointing to a '\0' character of a string, call
1862 zero_length_string on it. */
1865 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1867 gimple stmt
= gsi_stmt (*gsi
);
1868 tree lhs
= gimple_assign_lhs (stmt
), off
;
1869 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1877 tree off
= gimple_assign_rhs2 (stmt
);
1878 if (tree_fits_uhwi_p (off
)
1879 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1880 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1881 = ~(~idx
- (int) tree_to_uhwi (off
));
1885 si
= get_strinfo (idx
);
1886 if (si
== NULL
|| si
->length
== NULL_TREE
)
1889 off
= gimple_assign_rhs2 (stmt
);
1891 if (operand_equal_p (si
->length
, off
, 0))
1892 zsi
= zero_length_string (lhs
, si
);
1893 else if (TREE_CODE (off
) == SSA_NAME
)
1895 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1896 if (gimple_assign_single_p (def_stmt
)
1897 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1898 zsi
= zero_length_string (lhs
, si
);
1901 && si
->endptr
!= NULL_TREE
1902 && si
->endptr
!= lhs
1903 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1905 enum tree_code rhs_code
1906 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1907 ? SSA_NAME
: NOP_EXPR
;
1908 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1909 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1914 /* Handle a single character store. */
1917 handle_char_store (gimple_stmt_iterator
*gsi
)
1921 gimple stmt
= gsi_stmt (*gsi
);
1922 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1924 if (TREE_CODE (lhs
) == MEM_REF
1925 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1927 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1929 ssaname
= TREE_OPERAND (lhs
, 0);
1930 idx
= get_stridx (ssaname
);
1934 idx
= get_addr_stridx (lhs
);
1938 si
= get_strinfo (idx
);
1939 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1941 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1943 /* When storing '\0', the store can be removed
1944 if we know it has been stored in the current function. */
1945 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1947 unlink_stmt_vdef (stmt
);
1948 release_defs (stmt
);
1949 gsi_remove (gsi
, true);
1954 si
->writable
= true;
1960 /* Otherwise this statement overwrites the '\0' with
1961 something, if the previous stmt was a memcpy,
1962 its length may be decreased. */
1963 adjust_last_stmt (si
, stmt
, false);
1965 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1967 si
= unshare_strinfo (si
);
1968 si
->length
= build_int_cst (size_type_node
, 0);
1974 si
->writable
= true;
1975 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1976 si
->endptr
= ssaname
;
1977 si
->dont_invalidate
= true;
1979 /* If si->length is non-zero constant, we aren't overwriting '\0',
1980 and if we aren't storing '\0', we know that the length of the
1981 string and any other zero terminated string in memory remains
1982 the same. In that case we move to the next gimple statement and
1983 return to signal the caller that it shouldn't invalidate anything.
1985 This is benefical for cases like:
1990 strcpy (p, "foobar");
1991 size_t len = strlen (p); // This can be optimized into 6
1992 size_t len2 = strlen (q); // This has to be computed
1994 size_t len3 = strlen (p); // This can be optimized into 6
1995 size_t len4 = strlen (q); // This can be optimized into len2
1996 bar (len, len2, len3, len4);
1999 else if (si
!= NULL
&& si
->length
!= NULL_TREE
2000 && TREE_CODE (si
->length
) == INTEGER_CST
2001 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2007 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2011 si
= zero_length_string (ssaname
, NULL
);
2013 si
->dont_invalidate
= true;
2017 int idx
= new_addr_stridx (lhs
);
2020 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2021 build_int_cst (size_type_node
, 0));
2022 set_strinfo (idx
, si
);
2023 si
->dont_invalidate
= true;
2027 si
->writable
= true;
2030 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2031 && ssaname
== NULL_TREE
2032 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2034 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2035 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2036 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2038 int idx
= new_addr_stridx (lhs
);
2041 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2042 build_int_cst (size_type_node
, l
));
2043 set_strinfo (idx
, si
);
2044 si
->dont_invalidate
= true;
2049 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2051 /* Allow adjust_last_stmt to remove it if the stored '\0'
2052 is immediately overwritten. */
2053 laststmt
.stmt
= stmt
;
2054 laststmt
.len
= build_int_cst (size_type_node
, 1);
2055 laststmt
.stridx
= si
->idx
;
2060 /* Attempt to optimize a single statement at *GSI using string length
2064 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2066 gimple stmt
= gsi_stmt (*gsi
);
2068 if (is_gimple_call (stmt
))
2070 tree callee
= gimple_call_fndecl (stmt
);
2071 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2072 switch (DECL_FUNCTION_CODE (callee
))
2074 case BUILT_IN_STRLEN
:
2075 case BUILT_IN_STRLEN_CHKP
:
2076 handle_builtin_strlen (gsi
);
2078 case BUILT_IN_STRCHR
:
2079 case BUILT_IN_STRCHR_CHKP
:
2080 handle_builtin_strchr (gsi
);
2082 case BUILT_IN_STRCPY
:
2083 case BUILT_IN_STRCPY_CHK
:
2084 case BUILT_IN_STPCPY
:
2085 case BUILT_IN_STPCPY_CHK
:
2086 case BUILT_IN_STRCPY_CHKP
:
2087 case BUILT_IN_STRCPY_CHK_CHKP
:
2088 case BUILT_IN_STPCPY_CHKP
:
2089 case BUILT_IN_STPCPY_CHK_CHKP
:
2090 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2092 case BUILT_IN_MEMCPY
:
2093 case BUILT_IN_MEMCPY_CHK
:
2094 case BUILT_IN_MEMPCPY
:
2095 case BUILT_IN_MEMPCPY_CHK
:
2096 case BUILT_IN_MEMCPY_CHKP
:
2097 case BUILT_IN_MEMCPY_CHK_CHKP
:
2098 case BUILT_IN_MEMPCPY_CHKP
:
2099 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2100 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2102 case BUILT_IN_STRCAT
:
2103 case BUILT_IN_STRCAT_CHK
:
2104 case BUILT_IN_STRCAT_CHKP
:
2105 case BUILT_IN_STRCAT_CHK_CHKP
:
2106 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2108 case BUILT_IN_MALLOC
:
2109 case BUILT_IN_CALLOC
:
2110 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2112 case BUILT_IN_MEMSET
:
2113 if (!handle_builtin_memset (gsi
))
2120 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2122 tree lhs
= gimple_assign_lhs (stmt
);
2124 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2126 if (gimple_assign_single_p (stmt
)
2127 || (gimple_assign_cast_p (stmt
)
2128 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2130 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2131 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2133 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2134 handle_pointer_plus (gsi
);
2136 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2138 tree type
= TREE_TYPE (lhs
);
2139 if (TREE_CODE (type
) == ARRAY_TYPE
)
2140 type
= TREE_TYPE (type
);
2141 if (TREE_CODE (type
) == INTEGER_TYPE
2142 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2143 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2145 if (! handle_char_store (gsi
))
2151 if (gimple_vdef (stmt
))
2152 maybe_invalidate (stmt
);
2156 /* Recursively call maybe_invalidate on stmts that might be executed
2157 in between dombb and current bb and that contain a vdef. Stop when
2158 *count stmts are inspected, or if the whole strinfo vector has
2159 been invalidated. */
2162 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
2164 unsigned int i
, n
= gimple_phi_num_args (phi
);
2166 for (i
= 0; i
< n
; i
++)
2168 tree vuse
= gimple_phi_arg_def (phi
, i
);
2169 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
2170 basic_block bb
= gimple_bb (stmt
);
2173 || !bitmap_set_bit (visited
, bb
->index
)
2174 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2178 if (gimple_code (stmt
) == GIMPLE_PHI
)
2180 do_invalidate (dombb
, stmt
, visited
, count
);
2187 if (!maybe_invalidate (stmt
))
2192 vuse
= gimple_vuse (stmt
);
2193 stmt
= SSA_NAME_DEF_STMT (vuse
);
2194 if (gimple_bb (stmt
) != bb
)
2196 bb
= gimple_bb (stmt
);
2199 || !bitmap_set_bit (visited
, bb
->index
)
2200 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2207 class strlen_dom_walker
: public dom_walker
2210 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2212 virtual void before_dom_children (basic_block
);
2213 virtual void after_dom_children (basic_block
);
2216 /* Callback for walk_dominator_tree. Attempt to optimize various
2217 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2220 strlen_dom_walker::before_dom_children (basic_block bb
)
2222 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2225 stridx_to_strinfo
= NULL
;
2228 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
2229 if (stridx_to_strinfo
)
2231 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2234 gphi
*phi
= gsi
.phi ();
2235 if (virtual_operand_p (gimple_phi_result (phi
)))
2237 bitmap visited
= BITMAP_ALLOC (NULL
);
2238 int count_vdef
= 100;
2239 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2240 BITMAP_FREE (visited
);
2241 if (count_vdef
== 0)
2243 /* If there were too many vdefs in between immediate
2244 dominator and current bb, invalidate everything.
2245 If stridx_to_strinfo has been unshared, we need
2246 to free it, otherwise just set it to NULL. */
2247 if (!strinfo_shared ())
2253 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2257 (*stridx_to_strinfo
)[i
] = NULL
;
2261 stridx_to_strinfo
= NULL
;
2269 /* If all PHI arguments have the same string index, the PHI result
2271 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2274 gphi
*phi
= gsi
.phi ();
2275 tree result
= gimple_phi_result (phi
);
2276 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2278 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2281 unsigned int i
, n
= gimple_phi_num_args (phi
);
2282 for (i
= 1; i
< n
; i
++)
2283 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2286 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2291 /* Attempt to optimize individual statements. */
2292 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2293 if (strlen_optimize_stmt (&gsi
))
2296 bb
->aux
= stridx_to_strinfo
;
2297 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2298 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2301 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2302 owned by the current bb, clear bb->aux. */
2305 strlen_dom_walker::after_dom_children (basic_block bb
)
2309 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2310 if (vec_safe_length (stridx_to_strinfo
)
2311 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2316 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2318 vec_free (stridx_to_strinfo
);
2324 /* Main entry point. */
2328 const pass_data pass_data_strlen
=
2330 GIMPLE_PASS
, /* type */
2331 "strlen", /* name */
2332 OPTGROUP_NONE
, /* optinfo_flags */
2333 TV_TREE_STRLEN
, /* tv_id */
2334 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2335 0, /* properties_provided */
2336 0, /* properties_destroyed */
2337 0, /* todo_flags_start */
2338 0, /* todo_flags_finish */
2341 class pass_strlen
: public gimple_opt_pass
2344 pass_strlen (gcc::context
*ctxt
)
2345 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2348 /* opt_pass methods: */
2349 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2350 virtual unsigned int execute (function
*);
2352 }; // class pass_strlen
2355 pass_strlen::execute (function
*fun
)
2357 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2360 calculate_dominance_info (CDI_DOMINATORS
);
2362 /* String length optimization is implemented as a walk of the dominator
2363 tree and a forward walk of statements within each block. */
2364 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2366 ssa_ver_to_stridx
.release ();
2367 strinfo_pool
.release ();
2368 if (decl_to_stridxlist_htab
)
2370 obstack_free (&stridx_obstack
, NULL
);
2371 delete decl_to_stridxlist_htab
;
2372 decl_to_stridxlist_htab
= NULL
;
2374 laststmt
.stmt
= NULL
;
2375 laststmt
.len
= NULL_TREE
;
2376 laststmt
.stridx
= 0;
2384 make_pass_strlen (gcc::context
*ctxt
)
2386 return new pass_strlen (ctxt
);