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"
27 #include "double-int.h"
35 #include "fold-const.h"
36 #include "stor-layout.h"
37 #include "hash-table.h"
42 #include "hard-reg-set.h"
45 #include "dominance.h"
47 #include "basic-block.h"
48 #include "tree-ssa-alias.h"
49 #include "internal-fn.h"
50 #include "gimple-fold.h"
52 #include "gimple-expr.h"
56 #include "gimple-iterator.h"
57 #include "gimplify-me.h"
58 #include "gimple-ssa.h"
59 #include "tree-phinodes.h"
60 #include "ssa-iterators.h"
61 #include "stringpool.h"
62 #include "tree-ssanames.h"
65 #include "tree-pass.h"
67 #include "alloc-pool.h"
68 #include "tree-ssa-propagate.h"
69 #include "gimple-pretty-print.h"
72 #include "plugin-api.h"
77 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
78 is an index into strinfo vector, negative value stands for
79 string length of a string literal (~strlen). */
80 static vec
<int> ssa_ver_to_stridx
;
82 /* Number of currently active string indexes plus one. */
83 static int max_stridx
;
85 /* String information record. */
86 typedef struct strinfo_struct
88 /* String length of this string. */
90 /* Any of the corresponding pointers for querying alias oracle. */
92 /* Statement for delayed length computation. */
94 /* Pointer to '\0' if known, if NULL, it can be computed as
97 /* Reference count. Any changes to strinfo entry possibly shared
98 with dominating basic blocks need unshare_strinfo first, except
99 for dont_invalidate which affects only the immediately next
102 /* Copy of index. get_strinfo (si->idx) should return si; */
104 /* These 3 fields are for chaining related string pointers together.
106 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
107 strcpy (c, d); e = c + dl;
108 strinfo(a) -> strinfo(c) -> strinfo(e)
109 All have ->first field equal to strinfo(a)->idx and are doubly
110 chained through prev/next fields. The later strinfos are required
111 to point into the same string with zero or more bytes after
112 the previous pointer and all bytes in between the two pointers
113 must be non-zero. Functions like strcpy or memcpy are supposed
114 to adjust all previous strinfo lengths, but not following strinfo
115 lengths (those are uncertain, usually invalidated during
116 maybe_invalidate, except when the alias oracle knows better).
117 Functions like strcat on the other side adjust the whole
118 related strinfo chain.
119 They are updated lazily, so to use the chain the same first fields
120 and si->prev->next == si->idx needs to be verified. */
124 /* A flag whether the string is known to be written in the current
127 /* A flag for the next maybe_invalidate that this strinfo shouldn't
128 be invalidated. Always cleared by maybe_invalidate. */
129 bool dont_invalidate
;
132 /* Pool for allocating strinfo_struct entries. */
133 static alloc_pool strinfo_pool
;
135 /* Vector mapping positive string indexes to strinfo, for the
136 current basic block. The first pointer in the vector is special,
137 it is either NULL, meaning the vector isn't shared, or it is
138 a basic block pointer to the owner basic_block if shared.
139 If some other bb wants to modify the vector, the vector needs
140 to be unshared first, and only the owner bb is supposed to free it. */
141 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
143 /* One OFFSET->IDX mapping. */
146 struct stridxlist
*next
;
147 HOST_WIDE_INT offset
;
151 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
152 struct decl_stridxlist_map
154 struct tree_map_base base
;
155 struct stridxlist list
;
158 /* stridxlist hashtable helpers. */
160 struct stridxlist_hash_traits
: default_hashmap_traits
162 static inline hashval_t
hash (tree
);
165 /* Hash a from tree in a decl_stridxlist_map. */
168 stridxlist_hash_traits::hash (tree item
)
170 return DECL_UID (item
);
173 /* Hash table for mapping decls to a chained list of offset -> idx
175 static hash_map
<tree
, stridxlist
, stridxlist_hash_traits
>
176 *decl_to_stridxlist_htab
;
178 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
179 static struct obstack stridx_obstack
;
181 /* Last memcpy statement if it could be adjusted if the trailing
182 '\0' written is immediately overwritten, or
183 *x = '\0' store that could be removed if it is immediately overwritten. */
184 struct laststmt_struct
191 static int get_stridx_plus_constant (strinfo
, HOST_WIDE_INT
, tree
);
193 /* Return strinfo vector entry IDX. */
195 static inline strinfo
196 get_strinfo (int idx
)
198 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
200 return (*stridx_to_strinfo
)[idx
];
203 /* Helper function for get_stridx. */
206 get_addr_stridx (tree exp
)
209 struct stridxlist
*list
;
212 if (!decl_to_stridxlist_htab
)
215 base
= get_addr_base_and_unit_offset (exp
, &off
);
216 if (base
== NULL
|| !DECL_P (base
))
219 list
= decl_to_stridxlist_htab
->get (base
);
225 if (list
->offset
== off
)
233 /* Return string index for EXP. */
236 get_stridx (tree exp
)
240 if (TREE_CODE (exp
) == SSA_NAME
)
242 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
243 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
246 HOST_WIDE_INT off
= 0;
247 for (i
= 0; i
< 5; i
++)
249 gimple def_stmt
= SSA_NAME_DEF_STMT (e
);
250 if (!is_gimple_assign (def_stmt
)
251 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
253 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
254 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
255 if (TREE_CODE (rhs1
) != SSA_NAME
256 || !tree_fits_shwi_p (rhs2
))
258 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
261 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
264 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
267 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
270 && TREE_CODE (si
->length
) == INTEGER_CST
271 && compare_tree_int (si
->length
, off
) != -1)
272 return get_stridx_plus_constant (si
, off
, exp
);
279 if (TREE_CODE (exp
) == ADDR_EXPR
)
281 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
286 s
= string_constant (exp
, &o
);
288 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
289 && TREE_STRING_LENGTH (s
) > 0)
291 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
292 const char *p
= TREE_STRING_POINTER (s
);
293 int max
= TREE_STRING_LENGTH (s
) - 1;
295 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
296 return ~(int) strlen (p
+ offset
);
301 /* Return true if strinfo vector is shared with the immediate dominator. */
304 strinfo_shared (void)
306 return vec_safe_length (stridx_to_strinfo
)
307 && (*stridx_to_strinfo
)[0] != NULL
;
310 /* Unshare strinfo vector that is shared with the immediate dominator. */
313 unshare_strinfo_vec (void)
318 gcc_assert (strinfo_shared ());
319 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
320 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
323 (*stridx_to_strinfo
)[0] = NULL
;
326 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
327 Return a pointer to the location where the string index can
328 be stored (if 0) or is stored, or NULL if this can't be tracked. */
331 addr_stridxptr (tree exp
)
335 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
336 if (base
== NULL_TREE
|| !DECL_P (base
))
339 if (!decl_to_stridxlist_htab
)
341 decl_to_stridxlist_htab
342 = new hash_map
<tree
, stridxlist
, stridxlist_hash_traits
> (64);
343 gcc_obstack_init (&stridx_obstack
);
347 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
351 for (i
= 0; i
< 16; i
++)
353 if (list
->offset
== off
)
355 if (list
->next
== NULL
)
360 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
370 /* Create a new string index, or return 0 if reached limit. */
373 new_stridx (tree exp
)
376 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
378 if (TREE_CODE (exp
) == SSA_NAME
)
380 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
383 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
386 if (TREE_CODE (exp
) == ADDR_EXPR
)
388 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
391 gcc_assert (*pidx
== 0);
392 *pidx
= max_stridx
++;
399 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
402 new_addr_stridx (tree exp
)
405 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
407 pidx
= addr_stridxptr (exp
);
410 gcc_assert (*pidx
== 0);
411 *pidx
= max_stridx
++;
417 /* Create a new strinfo. */
420 new_strinfo (tree ptr
, int idx
, tree length
)
422 strinfo si
= (strinfo
) pool_alloc (strinfo_pool
);
426 si
->endptr
= NULL_TREE
;
432 si
->writable
= false;
433 si
->dont_invalidate
= false;
437 /* Decrease strinfo refcount and free it if not referenced anymore. */
440 free_strinfo (strinfo si
)
442 if (si
&& --si
->refcount
== 0)
443 pool_free (strinfo_pool
, si
);
446 /* Set strinfo in the vector entry IDX to SI. */
449 set_strinfo (int idx
, strinfo si
)
451 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
452 unshare_strinfo_vec ();
453 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
454 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
455 (*stridx_to_strinfo
)[idx
] = si
;
458 /* Return string length, or NULL if it can't be computed. */
461 get_string_length (strinfo si
)
468 gimple stmt
= si
->stmt
, lenstmt
;
469 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
470 tree callee
, lhs
, fn
, tem
;
472 gimple_stmt_iterator gsi
;
474 gcc_assert (is_gimple_call (stmt
));
475 callee
= gimple_call_fndecl (stmt
);
476 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
477 lhs
= gimple_call_lhs (stmt
);
478 /* unshare_strinfo is intentionally not called here. The (delayed)
479 transformation of strcpy or strcat into stpcpy is done at the place
480 of the former strcpy/strcat call and so can affect all the strinfos
481 with the same stmt. If they were unshared before and transformation
482 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
483 just compute the right length. */
484 switch (DECL_FUNCTION_CODE (callee
))
486 case BUILT_IN_STRCAT
:
487 case BUILT_IN_STRCAT_CHK
:
488 case BUILT_IN_STRCAT_CHKP
:
489 case BUILT_IN_STRCAT_CHK_CHKP
:
490 gsi
= gsi_for_stmt (stmt
);
491 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
492 gcc_assert (lhs
== NULL_TREE
);
493 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
496 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
497 2, tem
, gimple_call_arg (stmt
, 1));
498 gimple_call_set_with_bounds (lenstmt
, true);
501 lenstmt
= gimple_build_call (fn
, 1, tem
);
502 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
503 gimple_call_set_lhs (lenstmt
, lhs
);
504 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
505 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
506 tem
= gimple_call_arg (stmt
, 0);
507 if (!ptrofftype_p (TREE_TYPE (lhs
)))
509 lhs
= convert_to_ptrofftype (lhs
);
510 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
511 true, GSI_SAME_STMT
);
513 lenstmt
= gimple_build_assign
514 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
515 POINTER_PLUS_EXPR
,tem
, lhs
);
516 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
517 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
520 case BUILT_IN_STRCPY
:
521 case BUILT_IN_STRCPY_CHK
:
522 case BUILT_IN_STRCPY_CHKP
:
523 case BUILT_IN_STRCPY_CHK_CHKP
:
524 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
525 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
526 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
528 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
530 fn
= chkp_maybe_create_clone (fn
)->decl
;
531 gcc_assert (lhs
== NULL_TREE
);
532 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
534 fprintf (dump_file
, "Optimizing: ");
535 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
537 gimple_call_set_fndecl (stmt
, fn
);
538 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
539 gimple_call_set_lhs (stmt
, lhs
);
541 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
543 fprintf (dump_file
, "into: ");
544 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
547 case BUILT_IN_STPCPY
:
548 case BUILT_IN_STPCPY_CHK
:
549 case BUILT_IN_STPCPY_CHKP
:
550 case BUILT_IN_STPCPY_CHK_CHKP
:
551 gcc_assert (lhs
!= NULL_TREE
);
552 loc
= gimple_location (stmt
);
555 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
556 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
557 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
560 case BUILT_IN_MALLOC
:
562 /* BUILT_IN_CALLOC always has si->length set. */
572 /* Invalidate string length information for strings whose length
573 might change due to stores in stmt. */
576 maybe_invalidate (gimple stmt
)
580 bool nonempty
= false;
582 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
585 if (!si
->dont_invalidate
)
588 /* Do not use si->length. */
589 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
590 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
592 set_strinfo (i
, NULL
);
597 si
->dont_invalidate
= false;
603 /* Unshare strinfo record SI, if it has refcount > 1 or
604 if stridx_to_strinfo vector is shared with some other
608 unshare_strinfo (strinfo si
)
612 if (si
->refcount
== 1 && !strinfo_shared ())
615 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
616 nsi
->stmt
= si
->stmt
;
617 nsi
->endptr
= si
->endptr
;
618 nsi
->first
= si
->first
;
619 nsi
->prev
= si
->prev
;
620 nsi
->next
= si
->next
;
621 nsi
->writable
= si
->writable
;
622 set_strinfo (si
->idx
, nsi
);
627 /* Return first strinfo in the related strinfo chain
628 if all strinfos in between belong to the chain, otherwise
632 verify_related_strinfos (strinfo origsi
)
634 strinfo si
= origsi
, psi
;
636 if (origsi
->first
== 0)
638 for (; si
->prev
; si
= psi
)
640 if (si
->first
!= origsi
->first
)
642 psi
= get_strinfo (si
->prev
);
645 if (psi
->next
!= si
->idx
)
648 if (si
->idx
!= si
->first
)
653 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
654 strinfo if there is any. Return it's idx, or 0 if no strinfo has
658 get_stridx_plus_constant (strinfo basesi
, HOST_WIDE_INT off
, tree ptr
)
660 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
662 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
665 if (basesi
->length
== NULL_TREE
666 || TREE_CODE (basesi
->length
) != INTEGER_CST
667 || compare_tree_int (basesi
->length
, off
) == -1
668 || !tree_fits_shwi_p (basesi
->length
))
671 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
672 strinfo si
= basesi
, chainsi
;
673 if (si
->first
|| si
->prev
|| si
->next
)
674 si
= verify_related_strinfos (basesi
);
676 || si
->length
== NULL_TREE
677 || TREE_CODE (si
->length
) != INTEGER_CST
)
680 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
681 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
683 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
684 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
686 si
= get_strinfo (chainsi
->next
);
688 || si
->first
!= chainsi
->first
689 || si
->prev
!= chainsi
->idx
690 || si
->length
== NULL_TREE
691 || TREE_CODE (si
->length
) != INTEGER_CST
)
693 int r
= compare_tree_int (si
->length
, len
);
698 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
705 int idx
= new_stridx (ptr
);
708 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
709 set_strinfo (idx
, si
);
712 strinfo nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
713 si
->next
= nextsi
->idx
;
716 chainsi
= unshare_strinfo (chainsi
);
717 if (chainsi
->first
== 0)
718 chainsi
->first
= chainsi
->idx
;
720 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
721 chainsi
->endptr
= ptr
;
722 si
->endptr
= chainsi
->endptr
;
723 si
->prev
= chainsi
->idx
;
724 si
->first
= chainsi
->first
;
725 si
->writable
= chainsi
->writable
;
729 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
730 to a zero-length string and if possible chain it to a related strinfo
731 chain whose part is or might be CHAINSI. */
734 zero_length_string (tree ptr
, strinfo chainsi
)
738 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
739 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
740 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
741 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
743 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
747 si
= verify_related_strinfos (chainsi
);
751 for (; chainsi
->next
; chainsi
= si
)
753 if (chainsi
->endptr
== NULL_TREE
)
755 chainsi
= unshare_strinfo (chainsi
);
756 chainsi
->endptr
= ptr
;
758 si
= get_strinfo (chainsi
->next
);
760 || si
->first
!= chainsi
->first
761 || si
->prev
!= chainsi
->idx
)
764 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
765 if (chainsi
->endptr
== NULL_TREE
)
767 chainsi
= unshare_strinfo (chainsi
);
768 chainsi
->endptr
= ptr
;
770 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
774 chainsi
= unshare_strinfo (chainsi
);
777 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
781 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
783 chainsi
= unshare_strinfo (chainsi
);
789 idx
= new_stridx (ptr
);
792 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
793 set_strinfo (idx
, si
);
797 chainsi
= unshare_strinfo (chainsi
);
798 if (chainsi
->first
== 0)
799 chainsi
->first
= chainsi
->idx
;
801 if (chainsi
->endptr
== NULL_TREE
)
802 chainsi
->endptr
= ptr
;
803 si
->prev
= chainsi
->idx
;
804 si
->first
= chainsi
->first
;
805 si
->writable
= chainsi
->writable
;
810 /* For strinfo ORIGSI whose length has been just updated
811 update also related strinfo lengths (add ADJ to each,
812 but don't adjust ORIGSI). */
815 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
817 strinfo si
= verify_related_strinfos (origsi
);
830 si
= unshare_strinfo (si
);
833 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
834 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
835 TREE_TYPE (si
->length
), si
->length
,
838 else if (si
->stmt
!= NULL
)
839 /* Delayed length computation is unaffected. */
844 si
->endptr
= NULL_TREE
;
845 si
->dont_invalidate
= true;
849 nsi
= get_strinfo (si
->next
);
851 || nsi
->first
!= si
->first
852 || nsi
->prev
!= si
->idx
)
858 /* Find if there are other SSA_NAME pointers equal to PTR
859 for which we don't track their string lengths yet. If so, use
863 find_equal_ptrs (tree ptr
, int idx
)
865 if (TREE_CODE (ptr
) != SSA_NAME
)
869 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
870 if (!is_gimple_assign (stmt
))
872 ptr
= gimple_assign_rhs1 (stmt
);
873 switch (gimple_assign_rhs_code (stmt
))
878 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
880 if (TREE_CODE (ptr
) == SSA_NAME
)
882 if (TREE_CODE (ptr
) != ADDR_EXPR
)
887 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
888 if (pidx
!= NULL
&& *pidx
== 0)
896 /* We might find an endptr created in this pass. Grow the
897 vector in that case. */
898 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
899 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
901 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
903 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
907 /* If the last .MEM setter statement before STMT is
908 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
909 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
910 just memcpy (x, y, strlen (y)). SI must be the zero length
914 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
916 tree vuse
, callee
, len
;
917 struct laststmt_struct last
= laststmt
;
918 strinfo lastsi
, firstsi
;
919 unsigned len_arg_no
= 2;
921 laststmt
.stmt
= NULL
;
922 laststmt
.len
= NULL_TREE
;
925 if (last
.stmt
== NULL
)
928 vuse
= gimple_vuse (stmt
);
929 if (vuse
== NULL_TREE
930 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
931 || !has_single_use (vuse
))
934 gcc_assert (last
.stridx
> 0);
935 lastsi
= get_strinfo (last
.stridx
);
941 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
944 firstsi
= verify_related_strinfos (si
);
947 while (firstsi
!= lastsi
)
950 if (firstsi
->next
== 0)
952 nextsi
= get_strinfo (firstsi
->next
);
954 || nextsi
->prev
!= firstsi
->idx
955 || nextsi
->first
!= si
->first
)
963 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
967 if (is_gimple_assign (last
.stmt
))
969 gimple_stmt_iterator gsi
;
971 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
973 if (stmt_could_throw_p (last
.stmt
))
975 gsi
= gsi_for_stmt (last
.stmt
);
976 unlink_stmt_vdef (last
.stmt
);
977 release_defs (last
.stmt
);
978 gsi_remove (&gsi
, true);
982 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
985 callee
= gimple_call_fndecl (last
.stmt
);
986 switch (DECL_FUNCTION_CODE (callee
))
988 case BUILT_IN_MEMCPY
:
989 case BUILT_IN_MEMCPY_CHK
:
991 case BUILT_IN_MEMCPY_CHKP
:
992 case BUILT_IN_MEMCPY_CHK_CHKP
:
999 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
1000 if (tree_fits_uhwi_p (len
))
1002 if (!tree_fits_uhwi_p (last
.len
)
1003 || integer_zerop (len
)
1004 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
1006 /* Don't adjust the length if it is divisible by 4, it is more efficient
1007 to store the extra '\0' in that case. */
1008 if ((tree_to_uhwi (len
) & 3) == 0)
1011 else if (TREE_CODE (len
) == SSA_NAME
)
1013 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
1014 if (!is_gimple_assign (def_stmt
)
1015 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1016 || gimple_assign_rhs1 (def_stmt
) != last
.len
1017 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1023 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
1024 update_stmt (last
.stmt
);
1027 /* Handle a strlen call. If strlen of the argument is known, replace
1028 the strlen call with the known value, otherwise remember that strlen
1029 of the argument is stored in the lhs SSA_NAME. */
1032 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1036 gimple stmt
= gsi_stmt (*gsi
);
1037 tree lhs
= gimple_call_lhs (stmt
);
1039 if (lhs
== NULL_TREE
)
1042 src
= gimple_call_arg (stmt
, 0);
1043 idx
= get_stridx (src
);
1050 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1054 si
= get_strinfo (idx
);
1056 rhs
= get_string_length (si
);
1058 if (rhs
!= NULL_TREE
)
1060 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1062 fprintf (dump_file
, "Optimizing: ");
1063 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1065 rhs
= unshare_expr (rhs
);
1066 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1067 rhs
= fold_convert_loc (gimple_location (stmt
),
1068 TREE_TYPE (lhs
), rhs
);
1069 if (!update_call_from_tree (gsi
, rhs
))
1070 gimplify_and_update_call_from_tree (gsi
, rhs
);
1071 stmt
= gsi_stmt (*gsi
);
1073 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1075 fprintf (dump_file
, "into: ");
1076 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1079 && TREE_CODE (si
->length
) != SSA_NAME
1080 && TREE_CODE (si
->length
) != INTEGER_CST
1081 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1083 si
= unshare_strinfo (si
);
1089 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1092 idx
= new_stridx (src
);
1093 else if (get_strinfo (idx
) != NULL
)
1097 strinfo si
= new_strinfo (src
, idx
, lhs
);
1098 set_strinfo (idx
, si
);
1099 find_equal_ptrs (src
, idx
);
1103 /* Handle a strchr call. If strlen of the first argument is known, replace
1104 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1105 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1108 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1112 gimple stmt
= gsi_stmt (*gsi
);
1113 tree lhs
= gimple_call_lhs (stmt
);
1114 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1116 if (lhs
== NULL_TREE
)
1119 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1122 src
= gimple_call_arg (stmt
, 0);
1123 idx
= get_stridx (src
);
1130 rhs
= build_int_cst (size_type_node
, ~idx
);
1134 si
= get_strinfo (idx
);
1136 rhs
= get_string_length (si
);
1138 if (rhs
!= NULL_TREE
)
1140 location_t loc
= gimple_location (stmt
);
1142 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1144 fprintf (dump_file
, "Optimizing: ");
1145 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1147 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1149 rhs
= unshare_expr (si
->endptr
);
1150 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1152 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1156 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1157 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1158 TREE_TYPE (src
), src
, rhs
);
1159 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1161 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1163 if (!update_call_from_tree (gsi
, rhs
))
1164 gimplify_and_update_call_from_tree (gsi
, rhs
);
1165 stmt
= gsi_stmt (*gsi
);
1167 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1169 fprintf (dump_file
, "into: ");
1170 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1173 && si
->endptr
== NULL_TREE
1174 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1176 si
= unshare_strinfo (si
);
1179 zero_length_string (lhs
, si
);
1183 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1185 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1188 idx
= new_stridx (src
);
1189 else if (get_strinfo (idx
) != NULL
)
1191 zero_length_string (lhs
, NULL
);
1196 location_t loc
= gimple_location (stmt
);
1197 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1198 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1199 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1200 size_type_node
, lhsu
, srcu
);
1201 strinfo si
= new_strinfo (src
, idx
, length
);
1203 set_strinfo (idx
, si
);
1204 find_equal_ptrs (src
, idx
);
1205 zero_length_string (lhs
, si
);
1209 zero_length_string (lhs
, NULL
);
1212 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1213 If strlen of the second argument is known, strlen of the first argument
1214 is the same after this call. Furthermore, attempt to convert it to
1218 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1221 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1223 gimple stmt
= gsi_stmt (*gsi
);
1224 strinfo si
, dsi
, olddsi
, zsi
;
1226 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1228 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1229 dst
= gimple_call_arg (stmt
, 0);
1230 lhs
= gimple_call_lhs (stmt
);
1231 idx
= get_stridx (src
);
1234 si
= get_strinfo (idx
);
1236 didx
= get_stridx (dst
);
1240 olddsi
= get_strinfo (didx
);
1245 adjust_last_stmt (olddsi
, stmt
, false);
1249 srclen
= get_string_length (si
);
1251 srclen
= build_int_cst (size_type_node
, ~idx
);
1253 loc
= gimple_location (stmt
);
1254 if (srclen
== NULL_TREE
)
1257 case BUILT_IN_STRCPY
:
1258 case BUILT_IN_STRCPY_CHK
:
1259 case BUILT_IN_STRCPY_CHKP
:
1260 case BUILT_IN_STRCPY_CHK_CHKP
:
1261 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1264 case BUILT_IN_STPCPY
:
1265 case BUILT_IN_STPCPY_CHK
:
1266 case BUILT_IN_STPCPY_CHKP
:
1267 case BUILT_IN_STPCPY_CHK_CHKP
:
1268 if (lhs
== NULL_TREE
)
1272 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1273 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1274 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1284 didx
= new_stridx (dst
);
1290 oldlen
= olddsi
->length
;
1291 dsi
= unshare_strinfo (olddsi
);
1292 dsi
->length
= srclen
;
1293 /* Break the chain, so adjust_related_strinfo on later pointers in
1294 the chain won't adjust this one anymore. */
1297 dsi
->endptr
= NULL_TREE
;
1301 dsi
= new_strinfo (dst
, didx
, srclen
);
1302 set_strinfo (didx
, dsi
);
1303 find_equal_ptrs (dst
, didx
);
1305 dsi
->writable
= true;
1306 dsi
->dont_invalidate
= true;
1308 if (dsi
->length
== NULL_TREE
)
1312 /* If string length of src is unknown, use delayed length
1313 computation. If string lenth of dst will be needed, it
1314 can be computed by transforming this strcpy call into
1315 stpcpy and subtracting dst from the return value. */
1317 /* Look for earlier strings whose length could be determined if
1318 this strcpy is turned into an stpcpy. */
1320 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1322 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1324 /* When setting a stmt for delayed length computation
1325 prevent all strinfos through dsi from being
1327 chainsi
= unshare_strinfo (chainsi
);
1328 chainsi
->stmt
= stmt
;
1329 chainsi
->length
= NULL_TREE
;
1330 chainsi
->endptr
= NULL_TREE
;
1331 chainsi
->dont_invalidate
= true;
1340 tree adj
= NULL_TREE
;
1341 if (oldlen
== NULL_TREE
)
1343 else if (integer_zerop (oldlen
))
1345 else if (TREE_CODE (oldlen
) == INTEGER_CST
1346 || TREE_CODE (srclen
) == INTEGER_CST
)
1347 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1348 TREE_TYPE (srclen
), srclen
,
1349 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1351 if (adj
!= NULL_TREE
)
1352 adjust_related_strinfos (loc
, dsi
, adj
);
1356 /* strcpy src may not overlap dst, so src doesn't need to be
1357 invalidated either. */
1359 si
->dont_invalidate
= true;
1365 case BUILT_IN_STRCPY
:
1366 case BUILT_IN_STRCPY_CHKP
:
1367 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1369 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1371 case BUILT_IN_STRCPY_CHK
:
1372 case BUILT_IN_STRCPY_CHK_CHKP
:
1373 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1375 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1377 case BUILT_IN_STPCPY
:
1378 case BUILT_IN_STPCPY_CHKP
:
1379 /* This would need adjustment of the lhs (subtract one),
1380 or detection that the trailing '\0' doesn't need to be
1381 written, if it will be immediately overwritten.
1382 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1386 zsi
= zero_length_string (lhs
, dsi
);
1389 case BUILT_IN_STPCPY_CHK
:
1390 case BUILT_IN_STPCPY_CHK_CHKP
:
1391 /* This would need adjustment of the lhs (subtract one),
1392 or detection that the trailing '\0' doesn't need to be
1393 written, if it will be immediately overwritten.
1394 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1398 zsi
= zero_length_string (lhs
, dsi
);
1405 zsi
->dont_invalidate
= true;
1407 if (fn
== NULL_TREE
)
1410 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1411 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1413 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1414 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1415 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1417 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1419 fprintf (dump_file
, "Optimizing: ");
1420 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1424 fn
= chkp_maybe_create_clone (fn
)->decl
;
1425 if (gimple_call_num_args (stmt
) == 4)
1426 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1427 gimple_call_arg (stmt
, 1),
1429 gimple_call_arg (stmt
, 3),
1432 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1433 gimple_call_arg (stmt
, 1),
1435 gimple_call_arg (stmt
, 3),
1437 gimple_call_arg (stmt
, 4));
1440 if (gimple_call_num_args (stmt
) == 2)
1441 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1443 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1444 gimple_call_arg (stmt
, 2));
1447 stmt
= gsi_stmt (*gsi
);
1448 gimple_call_set_with_bounds (stmt
, with_bounds
);
1450 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1452 fprintf (dump_file
, "into: ");
1453 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1455 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1456 laststmt
.stmt
= stmt
;
1457 laststmt
.len
= srclen
;
1458 laststmt
.stridx
= dsi
->idx
;
1460 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1461 fprintf (dump_file
, "not possible.\n");
1464 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1465 If strlen of the second argument is known and length of the third argument
1466 is that plus one, strlen of the first argument is the same after this
1470 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1473 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1474 gimple stmt
= gsi_stmt (*gsi
);
1475 strinfo si
, dsi
, olddsi
;
1476 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1478 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1479 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1480 dst
= gimple_call_arg (stmt
, 0);
1481 idx
= get_stridx (src
);
1485 didx
= get_stridx (dst
);
1488 olddsi
= get_strinfo (didx
);
1493 && tree_fits_uhwi_p (len
)
1494 && !integer_zerop (len
))
1495 adjust_last_stmt (olddsi
, stmt
, false);
1501 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1502 si
= get_strinfo (idx
);
1503 if (si
== NULL
|| si
->length
== NULL_TREE
)
1505 if (TREE_CODE (len
) != SSA_NAME
)
1507 def_stmt
= SSA_NAME_DEF_STMT (len
);
1508 if (!is_gimple_assign (def_stmt
)
1509 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1510 || gimple_assign_rhs1 (def_stmt
) != si
->length
1511 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1517 /* Handle memcpy (x, "abcd", 5) or
1518 memcpy (x, "abc\0uvw", 7). */
1519 if (!tree_fits_uhwi_p (len
)
1520 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1524 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1525 adjust_last_stmt (olddsi
, stmt
, false);
1529 didx
= new_stridx (dst
);
1534 newlen
= si
->length
;
1536 newlen
= build_int_cst (size_type_node
, ~idx
);
1540 dsi
= unshare_strinfo (olddsi
);
1541 oldlen
= olddsi
->length
;
1542 dsi
->length
= newlen
;
1543 /* Break the chain, so adjust_related_strinfo on later pointers in
1544 the chain won't adjust this one anymore. */
1547 dsi
->endptr
= NULL_TREE
;
1551 dsi
= new_strinfo (dst
, didx
, newlen
);
1552 set_strinfo (didx
, dsi
);
1553 find_equal_ptrs (dst
, didx
);
1555 dsi
->writable
= true;
1556 dsi
->dont_invalidate
= true;
1559 tree adj
= NULL_TREE
;
1560 location_t loc
= gimple_location (stmt
);
1561 if (oldlen
== NULL_TREE
)
1563 else if (integer_zerop (oldlen
))
1565 else if (TREE_CODE (oldlen
) == INTEGER_CST
1566 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1567 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1568 TREE_TYPE (dsi
->length
), dsi
->length
,
1569 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1571 if (adj
!= NULL_TREE
)
1572 adjust_related_strinfos (loc
, dsi
, adj
);
1576 /* memcpy src may not overlap dst, so src doesn't need to be
1577 invalidated either. */
1579 si
->dont_invalidate
= true;
1581 lhs
= gimple_call_lhs (stmt
);
1584 case BUILT_IN_MEMCPY
:
1585 case BUILT_IN_MEMCPY_CHK
:
1586 case BUILT_IN_MEMCPY_CHKP
:
1587 case BUILT_IN_MEMCPY_CHK_CHKP
:
1588 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1589 laststmt
.stmt
= stmt
;
1590 laststmt
.len
= dsi
->length
;
1591 laststmt
.stridx
= dsi
->idx
;
1593 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1595 case BUILT_IN_MEMPCPY
:
1596 case BUILT_IN_MEMPCPY_CHK
:
1597 case BUILT_IN_MEMPCPY_CHKP
:
1598 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1605 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1606 If strlen of the second argument is known, strlen of the first argument
1607 is increased by the length of the second argument. Furthermore, attempt
1608 to convert it to memcpy/strcpy if the length of the first argument
1612 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1615 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1617 gimple stmt
= gsi_stmt (*gsi
);
1620 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1622 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1623 dst
= gimple_call_arg (stmt
, 0);
1624 lhs
= gimple_call_lhs (stmt
);
1626 didx
= get_stridx (dst
);
1632 dsi
= get_strinfo (didx
);
1633 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1635 /* strcat (p, q) can be transformed into
1636 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1637 with length endptr - p if we need to compute the length
1638 later on. Don't do this transformation if we don't need
1640 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1644 didx
= new_stridx (dst
);
1650 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1651 set_strinfo (didx
, dsi
);
1652 find_equal_ptrs (dst
, didx
);
1656 dsi
= unshare_strinfo (dsi
);
1657 dsi
->length
= NULL_TREE
;
1659 dsi
->endptr
= NULL_TREE
;
1661 dsi
->writable
= true;
1663 dsi
->dont_invalidate
= true;
1670 idx
= get_stridx (src
);
1672 srclen
= build_int_cst (size_type_node
, ~idx
);
1675 si
= get_strinfo (idx
);
1677 srclen
= get_string_length (si
);
1680 loc
= gimple_location (stmt
);
1681 dstlen
= dsi
->length
;
1682 endptr
= dsi
->endptr
;
1684 dsi
= unshare_strinfo (dsi
);
1685 dsi
->endptr
= NULL_TREE
;
1687 dsi
->writable
= true;
1689 if (srclen
!= NULL_TREE
)
1691 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1692 dsi
->length
, srclen
);
1693 adjust_related_strinfos (loc
, dsi
, srclen
);
1694 dsi
->dont_invalidate
= true;
1699 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1700 dsi
->dont_invalidate
= true;
1704 /* strcat src may not overlap dst, so src doesn't need to be
1705 invalidated either. */
1706 si
->dont_invalidate
= true;
1708 /* For now. Could remove the lhs from the call and add
1709 lhs = dst; afterwards. */
1717 case BUILT_IN_STRCAT
:
1718 case BUILT_IN_STRCAT_CHKP
:
1719 if (srclen
!= NULL_TREE
)
1720 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1722 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1724 case BUILT_IN_STRCAT_CHK
:
1725 case BUILT_IN_STRCAT_CHK_CHKP
:
1726 if (srclen
!= NULL_TREE
)
1727 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1729 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1730 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1736 if (fn
== NULL_TREE
)
1740 if (srclen
!= NULL_TREE
)
1742 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1743 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1745 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1746 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1747 build_int_cst (type
, 1));
1748 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1752 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1754 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1755 TREE_TYPE (dst
), unshare_expr (dst
),
1756 fold_convert_loc (loc
, sizetype
,
1757 unshare_expr (dstlen
)));
1758 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1760 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1762 fprintf (dump_file
, "Optimizing: ");
1763 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1767 fn
= chkp_maybe_create_clone (fn
)->decl
;
1768 if (srclen
!= NULL_TREE
)
1769 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1771 gimple_call_arg (stmt
, 1),
1773 gimple_call_arg (stmt
, 3),
1776 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1778 gimple_call_arg (stmt
, 1),
1780 gimple_call_arg (stmt
, 3),
1784 if (srclen
!= NULL_TREE
)
1785 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1786 dst
, src
, len
, objsz
);
1788 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1792 stmt
= gsi_stmt (*gsi
);
1793 gimple_call_set_with_bounds (stmt
, with_bounds
);
1795 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1797 fprintf (dump_file
, "into: ");
1798 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1800 /* If srclen == NULL, note that current string length can be
1801 computed by transforming this strcpy into stpcpy. */
1802 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1804 adjust_last_stmt (dsi
, stmt
, true);
1805 if (srclen
!= NULL_TREE
)
1807 laststmt
.stmt
= stmt
;
1808 laststmt
.len
= srclen
;
1809 laststmt
.stridx
= dsi
->idx
;
1812 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1813 fprintf (dump_file
, "not possible.\n");
1816 /* Handle a call to malloc or calloc. */
1819 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1821 gimple stmt
= gsi_stmt (*gsi
);
1822 tree lhs
= gimple_call_lhs (stmt
);
1823 gcc_assert (get_stridx (lhs
) == 0);
1824 int idx
= new_stridx (lhs
);
1825 tree length
= NULL_TREE
;
1826 if (bcode
== BUILT_IN_CALLOC
)
1827 length
= build_int_cst (size_type_node
, 0);
1828 strinfo si
= new_strinfo (lhs
, idx
, length
);
1829 if (bcode
== BUILT_IN_CALLOC
)
1831 set_strinfo (idx
, si
);
1832 si
->writable
= true;
1834 si
->dont_invalidate
= true;
1837 /* Handle a call to memset.
1838 After a call to calloc, memset(,0,) is unnecessary.
1839 memset(malloc(n),0,n) is calloc(n,1). */
1842 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1844 gimple stmt2
= gsi_stmt (*gsi
);
1845 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1847 tree ptr
= gimple_call_arg (stmt2
, 0);
1848 int idx1
= get_stridx (ptr
);
1851 strinfo si1
= get_strinfo (idx1
);
1854 gimple stmt1
= si1
->stmt
;
1855 if (!stmt1
|| !is_gimple_call (stmt1
))
1857 tree callee1
= gimple_call_fndecl (stmt1
);
1858 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1860 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1861 tree size
= gimple_call_arg (stmt2
, 2);
1862 if (code1
== BUILT_IN_CALLOC
)
1863 /* Not touching stmt1 */ ;
1864 else if (code1
== BUILT_IN_MALLOC
1865 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1867 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1868 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1869 size
, build_one_cst (size_type_node
));
1870 si1
->length
= build_int_cst (size_type_node
, 0);
1871 si1
->stmt
= gsi_stmt (gsi1
);
1875 tree lhs
= gimple_call_lhs (stmt2
);
1876 unlink_stmt_vdef (stmt2
);
1879 gimple assign
= gimple_build_assign (lhs
, ptr
);
1880 gsi_replace (gsi
, assign
, false);
1884 gsi_remove (gsi
, true);
1885 release_defs (stmt2
);
1891 /* Handle a POINTER_PLUS_EXPR statement.
1892 For p = "abcd" + 2; compute associated length, or if
1893 p = q + off is pointing to a '\0' character of a string, call
1894 zero_length_string on it. */
1897 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1899 gimple stmt
= gsi_stmt (*gsi
);
1900 tree lhs
= gimple_assign_lhs (stmt
), off
;
1901 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1909 tree off
= gimple_assign_rhs2 (stmt
);
1910 if (tree_fits_uhwi_p (off
)
1911 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1912 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1913 = ~(~idx
- (int) tree_to_uhwi (off
));
1917 si
= get_strinfo (idx
);
1918 if (si
== NULL
|| si
->length
== NULL_TREE
)
1921 off
= gimple_assign_rhs2 (stmt
);
1923 if (operand_equal_p (si
->length
, off
, 0))
1924 zsi
= zero_length_string (lhs
, si
);
1925 else if (TREE_CODE (off
) == SSA_NAME
)
1927 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1928 if (gimple_assign_single_p (def_stmt
)
1929 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1930 zsi
= zero_length_string (lhs
, si
);
1933 && si
->endptr
!= NULL_TREE
1934 && si
->endptr
!= lhs
1935 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1937 enum tree_code rhs_code
1938 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1939 ? SSA_NAME
: NOP_EXPR
;
1940 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1941 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1946 /* Handle a single character store. */
1949 handle_char_store (gimple_stmt_iterator
*gsi
)
1953 gimple stmt
= gsi_stmt (*gsi
);
1954 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1956 if (TREE_CODE (lhs
) == MEM_REF
1957 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1959 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1961 ssaname
= TREE_OPERAND (lhs
, 0);
1962 idx
= get_stridx (ssaname
);
1966 idx
= get_addr_stridx (lhs
);
1970 si
= get_strinfo (idx
);
1971 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1973 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1975 /* When storing '\0', the store can be removed
1976 if we know it has been stored in the current function. */
1977 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1979 unlink_stmt_vdef (stmt
);
1980 release_defs (stmt
);
1981 gsi_remove (gsi
, true);
1986 si
->writable
= true;
1992 /* Otherwise this statement overwrites the '\0' with
1993 something, if the previous stmt was a memcpy,
1994 its length may be decreased. */
1995 adjust_last_stmt (si
, stmt
, false);
1997 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
1999 si
= unshare_strinfo (si
);
2000 si
->length
= build_int_cst (size_type_node
, 0);
2006 si
->writable
= true;
2007 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2008 si
->endptr
= ssaname
;
2009 si
->dont_invalidate
= true;
2011 /* If si->length is non-zero constant, we aren't overwriting '\0',
2012 and if we aren't storing '\0', we know that the length of the
2013 string and any other zero terminated string in memory remains
2014 the same. In that case we move to the next gimple statement and
2015 return to signal the caller that it shouldn't invalidate anything.
2017 This is benefical for cases like:
2022 strcpy (p, "foobar");
2023 size_t len = strlen (p); // This can be optimized into 6
2024 size_t len2 = strlen (q); // This has to be computed
2026 size_t len3 = strlen (p); // This can be optimized into 6
2027 size_t len4 = strlen (q); // This can be optimized into len2
2028 bar (len, len2, len3, len4);
2031 else if (si
!= NULL
&& si
->length
!= NULL_TREE
2032 && TREE_CODE (si
->length
) == INTEGER_CST
2033 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2039 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2043 si
= zero_length_string (ssaname
, NULL
);
2045 si
->dont_invalidate
= true;
2049 int idx
= new_addr_stridx (lhs
);
2052 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2053 build_int_cst (size_type_node
, 0));
2054 set_strinfo (idx
, si
);
2055 si
->dont_invalidate
= true;
2059 si
->writable
= true;
2062 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2063 && ssaname
== NULL_TREE
2064 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2066 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2067 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2068 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2070 int idx
= new_addr_stridx (lhs
);
2073 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2074 build_int_cst (size_type_node
, l
));
2075 set_strinfo (idx
, si
);
2076 si
->dont_invalidate
= true;
2081 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2083 /* Allow adjust_last_stmt to remove it if the stored '\0'
2084 is immediately overwritten. */
2085 laststmt
.stmt
= stmt
;
2086 laststmt
.len
= build_int_cst (size_type_node
, 1);
2087 laststmt
.stridx
= si
->idx
;
2092 /* Attempt to optimize a single statement at *GSI using string length
2096 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2098 gimple stmt
= gsi_stmt (*gsi
);
2100 if (is_gimple_call (stmt
))
2102 tree callee
= gimple_call_fndecl (stmt
);
2103 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2104 switch (DECL_FUNCTION_CODE (callee
))
2106 case BUILT_IN_STRLEN
:
2107 case BUILT_IN_STRLEN_CHKP
:
2108 handle_builtin_strlen (gsi
);
2110 case BUILT_IN_STRCHR
:
2111 case BUILT_IN_STRCHR_CHKP
:
2112 handle_builtin_strchr (gsi
);
2114 case BUILT_IN_STRCPY
:
2115 case BUILT_IN_STRCPY_CHK
:
2116 case BUILT_IN_STPCPY
:
2117 case BUILT_IN_STPCPY_CHK
:
2118 case BUILT_IN_STRCPY_CHKP
:
2119 case BUILT_IN_STRCPY_CHK_CHKP
:
2120 case BUILT_IN_STPCPY_CHKP
:
2121 case BUILT_IN_STPCPY_CHK_CHKP
:
2122 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2124 case BUILT_IN_MEMCPY
:
2125 case BUILT_IN_MEMCPY_CHK
:
2126 case BUILT_IN_MEMPCPY
:
2127 case BUILT_IN_MEMPCPY_CHK
:
2128 case BUILT_IN_MEMCPY_CHKP
:
2129 case BUILT_IN_MEMCPY_CHK_CHKP
:
2130 case BUILT_IN_MEMPCPY_CHKP
:
2131 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2132 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2134 case BUILT_IN_STRCAT
:
2135 case BUILT_IN_STRCAT_CHK
:
2136 case BUILT_IN_STRCAT_CHKP
:
2137 case BUILT_IN_STRCAT_CHK_CHKP
:
2138 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2140 case BUILT_IN_MALLOC
:
2141 case BUILT_IN_CALLOC
:
2142 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2144 case BUILT_IN_MEMSET
:
2145 if (!handle_builtin_memset (gsi
))
2152 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2154 tree lhs
= gimple_assign_lhs (stmt
);
2156 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2158 if (gimple_assign_single_p (stmt
)
2159 || (gimple_assign_cast_p (stmt
)
2160 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2162 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2163 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2165 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2166 handle_pointer_plus (gsi
);
2168 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2170 tree type
= TREE_TYPE (lhs
);
2171 if (TREE_CODE (type
) == ARRAY_TYPE
)
2172 type
= TREE_TYPE (type
);
2173 if (TREE_CODE (type
) == INTEGER_TYPE
2174 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2175 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2177 if (! handle_char_store (gsi
))
2183 if (gimple_vdef (stmt
))
2184 maybe_invalidate (stmt
);
2188 /* Recursively call maybe_invalidate on stmts that might be executed
2189 in between dombb and current bb and that contain a vdef. Stop when
2190 *count stmts are inspected, or if the whole strinfo vector has
2191 been invalidated. */
2194 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
2196 unsigned int i
, n
= gimple_phi_num_args (phi
);
2198 for (i
= 0; i
< n
; i
++)
2200 tree vuse
= gimple_phi_arg_def (phi
, i
);
2201 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
2202 basic_block bb
= gimple_bb (stmt
);
2205 || !bitmap_set_bit (visited
, bb
->index
)
2206 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2210 if (gimple_code (stmt
) == GIMPLE_PHI
)
2212 do_invalidate (dombb
, stmt
, visited
, count
);
2219 if (!maybe_invalidate (stmt
))
2224 vuse
= gimple_vuse (stmt
);
2225 stmt
= SSA_NAME_DEF_STMT (vuse
);
2226 if (gimple_bb (stmt
) != bb
)
2228 bb
= gimple_bb (stmt
);
2231 || !bitmap_set_bit (visited
, bb
->index
)
2232 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2239 class strlen_dom_walker
: public dom_walker
2242 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2244 virtual void before_dom_children (basic_block
);
2245 virtual void after_dom_children (basic_block
);
2248 /* Callback for walk_dominator_tree. Attempt to optimize various
2249 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2252 strlen_dom_walker::before_dom_children (basic_block bb
)
2254 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2257 stridx_to_strinfo
= NULL
;
2260 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
2261 if (stridx_to_strinfo
)
2263 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2266 gphi
*phi
= gsi
.phi ();
2267 if (virtual_operand_p (gimple_phi_result (phi
)))
2269 bitmap visited
= BITMAP_ALLOC (NULL
);
2270 int count_vdef
= 100;
2271 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2272 BITMAP_FREE (visited
);
2273 if (count_vdef
== 0)
2275 /* If there were too many vdefs in between immediate
2276 dominator and current bb, invalidate everything.
2277 If stridx_to_strinfo has been unshared, we need
2278 to free it, otherwise just set it to NULL. */
2279 if (!strinfo_shared ())
2285 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2289 (*stridx_to_strinfo
)[i
] = NULL
;
2293 stridx_to_strinfo
= NULL
;
2301 /* If all PHI arguments have the same string index, the PHI result
2303 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2306 gphi
*phi
= gsi
.phi ();
2307 tree result
= gimple_phi_result (phi
);
2308 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2310 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2313 unsigned int i
, n
= gimple_phi_num_args (phi
);
2314 for (i
= 1; i
< n
; i
++)
2315 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2318 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2323 /* Attempt to optimize individual statements. */
2324 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2325 if (strlen_optimize_stmt (&gsi
))
2328 bb
->aux
= stridx_to_strinfo
;
2329 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2330 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2333 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2334 owned by the current bb, clear bb->aux. */
2337 strlen_dom_walker::after_dom_children (basic_block bb
)
2341 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2342 if (vec_safe_length (stridx_to_strinfo
)
2343 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2348 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2350 vec_free (stridx_to_strinfo
);
2356 /* Main entry point. */
2360 const pass_data pass_data_strlen
=
2362 GIMPLE_PASS
, /* type */
2363 "strlen", /* name */
2364 OPTGROUP_NONE
, /* optinfo_flags */
2365 TV_TREE_STRLEN
, /* tv_id */
2366 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2367 0, /* properties_provided */
2368 0, /* properties_destroyed */
2369 0, /* todo_flags_start */
2370 0, /* todo_flags_finish */
2373 class pass_strlen
: public gimple_opt_pass
2376 pass_strlen (gcc::context
*ctxt
)
2377 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2380 /* opt_pass methods: */
2381 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2382 virtual unsigned int execute (function
*);
2384 }; // class pass_strlen
2387 pass_strlen::execute (function
*fun
)
2389 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2391 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
2392 sizeof (struct strinfo_struct
), 64);
2394 calculate_dominance_info (CDI_DOMINATORS
);
2396 /* String length optimization is implemented as a walk of the dominator
2397 tree and a forward walk of statements within each block. */
2398 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2400 ssa_ver_to_stridx
.release ();
2401 free_alloc_pool (strinfo_pool
);
2402 if (decl_to_stridxlist_htab
)
2404 obstack_free (&stridx_obstack
, NULL
);
2405 delete decl_to_stridxlist_htab
;
2406 decl_to_stridxlist_htab
= NULL
;
2408 laststmt
.stmt
= NULL
;
2409 laststmt
.len
= NULL_TREE
;
2410 laststmt
.stridx
= 0;
2418 make_pass_strlen (gcc::context
*ctxt
)
2420 return new pass_strlen (ctxt
);