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 pool_allocator
<strinfo_struct
> strinfo_pool ("strinfo_struct pool", 64);
118 /* Vector mapping positive string indexes to strinfo, for the
119 current basic block. The first pointer in the vector is special,
120 it is either NULL, meaning the vector isn't shared, or it is
121 a basic block pointer to the owner basic_block if shared.
122 If some other bb wants to modify the vector, the vector needs
123 to be unshared first, and only the owner bb is supposed to free it. */
124 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
126 /* One OFFSET->IDX mapping. */
129 struct stridxlist
*next
;
130 HOST_WIDE_INT offset
;
134 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
135 struct decl_stridxlist_map
137 struct tree_map_base base
;
138 struct stridxlist list
;
141 /* Hash table for mapping decls to a chained list of offset -> idx
143 static hash_map
<tree_decl_hash
, stridxlist
> *decl_to_stridxlist_htab
;
145 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
146 static struct obstack stridx_obstack
;
148 /* Last memcpy statement if it could be adjusted if the trailing
149 '\0' written is immediately overwritten, or
150 *x = '\0' store that could be removed if it is immediately overwritten. */
151 struct laststmt_struct
158 static int get_stridx_plus_constant (strinfo
, HOST_WIDE_INT
, tree
);
160 /* Return strinfo vector entry IDX. */
162 static inline strinfo
163 get_strinfo (int idx
)
165 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
167 return (*stridx_to_strinfo
)[idx
];
170 /* Helper function for get_stridx. */
173 get_addr_stridx (tree exp
)
176 struct stridxlist
*list
;
179 if (!decl_to_stridxlist_htab
)
182 base
= get_addr_base_and_unit_offset (exp
, &off
);
183 if (base
== NULL
|| !DECL_P (base
))
186 list
= decl_to_stridxlist_htab
->get (base
);
192 if (list
->offset
== off
)
200 /* Return string index for EXP. */
203 get_stridx (tree exp
)
207 if (TREE_CODE (exp
) == SSA_NAME
)
209 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
210 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
213 HOST_WIDE_INT off
= 0;
214 for (i
= 0; i
< 5; i
++)
216 gimple def_stmt
= SSA_NAME_DEF_STMT (e
);
217 if (!is_gimple_assign (def_stmt
)
218 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
220 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
221 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
222 if (TREE_CODE (rhs1
) != SSA_NAME
223 || !tree_fits_shwi_p (rhs2
))
225 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
228 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
231 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
234 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
237 && TREE_CODE (si
->length
) == INTEGER_CST
238 && compare_tree_int (si
->length
, off
) != -1)
239 return get_stridx_plus_constant (si
, off
, exp
);
246 if (TREE_CODE (exp
) == ADDR_EXPR
)
248 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
253 s
= string_constant (exp
, &o
);
255 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
256 && TREE_STRING_LENGTH (s
) > 0)
258 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
259 const char *p
= TREE_STRING_POINTER (s
);
260 int max
= TREE_STRING_LENGTH (s
) - 1;
262 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
263 return ~(int) strlen (p
+ offset
);
268 /* Return true if strinfo vector is shared with the immediate dominator. */
271 strinfo_shared (void)
273 return vec_safe_length (stridx_to_strinfo
)
274 && (*stridx_to_strinfo
)[0] != NULL
;
277 /* Unshare strinfo vector that is shared with the immediate dominator. */
280 unshare_strinfo_vec (void)
285 gcc_assert (strinfo_shared ());
286 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
287 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
290 (*stridx_to_strinfo
)[0] = NULL
;
293 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
294 Return a pointer to the location where the string index can
295 be stored (if 0) or is stored, or NULL if this can't be tracked. */
298 addr_stridxptr (tree exp
)
302 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
303 if (base
== NULL_TREE
|| !DECL_P (base
))
306 if (!decl_to_stridxlist_htab
)
308 decl_to_stridxlist_htab
309 = new hash_map
<tree_decl_hash
, stridxlist
> (64);
310 gcc_obstack_init (&stridx_obstack
);
314 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
318 for (i
= 0; i
< 16; i
++)
320 if (list
->offset
== off
)
322 if (list
->next
== NULL
)
327 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
337 /* Create a new string index, or return 0 if reached limit. */
340 new_stridx (tree exp
)
343 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
345 if (TREE_CODE (exp
) == SSA_NAME
)
347 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
350 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
353 if (TREE_CODE (exp
) == ADDR_EXPR
)
355 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
358 gcc_assert (*pidx
== 0);
359 *pidx
= max_stridx
++;
366 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
369 new_addr_stridx (tree exp
)
372 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
374 pidx
= addr_stridxptr (exp
);
377 gcc_assert (*pidx
== 0);
378 *pidx
= max_stridx
++;
384 /* Create a new strinfo. */
387 new_strinfo (tree ptr
, int idx
, tree length
)
389 strinfo si
= strinfo_pool
.allocate ();
393 si
->endptr
= NULL_TREE
;
399 si
->writable
= false;
400 si
->dont_invalidate
= false;
404 /* Decrease strinfo refcount and free it if not referenced anymore. */
407 free_strinfo (strinfo si
)
409 if (si
&& --si
->refcount
== 0)
410 strinfo_pool
.remove (si
);
413 /* Set strinfo in the vector entry IDX to SI. */
416 set_strinfo (int idx
, strinfo si
)
418 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
419 unshare_strinfo_vec ();
420 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
421 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
422 (*stridx_to_strinfo
)[idx
] = si
;
425 /* Return string length, or NULL if it can't be computed. */
428 get_string_length (strinfo si
)
435 gimple stmt
= si
->stmt
, lenstmt
;
436 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
437 tree callee
, lhs
, fn
, tem
;
439 gimple_stmt_iterator gsi
;
441 gcc_assert (is_gimple_call (stmt
));
442 callee
= gimple_call_fndecl (stmt
);
443 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
444 lhs
= gimple_call_lhs (stmt
);
445 /* unshare_strinfo is intentionally not called here. The (delayed)
446 transformation of strcpy or strcat into stpcpy is done at the place
447 of the former strcpy/strcat call and so can affect all the strinfos
448 with the same stmt. If they were unshared before and transformation
449 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
450 just compute the right length. */
451 switch (DECL_FUNCTION_CODE (callee
))
453 case BUILT_IN_STRCAT
:
454 case BUILT_IN_STRCAT_CHK
:
455 case BUILT_IN_STRCAT_CHKP
:
456 case BUILT_IN_STRCAT_CHK_CHKP
:
457 gsi
= gsi_for_stmt (stmt
);
458 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
459 gcc_assert (lhs
== NULL_TREE
);
460 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
463 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
464 2, tem
, gimple_call_arg (stmt
, 1));
465 gimple_call_set_with_bounds (lenstmt
, true);
468 lenstmt
= gimple_build_call (fn
, 1, tem
);
469 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
470 gimple_call_set_lhs (lenstmt
, lhs
);
471 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
472 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
473 tem
= gimple_call_arg (stmt
, 0);
474 if (!ptrofftype_p (TREE_TYPE (lhs
)))
476 lhs
= convert_to_ptrofftype (lhs
);
477 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
478 true, GSI_SAME_STMT
);
480 lenstmt
= gimple_build_assign
481 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
482 POINTER_PLUS_EXPR
,tem
, lhs
);
483 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
484 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
487 case BUILT_IN_STRCPY
:
488 case BUILT_IN_STRCPY_CHK
:
489 case BUILT_IN_STRCPY_CHKP
:
490 case BUILT_IN_STRCPY_CHK_CHKP
:
491 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
492 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
493 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
495 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
497 fn
= chkp_maybe_create_clone (fn
)->decl
;
498 gcc_assert (lhs
== NULL_TREE
);
499 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
501 fprintf (dump_file
, "Optimizing: ");
502 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
504 gimple_call_set_fndecl (stmt
, fn
);
505 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
506 gimple_call_set_lhs (stmt
, lhs
);
508 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
510 fprintf (dump_file
, "into: ");
511 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
514 case BUILT_IN_STPCPY
:
515 case BUILT_IN_STPCPY_CHK
:
516 case BUILT_IN_STPCPY_CHKP
:
517 case BUILT_IN_STPCPY_CHK_CHKP
:
518 gcc_assert (lhs
!= NULL_TREE
);
519 loc
= gimple_location (stmt
);
522 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
523 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
524 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
527 case BUILT_IN_MALLOC
:
529 /* BUILT_IN_CALLOC always has si->length set. */
539 /* Invalidate string length information for strings whose length
540 might change due to stores in stmt. */
543 maybe_invalidate (gimple stmt
)
547 bool nonempty
= false;
549 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
552 if (!si
->dont_invalidate
)
555 /* Do not use si->length. */
556 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
557 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
559 set_strinfo (i
, NULL
);
564 si
->dont_invalidate
= false;
570 /* Unshare strinfo record SI, if it has refcount > 1 or
571 if stridx_to_strinfo vector is shared with some other
575 unshare_strinfo (strinfo si
)
579 if (si
->refcount
== 1 && !strinfo_shared ())
582 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
583 nsi
->stmt
= si
->stmt
;
584 nsi
->endptr
= si
->endptr
;
585 nsi
->first
= si
->first
;
586 nsi
->prev
= si
->prev
;
587 nsi
->next
= si
->next
;
588 nsi
->writable
= si
->writable
;
589 set_strinfo (si
->idx
, nsi
);
594 /* Return first strinfo in the related strinfo chain
595 if all strinfos in between belong to the chain, otherwise
599 verify_related_strinfos (strinfo origsi
)
601 strinfo si
= origsi
, psi
;
603 if (origsi
->first
== 0)
605 for (; si
->prev
; si
= psi
)
607 if (si
->first
!= origsi
->first
)
609 psi
= get_strinfo (si
->prev
);
612 if (psi
->next
!= si
->idx
)
615 if (si
->idx
!= si
->first
)
620 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
621 strinfo if there is any. Return it's idx, or 0 if no strinfo has
625 get_stridx_plus_constant (strinfo basesi
, HOST_WIDE_INT off
, tree ptr
)
627 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
629 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
632 if (basesi
->length
== NULL_TREE
633 || TREE_CODE (basesi
->length
) != INTEGER_CST
634 || compare_tree_int (basesi
->length
, off
) == -1
635 || !tree_fits_shwi_p (basesi
->length
))
638 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
639 strinfo si
= basesi
, chainsi
;
640 if (si
->first
|| si
->prev
|| si
->next
)
641 si
= verify_related_strinfos (basesi
);
643 || si
->length
== NULL_TREE
644 || TREE_CODE (si
->length
) != INTEGER_CST
)
647 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
648 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
650 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
651 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
653 si
= get_strinfo (chainsi
->next
);
655 || si
->first
!= chainsi
->first
656 || si
->prev
!= chainsi
->idx
657 || si
->length
== NULL_TREE
658 || TREE_CODE (si
->length
) != INTEGER_CST
)
660 int r
= compare_tree_int (si
->length
, len
);
665 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
672 int idx
= new_stridx (ptr
);
675 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
676 set_strinfo (idx
, si
);
679 strinfo nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
680 si
->next
= nextsi
->idx
;
683 chainsi
= unshare_strinfo (chainsi
);
684 if (chainsi
->first
== 0)
685 chainsi
->first
= chainsi
->idx
;
687 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
688 chainsi
->endptr
= ptr
;
689 si
->endptr
= chainsi
->endptr
;
690 si
->prev
= chainsi
->idx
;
691 si
->first
= chainsi
->first
;
692 si
->writable
= chainsi
->writable
;
696 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
697 to a zero-length string and if possible chain it to a related strinfo
698 chain whose part is or might be CHAINSI. */
701 zero_length_string (tree ptr
, strinfo chainsi
)
705 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
706 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
707 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
708 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
710 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
714 si
= verify_related_strinfos (chainsi
);
718 for (; chainsi
->next
; chainsi
= si
)
720 if (chainsi
->endptr
== NULL_TREE
)
722 chainsi
= unshare_strinfo (chainsi
);
723 chainsi
->endptr
= ptr
;
725 si
= get_strinfo (chainsi
->next
);
727 || si
->first
!= chainsi
->first
728 || si
->prev
!= chainsi
->idx
)
731 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
732 if (chainsi
->endptr
== NULL_TREE
)
734 chainsi
= unshare_strinfo (chainsi
);
735 chainsi
->endptr
= ptr
;
737 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
741 chainsi
= unshare_strinfo (chainsi
);
744 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
748 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
750 chainsi
= unshare_strinfo (chainsi
);
756 idx
= new_stridx (ptr
);
759 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
760 set_strinfo (idx
, si
);
764 chainsi
= unshare_strinfo (chainsi
);
765 if (chainsi
->first
== 0)
766 chainsi
->first
= chainsi
->idx
;
768 if (chainsi
->endptr
== NULL_TREE
)
769 chainsi
->endptr
= ptr
;
770 si
->prev
= chainsi
->idx
;
771 si
->first
= chainsi
->first
;
772 si
->writable
= chainsi
->writable
;
777 /* For strinfo ORIGSI whose length has been just updated
778 update also related strinfo lengths (add ADJ to each,
779 but don't adjust ORIGSI). */
782 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
784 strinfo si
= verify_related_strinfos (origsi
);
797 si
= unshare_strinfo (si
);
800 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
801 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
802 TREE_TYPE (si
->length
), si
->length
,
805 else if (si
->stmt
!= NULL
)
806 /* Delayed length computation is unaffected. */
811 si
->endptr
= NULL_TREE
;
812 si
->dont_invalidate
= true;
816 nsi
= get_strinfo (si
->next
);
818 || nsi
->first
!= si
->first
819 || nsi
->prev
!= si
->idx
)
825 /* Find if there are other SSA_NAME pointers equal to PTR
826 for which we don't track their string lengths yet. If so, use
830 find_equal_ptrs (tree ptr
, int idx
)
832 if (TREE_CODE (ptr
) != SSA_NAME
)
836 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
837 if (!is_gimple_assign (stmt
))
839 ptr
= gimple_assign_rhs1 (stmt
);
840 switch (gimple_assign_rhs_code (stmt
))
845 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
847 if (TREE_CODE (ptr
) == SSA_NAME
)
849 if (TREE_CODE (ptr
) != ADDR_EXPR
)
854 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
855 if (pidx
!= NULL
&& *pidx
== 0)
863 /* We might find an endptr created in this pass. Grow the
864 vector in that case. */
865 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
866 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
868 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
870 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
874 /* If the last .MEM setter statement before STMT is
875 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
876 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
877 just memcpy (x, y, strlen (y)). SI must be the zero length
881 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
883 tree vuse
, callee
, len
;
884 struct laststmt_struct last
= laststmt
;
885 strinfo lastsi
, firstsi
;
886 unsigned len_arg_no
= 2;
888 laststmt
.stmt
= NULL
;
889 laststmt
.len
= NULL_TREE
;
892 if (last
.stmt
== NULL
)
895 vuse
= gimple_vuse (stmt
);
896 if (vuse
== NULL_TREE
897 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
898 || !has_single_use (vuse
))
901 gcc_assert (last
.stridx
> 0);
902 lastsi
= get_strinfo (last
.stridx
);
908 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
911 firstsi
= verify_related_strinfos (si
);
914 while (firstsi
!= lastsi
)
917 if (firstsi
->next
== 0)
919 nextsi
= get_strinfo (firstsi
->next
);
921 || nextsi
->prev
!= firstsi
->idx
922 || nextsi
->first
!= si
->first
)
930 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
934 if (is_gimple_assign (last
.stmt
))
936 gimple_stmt_iterator gsi
;
938 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
940 if (stmt_could_throw_p (last
.stmt
))
942 gsi
= gsi_for_stmt (last
.stmt
);
943 unlink_stmt_vdef (last
.stmt
);
944 release_defs (last
.stmt
);
945 gsi_remove (&gsi
, true);
949 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
952 callee
= gimple_call_fndecl (last
.stmt
);
953 switch (DECL_FUNCTION_CODE (callee
))
955 case BUILT_IN_MEMCPY
:
956 case BUILT_IN_MEMCPY_CHK
:
958 case BUILT_IN_MEMCPY_CHKP
:
959 case BUILT_IN_MEMCPY_CHK_CHKP
:
966 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
967 if (tree_fits_uhwi_p (len
))
969 if (!tree_fits_uhwi_p (last
.len
)
970 || integer_zerop (len
)
971 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
973 /* Don't adjust the length if it is divisible by 4, it is more efficient
974 to store the extra '\0' in that case. */
975 if ((tree_to_uhwi (len
) & 3) == 0)
978 else if (TREE_CODE (len
) == SSA_NAME
)
980 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
981 if (!is_gimple_assign (def_stmt
)
982 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
983 || gimple_assign_rhs1 (def_stmt
) != last
.len
984 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
990 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
991 update_stmt (last
.stmt
);
994 /* Handle a strlen call. If strlen of the argument is known, replace
995 the strlen call with the known value, otherwise remember that strlen
996 of the argument is stored in the lhs SSA_NAME. */
999 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1003 gimple stmt
= gsi_stmt (*gsi
);
1004 tree lhs
= gimple_call_lhs (stmt
);
1006 if (lhs
== NULL_TREE
)
1009 src
= gimple_call_arg (stmt
, 0);
1010 idx
= get_stridx (src
);
1017 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1021 si
= get_strinfo (idx
);
1023 rhs
= get_string_length (si
);
1025 if (rhs
!= NULL_TREE
)
1027 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1029 fprintf (dump_file
, "Optimizing: ");
1030 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1032 rhs
= unshare_expr (rhs
);
1033 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1034 rhs
= fold_convert_loc (gimple_location (stmt
),
1035 TREE_TYPE (lhs
), rhs
);
1036 if (!update_call_from_tree (gsi
, rhs
))
1037 gimplify_and_update_call_from_tree (gsi
, rhs
);
1038 stmt
= gsi_stmt (*gsi
);
1040 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1042 fprintf (dump_file
, "into: ");
1043 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1046 && TREE_CODE (si
->length
) != SSA_NAME
1047 && TREE_CODE (si
->length
) != INTEGER_CST
1048 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1050 si
= unshare_strinfo (si
);
1056 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1059 idx
= new_stridx (src
);
1060 else if (get_strinfo (idx
) != NULL
)
1064 strinfo si
= new_strinfo (src
, idx
, lhs
);
1065 set_strinfo (idx
, si
);
1066 find_equal_ptrs (src
, idx
);
1070 /* Handle a strchr call. If strlen of the first argument is known, replace
1071 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1072 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1075 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1079 gimple stmt
= gsi_stmt (*gsi
);
1080 tree lhs
= gimple_call_lhs (stmt
);
1081 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1083 if (lhs
== NULL_TREE
)
1086 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1089 src
= gimple_call_arg (stmt
, 0);
1090 idx
= get_stridx (src
);
1097 rhs
= build_int_cst (size_type_node
, ~idx
);
1101 si
= get_strinfo (idx
);
1103 rhs
= get_string_length (si
);
1105 if (rhs
!= NULL_TREE
)
1107 location_t loc
= gimple_location (stmt
);
1109 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1111 fprintf (dump_file
, "Optimizing: ");
1112 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1114 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1116 rhs
= unshare_expr (si
->endptr
);
1117 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1119 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1123 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1124 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1125 TREE_TYPE (src
), src
, rhs
);
1126 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1128 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1130 if (!update_call_from_tree (gsi
, rhs
))
1131 gimplify_and_update_call_from_tree (gsi
, rhs
);
1132 stmt
= gsi_stmt (*gsi
);
1134 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1136 fprintf (dump_file
, "into: ");
1137 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1140 && si
->endptr
== NULL_TREE
1141 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1143 si
= unshare_strinfo (si
);
1146 zero_length_string (lhs
, si
);
1150 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1152 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1155 idx
= new_stridx (src
);
1156 else if (get_strinfo (idx
) != NULL
)
1158 zero_length_string (lhs
, NULL
);
1163 location_t loc
= gimple_location (stmt
);
1164 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1165 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1166 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1167 size_type_node
, lhsu
, srcu
);
1168 strinfo si
= new_strinfo (src
, idx
, length
);
1170 set_strinfo (idx
, si
);
1171 find_equal_ptrs (src
, idx
);
1172 zero_length_string (lhs
, si
);
1176 zero_length_string (lhs
, NULL
);
1179 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1180 If strlen of the second argument is known, strlen of the first argument
1181 is the same after this call. Furthermore, attempt to convert it to
1185 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1188 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1190 gimple stmt
= gsi_stmt (*gsi
);
1191 strinfo si
, dsi
, olddsi
, zsi
;
1193 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1195 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1196 dst
= gimple_call_arg (stmt
, 0);
1197 lhs
= gimple_call_lhs (stmt
);
1198 idx
= get_stridx (src
);
1201 si
= get_strinfo (idx
);
1203 didx
= get_stridx (dst
);
1207 olddsi
= get_strinfo (didx
);
1212 adjust_last_stmt (olddsi
, stmt
, false);
1216 srclen
= get_string_length (si
);
1218 srclen
= build_int_cst (size_type_node
, ~idx
);
1220 loc
= gimple_location (stmt
);
1221 if (srclen
== NULL_TREE
)
1224 case BUILT_IN_STRCPY
:
1225 case BUILT_IN_STRCPY_CHK
:
1226 case BUILT_IN_STRCPY_CHKP
:
1227 case BUILT_IN_STRCPY_CHK_CHKP
:
1228 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1231 case BUILT_IN_STPCPY
:
1232 case BUILT_IN_STPCPY_CHK
:
1233 case BUILT_IN_STPCPY_CHKP
:
1234 case BUILT_IN_STPCPY_CHK_CHKP
:
1235 if (lhs
== NULL_TREE
)
1239 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1240 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1241 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1251 didx
= new_stridx (dst
);
1257 oldlen
= olddsi
->length
;
1258 dsi
= unshare_strinfo (olddsi
);
1259 dsi
->length
= srclen
;
1260 /* Break the chain, so adjust_related_strinfo on later pointers in
1261 the chain won't adjust this one anymore. */
1264 dsi
->endptr
= NULL_TREE
;
1268 dsi
= new_strinfo (dst
, didx
, srclen
);
1269 set_strinfo (didx
, dsi
);
1270 find_equal_ptrs (dst
, didx
);
1272 dsi
->writable
= true;
1273 dsi
->dont_invalidate
= true;
1275 if (dsi
->length
== NULL_TREE
)
1279 /* If string length of src is unknown, use delayed length
1280 computation. If string lenth of dst will be needed, it
1281 can be computed by transforming this strcpy call into
1282 stpcpy and subtracting dst from the return value. */
1284 /* Look for earlier strings whose length could be determined if
1285 this strcpy is turned into an stpcpy. */
1287 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1289 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1291 /* When setting a stmt for delayed length computation
1292 prevent all strinfos through dsi from being
1294 chainsi
= unshare_strinfo (chainsi
);
1295 chainsi
->stmt
= stmt
;
1296 chainsi
->length
= NULL_TREE
;
1297 chainsi
->endptr
= NULL_TREE
;
1298 chainsi
->dont_invalidate
= true;
1307 tree adj
= NULL_TREE
;
1308 if (oldlen
== NULL_TREE
)
1310 else if (integer_zerop (oldlen
))
1312 else if (TREE_CODE (oldlen
) == INTEGER_CST
1313 || TREE_CODE (srclen
) == INTEGER_CST
)
1314 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1315 TREE_TYPE (srclen
), srclen
,
1316 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1318 if (adj
!= NULL_TREE
)
1319 adjust_related_strinfos (loc
, dsi
, adj
);
1323 /* strcpy src may not overlap dst, so src doesn't need to be
1324 invalidated either. */
1326 si
->dont_invalidate
= true;
1332 case BUILT_IN_STRCPY
:
1333 case BUILT_IN_STRCPY_CHKP
:
1334 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1336 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1338 case BUILT_IN_STRCPY_CHK
:
1339 case BUILT_IN_STRCPY_CHK_CHKP
:
1340 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1342 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1344 case BUILT_IN_STPCPY
:
1345 case BUILT_IN_STPCPY_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); */
1353 zsi
= zero_length_string (lhs
, dsi
);
1356 case BUILT_IN_STPCPY_CHK
:
1357 case BUILT_IN_STPCPY_CHK_CHKP
:
1358 /* This would need adjustment of the lhs (subtract one),
1359 or detection that the trailing '\0' doesn't need to be
1360 written, if it will be immediately overwritten.
1361 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1365 zsi
= zero_length_string (lhs
, dsi
);
1372 zsi
->dont_invalidate
= true;
1374 if (fn
== NULL_TREE
)
1377 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1378 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1380 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1381 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1382 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1384 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1386 fprintf (dump_file
, "Optimizing: ");
1387 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1391 fn
= chkp_maybe_create_clone (fn
)->decl
;
1392 if (gimple_call_num_args (stmt
) == 4)
1393 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1394 gimple_call_arg (stmt
, 1),
1396 gimple_call_arg (stmt
, 3),
1399 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1400 gimple_call_arg (stmt
, 1),
1402 gimple_call_arg (stmt
, 3),
1404 gimple_call_arg (stmt
, 4));
1407 if (gimple_call_num_args (stmt
) == 2)
1408 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1410 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1411 gimple_call_arg (stmt
, 2));
1414 stmt
= gsi_stmt (*gsi
);
1415 gimple_call_set_with_bounds (stmt
, with_bounds
);
1417 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1419 fprintf (dump_file
, "into: ");
1420 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1422 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1423 laststmt
.stmt
= stmt
;
1424 laststmt
.len
= srclen
;
1425 laststmt
.stridx
= dsi
->idx
;
1427 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1428 fprintf (dump_file
, "not possible.\n");
1431 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1432 If strlen of the second argument is known and length of the third argument
1433 is that plus one, strlen of the first argument is the same after this
1437 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1440 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1441 gimple stmt
= gsi_stmt (*gsi
);
1442 strinfo si
, dsi
, olddsi
;
1443 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1445 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1446 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1447 dst
= gimple_call_arg (stmt
, 0);
1448 idx
= get_stridx (src
);
1452 didx
= get_stridx (dst
);
1455 olddsi
= get_strinfo (didx
);
1460 && tree_fits_uhwi_p (len
)
1461 && !integer_zerop (len
))
1462 adjust_last_stmt (olddsi
, stmt
, false);
1468 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1469 si
= get_strinfo (idx
);
1470 if (si
== NULL
|| si
->length
== NULL_TREE
)
1472 if (TREE_CODE (len
) != SSA_NAME
)
1474 def_stmt
= SSA_NAME_DEF_STMT (len
);
1475 if (!is_gimple_assign (def_stmt
)
1476 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1477 || gimple_assign_rhs1 (def_stmt
) != si
->length
1478 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1484 /* Handle memcpy (x, "abcd", 5) or
1485 memcpy (x, "abc\0uvw", 7). */
1486 if (!tree_fits_uhwi_p (len
)
1487 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1491 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1492 adjust_last_stmt (olddsi
, stmt
, false);
1496 didx
= new_stridx (dst
);
1501 newlen
= si
->length
;
1503 newlen
= build_int_cst (size_type_node
, ~idx
);
1507 dsi
= unshare_strinfo (olddsi
);
1508 oldlen
= olddsi
->length
;
1509 dsi
->length
= newlen
;
1510 /* Break the chain, so adjust_related_strinfo on later pointers in
1511 the chain won't adjust this one anymore. */
1514 dsi
->endptr
= NULL_TREE
;
1518 dsi
= new_strinfo (dst
, didx
, newlen
);
1519 set_strinfo (didx
, dsi
);
1520 find_equal_ptrs (dst
, didx
);
1522 dsi
->writable
= true;
1523 dsi
->dont_invalidate
= true;
1526 tree adj
= NULL_TREE
;
1527 location_t loc
= gimple_location (stmt
);
1528 if (oldlen
== NULL_TREE
)
1530 else if (integer_zerop (oldlen
))
1532 else if (TREE_CODE (oldlen
) == INTEGER_CST
1533 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1534 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1535 TREE_TYPE (dsi
->length
), dsi
->length
,
1536 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1538 if (adj
!= NULL_TREE
)
1539 adjust_related_strinfos (loc
, dsi
, adj
);
1543 /* memcpy src may not overlap dst, so src doesn't need to be
1544 invalidated either. */
1546 si
->dont_invalidate
= true;
1548 lhs
= gimple_call_lhs (stmt
);
1551 case BUILT_IN_MEMCPY
:
1552 case BUILT_IN_MEMCPY_CHK
:
1553 case BUILT_IN_MEMCPY_CHKP
:
1554 case BUILT_IN_MEMCPY_CHK_CHKP
:
1555 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1556 laststmt
.stmt
= stmt
;
1557 laststmt
.len
= dsi
->length
;
1558 laststmt
.stridx
= dsi
->idx
;
1560 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1562 case BUILT_IN_MEMPCPY
:
1563 case BUILT_IN_MEMPCPY_CHK
:
1564 case BUILT_IN_MEMPCPY_CHKP
:
1565 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1572 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1573 If strlen of the second argument is known, strlen of the first argument
1574 is increased by the length of the second argument. Furthermore, attempt
1575 to convert it to memcpy/strcpy if the length of the first argument
1579 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1582 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1584 gimple stmt
= gsi_stmt (*gsi
);
1587 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1589 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1590 dst
= gimple_call_arg (stmt
, 0);
1591 lhs
= gimple_call_lhs (stmt
);
1593 didx
= get_stridx (dst
);
1599 dsi
= get_strinfo (didx
);
1600 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1602 /* strcat (p, q) can be transformed into
1603 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1604 with length endptr - p if we need to compute the length
1605 later on. Don't do this transformation if we don't need
1607 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1611 didx
= new_stridx (dst
);
1617 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1618 set_strinfo (didx
, dsi
);
1619 find_equal_ptrs (dst
, didx
);
1623 dsi
= unshare_strinfo (dsi
);
1624 dsi
->length
= NULL_TREE
;
1626 dsi
->endptr
= NULL_TREE
;
1628 dsi
->writable
= true;
1630 dsi
->dont_invalidate
= true;
1637 idx
= get_stridx (src
);
1639 srclen
= build_int_cst (size_type_node
, ~idx
);
1642 si
= get_strinfo (idx
);
1644 srclen
= get_string_length (si
);
1647 loc
= gimple_location (stmt
);
1648 dstlen
= dsi
->length
;
1649 endptr
= dsi
->endptr
;
1651 dsi
= unshare_strinfo (dsi
);
1652 dsi
->endptr
= NULL_TREE
;
1654 dsi
->writable
= true;
1656 if (srclen
!= NULL_TREE
)
1658 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1659 dsi
->length
, srclen
);
1660 adjust_related_strinfos (loc
, dsi
, srclen
);
1661 dsi
->dont_invalidate
= true;
1666 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1667 dsi
->dont_invalidate
= true;
1671 /* strcat src may not overlap dst, so src doesn't need to be
1672 invalidated either. */
1673 si
->dont_invalidate
= true;
1675 /* For now. Could remove the lhs from the call and add
1676 lhs = dst; afterwards. */
1684 case BUILT_IN_STRCAT
:
1685 case BUILT_IN_STRCAT_CHKP
:
1686 if (srclen
!= NULL_TREE
)
1687 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1689 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1691 case BUILT_IN_STRCAT_CHK
:
1692 case BUILT_IN_STRCAT_CHK_CHKP
:
1693 if (srclen
!= NULL_TREE
)
1694 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1696 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1697 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1703 if (fn
== NULL_TREE
)
1707 if (srclen
!= NULL_TREE
)
1709 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1710 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1712 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1713 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1714 build_int_cst (type
, 1));
1715 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1719 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1721 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1722 TREE_TYPE (dst
), unshare_expr (dst
),
1723 fold_convert_loc (loc
, sizetype
,
1724 unshare_expr (dstlen
)));
1725 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1727 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1729 fprintf (dump_file
, "Optimizing: ");
1730 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1734 fn
= chkp_maybe_create_clone (fn
)->decl
;
1735 if (srclen
!= NULL_TREE
)
1736 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1738 gimple_call_arg (stmt
, 1),
1740 gimple_call_arg (stmt
, 3),
1743 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1745 gimple_call_arg (stmt
, 1),
1747 gimple_call_arg (stmt
, 3),
1751 if (srclen
!= NULL_TREE
)
1752 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1753 dst
, src
, len
, objsz
);
1755 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1759 stmt
= gsi_stmt (*gsi
);
1760 gimple_call_set_with_bounds (stmt
, with_bounds
);
1762 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1764 fprintf (dump_file
, "into: ");
1765 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1767 /* If srclen == NULL, note that current string length can be
1768 computed by transforming this strcpy into stpcpy. */
1769 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1771 adjust_last_stmt (dsi
, stmt
, true);
1772 if (srclen
!= NULL_TREE
)
1774 laststmt
.stmt
= stmt
;
1775 laststmt
.len
= srclen
;
1776 laststmt
.stridx
= dsi
->idx
;
1779 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1780 fprintf (dump_file
, "not possible.\n");
1783 /* Handle a call to malloc or calloc. */
1786 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1788 gimple stmt
= gsi_stmt (*gsi
);
1789 tree lhs
= gimple_call_lhs (stmt
);
1790 gcc_assert (get_stridx (lhs
) == 0);
1791 int idx
= new_stridx (lhs
);
1792 tree length
= NULL_TREE
;
1793 if (bcode
== BUILT_IN_CALLOC
)
1794 length
= build_int_cst (size_type_node
, 0);
1795 strinfo si
= new_strinfo (lhs
, idx
, length
);
1796 if (bcode
== BUILT_IN_CALLOC
)
1798 set_strinfo (idx
, si
);
1799 si
->writable
= true;
1801 si
->dont_invalidate
= true;
1804 /* Handle a call to memset.
1805 After a call to calloc, memset(,0,) is unnecessary.
1806 memset(malloc(n),0,n) is calloc(n,1). */
1809 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1811 gimple stmt2
= gsi_stmt (*gsi
);
1812 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1814 tree ptr
= gimple_call_arg (stmt2
, 0);
1815 int idx1
= get_stridx (ptr
);
1818 strinfo si1
= get_strinfo (idx1
);
1821 gimple stmt1
= si1
->stmt
;
1822 if (!stmt1
|| !is_gimple_call (stmt1
))
1824 tree callee1
= gimple_call_fndecl (stmt1
);
1825 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1827 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1828 tree size
= gimple_call_arg (stmt2
, 2);
1829 if (code1
== BUILT_IN_CALLOC
)
1830 /* Not touching stmt1 */ ;
1831 else if (code1
== BUILT_IN_MALLOC
1832 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1834 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1835 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1836 size
, build_one_cst (size_type_node
));
1837 si1
->length
= build_int_cst (size_type_node
, 0);
1838 si1
->stmt
= gsi_stmt (gsi1
);
1842 tree lhs
= gimple_call_lhs (stmt2
);
1843 unlink_stmt_vdef (stmt2
);
1846 gimple assign
= gimple_build_assign (lhs
, ptr
);
1847 gsi_replace (gsi
, assign
, false);
1851 gsi_remove (gsi
, true);
1852 release_defs (stmt2
);
1858 /* Handle a POINTER_PLUS_EXPR statement.
1859 For p = "abcd" + 2; compute associated length, or if
1860 p = q + off is pointing to a '\0' character of a string, call
1861 zero_length_string on it. */
1864 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1866 gimple stmt
= gsi_stmt (*gsi
);
1867 tree lhs
= gimple_assign_lhs (stmt
), off
;
1868 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1876 tree off
= gimple_assign_rhs2 (stmt
);
1877 if (tree_fits_uhwi_p (off
)
1878 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1879 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1880 = ~(~idx
- (int) tree_to_uhwi (off
));
1884 si
= get_strinfo (idx
);
1885 if (si
== NULL
|| si
->length
== NULL_TREE
)
1888 off
= gimple_assign_rhs2 (stmt
);
1890 if (operand_equal_p (si
->length
, off
, 0))
1891 zsi
= zero_length_string (lhs
, si
);
1892 else if (TREE_CODE (off
) == SSA_NAME
)
1894 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1895 if (gimple_assign_single_p (def_stmt
)
1896 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1897 zsi
= zero_length_string (lhs
, si
);
1900 && si
->endptr
!= NULL_TREE
1901 && si
->endptr
!= lhs
1902 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1904 enum tree_code rhs_code
1905 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1906 ? SSA_NAME
: NOP_EXPR
;
1907 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1908 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1913 /* Handle a single character store. */
1916 handle_char_store (gimple_stmt_iterator
*gsi
)
1920 gimple stmt
= gsi_stmt (*gsi
);
1921 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1923 if (TREE_CODE (lhs
) == MEM_REF
1924 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1926 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1928 ssaname
= TREE_OPERAND (lhs
, 0);
1929 idx
= get_stridx (ssaname
);
1933 idx
= get_addr_stridx (lhs
);
1937 si
= get_strinfo (idx
);
1938 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1940 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1942 /* When storing '\0', the store can be removed
1943 if we know it has been stored in the current function. */
1944 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1946 unlink_stmt_vdef (stmt
);
1947 release_defs (stmt
);
1948 gsi_remove (gsi
, true);
1953 si
->writable
= true;
1959 /* Otherwise this statement overwrites the '\0' with
1960 something, if the previous stmt was a memcpy,
1961 its length may be decreased. */
1962 adjust_last_stmt (si
, stmt
, false);
1964 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1966 si
= unshare_strinfo (si
);
1967 si
->length
= build_int_cst (size_type_node
, 0);
1973 si
->writable
= true;
1974 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
1975 si
->endptr
= ssaname
;
1976 si
->dont_invalidate
= true;
1978 /* If si->length is non-zero constant, we aren't overwriting '\0',
1979 and if we aren't storing '\0', we know that the length of the
1980 string and any other zero terminated string in memory remains
1981 the same. In that case we move to the next gimple statement and
1982 return to signal the caller that it shouldn't invalidate anything.
1984 This is benefical for cases like:
1989 strcpy (p, "foobar");
1990 size_t len = strlen (p); // This can be optimized into 6
1991 size_t len2 = strlen (q); // This has to be computed
1993 size_t len3 = strlen (p); // This can be optimized into 6
1994 size_t len4 = strlen (q); // This can be optimized into len2
1995 bar (len, len2, len3, len4);
1998 else if (si
!= NULL
&& si
->length
!= NULL_TREE
1999 && TREE_CODE (si
->length
) == INTEGER_CST
2000 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2006 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2010 si
= zero_length_string (ssaname
, NULL
);
2012 si
->dont_invalidate
= true;
2016 int idx
= new_addr_stridx (lhs
);
2019 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2020 build_int_cst (size_type_node
, 0));
2021 set_strinfo (idx
, si
);
2022 si
->dont_invalidate
= true;
2026 si
->writable
= true;
2029 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2030 && ssaname
== NULL_TREE
2031 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2033 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2034 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2035 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2037 int idx
= new_addr_stridx (lhs
);
2040 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2041 build_int_cst (size_type_node
, l
));
2042 set_strinfo (idx
, si
);
2043 si
->dont_invalidate
= true;
2048 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2050 /* Allow adjust_last_stmt to remove it if the stored '\0'
2051 is immediately overwritten. */
2052 laststmt
.stmt
= stmt
;
2053 laststmt
.len
= build_int_cst (size_type_node
, 1);
2054 laststmt
.stridx
= si
->idx
;
2059 /* Attempt to optimize a single statement at *GSI using string length
2063 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2065 gimple stmt
= gsi_stmt (*gsi
);
2067 if (is_gimple_call (stmt
))
2069 tree callee
= gimple_call_fndecl (stmt
);
2070 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2071 switch (DECL_FUNCTION_CODE (callee
))
2073 case BUILT_IN_STRLEN
:
2074 case BUILT_IN_STRLEN_CHKP
:
2075 handle_builtin_strlen (gsi
);
2077 case BUILT_IN_STRCHR
:
2078 case BUILT_IN_STRCHR_CHKP
:
2079 handle_builtin_strchr (gsi
);
2081 case BUILT_IN_STRCPY
:
2082 case BUILT_IN_STRCPY_CHK
:
2083 case BUILT_IN_STPCPY
:
2084 case BUILT_IN_STPCPY_CHK
:
2085 case BUILT_IN_STRCPY_CHKP
:
2086 case BUILT_IN_STRCPY_CHK_CHKP
:
2087 case BUILT_IN_STPCPY_CHKP
:
2088 case BUILT_IN_STPCPY_CHK_CHKP
:
2089 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2091 case BUILT_IN_MEMCPY
:
2092 case BUILT_IN_MEMCPY_CHK
:
2093 case BUILT_IN_MEMPCPY
:
2094 case BUILT_IN_MEMPCPY_CHK
:
2095 case BUILT_IN_MEMCPY_CHKP
:
2096 case BUILT_IN_MEMCPY_CHK_CHKP
:
2097 case BUILT_IN_MEMPCPY_CHKP
:
2098 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2099 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2101 case BUILT_IN_STRCAT
:
2102 case BUILT_IN_STRCAT_CHK
:
2103 case BUILT_IN_STRCAT_CHKP
:
2104 case BUILT_IN_STRCAT_CHK_CHKP
:
2105 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2107 case BUILT_IN_MALLOC
:
2108 case BUILT_IN_CALLOC
:
2109 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2111 case BUILT_IN_MEMSET
:
2112 if (!handle_builtin_memset (gsi
))
2119 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2121 tree lhs
= gimple_assign_lhs (stmt
);
2123 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2125 if (gimple_assign_single_p (stmt
)
2126 || (gimple_assign_cast_p (stmt
)
2127 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2129 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2130 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2132 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2133 handle_pointer_plus (gsi
);
2135 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2137 tree type
= TREE_TYPE (lhs
);
2138 if (TREE_CODE (type
) == ARRAY_TYPE
)
2139 type
= TREE_TYPE (type
);
2140 if (TREE_CODE (type
) == INTEGER_TYPE
2141 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2142 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2144 if (! handle_char_store (gsi
))
2150 if (gimple_vdef (stmt
))
2151 maybe_invalidate (stmt
);
2155 /* Recursively call maybe_invalidate on stmts that might be executed
2156 in between dombb and current bb and that contain a vdef. Stop when
2157 *count stmts are inspected, or if the whole strinfo vector has
2158 been invalidated. */
2161 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
2163 unsigned int i
, n
= gimple_phi_num_args (phi
);
2165 for (i
= 0; i
< n
; i
++)
2167 tree vuse
= gimple_phi_arg_def (phi
, i
);
2168 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
2169 basic_block bb
= gimple_bb (stmt
);
2172 || !bitmap_set_bit (visited
, bb
->index
)
2173 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2177 if (gimple_code (stmt
) == GIMPLE_PHI
)
2179 do_invalidate (dombb
, stmt
, visited
, count
);
2186 if (!maybe_invalidate (stmt
))
2191 vuse
= gimple_vuse (stmt
);
2192 stmt
= SSA_NAME_DEF_STMT (vuse
);
2193 if (gimple_bb (stmt
) != bb
)
2195 bb
= gimple_bb (stmt
);
2198 || !bitmap_set_bit (visited
, bb
->index
)
2199 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2206 class strlen_dom_walker
: public dom_walker
2209 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2211 virtual void before_dom_children (basic_block
);
2212 virtual void after_dom_children (basic_block
);
2215 /* Callback for walk_dominator_tree. Attempt to optimize various
2216 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2219 strlen_dom_walker::before_dom_children (basic_block bb
)
2221 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2224 stridx_to_strinfo
= NULL
;
2227 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
2228 if (stridx_to_strinfo
)
2230 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2233 gphi
*phi
= gsi
.phi ();
2234 if (virtual_operand_p (gimple_phi_result (phi
)))
2236 bitmap visited
= BITMAP_ALLOC (NULL
);
2237 int count_vdef
= 100;
2238 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2239 BITMAP_FREE (visited
);
2240 if (count_vdef
== 0)
2242 /* If there were too many vdefs in between immediate
2243 dominator and current bb, invalidate everything.
2244 If stridx_to_strinfo has been unshared, we need
2245 to free it, otherwise just set it to NULL. */
2246 if (!strinfo_shared ())
2252 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2256 (*stridx_to_strinfo
)[i
] = NULL
;
2260 stridx_to_strinfo
= NULL
;
2268 /* If all PHI arguments have the same string index, the PHI result
2270 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2273 gphi
*phi
= gsi
.phi ();
2274 tree result
= gimple_phi_result (phi
);
2275 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2277 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2280 unsigned int i
, n
= gimple_phi_num_args (phi
);
2281 for (i
= 1; i
< n
; i
++)
2282 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2285 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2290 /* Attempt to optimize individual statements. */
2291 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2292 if (strlen_optimize_stmt (&gsi
))
2295 bb
->aux
= stridx_to_strinfo
;
2296 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2297 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2300 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2301 owned by the current bb, clear bb->aux. */
2304 strlen_dom_walker::after_dom_children (basic_block bb
)
2308 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2309 if (vec_safe_length (stridx_to_strinfo
)
2310 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2315 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2317 vec_free (stridx_to_strinfo
);
2323 /* Main entry point. */
2327 const pass_data pass_data_strlen
=
2329 GIMPLE_PASS
, /* type */
2330 "strlen", /* name */
2331 OPTGROUP_NONE
, /* optinfo_flags */
2332 TV_TREE_STRLEN
, /* tv_id */
2333 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2334 0, /* properties_provided */
2335 0, /* properties_destroyed */
2336 0, /* todo_flags_start */
2337 0, /* todo_flags_finish */
2340 class pass_strlen
: public gimple_opt_pass
2343 pass_strlen (gcc::context
*ctxt
)
2344 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2347 /* opt_pass methods: */
2348 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2349 virtual unsigned int execute (function
*);
2351 }; // class pass_strlen
2354 pass_strlen::execute (function
*fun
)
2356 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2359 calculate_dominance_info (CDI_DOMINATORS
);
2361 /* String length optimization is implemented as a walk of the dominator
2362 tree and a forward walk of statements within each block. */
2363 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2365 ssa_ver_to_stridx
.release ();
2366 strinfo_pool
.release ();
2367 if (decl_to_stridxlist_htab
)
2369 obstack_free (&stridx_obstack
, NULL
);
2370 delete decl_to_stridxlist_htab
;
2371 decl_to_stridxlist_htab
= NULL
;
2373 laststmt
.stmt
= NULL
;
2374 laststmt
.len
= NULL_TREE
;
2375 laststmt
.stridx
= 0;
2383 make_pass_strlen (gcc::context
*ctxt
)
2385 return new pass_strlen (ctxt
);