1 /* String length optimization
2 Copyright (C) 2011-2015 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
28 #include "fold-const.h"
29 #include "stor-layout.h"
33 #include "hard-reg-set.h"
35 #include "dominance.h"
37 #include "basic-block.h"
38 #include "tree-ssa-alias.h"
39 #include "internal-fn.h"
40 #include "gimple-fold.h"
42 #include "gimple-expr.h"
45 #include "gimple-iterator.h"
46 #include "gimplify-me.h"
47 #include "gimple-ssa.h"
48 #include "tree-phinodes.h"
49 #include "ssa-iterators.h"
50 #include "stringpool.h"
51 #include "tree-ssanames.h"
54 #include "insn-config.h"
64 #include "tree-pass.h"
66 #include "alloc-pool.h"
67 #include "tree-ssa-propagate.h"
68 #include "gimple-pretty-print.h"
70 #include "plugin-api.h"
75 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
76 is an index into strinfo vector, negative value stands for
77 string length of a string literal (~strlen). */
78 static vec
<int> ssa_ver_to_stridx
;
80 /* Number of currently active string indexes plus one. */
81 static int max_stridx
;
83 /* String information record. */
84 typedef struct strinfo_struct
86 /* String length of this string. */
88 /* Any of the corresponding pointers for querying alias oracle. */
90 /* Statement for delayed length computation. */
92 /* Pointer to '\0' if known, if NULL, it can be computed as
95 /* Reference count. Any changes to strinfo entry possibly shared
96 with dominating basic blocks need unshare_strinfo first, except
97 for dont_invalidate which affects only the immediately next
100 /* Copy of index. get_strinfo (si->idx) should return si; */
102 /* These 3 fields are for chaining related string pointers together.
104 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
105 strcpy (c, d); e = c + dl;
106 strinfo(a) -> strinfo(c) -> strinfo(e)
107 All have ->first field equal to strinfo(a)->idx and are doubly
108 chained through prev/next fields. The later strinfos are required
109 to point into the same string with zero or more bytes after
110 the previous pointer and all bytes in between the two pointers
111 must be non-zero. Functions like strcpy or memcpy are supposed
112 to adjust all previous strinfo lengths, but not following strinfo
113 lengths (those are uncertain, usually invalidated during
114 maybe_invalidate, except when the alias oracle knows better).
115 Functions like strcat on the other side adjust the whole
116 related strinfo chain.
117 They are updated lazily, so to use the chain the same first fields
118 and si->prev->next == si->idx needs to be verified. */
122 /* A flag whether the string is known to be written in the current
125 /* A flag for the next maybe_invalidate that this strinfo shouldn't
126 be invalidated. Always cleared by maybe_invalidate. */
127 bool dont_invalidate
;
130 /* Pool for allocating strinfo_struct entries. */
131 static pool_allocator
<strinfo_struct
> strinfo_pool ("strinfo_struct pool", 64);
133 /* Vector mapping positive string indexes to strinfo, for the
134 current basic block. The first pointer in the vector is special,
135 it is either NULL, meaning the vector isn't shared, or it is
136 a basic block pointer to the owner basic_block if shared.
137 If some other bb wants to modify the vector, the vector needs
138 to be unshared first, and only the owner bb is supposed to free it. */
139 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
141 /* One OFFSET->IDX mapping. */
144 struct stridxlist
*next
;
145 HOST_WIDE_INT offset
;
149 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
150 struct decl_stridxlist_map
152 struct tree_map_base base
;
153 struct stridxlist list
;
156 /* stridxlist hashtable helpers. */
158 struct stridxlist_hash_traits
: default_hashmap_traits
160 static inline hashval_t
hash (tree
);
163 /* Hash a from tree in a decl_stridxlist_map. */
166 stridxlist_hash_traits::hash (tree item
)
168 return DECL_UID (item
);
171 /* Hash table for mapping decls to a chained list of offset -> idx
173 static hash_map
<tree
, stridxlist
, stridxlist_hash_traits
>
174 *decl_to_stridxlist_htab
;
176 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
177 static struct obstack stridx_obstack
;
179 /* Last memcpy statement if it could be adjusted if the trailing
180 '\0' written is immediately overwritten, or
181 *x = '\0' store that could be removed if it is immediately overwritten. */
182 struct laststmt_struct
189 static int get_stridx_plus_constant (strinfo
, HOST_WIDE_INT
, tree
);
191 /* Return strinfo vector entry IDX. */
193 static inline strinfo
194 get_strinfo (int idx
)
196 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
198 return (*stridx_to_strinfo
)[idx
];
201 /* Helper function for get_stridx. */
204 get_addr_stridx (tree exp
)
207 struct stridxlist
*list
;
210 if (!decl_to_stridxlist_htab
)
213 base
= get_addr_base_and_unit_offset (exp
, &off
);
214 if (base
== NULL
|| !DECL_P (base
))
217 list
= decl_to_stridxlist_htab
->get (base
);
223 if (list
->offset
== off
)
231 /* Return string index for EXP. */
234 get_stridx (tree exp
)
238 if (TREE_CODE (exp
) == SSA_NAME
)
240 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
241 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
244 HOST_WIDE_INT off
= 0;
245 for (i
= 0; i
< 5; i
++)
247 gimple def_stmt
= SSA_NAME_DEF_STMT (e
);
248 if (!is_gimple_assign (def_stmt
)
249 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
251 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
252 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
253 if (TREE_CODE (rhs1
) != SSA_NAME
254 || !tree_fits_shwi_p (rhs2
))
256 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
259 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
262 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
265 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
268 && TREE_CODE (si
->length
) == INTEGER_CST
269 && compare_tree_int (si
->length
, off
) != -1)
270 return get_stridx_plus_constant (si
, off
, exp
);
277 if (TREE_CODE (exp
) == ADDR_EXPR
)
279 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
284 s
= string_constant (exp
, &o
);
286 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
287 && TREE_STRING_LENGTH (s
) > 0)
289 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
290 const char *p
= TREE_STRING_POINTER (s
);
291 int max
= TREE_STRING_LENGTH (s
) - 1;
293 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
294 return ~(int) strlen (p
+ offset
);
299 /* Return true if strinfo vector is shared with the immediate dominator. */
302 strinfo_shared (void)
304 return vec_safe_length (stridx_to_strinfo
)
305 && (*stridx_to_strinfo
)[0] != NULL
;
308 /* Unshare strinfo vector that is shared with the immediate dominator. */
311 unshare_strinfo_vec (void)
316 gcc_assert (strinfo_shared ());
317 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
318 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
321 (*stridx_to_strinfo
)[0] = NULL
;
324 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
325 Return a pointer to the location where the string index can
326 be stored (if 0) or is stored, or NULL if this can't be tracked. */
329 addr_stridxptr (tree exp
)
333 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
334 if (base
== NULL_TREE
|| !DECL_P (base
))
337 if (!decl_to_stridxlist_htab
)
339 decl_to_stridxlist_htab
340 = new hash_map
<tree
, stridxlist
, stridxlist_hash_traits
> (64);
341 gcc_obstack_init (&stridx_obstack
);
345 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
349 for (i
= 0; i
< 16; i
++)
351 if (list
->offset
== off
)
353 if (list
->next
== NULL
)
358 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
368 /* Create a new string index, or return 0 if reached limit. */
371 new_stridx (tree exp
)
374 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
376 if (TREE_CODE (exp
) == SSA_NAME
)
378 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
381 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
384 if (TREE_CODE (exp
) == ADDR_EXPR
)
386 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
389 gcc_assert (*pidx
== 0);
390 *pidx
= max_stridx
++;
397 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
400 new_addr_stridx (tree exp
)
403 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
405 pidx
= addr_stridxptr (exp
);
408 gcc_assert (*pidx
== 0);
409 *pidx
= max_stridx
++;
415 /* Create a new strinfo. */
418 new_strinfo (tree ptr
, int idx
, tree length
)
420 strinfo si
= strinfo_pool
.allocate ();
424 si
->endptr
= NULL_TREE
;
430 si
->writable
= false;
431 si
->dont_invalidate
= false;
435 /* Decrease strinfo refcount and free it if not referenced anymore. */
438 free_strinfo (strinfo si
)
440 if (si
&& --si
->refcount
== 0)
441 strinfo_pool
.remove (si
);
444 /* Set strinfo in the vector entry IDX to SI. */
447 set_strinfo (int idx
, strinfo si
)
449 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
450 unshare_strinfo_vec ();
451 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
452 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
453 (*stridx_to_strinfo
)[idx
] = si
;
456 /* Return string length, or NULL if it can't be computed. */
459 get_string_length (strinfo si
)
466 gimple stmt
= si
->stmt
, lenstmt
;
467 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
468 tree callee
, lhs
, fn
, tem
;
470 gimple_stmt_iterator gsi
;
472 gcc_assert (is_gimple_call (stmt
));
473 callee
= gimple_call_fndecl (stmt
);
474 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
475 lhs
= gimple_call_lhs (stmt
);
476 /* unshare_strinfo is intentionally not called here. The (delayed)
477 transformation of strcpy or strcat into stpcpy is done at the place
478 of the former strcpy/strcat call and so can affect all the strinfos
479 with the same stmt. If they were unshared before and transformation
480 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
481 just compute the right length. */
482 switch (DECL_FUNCTION_CODE (callee
))
484 case BUILT_IN_STRCAT
:
485 case BUILT_IN_STRCAT_CHK
:
486 case BUILT_IN_STRCAT_CHKP
:
487 case BUILT_IN_STRCAT_CHK_CHKP
:
488 gsi
= gsi_for_stmt (stmt
);
489 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
490 gcc_assert (lhs
== NULL_TREE
);
491 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
494 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
495 2, tem
, gimple_call_arg (stmt
, 1));
496 gimple_call_set_with_bounds (lenstmt
, true);
499 lenstmt
= gimple_build_call (fn
, 1, tem
);
500 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
501 gimple_call_set_lhs (lenstmt
, lhs
);
502 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
503 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
504 tem
= gimple_call_arg (stmt
, 0);
505 if (!ptrofftype_p (TREE_TYPE (lhs
)))
507 lhs
= convert_to_ptrofftype (lhs
);
508 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
509 true, GSI_SAME_STMT
);
511 lenstmt
= gimple_build_assign
512 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
513 POINTER_PLUS_EXPR
,tem
, lhs
);
514 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
515 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
518 case BUILT_IN_STRCPY
:
519 case BUILT_IN_STRCPY_CHK
:
520 case BUILT_IN_STRCPY_CHKP
:
521 case BUILT_IN_STRCPY_CHK_CHKP
:
522 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
523 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
524 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
526 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
528 fn
= chkp_maybe_create_clone (fn
)->decl
;
529 gcc_assert (lhs
== NULL_TREE
);
530 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
532 fprintf (dump_file
, "Optimizing: ");
533 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
535 gimple_call_set_fndecl (stmt
, fn
);
536 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
537 gimple_call_set_lhs (stmt
, lhs
);
539 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
541 fprintf (dump_file
, "into: ");
542 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
545 case BUILT_IN_STPCPY
:
546 case BUILT_IN_STPCPY_CHK
:
547 case BUILT_IN_STPCPY_CHKP
:
548 case BUILT_IN_STPCPY_CHK_CHKP
:
549 gcc_assert (lhs
!= NULL_TREE
);
550 loc
= gimple_location (stmt
);
553 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
554 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
555 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
558 case BUILT_IN_MALLOC
:
560 /* BUILT_IN_CALLOC always has si->length set. */
570 /* Invalidate string length information for strings whose length
571 might change due to stores in stmt. */
574 maybe_invalidate (gimple stmt
)
578 bool nonempty
= false;
580 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
583 if (!si
->dont_invalidate
)
586 /* Do not use si->length. */
587 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
588 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
590 set_strinfo (i
, NULL
);
595 si
->dont_invalidate
= false;
601 /* Unshare strinfo record SI, if it has refcount > 1 or
602 if stridx_to_strinfo vector is shared with some other
606 unshare_strinfo (strinfo si
)
610 if (si
->refcount
== 1 && !strinfo_shared ())
613 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
614 nsi
->stmt
= si
->stmt
;
615 nsi
->endptr
= si
->endptr
;
616 nsi
->first
= si
->first
;
617 nsi
->prev
= si
->prev
;
618 nsi
->next
= si
->next
;
619 nsi
->writable
= si
->writable
;
620 set_strinfo (si
->idx
, nsi
);
625 /* Return first strinfo in the related strinfo chain
626 if all strinfos in between belong to the chain, otherwise
630 verify_related_strinfos (strinfo origsi
)
632 strinfo si
= origsi
, psi
;
634 if (origsi
->first
== 0)
636 for (; si
->prev
; si
= psi
)
638 if (si
->first
!= origsi
->first
)
640 psi
= get_strinfo (si
->prev
);
643 if (psi
->next
!= si
->idx
)
646 if (si
->idx
!= si
->first
)
651 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
652 strinfo if there is any. Return it's idx, or 0 if no strinfo has
656 get_stridx_plus_constant (strinfo basesi
, HOST_WIDE_INT off
, tree ptr
)
658 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
660 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
663 if (basesi
->length
== NULL_TREE
664 || TREE_CODE (basesi
->length
) != INTEGER_CST
665 || compare_tree_int (basesi
->length
, off
) == -1
666 || !tree_fits_shwi_p (basesi
->length
))
669 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
670 strinfo si
= basesi
, chainsi
;
671 if (si
->first
|| si
->prev
|| si
->next
)
672 si
= verify_related_strinfos (basesi
);
674 || si
->length
== NULL_TREE
675 || TREE_CODE (si
->length
) != INTEGER_CST
)
678 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
679 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
681 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
682 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
684 si
= get_strinfo (chainsi
->next
);
686 || si
->first
!= chainsi
->first
687 || si
->prev
!= chainsi
->idx
688 || si
->length
== NULL_TREE
689 || TREE_CODE (si
->length
) != INTEGER_CST
)
691 int r
= compare_tree_int (si
->length
, len
);
696 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
703 int idx
= new_stridx (ptr
);
706 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
707 set_strinfo (idx
, si
);
710 strinfo nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
711 si
->next
= nextsi
->idx
;
714 chainsi
= unshare_strinfo (chainsi
);
715 if (chainsi
->first
== 0)
716 chainsi
->first
= chainsi
->idx
;
718 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
719 chainsi
->endptr
= ptr
;
720 si
->endptr
= chainsi
->endptr
;
721 si
->prev
= chainsi
->idx
;
722 si
->first
= chainsi
->first
;
723 si
->writable
= chainsi
->writable
;
727 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
728 to a zero-length string and if possible chain it to a related strinfo
729 chain whose part is or might be CHAINSI. */
732 zero_length_string (tree ptr
, strinfo chainsi
)
736 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
737 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
738 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
739 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
741 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
745 si
= verify_related_strinfos (chainsi
);
749 for (; chainsi
->next
; chainsi
= si
)
751 if (chainsi
->endptr
== NULL_TREE
)
753 chainsi
= unshare_strinfo (chainsi
);
754 chainsi
->endptr
= ptr
;
756 si
= get_strinfo (chainsi
->next
);
758 || si
->first
!= chainsi
->first
759 || si
->prev
!= chainsi
->idx
)
762 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
763 if (chainsi
->endptr
== NULL_TREE
)
765 chainsi
= unshare_strinfo (chainsi
);
766 chainsi
->endptr
= ptr
;
768 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
772 chainsi
= unshare_strinfo (chainsi
);
775 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
779 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
781 chainsi
= unshare_strinfo (chainsi
);
787 idx
= new_stridx (ptr
);
790 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
791 set_strinfo (idx
, si
);
795 chainsi
= unshare_strinfo (chainsi
);
796 if (chainsi
->first
== 0)
797 chainsi
->first
= chainsi
->idx
;
799 if (chainsi
->endptr
== NULL_TREE
)
800 chainsi
->endptr
= ptr
;
801 si
->prev
= chainsi
->idx
;
802 si
->first
= chainsi
->first
;
803 si
->writable
= chainsi
->writable
;
808 /* For strinfo ORIGSI whose length has been just updated
809 update also related strinfo lengths (add ADJ to each,
810 but don't adjust ORIGSI). */
813 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
815 strinfo si
= verify_related_strinfos (origsi
);
828 si
= unshare_strinfo (si
);
831 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
832 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
833 TREE_TYPE (si
->length
), si
->length
,
836 else if (si
->stmt
!= NULL
)
837 /* Delayed length computation is unaffected. */
842 si
->endptr
= NULL_TREE
;
843 si
->dont_invalidate
= true;
847 nsi
= get_strinfo (si
->next
);
849 || nsi
->first
!= si
->first
850 || nsi
->prev
!= si
->idx
)
856 /* Find if there are other SSA_NAME pointers equal to PTR
857 for which we don't track their string lengths yet. If so, use
861 find_equal_ptrs (tree ptr
, int idx
)
863 if (TREE_CODE (ptr
) != SSA_NAME
)
867 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
868 if (!is_gimple_assign (stmt
))
870 ptr
= gimple_assign_rhs1 (stmt
);
871 switch (gimple_assign_rhs_code (stmt
))
876 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
878 if (TREE_CODE (ptr
) == SSA_NAME
)
880 if (TREE_CODE (ptr
) != ADDR_EXPR
)
885 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
886 if (pidx
!= NULL
&& *pidx
== 0)
894 /* We might find an endptr created in this pass. Grow the
895 vector in that case. */
896 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
897 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
899 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
901 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
905 /* If the last .MEM setter statement before STMT is
906 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
907 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
908 just memcpy (x, y, strlen (y)). SI must be the zero length
912 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
914 tree vuse
, callee
, len
;
915 struct laststmt_struct last
= laststmt
;
916 strinfo lastsi
, firstsi
;
917 unsigned len_arg_no
= 2;
919 laststmt
.stmt
= NULL
;
920 laststmt
.len
= NULL_TREE
;
923 if (last
.stmt
== NULL
)
926 vuse
= gimple_vuse (stmt
);
927 if (vuse
== NULL_TREE
928 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
929 || !has_single_use (vuse
))
932 gcc_assert (last
.stridx
> 0);
933 lastsi
= get_strinfo (last
.stridx
);
939 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
942 firstsi
= verify_related_strinfos (si
);
945 while (firstsi
!= lastsi
)
948 if (firstsi
->next
== 0)
950 nextsi
= get_strinfo (firstsi
->next
);
952 || nextsi
->prev
!= firstsi
->idx
953 || nextsi
->first
!= si
->first
)
961 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
965 if (is_gimple_assign (last
.stmt
))
967 gimple_stmt_iterator gsi
;
969 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
971 if (stmt_could_throw_p (last
.stmt
))
973 gsi
= gsi_for_stmt (last
.stmt
);
974 unlink_stmt_vdef (last
.stmt
);
975 release_defs (last
.stmt
);
976 gsi_remove (&gsi
, true);
980 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
983 callee
= gimple_call_fndecl (last
.stmt
);
984 switch (DECL_FUNCTION_CODE (callee
))
986 case BUILT_IN_MEMCPY
:
987 case BUILT_IN_MEMCPY_CHK
:
989 case BUILT_IN_MEMCPY_CHKP
:
990 case BUILT_IN_MEMCPY_CHK_CHKP
:
997 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
998 if (tree_fits_uhwi_p (len
))
1000 if (!tree_fits_uhwi_p (last
.len
)
1001 || integer_zerop (len
)
1002 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
1004 /* Don't adjust the length if it is divisible by 4, it is more efficient
1005 to store the extra '\0' in that case. */
1006 if ((tree_to_uhwi (len
) & 3) == 0)
1009 else if (TREE_CODE (len
) == SSA_NAME
)
1011 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
1012 if (!is_gimple_assign (def_stmt
)
1013 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1014 || gimple_assign_rhs1 (def_stmt
) != last
.len
1015 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1021 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
1022 update_stmt (last
.stmt
);
1025 /* Handle a strlen call. If strlen of the argument is known, replace
1026 the strlen call with the known value, otherwise remember that strlen
1027 of the argument is stored in the lhs SSA_NAME. */
1030 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1034 gimple stmt
= gsi_stmt (*gsi
);
1035 tree lhs
= gimple_call_lhs (stmt
);
1037 if (lhs
== NULL_TREE
)
1040 src
= gimple_call_arg (stmt
, 0);
1041 idx
= get_stridx (src
);
1048 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1052 si
= get_strinfo (idx
);
1054 rhs
= get_string_length (si
);
1056 if (rhs
!= NULL_TREE
)
1058 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1060 fprintf (dump_file
, "Optimizing: ");
1061 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1063 rhs
= unshare_expr (rhs
);
1064 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1065 rhs
= fold_convert_loc (gimple_location (stmt
),
1066 TREE_TYPE (lhs
), rhs
);
1067 if (!update_call_from_tree (gsi
, rhs
))
1068 gimplify_and_update_call_from_tree (gsi
, rhs
);
1069 stmt
= gsi_stmt (*gsi
);
1071 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1073 fprintf (dump_file
, "into: ");
1074 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1077 && TREE_CODE (si
->length
) != SSA_NAME
1078 && TREE_CODE (si
->length
) != INTEGER_CST
1079 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1081 si
= unshare_strinfo (si
);
1087 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1090 idx
= new_stridx (src
);
1091 else if (get_strinfo (idx
) != NULL
)
1095 strinfo si
= new_strinfo (src
, idx
, lhs
);
1096 set_strinfo (idx
, si
);
1097 find_equal_ptrs (src
, idx
);
1101 /* Handle a strchr call. If strlen of the first argument is known, replace
1102 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1103 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1106 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1110 gimple stmt
= gsi_stmt (*gsi
);
1111 tree lhs
= gimple_call_lhs (stmt
);
1112 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1114 if (lhs
== NULL_TREE
)
1117 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1120 src
= gimple_call_arg (stmt
, 0);
1121 idx
= get_stridx (src
);
1128 rhs
= build_int_cst (size_type_node
, ~idx
);
1132 si
= get_strinfo (idx
);
1134 rhs
= get_string_length (si
);
1136 if (rhs
!= NULL_TREE
)
1138 location_t loc
= gimple_location (stmt
);
1140 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1142 fprintf (dump_file
, "Optimizing: ");
1143 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1145 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1147 rhs
= unshare_expr (si
->endptr
);
1148 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1150 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1154 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1155 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1156 TREE_TYPE (src
), src
, rhs
);
1157 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1159 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1161 if (!update_call_from_tree (gsi
, rhs
))
1162 gimplify_and_update_call_from_tree (gsi
, rhs
);
1163 stmt
= gsi_stmt (*gsi
);
1165 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1167 fprintf (dump_file
, "into: ");
1168 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1171 && si
->endptr
== NULL_TREE
1172 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1174 si
= unshare_strinfo (si
);
1177 zero_length_string (lhs
, si
);
1181 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1183 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1186 idx
= new_stridx (src
);
1187 else if (get_strinfo (idx
) != NULL
)
1189 zero_length_string (lhs
, NULL
);
1194 location_t loc
= gimple_location (stmt
);
1195 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1196 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1197 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1198 size_type_node
, lhsu
, srcu
);
1199 strinfo si
= new_strinfo (src
, idx
, length
);
1201 set_strinfo (idx
, si
);
1202 find_equal_ptrs (src
, idx
);
1203 zero_length_string (lhs
, si
);
1207 zero_length_string (lhs
, NULL
);
1210 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1211 If strlen of the second argument is known, strlen of the first argument
1212 is the same after this call. Furthermore, attempt to convert it to
1216 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1219 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1221 gimple stmt
= gsi_stmt (*gsi
);
1222 strinfo si
, dsi
, olddsi
, zsi
;
1224 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1226 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1227 dst
= gimple_call_arg (stmt
, 0);
1228 lhs
= gimple_call_lhs (stmt
);
1229 idx
= get_stridx (src
);
1232 si
= get_strinfo (idx
);
1234 didx
= get_stridx (dst
);
1238 olddsi
= get_strinfo (didx
);
1243 adjust_last_stmt (olddsi
, stmt
, false);
1247 srclen
= get_string_length (si
);
1249 srclen
= build_int_cst (size_type_node
, ~idx
);
1251 loc
= gimple_location (stmt
);
1252 if (srclen
== NULL_TREE
)
1255 case BUILT_IN_STRCPY
:
1256 case BUILT_IN_STRCPY_CHK
:
1257 case BUILT_IN_STRCPY_CHKP
:
1258 case BUILT_IN_STRCPY_CHK_CHKP
:
1259 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1262 case BUILT_IN_STPCPY
:
1263 case BUILT_IN_STPCPY_CHK
:
1264 case BUILT_IN_STPCPY_CHKP
:
1265 case BUILT_IN_STPCPY_CHK_CHKP
:
1266 if (lhs
== NULL_TREE
)
1270 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1271 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1272 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1282 didx
= new_stridx (dst
);
1288 oldlen
= olddsi
->length
;
1289 dsi
= unshare_strinfo (olddsi
);
1290 dsi
->length
= srclen
;
1291 /* Break the chain, so adjust_related_strinfo on later pointers in
1292 the chain won't adjust this one anymore. */
1295 dsi
->endptr
= NULL_TREE
;
1299 dsi
= new_strinfo (dst
, didx
, srclen
);
1300 set_strinfo (didx
, dsi
);
1301 find_equal_ptrs (dst
, didx
);
1303 dsi
->writable
= true;
1304 dsi
->dont_invalidate
= true;
1306 if (dsi
->length
== NULL_TREE
)
1310 /* If string length of src is unknown, use delayed length
1311 computation. If string lenth of dst will be needed, it
1312 can be computed by transforming this strcpy call into
1313 stpcpy and subtracting dst from the return value. */
1315 /* Look for earlier strings whose length could be determined if
1316 this strcpy is turned into an stpcpy. */
1318 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1320 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1322 /* When setting a stmt for delayed length computation
1323 prevent all strinfos through dsi from being
1325 chainsi
= unshare_strinfo (chainsi
);
1326 chainsi
->stmt
= stmt
;
1327 chainsi
->length
= NULL_TREE
;
1328 chainsi
->endptr
= NULL_TREE
;
1329 chainsi
->dont_invalidate
= true;
1338 tree adj
= NULL_TREE
;
1339 if (oldlen
== NULL_TREE
)
1341 else if (integer_zerop (oldlen
))
1343 else if (TREE_CODE (oldlen
) == INTEGER_CST
1344 || TREE_CODE (srclen
) == INTEGER_CST
)
1345 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1346 TREE_TYPE (srclen
), srclen
,
1347 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1349 if (adj
!= NULL_TREE
)
1350 adjust_related_strinfos (loc
, dsi
, adj
);
1354 /* strcpy src may not overlap dst, so src doesn't need to be
1355 invalidated either. */
1357 si
->dont_invalidate
= true;
1363 case BUILT_IN_STRCPY
:
1364 case BUILT_IN_STRCPY_CHKP
:
1365 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1367 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1369 case BUILT_IN_STRCPY_CHK
:
1370 case BUILT_IN_STRCPY_CHK_CHKP
:
1371 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1373 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1375 case BUILT_IN_STPCPY
:
1376 case BUILT_IN_STPCPY_CHKP
:
1377 /* This would need adjustment of the lhs (subtract one),
1378 or detection that the trailing '\0' doesn't need to be
1379 written, if it will be immediately overwritten.
1380 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1384 zsi
= zero_length_string (lhs
, dsi
);
1387 case BUILT_IN_STPCPY_CHK
:
1388 case BUILT_IN_STPCPY_CHK_CHKP
:
1389 /* This would need adjustment of the lhs (subtract one),
1390 or detection that the trailing '\0' doesn't need to be
1391 written, if it will be immediately overwritten.
1392 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1396 zsi
= zero_length_string (lhs
, dsi
);
1403 zsi
->dont_invalidate
= true;
1405 if (fn
== NULL_TREE
)
1408 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1409 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1411 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1412 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1413 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1415 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1417 fprintf (dump_file
, "Optimizing: ");
1418 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1422 fn
= chkp_maybe_create_clone (fn
)->decl
;
1423 if (gimple_call_num_args (stmt
) == 4)
1424 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1425 gimple_call_arg (stmt
, 1),
1427 gimple_call_arg (stmt
, 3),
1430 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1431 gimple_call_arg (stmt
, 1),
1433 gimple_call_arg (stmt
, 3),
1435 gimple_call_arg (stmt
, 4));
1438 if (gimple_call_num_args (stmt
) == 2)
1439 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1441 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1442 gimple_call_arg (stmt
, 2));
1445 stmt
= gsi_stmt (*gsi
);
1446 gimple_call_set_with_bounds (stmt
, with_bounds
);
1448 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1450 fprintf (dump_file
, "into: ");
1451 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1453 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1454 laststmt
.stmt
= stmt
;
1455 laststmt
.len
= srclen
;
1456 laststmt
.stridx
= dsi
->idx
;
1458 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1459 fprintf (dump_file
, "not possible.\n");
1462 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1463 If strlen of the second argument is known and length of the third argument
1464 is that plus one, strlen of the first argument is the same after this
1468 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1471 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1472 gimple stmt
= gsi_stmt (*gsi
);
1473 strinfo si
, dsi
, olddsi
;
1474 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1476 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1477 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1478 dst
= gimple_call_arg (stmt
, 0);
1479 idx
= get_stridx (src
);
1483 didx
= get_stridx (dst
);
1486 olddsi
= get_strinfo (didx
);
1491 && tree_fits_uhwi_p (len
)
1492 && !integer_zerop (len
))
1493 adjust_last_stmt (olddsi
, stmt
, false);
1499 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1500 si
= get_strinfo (idx
);
1501 if (si
== NULL
|| si
->length
== NULL_TREE
)
1503 if (TREE_CODE (len
) != SSA_NAME
)
1505 def_stmt
= SSA_NAME_DEF_STMT (len
);
1506 if (!is_gimple_assign (def_stmt
)
1507 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1508 || gimple_assign_rhs1 (def_stmt
) != si
->length
1509 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1515 /* Handle memcpy (x, "abcd", 5) or
1516 memcpy (x, "abc\0uvw", 7). */
1517 if (!tree_fits_uhwi_p (len
)
1518 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1522 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1523 adjust_last_stmt (olddsi
, stmt
, false);
1527 didx
= new_stridx (dst
);
1532 newlen
= si
->length
;
1534 newlen
= build_int_cst (size_type_node
, ~idx
);
1538 dsi
= unshare_strinfo (olddsi
);
1539 oldlen
= olddsi
->length
;
1540 dsi
->length
= newlen
;
1541 /* Break the chain, so adjust_related_strinfo on later pointers in
1542 the chain won't adjust this one anymore. */
1545 dsi
->endptr
= NULL_TREE
;
1549 dsi
= new_strinfo (dst
, didx
, newlen
);
1550 set_strinfo (didx
, dsi
);
1551 find_equal_ptrs (dst
, didx
);
1553 dsi
->writable
= true;
1554 dsi
->dont_invalidate
= true;
1557 tree adj
= NULL_TREE
;
1558 location_t loc
= gimple_location (stmt
);
1559 if (oldlen
== NULL_TREE
)
1561 else if (integer_zerop (oldlen
))
1563 else if (TREE_CODE (oldlen
) == INTEGER_CST
1564 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1565 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1566 TREE_TYPE (dsi
->length
), dsi
->length
,
1567 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1569 if (adj
!= NULL_TREE
)
1570 adjust_related_strinfos (loc
, dsi
, adj
);
1574 /* memcpy src may not overlap dst, so src doesn't need to be
1575 invalidated either. */
1577 si
->dont_invalidate
= true;
1579 lhs
= gimple_call_lhs (stmt
);
1582 case BUILT_IN_MEMCPY
:
1583 case BUILT_IN_MEMCPY_CHK
:
1584 case BUILT_IN_MEMCPY_CHKP
:
1585 case BUILT_IN_MEMCPY_CHK_CHKP
:
1586 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1587 laststmt
.stmt
= stmt
;
1588 laststmt
.len
= dsi
->length
;
1589 laststmt
.stridx
= dsi
->idx
;
1591 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1593 case BUILT_IN_MEMPCPY
:
1594 case BUILT_IN_MEMPCPY_CHK
:
1595 case BUILT_IN_MEMPCPY_CHKP
:
1596 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1603 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1604 If strlen of the second argument is known, strlen of the first argument
1605 is increased by the length of the second argument. Furthermore, attempt
1606 to convert it to memcpy/strcpy if the length of the first argument
1610 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1613 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1615 gimple stmt
= gsi_stmt (*gsi
);
1618 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1620 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1621 dst
= gimple_call_arg (stmt
, 0);
1622 lhs
= gimple_call_lhs (stmt
);
1624 didx
= get_stridx (dst
);
1630 dsi
= get_strinfo (didx
);
1631 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1633 /* strcat (p, q) can be transformed into
1634 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1635 with length endptr - p if we need to compute the length
1636 later on. Don't do this transformation if we don't need
1638 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1642 didx
= new_stridx (dst
);
1648 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1649 set_strinfo (didx
, dsi
);
1650 find_equal_ptrs (dst
, didx
);
1654 dsi
= unshare_strinfo (dsi
);
1655 dsi
->length
= NULL_TREE
;
1657 dsi
->endptr
= NULL_TREE
;
1659 dsi
->writable
= true;
1661 dsi
->dont_invalidate
= true;
1668 idx
= get_stridx (src
);
1670 srclen
= build_int_cst (size_type_node
, ~idx
);
1673 si
= get_strinfo (idx
);
1675 srclen
= get_string_length (si
);
1678 loc
= gimple_location (stmt
);
1679 dstlen
= dsi
->length
;
1680 endptr
= dsi
->endptr
;
1682 dsi
= unshare_strinfo (dsi
);
1683 dsi
->endptr
= NULL_TREE
;
1685 dsi
->writable
= true;
1687 if (srclen
!= NULL_TREE
)
1689 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1690 dsi
->length
, srclen
);
1691 adjust_related_strinfos (loc
, dsi
, srclen
);
1692 dsi
->dont_invalidate
= true;
1697 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1698 dsi
->dont_invalidate
= true;
1702 /* strcat src may not overlap dst, so src doesn't need to be
1703 invalidated either. */
1704 si
->dont_invalidate
= true;
1706 /* For now. Could remove the lhs from the call and add
1707 lhs = dst; afterwards. */
1715 case BUILT_IN_STRCAT
:
1716 case BUILT_IN_STRCAT_CHKP
:
1717 if (srclen
!= NULL_TREE
)
1718 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1720 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1722 case BUILT_IN_STRCAT_CHK
:
1723 case BUILT_IN_STRCAT_CHK_CHKP
:
1724 if (srclen
!= NULL_TREE
)
1725 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1727 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1728 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1734 if (fn
== NULL_TREE
)
1738 if (srclen
!= NULL_TREE
)
1740 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1741 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1743 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1744 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1745 build_int_cst (type
, 1));
1746 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1750 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1752 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1753 TREE_TYPE (dst
), unshare_expr (dst
),
1754 fold_convert_loc (loc
, sizetype
,
1755 unshare_expr (dstlen
)));
1756 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1758 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1760 fprintf (dump_file
, "Optimizing: ");
1761 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1765 fn
= chkp_maybe_create_clone (fn
)->decl
;
1766 if (srclen
!= NULL_TREE
)
1767 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1769 gimple_call_arg (stmt
, 1),
1771 gimple_call_arg (stmt
, 3),
1774 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1776 gimple_call_arg (stmt
, 1),
1778 gimple_call_arg (stmt
, 3),
1782 if (srclen
!= NULL_TREE
)
1783 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1784 dst
, src
, len
, objsz
);
1786 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1790 stmt
= gsi_stmt (*gsi
);
1791 gimple_call_set_with_bounds (stmt
, with_bounds
);
1793 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1795 fprintf (dump_file
, "into: ");
1796 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1798 /* If srclen == NULL, note that current string length can be
1799 computed by transforming this strcpy into stpcpy. */
1800 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1802 adjust_last_stmt (dsi
, stmt
, true);
1803 if (srclen
!= NULL_TREE
)
1805 laststmt
.stmt
= stmt
;
1806 laststmt
.len
= srclen
;
1807 laststmt
.stridx
= dsi
->idx
;
1810 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1811 fprintf (dump_file
, "not possible.\n");
1814 /* Handle a call to malloc or calloc. */
1817 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1819 gimple stmt
= gsi_stmt (*gsi
);
1820 tree lhs
= gimple_call_lhs (stmt
);
1821 gcc_assert (get_stridx (lhs
) == 0);
1822 int idx
= new_stridx (lhs
);
1823 tree length
= NULL_TREE
;
1824 if (bcode
== BUILT_IN_CALLOC
)
1825 length
= build_int_cst (size_type_node
, 0);
1826 strinfo si
= new_strinfo (lhs
, idx
, length
);
1827 if (bcode
== BUILT_IN_CALLOC
)
1829 set_strinfo (idx
, si
);
1830 si
->writable
= true;
1832 si
->dont_invalidate
= true;
1835 /* Handle a call to memset.
1836 After a call to calloc, memset(,0,) is unnecessary.
1837 memset(malloc(n),0,n) is calloc(n,1). */
1840 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1842 gimple stmt2
= gsi_stmt (*gsi
);
1843 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1845 tree ptr
= gimple_call_arg (stmt2
, 0);
1846 int idx1
= get_stridx (ptr
);
1849 strinfo si1
= get_strinfo (idx1
);
1852 gimple stmt1
= si1
->stmt
;
1853 if (!stmt1
|| !is_gimple_call (stmt1
))
1855 tree callee1
= gimple_call_fndecl (stmt1
);
1856 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1858 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1859 tree size
= gimple_call_arg (stmt2
, 2);
1860 if (code1
== BUILT_IN_CALLOC
)
1861 /* Not touching stmt1 */ ;
1862 else if (code1
== BUILT_IN_MALLOC
1863 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1865 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1866 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1867 size
, build_one_cst (size_type_node
));
1868 si1
->length
= build_int_cst (size_type_node
, 0);
1869 si1
->stmt
= gsi_stmt (gsi1
);
1873 tree lhs
= gimple_call_lhs (stmt2
);
1874 unlink_stmt_vdef (stmt2
);
1877 gimple assign
= gimple_build_assign (lhs
, ptr
);
1878 gsi_replace (gsi
, assign
, false);
1882 gsi_remove (gsi
, true);
1883 release_defs (stmt2
);
1889 /* Handle a POINTER_PLUS_EXPR statement.
1890 For p = "abcd" + 2; compute associated length, or if
1891 p = q + off is pointing to a '\0' character of a string, call
1892 zero_length_string on it. */
1895 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1897 gimple stmt
= gsi_stmt (*gsi
);
1898 tree lhs
= gimple_assign_lhs (stmt
), off
;
1899 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1907 tree off
= gimple_assign_rhs2 (stmt
);
1908 if (tree_fits_uhwi_p (off
)
1909 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1910 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1911 = ~(~idx
- (int) tree_to_uhwi (off
));
1915 si
= get_strinfo (idx
);
1916 if (si
== NULL
|| si
->length
== NULL_TREE
)
1919 off
= gimple_assign_rhs2 (stmt
);
1921 if (operand_equal_p (si
->length
, off
, 0))
1922 zsi
= zero_length_string (lhs
, si
);
1923 else if (TREE_CODE (off
) == SSA_NAME
)
1925 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1926 if (gimple_assign_single_p (def_stmt
)
1927 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1928 zsi
= zero_length_string (lhs
, si
);
1931 && si
->endptr
!= NULL_TREE
1932 && si
->endptr
!= lhs
1933 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1935 enum tree_code rhs_code
1936 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1937 ? SSA_NAME
: NOP_EXPR
;
1938 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1939 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1944 /* Handle a single character store. */
1947 handle_char_store (gimple_stmt_iterator
*gsi
)
1951 gimple stmt
= gsi_stmt (*gsi
);
1952 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1954 if (TREE_CODE (lhs
) == MEM_REF
1955 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1957 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1959 ssaname
= TREE_OPERAND (lhs
, 0);
1960 idx
= get_stridx (ssaname
);
1964 idx
= get_addr_stridx (lhs
);
1968 si
= get_strinfo (idx
);
1969 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1971 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1973 /* When storing '\0', the store can be removed
1974 if we know it has been stored in the current function. */
1975 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1977 unlink_stmt_vdef (stmt
);
1978 release_defs (stmt
);
1979 gsi_remove (gsi
, true);
1984 si
->writable
= true;
1990 /* Otherwise this statement overwrites the '\0' with
1991 something, if the previous stmt was a memcpy,
1992 its length may be decreased. */
1993 adjust_last_stmt (si
, stmt
, false);
1995 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1997 si
= unshare_strinfo (si
);
1998 si
->length
= build_int_cst (size_type_node
, 0);
2004 si
->writable
= true;
2005 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2006 si
->endptr
= ssaname
;
2007 si
->dont_invalidate
= true;
2009 /* If si->length is non-zero constant, we aren't overwriting '\0',
2010 and if we aren't storing '\0', we know that the length of the
2011 string and any other zero terminated string in memory remains
2012 the same. In that case we move to the next gimple statement and
2013 return to signal the caller that it shouldn't invalidate anything.
2015 This is benefical for cases like:
2020 strcpy (p, "foobar");
2021 size_t len = strlen (p); // This can be optimized into 6
2022 size_t len2 = strlen (q); // This has to be computed
2024 size_t len3 = strlen (p); // This can be optimized into 6
2025 size_t len4 = strlen (q); // This can be optimized into len2
2026 bar (len, len2, len3, len4);
2029 else if (si
!= NULL
&& si
->length
!= NULL_TREE
2030 && TREE_CODE (si
->length
) == INTEGER_CST
2031 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2037 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2041 si
= zero_length_string (ssaname
, NULL
);
2043 si
->dont_invalidate
= true;
2047 int idx
= new_addr_stridx (lhs
);
2050 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2051 build_int_cst (size_type_node
, 0));
2052 set_strinfo (idx
, si
);
2053 si
->dont_invalidate
= true;
2057 si
->writable
= true;
2060 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2061 && ssaname
== NULL_TREE
2062 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2064 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2065 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2066 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2068 int idx
= new_addr_stridx (lhs
);
2071 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2072 build_int_cst (size_type_node
, l
));
2073 set_strinfo (idx
, si
);
2074 si
->dont_invalidate
= true;
2079 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2081 /* Allow adjust_last_stmt to remove it if the stored '\0'
2082 is immediately overwritten. */
2083 laststmt
.stmt
= stmt
;
2084 laststmt
.len
= build_int_cst (size_type_node
, 1);
2085 laststmt
.stridx
= si
->idx
;
2090 /* Attempt to optimize a single statement at *GSI using string length
2094 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2096 gimple stmt
= gsi_stmt (*gsi
);
2098 if (is_gimple_call (stmt
))
2100 tree callee
= gimple_call_fndecl (stmt
);
2101 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2102 switch (DECL_FUNCTION_CODE (callee
))
2104 case BUILT_IN_STRLEN
:
2105 case BUILT_IN_STRLEN_CHKP
:
2106 handle_builtin_strlen (gsi
);
2108 case BUILT_IN_STRCHR
:
2109 case BUILT_IN_STRCHR_CHKP
:
2110 handle_builtin_strchr (gsi
);
2112 case BUILT_IN_STRCPY
:
2113 case BUILT_IN_STRCPY_CHK
:
2114 case BUILT_IN_STPCPY
:
2115 case BUILT_IN_STPCPY_CHK
:
2116 case BUILT_IN_STRCPY_CHKP
:
2117 case BUILT_IN_STRCPY_CHK_CHKP
:
2118 case BUILT_IN_STPCPY_CHKP
:
2119 case BUILT_IN_STPCPY_CHK_CHKP
:
2120 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2122 case BUILT_IN_MEMCPY
:
2123 case BUILT_IN_MEMCPY_CHK
:
2124 case BUILT_IN_MEMPCPY
:
2125 case BUILT_IN_MEMPCPY_CHK
:
2126 case BUILT_IN_MEMCPY_CHKP
:
2127 case BUILT_IN_MEMCPY_CHK_CHKP
:
2128 case BUILT_IN_MEMPCPY_CHKP
:
2129 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2130 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2132 case BUILT_IN_STRCAT
:
2133 case BUILT_IN_STRCAT_CHK
:
2134 case BUILT_IN_STRCAT_CHKP
:
2135 case BUILT_IN_STRCAT_CHK_CHKP
:
2136 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2138 case BUILT_IN_MALLOC
:
2139 case BUILT_IN_CALLOC
:
2140 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2142 case BUILT_IN_MEMSET
:
2143 if (!handle_builtin_memset (gsi
))
2150 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2152 tree lhs
= gimple_assign_lhs (stmt
);
2154 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2156 if (gimple_assign_single_p (stmt
)
2157 || (gimple_assign_cast_p (stmt
)
2158 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2160 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2161 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2163 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2164 handle_pointer_plus (gsi
);
2166 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2168 tree type
= TREE_TYPE (lhs
);
2169 if (TREE_CODE (type
) == ARRAY_TYPE
)
2170 type
= TREE_TYPE (type
);
2171 if (TREE_CODE (type
) == INTEGER_TYPE
2172 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2173 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2175 if (! handle_char_store (gsi
))
2181 if (gimple_vdef (stmt
))
2182 maybe_invalidate (stmt
);
2186 /* Recursively call maybe_invalidate on stmts that might be executed
2187 in between dombb and current bb and that contain a vdef. Stop when
2188 *count stmts are inspected, or if the whole strinfo vector has
2189 been invalidated. */
2192 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
2194 unsigned int i
, n
= gimple_phi_num_args (phi
);
2196 for (i
= 0; i
< n
; i
++)
2198 tree vuse
= gimple_phi_arg_def (phi
, i
);
2199 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
2200 basic_block bb
= gimple_bb (stmt
);
2203 || !bitmap_set_bit (visited
, bb
->index
)
2204 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2208 if (gimple_code (stmt
) == GIMPLE_PHI
)
2210 do_invalidate (dombb
, stmt
, visited
, count
);
2217 if (!maybe_invalidate (stmt
))
2222 vuse
= gimple_vuse (stmt
);
2223 stmt
= SSA_NAME_DEF_STMT (vuse
);
2224 if (gimple_bb (stmt
) != bb
)
2226 bb
= gimple_bb (stmt
);
2229 || !bitmap_set_bit (visited
, bb
->index
)
2230 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2237 class strlen_dom_walker
: public dom_walker
2240 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2242 virtual void before_dom_children (basic_block
);
2243 virtual void after_dom_children (basic_block
);
2246 /* Callback for walk_dominator_tree. Attempt to optimize various
2247 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2250 strlen_dom_walker::before_dom_children (basic_block bb
)
2252 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2255 stridx_to_strinfo
= NULL
;
2258 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
2259 if (stridx_to_strinfo
)
2261 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2264 gphi
*phi
= gsi
.phi ();
2265 if (virtual_operand_p (gimple_phi_result (phi
)))
2267 bitmap visited
= BITMAP_ALLOC (NULL
);
2268 int count_vdef
= 100;
2269 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2270 BITMAP_FREE (visited
);
2271 if (count_vdef
== 0)
2273 /* If there were too many vdefs in between immediate
2274 dominator and current bb, invalidate everything.
2275 If stridx_to_strinfo has been unshared, we need
2276 to free it, otherwise just set it to NULL. */
2277 if (!strinfo_shared ())
2283 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2287 (*stridx_to_strinfo
)[i
] = NULL
;
2291 stridx_to_strinfo
= NULL
;
2299 /* If all PHI arguments have the same string index, the PHI result
2301 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2304 gphi
*phi
= gsi
.phi ();
2305 tree result
= gimple_phi_result (phi
);
2306 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2308 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2311 unsigned int i
, n
= gimple_phi_num_args (phi
);
2312 for (i
= 1; i
< n
; i
++)
2313 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2316 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2321 /* Attempt to optimize individual statements. */
2322 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2323 if (strlen_optimize_stmt (&gsi
))
2326 bb
->aux
= stridx_to_strinfo
;
2327 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2328 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2331 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2332 owned by the current bb, clear bb->aux. */
2335 strlen_dom_walker::after_dom_children (basic_block bb
)
2339 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2340 if (vec_safe_length (stridx_to_strinfo
)
2341 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2346 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2348 vec_free (stridx_to_strinfo
);
2354 /* Main entry point. */
2358 const pass_data pass_data_strlen
=
2360 GIMPLE_PASS
, /* type */
2361 "strlen", /* name */
2362 OPTGROUP_NONE
, /* optinfo_flags */
2363 TV_TREE_STRLEN
, /* tv_id */
2364 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2365 0, /* properties_provided */
2366 0, /* properties_destroyed */
2367 0, /* todo_flags_start */
2368 0, /* todo_flags_finish */
2371 class pass_strlen
: public gimple_opt_pass
2374 pass_strlen (gcc::context
*ctxt
)
2375 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2378 /* opt_pass methods: */
2379 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2380 virtual unsigned int execute (function
*);
2382 }; // class pass_strlen
2385 pass_strlen::execute (function
*fun
)
2387 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2390 calculate_dominance_info (CDI_DOMINATORS
);
2392 /* String length optimization is implemented as a walk of the dominator
2393 tree and a forward walk of statements within each block. */
2394 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2396 ssa_ver_to_stridx
.release ();
2397 strinfo_pool
.release ();
2398 if (decl_to_stridxlist_htab
)
2400 obstack_free (&stridx_obstack
, NULL
);
2401 delete decl_to_stridxlist_htab
;
2402 decl_to_stridxlist_htab
= NULL
;
2404 laststmt
.stmt
= NULL
;
2405 laststmt
.len
= NULL_TREE
;
2406 laststmt
.stridx
= 0;
2414 make_pass_strlen (gcc::context
*ctxt
)
2416 return new pass_strlen (ctxt
);