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"
44 #include "dominance.h"
46 #include "basic-block.h"
47 #include "tree-ssa-alias.h"
48 #include "internal-fn.h"
49 #include "gimple-fold.h"
51 #include "gimple-expr.h"
55 #include "gimple-iterator.h"
56 #include "gimplify-me.h"
57 #include "gimple-ssa.h"
58 #include "tree-phinodes.h"
59 #include "ssa-iterators.h"
60 #include "stringpool.h"
61 #include "tree-ssanames.h"
65 #include "statistics.h"
67 #include "fixed-value.h"
68 #include "insn-config.h"
78 #include "tree-pass.h"
80 #include "alloc-pool.h"
81 #include "tree-ssa-propagate.h"
82 #include "gimple-pretty-print.h"
84 #include "plugin-api.h"
89 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
90 is an index into strinfo vector, negative value stands for
91 string length of a string literal (~strlen). */
92 static vec
<int> ssa_ver_to_stridx
;
94 /* Number of currently active string indexes plus one. */
95 static int max_stridx
;
97 /* String information record. */
98 typedef struct strinfo_struct
100 /* String length of this string. */
102 /* Any of the corresponding pointers for querying alias oracle. */
104 /* Statement for delayed length computation. */
106 /* Pointer to '\0' if known, if NULL, it can be computed as
109 /* Reference count. Any changes to strinfo entry possibly shared
110 with dominating basic blocks need unshare_strinfo first, except
111 for dont_invalidate which affects only the immediately next
114 /* Copy of index. get_strinfo (si->idx) should return si; */
116 /* These 3 fields are for chaining related string pointers together.
118 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
119 strcpy (c, d); e = c + dl;
120 strinfo(a) -> strinfo(c) -> strinfo(e)
121 All have ->first field equal to strinfo(a)->idx and are doubly
122 chained through prev/next fields. The later strinfos are required
123 to point into the same string with zero or more bytes after
124 the previous pointer and all bytes in between the two pointers
125 must be non-zero. Functions like strcpy or memcpy are supposed
126 to adjust all previous strinfo lengths, but not following strinfo
127 lengths (those are uncertain, usually invalidated during
128 maybe_invalidate, except when the alias oracle knows better).
129 Functions like strcat on the other side adjust the whole
130 related strinfo chain.
131 They are updated lazily, so to use the chain the same first fields
132 and si->prev->next == si->idx needs to be verified. */
136 /* A flag whether the string is known to be written in the current
139 /* A flag for the next maybe_invalidate that this strinfo shouldn't
140 be invalidated. Always cleared by maybe_invalidate. */
141 bool dont_invalidate
;
144 /* Pool for allocating strinfo_struct entries. */
145 static alloc_pool strinfo_pool
;
147 /* Vector mapping positive string indexes to strinfo, for the
148 current basic block. The first pointer in the vector is special,
149 it is either NULL, meaning the vector isn't shared, or it is
150 a basic block pointer to the owner basic_block if shared.
151 If some other bb wants to modify the vector, the vector needs
152 to be unshared first, and only the owner bb is supposed to free it. */
153 static vec
<strinfo
, va_heap
, vl_embed
> *stridx_to_strinfo
;
155 /* One OFFSET->IDX mapping. */
158 struct stridxlist
*next
;
159 HOST_WIDE_INT offset
;
163 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
164 struct decl_stridxlist_map
166 struct tree_map_base base
;
167 struct stridxlist list
;
170 /* stridxlist hashtable helpers. */
172 struct stridxlist_hash_traits
: default_hashmap_traits
174 static inline hashval_t
hash (tree
);
177 /* Hash a from tree in a decl_stridxlist_map. */
180 stridxlist_hash_traits::hash (tree item
)
182 return DECL_UID (item
);
185 /* Hash table for mapping decls to a chained list of offset -> idx
187 static hash_map
<tree
, stridxlist
, stridxlist_hash_traits
>
188 *decl_to_stridxlist_htab
;
190 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
191 static struct obstack stridx_obstack
;
193 /* Last memcpy statement if it could be adjusted if the trailing
194 '\0' written is immediately overwritten, or
195 *x = '\0' store that could be removed if it is immediately overwritten. */
196 struct laststmt_struct
203 static int get_stridx_plus_constant (strinfo
, HOST_WIDE_INT
, tree
);
205 /* Return strinfo vector entry IDX. */
207 static inline strinfo
208 get_strinfo (int idx
)
210 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
212 return (*stridx_to_strinfo
)[idx
];
215 /* Helper function for get_stridx. */
218 get_addr_stridx (tree exp
)
221 struct stridxlist
*list
;
224 if (!decl_to_stridxlist_htab
)
227 base
= get_addr_base_and_unit_offset (exp
, &off
);
228 if (base
== NULL
|| !DECL_P (base
))
231 list
= decl_to_stridxlist_htab
->get (base
);
237 if (list
->offset
== off
)
245 /* Return string index for EXP. */
248 get_stridx (tree exp
)
252 if (TREE_CODE (exp
) == SSA_NAME
)
254 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
255 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
258 HOST_WIDE_INT off
= 0;
259 for (i
= 0; i
< 5; i
++)
261 gimple def_stmt
= SSA_NAME_DEF_STMT (e
);
262 if (!is_gimple_assign (def_stmt
)
263 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
265 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
266 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
267 if (TREE_CODE (rhs1
) != SSA_NAME
268 || !tree_fits_shwi_p (rhs2
))
270 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
273 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
276 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
279 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
282 && TREE_CODE (si
->length
) == INTEGER_CST
283 && compare_tree_int (si
->length
, off
) != -1)
284 return get_stridx_plus_constant (si
, off
, exp
);
291 if (TREE_CODE (exp
) == ADDR_EXPR
)
293 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0));
298 s
= string_constant (exp
, &o
);
300 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
301 && TREE_STRING_LENGTH (s
) > 0)
303 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
304 const char *p
= TREE_STRING_POINTER (s
);
305 int max
= TREE_STRING_LENGTH (s
) - 1;
307 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
308 return ~(int) strlen (p
+ offset
);
313 /* Return true if strinfo vector is shared with the immediate dominator. */
316 strinfo_shared (void)
318 return vec_safe_length (stridx_to_strinfo
)
319 && (*stridx_to_strinfo
)[0] != NULL
;
322 /* Unshare strinfo vector that is shared with the immediate dominator. */
325 unshare_strinfo_vec (void)
330 gcc_assert (strinfo_shared ());
331 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
332 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
335 (*stridx_to_strinfo
)[0] = NULL
;
338 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
339 Return a pointer to the location where the string index can
340 be stored (if 0) or is stored, or NULL if this can't be tracked. */
343 addr_stridxptr (tree exp
)
347 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
348 if (base
== NULL_TREE
|| !DECL_P (base
))
351 if (!decl_to_stridxlist_htab
)
353 decl_to_stridxlist_htab
354 = new hash_map
<tree
, stridxlist
, stridxlist_hash_traits
> (64);
355 gcc_obstack_init (&stridx_obstack
);
359 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
363 for (i
= 0; i
< 16; i
++)
365 if (list
->offset
== off
)
367 if (list
->next
== NULL
)
372 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
382 /* Create a new string index, or return 0 if reached limit. */
385 new_stridx (tree exp
)
388 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
390 if (TREE_CODE (exp
) == SSA_NAME
)
392 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
395 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
398 if (TREE_CODE (exp
) == ADDR_EXPR
)
400 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
403 gcc_assert (*pidx
== 0);
404 *pidx
= max_stridx
++;
411 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
414 new_addr_stridx (tree exp
)
417 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
419 pidx
= addr_stridxptr (exp
);
422 gcc_assert (*pidx
== 0);
423 *pidx
= max_stridx
++;
429 /* Create a new strinfo. */
432 new_strinfo (tree ptr
, int idx
, tree length
)
434 strinfo si
= (strinfo
) pool_alloc (strinfo_pool
);
438 si
->endptr
= NULL_TREE
;
444 si
->writable
= false;
445 si
->dont_invalidate
= false;
449 /* Decrease strinfo refcount and free it if not referenced anymore. */
452 free_strinfo (strinfo si
)
454 if (si
&& --si
->refcount
== 0)
455 pool_free (strinfo_pool
, si
);
458 /* Set strinfo in the vector entry IDX to SI. */
461 set_strinfo (int idx
, strinfo si
)
463 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
464 unshare_strinfo_vec ();
465 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
466 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
467 (*stridx_to_strinfo
)[idx
] = si
;
470 /* Return string length, or NULL if it can't be computed. */
473 get_string_length (strinfo si
)
480 gimple stmt
= si
->stmt
, lenstmt
;
481 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
482 tree callee
, lhs
, fn
, tem
;
484 gimple_stmt_iterator gsi
;
486 gcc_assert (is_gimple_call (stmt
));
487 callee
= gimple_call_fndecl (stmt
);
488 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
489 lhs
= gimple_call_lhs (stmt
);
490 /* unshare_strinfo is intentionally not called here. The (delayed)
491 transformation of strcpy or strcat into stpcpy is done at the place
492 of the former strcpy/strcat call and so can affect all the strinfos
493 with the same stmt. If they were unshared before and transformation
494 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
495 just compute the right length. */
496 switch (DECL_FUNCTION_CODE (callee
))
498 case BUILT_IN_STRCAT
:
499 case BUILT_IN_STRCAT_CHK
:
500 case BUILT_IN_STRCAT_CHKP
:
501 case BUILT_IN_STRCAT_CHK_CHKP
:
502 gsi
= gsi_for_stmt (stmt
);
503 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
504 gcc_assert (lhs
== NULL_TREE
);
505 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
508 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
509 2, tem
, gimple_call_arg (stmt
, 1));
510 gimple_call_set_with_bounds (lenstmt
, true);
513 lenstmt
= gimple_build_call (fn
, 1, tem
);
514 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
515 gimple_call_set_lhs (lenstmt
, lhs
);
516 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
517 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
518 tem
= gimple_call_arg (stmt
, 0);
519 if (!ptrofftype_p (TREE_TYPE (lhs
)))
521 lhs
= convert_to_ptrofftype (lhs
);
522 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
523 true, GSI_SAME_STMT
);
525 lenstmt
= gimple_build_assign
526 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
527 POINTER_PLUS_EXPR
,tem
, lhs
);
528 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
529 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
532 case BUILT_IN_STRCPY
:
533 case BUILT_IN_STRCPY_CHK
:
534 case BUILT_IN_STRCPY_CHKP
:
535 case BUILT_IN_STRCPY_CHK_CHKP
:
536 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
537 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
538 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
540 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
542 fn
= chkp_maybe_create_clone (fn
)->decl
;
543 gcc_assert (lhs
== NULL_TREE
);
544 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
546 fprintf (dump_file
, "Optimizing: ");
547 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
549 gimple_call_set_fndecl (stmt
, fn
);
550 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
551 gimple_call_set_lhs (stmt
, lhs
);
553 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
555 fprintf (dump_file
, "into: ");
556 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
559 case BUILT_IN_STPCPY
:
560 case BUILT_IN_STPCPY_CHK
:
561 case BUILT_IN_STPCPY_CHKP
:
562 case BUILT_IN_STPCPY_CHK_CHKP
:
563 gcc_assert (lhs
!= NULL_TREE
);
564 loc
= gimple_location (stmt
);
567 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
568 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
569 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
572 case BUILT_IN_MALLOC
:
574 /* BUILT_IN_CALLOC always has si->length set. */
584 /* Invalidate string length information for strings whose length
585 might change due to stores in stmt. */
588 maybe_invalidate (gimple stmt
)
592 bool nonempty
= false;
594 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
597 if (!si
->dont_invalidate
)
600 /* Do not use si->length. */
601 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
602 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
604 set_strinfo (i
, NULL
);
609 si
->dont_invalidate
= false;
615 /* Unshare strinfo record SI, if it has refcount > 1 or
616 if stridx_to_strinfo vector is shared with some other
620 unshare_strinfo (strinfo si
)
624 if (si
->refcount
== 1 && !strinfo_shared ())
627 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
628 nsi
->stmt
= si
->stmt
;
629 nsi
->endptr
= si
->endptr
;
630 nsi
->first
= si
->first
;
631 nsi
->prev
= si
->prev
;
632 nsi
->next
= si
->next
;
633 nsi
->writable
= si
->writable
;
634 set_strinfo (si
->idx
, nsi
);
639 /* Return first strinfo in the related strinfo chain
640 if all strinfos in between belong to the chain, otherwise
644 verify_related_strinfos (strinfo origsi
)
646 strinfo si
= origsi
, psi
;
648 if (origsi
->first
== 0)
650 for (; si
->prev
; si
= psi
)
652 if (si
->first
!= origsi
->first
)
654 psi
= get_strinfo (si
->prev
);
657 if (psi
->next
!= si
->idx
)
660 if (si
->idx
!= si
->first
)
665 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
666 strinfo if there is any. Return it's idx, or 0 if no strinfo has
670 get_stridx_plus_constant (strinfo basesi
, HOST_WIDE_INT off
, tree ptr
)
672 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
);
674 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
677 if (basesi
->length
== NULL_TREE
678 || TREE_CODE (basesi
->length
) != INTEGER_CST
679 || compare_tree_int (basesi
->length
, off
) == -1
680 || !tree_fits_shwi_p (basesi
->length
))
683 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
684 strinfo si
= basesi
, chainsi
;
685 if (si
->first
|| si
->prev
|| si
->next
)
686 si
= verify_related_strinfos (basesi
);
688 || si
->length
== NULL_TREE
689 || TREE_CODE (si
->length
) != INTEGER_CST
)
692 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
693 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
695 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
696 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
698 si
= get_strinfo (chainsi
->next
);
700 || si
->first
!= chainsi
->first
701 || si
->prev
!= chainsi
->idx
702 || si
->length
== NULL_TREE
703 || TREE_CODE (si
->length
) != INTEGER_CST
)
705 int r
= compare_tree_int (si
->length
, len
);
710 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
717 int idx
= new_stridx (ptr
);
720 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, len
));
721 set_strinfo (idx
, si
);
724 strinfo nextsi
= unshare_strinfo (get_strinfo (chainsi
->next
));
725 si
->next
= nextsi
->idx
;
728 chainsi
= unshare_strinfo (chainsi
);
729 if (chainsi
->first
== 0)
730 chainsi
->first
= chainsi
->idx
;
732 if (chainsi
->endptr
== NULL_TREE
&& len
== 0)
733 chainsi
->endptr
= ptr
;
734 si
->endptr
= chainsi
->endptr
;
735 si
->prev
= chainsi
->idx
;
736 si
->first
= chainsi
->first
;
737 si
->writable
= chainsi
->writable
;
741 /* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
742 to a zero-length string and if possible chain it to a related strinfo
743 chain whose part is or might be CHAINSI. */
746 zero_length_string (tree ptr
, strinfo chainsi
)
750 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
751 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
752 gcc_checking_assert (TREE_CODE (ptr
) == SSA_NAME
753 && ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] == 0);
755 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
759 si
= verify_related_strinfos (chainsi
);
763 for (; chainsi
->next
; chainsi
= si
)
765 if (chainsi
->endptr
== NULL_TREE
)
767 chainsi
= unshare_strinfo (chainsi
);
768 chainsi
->endptr
= ptr
;
770 si
= get_strinfo (chainsi
->next
);
772 || si
->first
!= chainsi
->first
773 || si
->prev
!= chainsi
->idx
)
776 gcc_assert (chainsi
->length
|| chainsi
->stmt
);
777 if (chainsi
->endptr
== NULL_TREE
)
779 chainsi
= unshare_strinfo (chainsi
);
780 chainsi
->endptr
= ptr
;
782 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
786 chainsi
= unshare_strinfo (chainsi
);
789 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
793 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
795 chainsi
= unshare_strinfo (chainsi
);
801 idx
= new_stridx (ptr
);
804 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
805 set_strinfo (idx
, si
);
809 chainsi
= unshare_strinfo (chainsi
);
810 if (chainsi
->first
== 0)
811 chainsi
->first
= chainsi
->idx
;
813 if (chainsi
->endptr
== NULL_TREE
)
814 chainsi
->endptr
= ptr
;
815 si
->prev
= chainsi
->idx
;
816 si
->first
= chainsi
->first
;
817 si
->writable
= chainsi
->writable
;
822 /* For strinfo ORIGSI whose length has been just updated
823 update also related strinfo lengths (add ADJ to each,
824 but don't adjust ORIGSI). */
827 adjust_related_strinfos (location_t loc
, strinfo origsi
, tree adj
)
829 strinfo si
= verify_related_strinfos (origsi
);
842 si
= unshare_strinfo (si
);
845 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
846 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
847 TREE_TYPE (si
->length
), si
->length
,
850 else if (si
->stmt
!= NULL
)
851 /* Delayed length computation is unaffected. */
856 si
->endptr
= NULL_TREE
;
857 si
->dont_invalidate
= true;
861 nsi
= get_strinfo (si
->next
);
863 || nsi
->first
!= si
->first
864 || nsi
->prev
!= si
->idx
)
870 /* Find if there are other SSA_NAME pointers equal to PTR
871 for which we don't track their string lengths yet. If so, use
875 find_equal_ptrs (tree ptr
, int idx
)
877 if (TREE_CODE (ptr
) != SSA_NAME
)
881 gimple stmt
= SSA_NAME_DEF_STMT (ptr
);
882 if (!is_gimple_assign (stmt
))
884 ptr
= gimple_assign_rhs1 (stmt
);
885 switch (gimple_assign_rhs_code (stmt
))
890 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
892 if (TREE_CODE (ptr
) == SSA_NAME
)
894 if (TREE_CODE (ptr
) != ADDR_EXPR
)
899 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
900 if (pidx
!= NULL
&& *pidx
== 0)
908 /* We might find an endptr created in this pass. Grow the
909 vector in that case. */
910 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
911 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
913 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
915 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
919 /* If the last .MEM setter statement before STMT is
920 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
921 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
922 just memcpy (x, y, strlen (y)). SI must be the zero length
926 adjust_last_stmt (strinfo si
, gimple stmt
, bool is_strcat
)
928 tree vuse
, callee
, len
;
929 struct laststmt_struct last
= laststmt
;
930 strinfo lastsi
, firstsi
;
931 unsigned len_arg_no
= 2;
933 laststmt
.stmt
= NULL
;
934 laststmt
.len
= NULL_TREE
;
937 if (last
.stmt
== NULL
)
940 vuse
= gimple_vuse (stmt
);
941 if (vuse
== NULL_TREE
942 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
943 || !has_single_use (vuse
))
946 gcc_assert (last
.stridx
> 0);
947 lastsi
= get_strinfo (last
.stridx
);
953 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
956 firstsi
= verify_related_strinfos (si
);
959 while (firstsi
!= lastsi
)
962 if (firstsi
->next
== 0)
964 nextsi
= get_strinfo (firstsi
->next
);
966 || nextsi
->prev
!= firstsi
->idx
967 || nextsi
->first
!= si
->first
)
975 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
979 if (is_gimple_assign (last
.stmt
))
981 gimple_stmt_iterator gsi
;
983 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
985 if (stmt_could_throw_p (last
.stmt
))
987 gsi
= gsi_for_stmt (last
.stmt
);
988 unlink_stmt_vdef (last
.stmt
);
989 release_defs (last
.stmt
);
990 gsi_remove (&gsi
, true);
994 if (!gimple_call_builtin_p (last
.stmt
, BUILT_IN_NORMAL
))
997 callee
= gimple_call_fndecl (last
.stmt
);
998 switch (DECL_FUNCTION_CODE (callee
))
1000 case BUILT_IN_MEMCPY
:
1001 case BUILT_IN_MEMCPY_CHK
:
1003 case BUILT_IN_MEMCPY_CHKP
:
1004 case BUILT_IN_MEMCPY_CHK_CHKP
:
1011 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
1012 if (tree_fits_uhwi_p (len
))
1014 if (!tree_fits_uhwi_p (last
.len
)
1015 || integer_zerop (len
)
1016 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
1018 /* Don't adjust the length if it is divisible by 4, it is more efficient
1019 to store the extra '\0' in that case. */
1020 if ((tree_to_uhwi (len
) & 3) == 0)
1023 else if (TREE_CODE (len
) == SSA_NAME
)
1025 gimple def_stmt
= SSA_NAME_DEF_STMT (len
);
1026 if (!is_gimple_assign (def_stmt
)
1027 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1028 || gimple_assign_rhs1 (def_stmt
) != last
.len
1029 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1035 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
1036 update_stmt (last
.stmt
);
1039 /* Handle a strlen call. If strlen of the argument is known, replace
1040 the strlen call with the known value, otherwise remember that strlen
1041 of the argument is stored in the lhs SSA_NAME. */
1044 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1048 gimple stmt
= gsi_stmt (*gsi
);
1049 tree lhs
= gimple_call_lhs (stmt
);
1051 if (lhs
== NULL_TREE
)
1054 src
= gimple_call_arg (stmt
, 0);
1055 idx
= get_stridx (src
);
1062 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1066 si
= get_strinfo (idx
);
1068 rhs
= get_string_length (si
);
1070 if (rhs
!= NULL_TREE
)
1072 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1074 fprintf (dump_file
, "Optimizing: ");
1075 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1077 rhs
= unshare_expr (rhs
);
1078 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1079 rhs
= fold_convert_loc (gimple_location (stmt
),
1080 TREE_TYPE (lhs
), rhs
);
1081 if (!update_call_from_tree (gsi
, rhs
))
1082 gimplify_and_update_call_from_tree (gsi
, rhs
);
1083 stmt
= gsi_stmt (*gsi
);
1085 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1087 fprintf (dump_file
, "into: ");
1088 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1091 && TREE_CODE (si
->length
) != SSA_NAME
1092 && TREE_CODE (si
->length
) != INTEGER_CST
1093 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1095 si
= unshare_strinfo (si
);
1101 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1104 idx
= new_stridx (src
);
1105 else if (get_strinfo (idx
) != NULL
)
1109 strinfo si
= new_strinfo (src
, idx
, lhs
);
1110 set_strinfo (idx
, si
);
1111 find_equal_ptrs (src
, idx
);
1115 /* Handle a strchr call. If strlen of the first argument is known, replace
1116 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1117 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1120 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1124 gimple stmt
= gsi_stmt (*gsi
);
1125 tree lhs
= gimple_call_lhs (stmt
);
1126 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1128 if (lhs
== NULL_TREE
)
1131 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1134 src
= gimple_call_arg (stmt
, 0);
1135 idx
= get_stridx (src
);
1142 rhs
= build_int_cst (size_type_node
, ~idx
);
1146 si
= get_strinfo (idx
);
1148 rhs
= get_string_length (si
);
1150 if (rhs
!= NULL_TREE
)
1152 location_t loc
= gimple_location (stmt
);
1154 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1156 fprintf (dump_file
, "Optimizing: ");
1157 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1159 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1161 rhs
= unshare_expr (si
->endptr
);
1162 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1164 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1168 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1169 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1170 TREE_TYPE (src
), src
, rhs
);
1171 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1173 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1175 if (!update_call_from_tree (gsi
, rhs
))
1176 gimplify_and_update_call_from_tree (gsi
, rhs
);
1177 stmt
= gsi_stmt (*gsi
);
1179 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1181 fprintf (dump_file
, "into: ");
1182 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1185 && si
->endptr
== NULL_TREE
1186 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1188 si
= unshare_strinfo (si
);
1191 zero_length_string (lhs
, si
);
1195 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1197 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1200 idx
= new_stridx (src
);
1201 else if (get_strinfo (idx
) != NULL
)
1203 zero_length_string (lhs
, NULL
);
1208 location_t loc
= gimple_location (stmt
);
1209 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1210 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1211 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1212 size_type_node
, lhsu
, srcu
);
1213 strinfo si
= new_strinfo (src
, idx
, length
);
1215 set_strinfo (idx
, si
);
1216 find_equal_ptrs (src
, idx
);
1217 zero_length_string (lhs
, si
);
1221 zero_length_string (lhs
, NULL
);
1224 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1225 If strlen of the second argument is known, strlen of the first argument
1226 is the same after this call. Furthermore, attempt to convert it to
1230 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1233 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1235 gimple stmt
= gsi_stmt (*gsi
);
1236 strinfo si
, dsi
, olddsi
, zsi
;
1238 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1240 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1241 dst
= gimple_call_arg (stmt
, 0);
1242 lhs
= gimple_call_lhs (stmt
);
1243 idx
= get_stridx (src
);
1246 si
= get_strinfo (idx
);
1248 didx
= get_stridx (dst
);
1252 olddsi
= get_strinfo (didx
);
1257 adjust_last_stmt (olddsi
, stmt
, false);
1261 srclen
= get_string_length (si
);
1263 srclen
= build_int_cst (size_type_node
, ~idx
);
1265 loc
= gimple_location (stmt
);
1266 if (srclen
== NULL_TREE
)
1269 case BUILT_IN_STRCPY
:
1270 case BUILT_IN_STRCPY_CHK
:
1271 case BUILT_IN_STRCPY_CHKP
:
1272 case BUILT_IN_STRCPY_CHK_CHKP
:
1273 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1276 case BUILT_IN_STPCPY
:
1277 case BUILT_IN_STPCPY_CHK
:
1278 case BUILT_IN_STPCPY_CHKP
:
1279 case BUILT_IN_STPCPY_CHK_CHKP
:
1280 if (lhs
== NULL_TREE
)
1284 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1285 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1286 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1296 didx
= new_stridx (dst
);
1302 oldlen
= olddsi
->length
;
1303 dsi
= unshare_strinfo (olddsi
);
1304 dsi
->length
= srclen
;
1305 /* Break the chain, so adjust_related_strinfo on later pointers in
1306 the chain won't adjust this one anymore. */
1309 dsi
->endptr
= NULL_TREE
;
1313 dsi
= new_strinfo (dst
, didx
, srclen
);
1314 set_strinfo (didx
, dsi
);
1315 find_equal_ptrs (dst
, didx
);
1317 dsi
->writable
= true;
1318 dsi
->dont_invalidate
= true;
1320 if (dsi
->length
== NULL_TREE
)
1324 /* If string length of src is unknown, use delayed length
1325 computation. If string lenth of dst will be needed, it
1326 can be computed by transforming this strcpy call into
1327 stpcpy and subtracting dst from the return value. */
1329 /* Look for earlier strings whose length could be determined if
1330 this strcpy is turned into an stpcpy. */
1332 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1334 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1336 /* When setting a stmt for delayed length computation
1337 prevent all strinfos through dsi from being
1339 chainsi
= unshare_strinfo (chainsi
);
1340 chainsi
->stmt
= stmt
;
1341 chainsi
->length
= NULL_TREE
;
1342 chainsi
->endptr
= NULL_TREE
;
1343 chainsi
->dont_invalidate
= true;
1352 tree adj
= NULL_TREE
;
1353 if (oldlen
== NULL_TREE
)
1355 else if (integer_zerop (oldlen
))
1357 else if (TREE_CODE (oldlen
) == INTEGER_CST
1358 || TREE_CODE (srclen
) == INTEGER_CST
)
1359 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1360 TREE_TYPE (srclen
), srclen
,
1361 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1363 if (adj
!= NULL_TREE
)
1364 adjust_related_strinfos (loc
, dsi
, adj
);
1368 /* strcpy src may not overlap dst, so src doesn't need to be
1369 invalidated either. */
1371 si
->dont_invalidate
= true;
1377 case BUILT_IN_STRCPY
:
1378 case BUILT_IN_STRCPY_CHKP
:
1379 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1381 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1383 case BUILT_IN_STRCPY_CHK
:
1384 case BUILT_IN_STRCPY_CHK_CHKP
:
1385 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1387 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1389 case BUILT_IN_STPCPY
:
1390 case BUILT_IN_STPCPY_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); */
1398 zsi
= zero_length_string (lhs
, dsi
);
1401 case BUILT_IN_STPCPY_CHK
:
1402 case BUILT_IN_STPCPY_CHK_CHKP
:
1403 /* This would need adjustment of the lhs (subtract one),
1404 or detection that the trailing '\0' doesn't need to be
1405 written, if it will be immediately overwritten.
1406 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1410 zsi
= zero_length_string (lhs
, dsi
);
1417 zsi
->dont_invalidate
= true;
1419 if (fn
== NULL_TREE
)
1422 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1423 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1425 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1426 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1427 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1429 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1431 fprintf (dump_file
, "Optimizing: ");
1432 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1436 fn
= chkp_maybe_create_clone (fn
)->decl
;
1437 if (gimple_call_num_args (stmt
) == 4)
1438 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1439 gimple_call_arg (stmt
, 1),
1441 gimple_call_arg (stmt
, 3),
1444 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1445 gimple_call_arg (stmt
, 1),
1447 gimple_call_arg (stmt
, 3),
1449 gimple_call_arg (stmt
, 4));
1452 if (gimple_call_num_args (stmt
) == 2)
1453 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1455 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1456 gimple_call_arg (stmt
, 2));
1459 stmt
= gsi_stmt (*gsi
);
1460 gimple_call_set_with_bounds (stmt
, with_bounds
);
1462 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1464 fprintf (dump_file
, "into: ");
1465 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1467 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1468 laststmt
.stmt
= stmt
;
1469 laststmt
.len
= srclen
;
1470 laststmt
.stridx
= dsi
->idx
;
1472 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1473 fprintf (dump_file
, "not possible.\n");
1476 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1477 If strlen of the second argument is known and length of the third argument
1478 is that plus one, strlen of the first argument is the same after this
1482 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1485 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1486 gimple stmt
= gsi_stmt (*gsi
);
1487 strinfo si
, dsi
, olddsi
;
1488 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1490 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1491 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1492 dst
= gimple_call_arg (stmt
, 0);
1493 idx
= get_stridx (src
);
1497 didx
= get_stridx (dst
);
1500 olddsi
= get_strinfo (didx
);
1505 && tree_fits_uhwi_p (len
)
1506 && !integer_zerop (len
))
1507 adjust_last_stmt (olddsi
, stmt
, false);
1513 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1514 si
= get_strinfo (idx
);
1515 if (si
== NULL
|| si
->length
== NULL_TREE
)
1517 if (TREE_CODE (len
) != SSA_NAME
)
1519 def_stmt
= SSA_NAME_DEF_STMT (len
);
1520 if (!is_gimple_assign (def_stmt
)
1521 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1522 || gimple_assign_rhs1 (def_stmt
) != si
->length
1523 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1529 /* Handle memcpy (x, "abcd", 5) or
1530 memcpy (x, "abc\0uvw", 7). */
1531 if (!tree_fits_uhwi_p (len
)
1532 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1536 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1537 adjust_last_stmt (olddsi
, stmt
, false);
1541 didx
= new_stridx (dst
);
1546 newlen
= si
->length
;
1548 newlen
= build_int_cst (size_type_node
, ~idx
);
1552 dsi
= unshare_strinfo (olddsi
);
1553 oldlen
= olddsi
->length
;
1554 dsi
->length
= newlen
;
1555 /* Break the chain, so adjust_related_strinfo on later pointers in
1556 the chain won't adjust this one anymore. */
1559 dsi
->endptr
= NULL_TREE
;
1563 dsi
= new_strinfo (dst
, didx
, newlen
);
1564 set_strinfo (didx
, dsi
);
1565 find_equal_ptrs (dst
, didx
);
1567 dsi
->writable
= true;
1568 dsi
->dont_invalidate
= true;
1571 tree adj
= NULL_TREE
;
1572 location_t loc
= gimple_location (stmt
);
1573 if (oldlen
== NULL_TREE
)
1575 else if (integer_zerop (oldlen
))
1577 else if (TREE_CODE (oldlen
) == INTEGER_CST
1578 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1579 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1580 TREE_TYPE (dsi
->length
), dsi
->length
,
1581 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1583 if (adj
!= NULL_TREE
)
1584 adjust_related_strinfos (loc
, dsi
, adj
);
1588 /* memcpy src may not overlap dst, so src doesn't need to be
1589 invalidated either. */
1591 si
->dont_invalidate
= true;
1593 lhs
= gimple_call_lhs (stmt
);
1596 case BUILT_IN_MEMCPY
:
1597 case BUILT_IN_MEMCPY_CHK
:
1598 case BUILT_IN_MEMCPY_CHKP
:
1599 case BUILT_IN_MEMCPY_CHK_CHKP
:
1600 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1601 laststmt
.stmt
= stmt
;
1602 laststmt
.len
= dsi
->length
;
1603 laststmt
.stridx
= dsi
->idx
;
1605 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1607 case BUILT_IN_MEMPCPY
:
1608 case BUILT_IN_MEMPCPY_CHK
:
1609 case BUILT_IN_MEMPCPY_CHKP
:
1610 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1617 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1618 If strlen of the second argument is known, strlen of the first argument
1619 is increased by the length of the second argument. Furthermore, attempt
1620 to convert it to memcpy/strcpy if the length of the first argument
1624 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1627 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1629 gimple stmt
= gsi_stmt (*gsi
);
1632 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1634 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1635 dst
= gimple_call_arg (stmt
, 0);
1636 lhs
= gimple_call_lhs (stmt
);
1638 didx
= get_stridx (dst
);
1644 dsi
= get_strinfo (didx
);
1645 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1647 /* strcat (p, q) can be transformed into
1648 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1649 with length endptr - p if we need to compute the length
1650 later on. Don't do this transformation if we don't need
1652 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1656 didx
= new_stridx (dst
);
1662 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1663 set_strinfo (didx
, dsi
);
1664 find_equal_ptrs (dst
, didx
);
1668 dsi
= unshare_strinfo (dsi
);
1669 dsi
->length
= NULL_TREE
;
1671 dsi
->endptr
= NULL_TREE
;
1673 dsi
->writable
= true;
1675 dsi
->dont_invalidate
= true;
1682 idx
= get_stridx (src
);
1684 srclen
= build_int_cst (size_type_node
, ~idx
);
1687 si
= get_strinfo (idx
);
1689 srclen
= get_string_length (si
);
1692 loc
= gimple_location (stmt
);
1693 dstlen
= dsi
->length
;
1694 endptr
= dsi
->endptr
;
1696 dsi
= unshare_strinfo (dsi
);
1697 dsi
->endptr
= NULL_TREE
;
1699 dsi
->writable
= true;
1701 if (srclen
!= NULL_TREE
)
1703 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1704 dsi
->length
, srclen
);
1705 adjust_related_strinfos (loc
, dsi
, srclen
);
1706 dsi
->dont_invalidate
= true;
1711 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1712 dsi
->dont_invalidate
= true;
1716 /* strcat src may not overlap dst, so src doesn't need to be
1717 invalidated either. */
1718 si
->dont_invalidate
= true;
1720 /* For now. Could remove the lhs from the call and add
1721 lhs = dst; afterwards. */
1729 case BUILT_IN_STRCAT
:
1730 case BUILT_IN_STRCAT_CHKP
:
1731 if (srclen
!= NULL_TREE
)
1732 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1734 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1736 case BUILT_IN_STRCAT_CHK
:
1737 case BUILT_IN_STRCAT_CHK_CHKP
:
1738 if (srclen
!= NULL_TREE
)
1739 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1741 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1742 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1748 if (fn
== NULL_TREE
)
1752 if (srclen
!= NULL_TREE
)
1754 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1755 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1757 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1758 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1759 build_int_cst (type
, 1));
1760 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1764 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1766 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1767 TREE_TYPE (dst
), unshare_expr (dst
),
1768 fold_convert_loc (loc
, sizetype
,
1769 unshare_expr (dstlen
)));
1770 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1772 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1774 fprintf (dump_file
, "Optimizing: ");
1775 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1779 fn
= chkp_maybe_create_clone (fn
)->decl
;
1780 if (srclen
!= NULL_TREE
)
1781 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1783 gimple_call_arg (stmt
, 1),
1785 gimple_call_arg (stmt
, 3),
1788 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1790 gimple_call_arg (stmt
, 1),
1792 gimple_call_arg (stmt
, 3),
1796 if (srclen
!= NULL_TREE
)
1797 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1798 dst
, src
, len
, objsz
);
1800 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1804 stmt
= gsi_stmt (*gsi
);
1805 gimple_call_set_with_bounds (stmt
, with_bounds
);
1807 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1809 fprintf (dump_file
, "into: ");
1810 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1812 /* If srclen == NULL, note that current string length can be
1813 computed by transforming this strcpy into stpcpy. */
1814 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1816 adjust_last_stmt (dsi
, stmt
, true);
1817 if (srclen
!= NULL_TREE
)
1819 laststmt
.stmt
= stmt
;
1820 laststmt
.len
= srclen
;
1821 laststmt
.stridx
= dsi
->idx
;
1824 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1825 fprintf (dump_file
, "not possible.\n");
1828 /* Handle a call to malloc or calloc. */
1831 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1833 gimple stmt
= gsi_stmt (*gsi
);
1834 tree lhs
= gimple_call_lhs (stmt
);
1835 gcc_assert (get_stridx (lhs
) == 0);
1836 int idx
= new_stridx (lhs
);
1837 tree length
= NULL_TREE
;
1838 if (bcode
== BUILT_IN_CALLOC
)
1839 length
= build_int_cst (size_type_node
, 0);
1840 strinfo si
= new_strinfo (lhs
, idx
, length
);
1841 if (bcode
== BUILT_IN_CALLOC
)
1843 set_strinfo (idx
, si
);
1844 si
->writable
= true;
1846 si
->dont_invalidate
= true;
1849 /* Handle a call to memset.
1850 After a call to calloc, memset(,0,) is unnecessary.
1851 memset(malloc(n),0,n) is calloc(n,1). */
1854 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1856 gimple stmt2
= gsi_stmt (*gsi
);
1857 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1859 tree ptr
= gimple_call_arg (stmt2
, 0);
1860 int idx1
= get_stridx (ptr
);
1863 strinfo si1
= get_strinfo (idx1
);
1866 gimple stmt1
= si1
->stmt
;
1867 if (!stmt1
|| !is_gimple_call (stmt1
))
1869 tree callee1
= gimple_call_fndecl (stmt1
);
1870 if (!gimple_call_builtin_p (stmt1
, BUILT_IN_NORMAL
))
1872 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1873 tree size
= gimple_call_arg (stmt2
, 2);
1874 if (code1
== BUILT_IN_CALLOC
)
1875 /* Not touching stmt1 */ ;
1876 else if (code1
== BUILT_IN_MALLOC
1877 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1879 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1880 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1881 size
, build_one_cst (size_type_node
));
1882 si1
->length
= build_int_cst (size_type_node
, 0);
1883 si1
->stmt
= gsi_stmt (gsi1
);
1887 tree lhs
= gimple_call_lhs (stmt2
);
1888 unlink_stmt_vdef (stmt2
);
1891 gimple assign
= gimple_build_assign (lhs
, ptr
);
1892 gsi_replace (gsi
, assign
, false);
1896 gsi_remove (gsi
, true);
1897 release_defs (stmt2
);
1903 /* Handle a POINTER_PLUS_EXPR statement.
1904 For p = "abcd" + 2; compute associated length, or if
1905 p = q + off is pointing to a '\0' character of a string, call
1906 zero_length_string on it. */
1909 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
1911 gimple stmt
= gsi_stmt (*gsi
);
1912 tree lhs
= gimple_assign_lhs (stmt
), off
;
1913 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
1921 tree off
= gimple_assign_rhs2 (stmt
);
1922 if (tree_fits_uhwi_p (off
)
1923 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1924 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
1925 = ~(~idx
- (int) tree_to_uhwi (off
));
1929 si
= get_strinfo (idx
);
1930 if (si
== NULL
|| si
->length
== NULL_TREE
)
1933 off
= gimple_assign_rhs2 (stmt
);
1935 if (operand_equal_p (si
->length
, off
, 0))
1936 zsi
= zero_length_string (lhs
, si
);
1937 else if (TREE_CODE (off
) == SSA_NAME
)
1939 gimple def_stmt
= SSA_NAME_DEF_STMT (off
);
1940 if (gimple_assign_single_p (def_stmt
)
1941 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
1942 zsi
= zero_length_string (lhs
, si
);
1945 && si
->endptr
!= NULL_TREE
1946 && si
->endptr
!= lhs
1947 && TREE_CODE (si
->endptr
) == SSA_NAME
)
1949 enum tree_code rhs_code
1950 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
1951 ? SSA_NAME
: NOP_EXPR
;
1952 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
1953 gcc_assert (gsi_stmt (*gsi
) == stmt
);
1958 /* Handle a single character store. */
1961 handle_char_store (gimple_stmt_iterator
*gsi
)
1965 gimple stmt
= gsi_stmt (*gsi
);
1966 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
1968 if (TREE_CODE (lhs
) == MEM_REF
1969 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
1971 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
1973 ssaname
= TREE_OPERAND (lhs
, 0);
1974 idx
= get_stridx (ssaname
);
1978 idx
= get_addr_stridx (lhs
);
1982 si
= get_strinfo (idx
);
1983 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
1985 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
1987 /* When storing '\0', the store can be removed
1988 if we know it has been stored in the current function. */
1989 if (!stmt_could_throw_p (stmt
) && si
->writable
)
1991 unlink_stmt_vdef (stmt
);
1992 release_defs (stmt
);
1993 gsi_remove (gsi
, true);
1998 si
->writable
= true;
2004 /* Otherwise this statement overwrites the '\0' with
2005 something, if the previous stmt was a memcpy,
2006 its length may be decreased. */
2007 adjust_last_stmt (si
, stmt
, false);
2009 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
2011 si
= unshare_strinfo (si
);
2012 si
->length
= build_int_cst (size_type_node
, 0);
2018 si
->writable
= true;
2019 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2020 si
->endptr
= ssaname
;
2021 si
->dont_invalidate
= true;
2023 /* If si->length is non-zero constant, we aren't overwriting '\0',
2024 and if we aren't storing '\0', we know that the length of the
2025 string and any other zero terminated string in memory remains
2026 the same. In that case we move to the next gimple statement and
2027 return to signal the caller that it shouldn't invalidate anything.
2029 This is benefical for cases like:
2034 strcpy (p, "foobar");
2035 size_t len = strlen (p); // This can be optimized into 6
2036 size_t len2 = strlen (q); // This has to be computed
2038 size_t len3 = strlen (p); // This can be optimized into 6
2039 size_t len4 = strlen (q); // This can be optimized into len2
2040 bar (len, len2, len3, len4);
2043 else if (si
!= NULL
&& si
->length
!= NULL_TREE
2044 && TREE_CODE (si
->length
) == INTEGER_CST
2045 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2051 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2055 si
= zero_length_string (ssaname
, NULL
);
2057 si
->dont_invalidate
= true;
2061 int idx
= new_addr_stridx (lhs
);
2064 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2065 build_int_cst (size_type_node
, 0));
2066 set_strinfo (idx
, si
);
2067 si
->dont_invalidate
= true;
2071 si
->writable
= true;
2074 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2075 && ssaname
== NULL_TREE
2076 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2078 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2079 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2080 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2082 int idx
= new_addr_stridx (lhs
);
2085 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2086 build_int_cst (size_type_node
, l
));
2087 set_strinfo (idx
, si
);
2088 si
->dont_invalidate
= true;
2093 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2095 /* Allow adjust_last_stmt to remove it if the stored '\0'
2096 is immediately overwritten. */
2097 laststmt
.stmt
= stmt
;
2098 laststmt
.len
= build_int_cst (size_type_node
, 1);
2099 laststmt
.stridx
= si
->idx
;
2104 /* Attempt to optimize a single statement at *GSI using string length
2108 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2110 gimple stmt
= gsi_stmt (*gsi
);
2112 if (is_gimple_call (stmt
))
2114 tree callee
= gimple_call_fndecl (stmt
);
2115 if (gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
2116 switch (DECL_FUNCTION_CODE (callee
))
2118 case BUILT_IN_STRLEN
:
2119 case BUILT_IN_STRLEN_CHKP
:
2120 handle_builtin_strlen (gsi
);
2122 case BUILT_IN_STRCHR
:
2123 case BUILT_IN_STRCHR_CHKP
:
2124 handle_builtin_strchr (gsi
);
2126 case BUILT_IN_STRCPY
:
2127 case BUILT_IN_STRCPY_CHK
:
2128 case BUILT_IN_STPCPY
:
2129 case BUILT_IN_STPCPY_CHK
:
2130 case BUILT_IN_STRCPY_CHKP
:
2131 case BUILT_IN_STRCPY_CHK_CHKP
:
2132 case BUILT_IN_STPCPY_CHKP
:
2133 case BUILT_IN_STPCPY_CHK_CHKP
:
2134 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2136 case BUILT_IN_MEMCPY
:
2137 case BUILT_IN_MEMCPY_CHK
:
2138 case BUILT_IN_MEMPCPY
:
2139 case BUILT_IN_MEMPCPY_CHK
:
2140 case BUILT_IN_MEMCPY_CHKP
:
2141 case BUILT_IN_MEMCPY_CHK_CHKP
:
2142 case BUILT_IN_MEMPCPY_CHKP
:
2143 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2144 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2146 case BUILT_IN_STRCAT
:
2147 case BUILT_IN_STRCAT_CHK
:
2148 case BUILT_IN_STRCAT_CHKP
:
2149 case BUILT_IN_STRCAT_CHK_CHKP
:
2150 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2152 case BUILT_IN_MALLOC
:
2153 case BUILT_IN_CALLOC
:
2154 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2156 case BUILT_IN_MEMSET
:
2157 if (!handle_builtin_memset (gsi
))
2164 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2166 tree lhs
= gimple_assign_lhs (stmt
);
2168 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2170 if (gimple_assign_single_p (stmt
)
2171 || (gimple_assign_cast_p (stmt
)
2172 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2174 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2175 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2177 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2178 handle_pointer_plus (gsi
);
2180 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2182 tree type
= TREE_TYPE (lhs
);
2183 if (TREE_CODE (type
) == ARRAY_TYPE
)
2184 type
= TREE_TYPE (type
);
2185 if (TREE_CODE (type
) == INTEGER_TYPE
2186 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2187 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2189 if (! handle_char_store (gsi
))
2195 if (gimple_vdef (stmt
))
2196 maybe_invalidate (stmt
);
2200 /* Recursively call maybe_invalidate on stmts that might be executed
2201 in between dombb and current bb and that contain a vdef. Stop when
2202 *count stmts are inspected, or if the whole strinfo vector has
2203 been invalidated. */
2206 do_invalidate (basic_block dombb
, gimple phi
, bitmap visited
, int *count
)
2208 unsigned int i
, n
= gimple_phi_num_args (phi
);
2210 for (i
= 0; i
< n
; i
++)
2212 tree vuse
= gimple_phi_arg_def (phi
, i
);
2213 gimple stmt
= SSA_NAME_DEF_STMT (vuse
);
2214 basic_block bb
= gimple_bb (stmt
);
2217 || !bitmap_set_bit (visited
, bb
->index
)
2218 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2222 if (gimple_code (stmt
) == GIMPLE_PHI
)
2224 do_invalidate (dombb
, stmt
, visited
, count
);
2231 if (!maybe_invalidate (stmt
))
2236 vuse
= gimple_vuse (stmt
);
2237 stmt
= SSA_NAME_DEF_STMT (vuse
);
2238 if (gimple_bb (stmt
) != bb
)
2240 bb
= gimple_bb (stmt
);
2243 || !bitmap_set_bit (visited
, bb
->index
)
2244 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2251 class strlen_dom_walker
: public dom_walker
2254 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2256 virtual void before_dom_children (basic_block
);
2257 virtual void after_dom_children (basic_block
);
2260 /* Callback for walk_dominator_tree. Attempt to optimize various
2261 string ops by remembering string lenths pointed by pointer SSA_NAMEs. */
2264 strlen_dom_walker::before_dom_children (basic_block bb
)
2266 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2269 stridx_to_strinfo
= NULL
;
2272 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) dombb
->aux
);
2273 if (stridx_to_strinfo
)
2275 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2278 gphi
*phi
= gsi
.phi ();
2279 if (virtual_operand_p (gimple_phi_result (phi
)))
2281 bitmap visited
= BITMAP_ALLOC (NULL
);
2282 int count_vdef
= 100;
2283 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2284 BITMAP_FREE (visited
);
2285 if (count_vdef
== 0)
2287 /* If there were too many vdefs in between immediate
2288 dominator and current bb, invalidate everything.
2289 If stridx_to_strinfo has been unshared, we need
2290 to free it, otherwise just set it to NULL. */
2291 if (!strinfo_shared ())
2297 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2301 (*stridx_to_strinfo
)[i
] = NULL
;
2305 stridx_to_strinfo
= NULL
;
2313 /* If all PHI arguments have the same string index, the PHI result
2315 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2318 gphi
*phi
= gsi
.phi ();
2319 tree result
= gimple_phi_result (phi
);
2320 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2322 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2325 unsigned int i
, n
= gimple_phi_num_args (phi
);
2326 for (i
= 1; i
< n
; i
++)
2327 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2330 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2335 /* Attempt to optimize individual statements. */
2336 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2337 if (strlen_optimize_stmt (&gsi
))
2340 bb
->aux
= stridx_to_strinfo
;
2341 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2342 (*stridx_to_strinfo
)[0] = (strinfo
) bb
;
2345 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2346 owned by the current bb, clear bb->aux. */
2349 strlen_dom_walker::after_dom_children (basic_block bb
)
2353 stridx_to_strinfo
= ((vec
<strinfo
, va_heap
, vl_embed
> *) bb
->aux
);
2354 if (vec_safe_length (stridx_to_strinfo
)
2355 && (*stridx_to_strinfo
)[0] == (strinfo
) bb
)
2360 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2362 vec_free (stridx_to_strinfo
);
2368 /* Main entry point. */
2372 const pass_data pass_data_strlen
=
2374 GIMPLE_PASS
, /* type */
2375 "strlen", /* name */
2376 OPTGROUP_NONE
, /* optinfo_flags */
2377 TV_TREE_STRLEN
, /* tv_id */
2378 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2379 0, /* properties_provided */
2380 0, /* properties_destroyed */
2381 0, /* todo_flags_start */
2382 0, /* todo_flags_finish */
2385 class pass_strlen
: public gimple_opt_pass
2388 pass_strlen (gcc::context
*ctxt
)
2389 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2392 /* opt_pass methods: */
2393 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2394 virtual unsigned int execute (function
*);
2396 }; // class pass_strlen
2399 pass_strlen::execute (function
*fun
)
2401 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2403 strinfo_pool
= create_alloc_pool ("strinfo_struct pool",
2404 sizeof (struct strinfo_struct
), 64);
2406 calculate_dominance_info (CDI_DOMINATORS
);
2408 /* String length optimization is implemented as a walk of the dominator
2409 tree and a forward walk of statements within each block. */
2410 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2412 ssa_ver_to_stridx
.release ();
2413 free_alloc_pool (strinfo_pool
);
2414 if (decl_to_stridxlist_htab
)
2416 obstack_free (&stridx_obstack
, NULL
);
2417 delete decl_to_stridxlist_htab
;
2418 decl_to_stridxlist_htab
= NULL
;
2420 laststmt
.stmt
= NULL
;
2421 laststmt
.len
= NULL_TREE
;
2422 laststmt
.stridx
= 0;
2430 make_pass_strlen (gcc::context
*ctxt
)
2432 return new pass_strlen (ctxt
);