1 /* String length optimization
2 Copyright (C) 2011-2017 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
28 #include "alloc-pool.h"
29 #include "tree-pass.h"
32 #include "gimple-pretty-print.h"
33 #include "fold-const.h"
34 #include "stor-layout.h"
35 #include "gimple-fold.h"
38 #include "gimple-iterator.h"
39 #include "gimplify-me.h"
43 #include "tree-ssa-propagate.h"
46 #include "tree-hash-traits.h"
49 /* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
50 is an index into strinfo vector, negative value stands for
51 string length of a string literal (~strlen). */
52 static vec
<int> ssa_ver_to_stridx
;
54 /* Number of currently active string indexes plus one. */
55 static int max_stridx
;
57 /* String information record. */
60 /* String length of this string. */
62 /* Any of the corresponding pointers for querying alias oracle. */
64 /* Statement for delayed length computation. */
66 /* Pointer to '\0' if known, if NULL, it can be computed as
69 /* Reference count. Any changes to strinfo entry possibly shared
70 with dominating basic blocks need unshare_strinfo first, except
71 for dont_invalidate which affects only the immediately next
74 /* Copy of index. get_strinfo (si->idx) should return si; */
76 /* These 3 fields are for chaining related string pointers together.
78 bl = strlen (b); dl = strlen (d); strcpy (a, b); c = a + bl;
79 strcpy (c, d); e = c + dl;
80 strinfo(a) -> strinfo(c) -> strinfo(e)
81 All have ->first field equal to strinfo(a)->idx and are doubly
82 chained through prev/next fields. The later strinfos are required
83 to point into the same string with zero or more bytes after
84 the previous pointer and all bytes in between the two pointers
85 must be non-zero. Functions like strcpy or memcpy are supposed
86 to adjust all previous strinfo lengths, but not following strinfo
87 lengths (those are uncertain, usually invalidated during
88 maybe_invalidate, except when the alias oracle knows better).
89 Functions like strcat on the other side adjust the whole
90 related strinfo chain.
91 They are updated lazily, so to use the chain the same first fields
92 and si->prev->next == si->idx needs to be verified. */
96 /* A flag whether the string is known to be written in the current
99 /* A flag for the next maybe_invalidate that this strinfo shouldn't
100 be invalidated. Always cleared by maybe_invalidate. */
101 bool dont_invalidate
;
104 /* Pool for allocating strinfo_struct entries. */
105 static object_allocator
<strinfo
> strinfo_pool ("strinfo pool");
107 /* Vector mapping positive string indexes to strinfo, for the
108 current basic block. The first pointer in the vector is special,
109 it is either NULL, meaning the vector isn't shared, or it is
110 a basic block pointer to the owner basic_block if shared.
111 If some other bb wants to modify the vector, the vector needs
112 to be unshared first, and only the owner bb is supposed to free it. */
113 static vec
<strinfo
*, va_heap
, vl_embed
> *stridx_to_strinfo
;
115 /* One OFFSET->IDX mapping. */
118 struct stridxlist
*next
;
119 HOST_WIDE_INT offset
;
123 /* Hash table entry, mapping a DECL to a chain of OFFSET->IDX mappings. */
124 struct decl_stridxlist_map
126 struct tree_map_base base
;
127 struct stridxlist list
;
130 /* Hash table for mapping decls to a chained list of offset -> idx
132 static hash_map
<tree_decl_hash
, stridxlist
> *decl_to_stridxlist_htab
;
134 /* Obstack for struct stridxlist and struct decl_stridxlist_map. */
135 static struct obstack stridx_obstack
;
137 /* Last memcpy statement if it could be adjusted if the trailing
138 '\0' written is immediately overwritten, or
139 *x = '\0' store that could be removed if it is immediately overwritten. */
140 struct laststmt_struct
147 static int get_stridx_plus_constant (strinfo
*, HOST_WIDE_INT
, tree
);
149 /* Return strinfo vector entry IDX. */
151 static inline strinfo
*
152 get_strinfo (int idx
)
154 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
156 return (*stridx_to_strinfo
)[idx
];
159 /* Get the next strinfo in the chain after SI, or null if none. */
161 static inline strinfo
*
162 get_next_strinfo (strinfo
*si
)
166 strinfo
*nextsi
= get_strinfo (si
->next
);
167 if (nextsi
== NULL
|| nextsi
->first
!= si
->first
|| nextsi
->prev
!= si
->idx
)
172 /* Helper function for get_stridx. */
175 get_addr_stridx (tree exp
, tree ptr
)
178 struct stridxlist
*list
, *last
= NULL
;
181 if (!decl_to_stridxlist_htab
)
184 base
= get_addr_base_and_unit_offset (exp
, &off
);
185 if (base
== NULL
|| !DECL_P (base
))
188 list
= decl_to_stridxlist_htab
->get (base
);
194 if (list
->offset
== off
)
196 if (list
->offset
> off
)
203 if (ptr
&& last
&& last
->idx
> 0)
205 strinfo
*si
= get_strinfo (last
->idx
);
208 && TREE_CODE (si
->length
) == INTEGER_CST
209 && compare_tree_int (si
->length
, off
- last
->offset
) != -1)
210 return get_stridx_plus_constant (si
, off
- last
->offset
, ptr
);
215 /* Return string index for EXP. */
218 get_stridx (tree exp
)
222 if (TREE_CODE (exp
) == SSA_NAME
)
224 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)])
225 return ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)];
228 HOST_WIDE_INT off
= 0;
229 for (i
= 0; i
< 5; i
++)
231 gimple
*def_stmt
= SSA_NAME_DEF_STMT (e
);
232 if (!is_gimple_assign (def_stmt
)
233 || gimple_assign_rhs_code (def_stmt
) != POINTER_PLUS_EXPR
)
235 tree rhs1
= gimple_assign_rhs1 (def_stmt
);
236 tree rhs2
= gimple_assign_rhs2 (def_stmt
);
237 if (TREE_CODE (rhs1
) != SSA_NAME
238 || !tree_fits_shwi_p (rhs2
))
240 HOST_WIDE_INT this_off
= tree_to_shwi (rhs2
);
243 off
= (unsigned HOST_WIDE_INT
) off
+ this_off
;
246 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)])
249 = get_strinfo (ssa_ver_to_stridx
[SSA_NAME_VERSION (rhs1
)]);
252 && TREE_CODE (si
->length
) == INTEGER_CST
253 && compare_tree_int (si
->length
, off
) != -1)
254 return get_stridx_plus_constant (si
, off
, exp
);
261 if (TREE_CODE (exp
) == ADDR_EXPR
)
263 int idx
= get_addr_stridx (TREE_OPERAND (exp
, 0), exp
);
268 s
= string_constant (exp
, &o
);
270 && (o
== NULL_TREE
|| tree_fits_shwi_p (o
))
271 && TREE_STRING_LENGTH (s
) > 0)
273 HOST_WIDE_INT offset
= o
? tree_to_shwi (o
) : 0;
274 const char *p
= TREE_STRING_POINTER (s
);
275 int max
= TREE_STRING_LENGTH (s
) - 1;
277 if (p
[max
] == '\0' && offset
>= 0 && offset
<= max
)
278 return ~(int) strlen (p
+ offset
);
283 /* Return true if strinfo vector is shared with the immediate dominator. */
286 strinfo_shared (void)
288 return vec_safe_length (stridx_to_strinfo
)
289 && (*stridx_to_strinfo
)[0] != NULL
;
292 /* Unshare strinfo vector that is shared with the immediate dominator. */
295 unshare_strinfo_vec (void)
300 gcc_assert (strinfo_shared ());
301 stridx_to_strinfo
= vec_safe_copy (stridx_to_strinfo
);
302 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
305 (*stridx_to_strinfo
)[0] = NULL
;
308 /* Attempt to create a string index for exp, ADDR_EXPR's operand.
309 Return a pointer to the location where the string index can
310 be stored (if 0) or is stored, or NULL if this can't be tracked. */
313 addr_stridxptr (tree exp
)
317 tree base
= get_addr_base_and_unit_offset (exp
, &off
);
318 if (base
== NULL_TREE
|| !DECL_P (base
))
321 if (!decl_to_stridxlist_htab
)
323 decl_to_stridxlist_htab
324 = new hash_map
<tree_decl_hash
, stridxlist
> (64);
325 gcc_obstack_init (&stridx_obstack
);
329 stridxlist
*list
= &decl_to_stridxlist_htab
->get_or_insert (base
, &existed
);
333 stridxlist
*before
= NULL
;
334 for (i
= 0; i
< 32; i
++)
336 if (list
->offset
== off
)
338 if (list
->offset
> off
&& before
== NULL
)
340 if (list
->next
== NULL
)
349 before
= XOBNEW (&stridx_obstack
, struct stridxlist
);
356 list
->next
= XOBNEW (&stridx_obstack
, struct stridxlist
);
366 /* Create a new string index, or return 0 if reached limit. */
369 new_stridx (tree exp
)
372 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
374 if (TREE_CODE (exp
) == SSA_NAME
)
376 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp
))
379 ssa_ver_to_stridx
[SSA_NAME_VERSION (exp
)] = idx
;
382 if (TREE_CODE (exp
) == ADDR_EXPR
)
384 int *pidx
= addr_stridxptr (TREE_OPERAND (exp
, 0));
387 gcc_assert (*pidx
== 0);
388 *pidx
= max_stridx
++;
395 /* Like new_stridx, but for ADDR_EXPR's operand instead. */
398 new_addr_stridx (tree exp
)
401 if (max_stridx
>= PARAM_VALUE (PARAM_MAX_TRACKED_STRLENS
))
403 pidx
= addr_stridxptr (exp
);
406 gcc_assert (*pidx
== 0);
407 *pidx
= max_stridx
++;
413 /* Create a new strinfo. */
416 new_strinfo (tree ptr
, int idx
, tree length
)
418 strinfo
*si
= strinfo_pool
.allocate ();
422 si
->endptr
= NULL_TREE
;
428 si
->writable
= false;
429 si
->dont_invalidate
= false;
433 /* Decrease strinfo refcount and free it if not referenced anymore. */
436 free_strinfo (strinfo
*si
)
438 if (si
&& --si
->refcount
== 0)
439 strinfo_pool
.remove (si
);
442 /* Set strinfo in the vector entry IDX to SI. */
445 set_strinfo (int idx
, strinfo
*si
)
447 if (vec_safe_length (stridx_to_strinfo
) && (*stridx_to_strinfo
)[0])
448 unshare_strinfo_vec ();
449 if (vec_safe_length (stridx_to_strinfo
) <= (unsigned int) idx
)
450 vec_safe_grow_cleared (stridx_to_strinfo
, idx
+ 1);
451 (*stridx_to_strinfo
)[idx
] = si
;
454 /* Return string length, or NULL if it can't be computed. */
457 get_string_length (strinfo
*si
)
464 gimple
*stmt
= si
->stmt
, *lenstmt
;
465 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
466 tree callee
, lhs
, fn
, tem
;
468 gimple_stmt_iterator gsi
;
470 gcc_assert (is_gimple_call (stmt
));
471 callee
= gimple_call_fndecl (stmt
);
472 gcc_assert (callee
&& DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
);
473 lhs
= gimple_call_lhs (stmt
);
474 /* unshare_strinfo is intentionally not called here. The (delayed)
475 transformation of strcpy or strcat into stpcpy is done at the place
476 of the former strcpy/strcat call and so can affect all the strinfos
477 with the same stmt. If they were unshared before and transformation
478 has been already done, the handling of BUILT_IN_STPCPY{,_CHK} should
479 just compute the right length. */
480 switch (DECL_FUNCTION_CODE (callee
))
482 case BUILT_IN_STRCAT
:
483 case BUILT_IN_STRCAT_CHK
:
484 case BUILT_IN_STRCAT_CHKP
:
485 case BUILT_IN_STRCAT_CHK_CHKP
:
486 gsi
= gsi_for_stmt (stmt
);
487 fn
= builtin_decl_implicit (BUILT_IN_STRLEN
);
488 gcc_assert (lhs
== NULL_TREE
);
489 tem
= unshare_expr (gimple_call_arg (stmt
, 0));
492 lenstmt
= gimple_build_call (chkp_maybe_create_clone (fn
)->decl
,
493 2, tem
, gimple_call_arg (stmt
, 1));
494 gimple_call_set_with_bounds (lenstmt
, true);
497 lenstmt
= gimple_build_call (fn
, 1, tem
);
498 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), lenstmt
);
499 gimple_call_set_lhs (lenstmt
, lhs
);
500 gimple_set_vuse (lenstmt
, gimple_vuse (stmt
));
501 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
502 tem
= gimple_call_arg (stmt
, 0);
503 if (!ptrofftype_p (TREE_TYPE (lhs
)))
505 lhs
= convert_to_ptrofftype (lhs
);
506 lhs
= force_gimple_operand_gsi (&gsi
, lhs
, true, NULL_TREE
,
507 true, GSI_SAME_STMT
);
509 lenstmt
= gimple_build_assign
510 (make_ssa_name (TREE_TYPE (gimple_call_arg (stmt
, 0))),
511 POINTER_PLUS_EXPR
,tem
, lhs
);
512 gsi_insert_before (&gsi
, lenstmt
, GSI_SAME_STMT
);
513 gimple_call_set_arg (stmt
, 0, gimple_assign_lhs (lenstmt
));
516 case BUILT_IN_STRCPY
:
517 case BUILT_IN_STRCPY_CHK
:
518 case BUILT_IN_STRCPY_CHKP
:
519 case BUILT_IN_STRCPY_CHK_CHKP
:
520 gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY
));
521 if (gimple_call_num_args (stmt
) == (with_bounds
? 4 : 2))
522 fn
= builtin_decl_implicit (BUILT_IN_STPCPY
);
524 fn
= builtin_decl_explicit (BUILT_IN_STPCPY_CHK
);
526 fn
= chkp_maybe_create_clone (fn
)->decl
;
527 gcc_assert (lhs
== NULL_TREE
);
528 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
530 fprintf (dump_file
, "Optimizing: ");
531 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
533 gimple_call_set_fndecl (stmt
, fn
);
534 lhs
= make_ssa_name (TREE_TYPE (TREE_TYPE (fn
)), stmt
);
535 gimple_call_set_lhs (stmt
, lhs
);
537 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
539 fprintf (dump_file
, "into: ");
540 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
543 case BUILT_IN_STPCPY
:
544 case BUILT_IN_STPCPY_CHK
:
545 case BUILT_IN_STPCPY_CHKP
:
546 case BUILT_IN_STPCPY_CHK_CHKP
:
547 gcc_assert (lhs
!= NULL_TREE
);
548 loc
= gimple_location (stmt
);
551 lhs
= fold_convert_loc (loc
, size_type_node
, lhs
);
552 si
->length
= fold_convert_loc (loc
, size_type_node
, si
->ptr
);
553 si
->length
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
556 case BUILT_IN_MALLOC
:
558 /* BUILT_IN_CALLOC always has si->length set. */
568 /* Invalidate string length information for strings whose length
569 might change due to stores in stmt. */
572 maybe_invalidate (gimple
*stmt
)
576 bool nonempty
= false;
578 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
581 if (!si
->dont_invalidate
)
584 /* Do not use si->length. */
585 ao_ref_init_from_ptr_and_size (&r
, si
->ptr
, NULL_TREE
);
586 if (stmt_may_clobber_ref_p_1 (stmt
, &r
))
588 set_strinfo (i
, NULL
);
593 si
->dont_invalidate
= false;
599 /* Unshare strinfo record SI, if it has refcount > 1 or
600 if stridx_to_strinfo vector is shared with some other
604 unshare_strinfo (strinfo
*si
)
608 if (si
->refcount
== 1 && !strinfo_shared ())
611 nsi
= new_strinfo (si
->ptr
, si
->idx
, si
->length
);
612 nsi
->stmt
= si
->stmt
;
613 nsi
->endptr
= si
->endptr
;
614 nsi
->first
= si
->first
;
615 nsi
->prev
= si
->prev
;
616 nsi
->next
= si
->next
;
617 nsi
->writable
= si
->writable
;
618 set_strinfo (si
->idx
, nsi
);
623 /* Return first strinfo in the related strinfo chain
624 if all strinfos in between belong to the chain, otherwise
628 verify_related_strinfos (strinfo
*origsi
)
630 strinfo
*si
= origsi
, *psi
;
632 if (origsi
->first
== 0)
634 for (; si
->prev
; si
= psi
)
636 if (si
->first
!= origsi
->first
)
638 psi
= get_strinfo (si
->prev
);
641 if (psi
->next
!= si
->idx
)
644 if (si
->idx
!= si
->first
)
649 /* Attempt to create a new strinfo for BASESI + OFF, or find existing
650 strinfo if there is any. Return it's idx, or 0 if no strinfo has
654 get_stridx_plus_constant (strinfo
*basesi
, HOST_WIDE_INT off
, tree ptr
)
656 if (TREE_CODE (ptr
) == SSA_NAME
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr
))
659 if (basesi
->length
== NULL_TREE
660 || TREE_CODE (basesi
->length
) != INTEGER_CST
661 || compare_tree_int (basesi
->length
, off
) == -1
662 || !tree_fits_shwi_p (basesi
->length
))
665 HOST_WIDE_INT len
= tree_to_shwi (basesi
->length
) - off
;
666 strinfo
*si
= basesi
, *chainsi
;
667 if (si
->first
|| si
->prev
|| si
->next
)
668 si
= verify_related_strinfos (basesi
);
670 || si
->length
== NULL_TREE
671 || TREE_CODE (si
->length
) != INTEGER_CST
)
674 if (TREE_CODE (ptr
) == SSA_NAME
675 && ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
676 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
678 gcc_checking_assert (compare_tree_int (si
->length
, off
) != -1);
679 for (chainsi
= si
; chainsi
->next
; chainsi
= si
)
681 si
= get_next_strinfo (chainsi
);
683 || si
->length
== NULL_TREE
684 || TREE_CODE (si
->length
) != INTEGER_CST
)
686 int r
= compare_tree_int (si
->length
, len
);
691 if (TREE_CODE (ptr
) == SSA_NAME
)
692 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = si
->idx
;
695 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
696 if (pidx
!= NULL
&& *pidx
== 0)
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
);
752 gcc_assert (si
->length
|| si
->stmt
);
753 if (si
->endptr
== NULL_TREE
)
755 si
= unshare_strinfo (si
);
759 si
= get_next_strinfo (si
);
762 if (chainsi
->length
&& integer_zerop (chainsi
->length
))
766 chainsi
= unshare_strinfo (chainsi
);
769 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = chainsi
->idx
;
773 else if (chainsi
->first
|| chainsi
->prev
|| chainsi
->next
)
775 chainsi
= unshare_strinfo (chainsi
);
781 idx
= new_stridx (ptr
);
784 si
= new_strinfo (ptr
, idx
, build_int_cst (size_type_node
, 0));
785 set_strinfo (idx
, si
);
789 chainsi
= unshare_strinfo (chainsi
);
790 if (chainsi
->first
== 0)
791 chainsi
->first
= chainsi
->idx
;
793 if (chainsi
->endptr
== NULL_TREE
)
794 chainsi
->endptr
= ptr
;
795 si
->prev
= chainsi
->idx
;
796 si
->first
= chainsi
->first
;
797 si
->writable
= chainsi
->writable
;
802 /* For strinfo ORIGSI whose length has been just updated
803 update also related strinfo lengths (add ADJ to each,
804 but don't adjust ORIGSI). */
807 adjust_related_strinfos (location_t loc
, strinfo
*origsi
, tree adj
)
809 strinfo
*si
= verify_related_strinfos (origsi
);
822 si
= unshare_strinfo (si
);
825 tem
= fold_convert_loc (loc
, TREE_TYPE (si
->length
), adj
);
826 si
->length
= fold_build2_loc (loc
, PLUS_EXPR
,
827 TREE_TYPE (si
->length
), si
->length
,
830 else if (si
->stmt
!= NULL
)
831 /* Delayed length computation is unaffected. */
836 si
->endptr
= NULL_TREE
;
837 si
->dont_invalidate
= true;
839 nsi
= get_next_strinfo (si
);
846 /* Find if there are other SSA_NAME pointers equal to PTR
847 for which we don't track their string lengths yet. If so, use
851 find_equal_ptrs (tree ptr
, int idx
)
853 if (TREE_CODE (ptr
) != SSA_NAME
)
857 gimple
*stmt
= SSA_NAME_DEF_STMT (ptr
);
858 if (!is_gimple_assign (stmt
))
860 ptr
= gimple_assign_rhs1 (stmt
);
861 switch (gimple_assign_rhs_code (stmt
))
866 if (!POINTER_TYPE_P (TREE_TYPE (ptr
)))
868 if (TREE_CODE (ptr
) == SSA_NAME
)
870 if (TREE_CODE (ptr
) != ADDR_EXPR
)
875 int *pidx
= addr_stridxptr (TREE_OPERAND (ptr
, 0));
876 if (pidx
!= NULL
&& *pidx
== 0)
884 /* We might find an endptr created in this pass. Grow the
885 vector in that case. */
886 if (ssa_ver_to_stridx
.length () <= SSA_NAME_VERSION (ptr
))
887 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
889 if (ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] != 0)
891 ssa_ver_to_stridx
[SSA_NAME_VERSION (ptr
)] = idx
;
895 /* Return true if STMT is a call to a builtin function with the right
896 arguments and attributes that should be considered for optimization
900 valid_builtin_call (gimple
*stmt
)
902 if (!gimple_call_builtin_p (stmt
, BUILT_IN_NORMAL
))
905 tree callee
= gimple_call_fndecl (stmt
);
906 switch (DECL_FUNCTION_CODE (callee
))
908 case BUILT_IN_MEMCMP
:
909 case BUILT_IN_MEMCMP_EQ
:
910 case BUILT_IN_STRCHR
:
911 case BUILT_IN_STRCHR_CHKP
:
912 case BUILT_IN_STRLEN
:
913 case BUILT_IN_STRLEN_CHKP
:
914 /* The above functions should be pure. Punt if they aren't. */
915 if (gimple_vdef (stmt
) || gimple_vuse (stmt
) == NULL_TREE
)
919 case BUILT_IN_CALLOC
:
920 case BUILT_IN_MALLOC
:
921 case BUILT_IN_MEMCPY
:
922 case BUILT_IN_MEMCPY_CHK
:
923 case BUILT_IN_MEMCPY_CHKP
:
924 case BUILT_IN_MEMCPY_CHK_CHKP
:
925 case BUILT_IN_MEMPCPY
:
926 case BUILT_IN_MEMPCPY_CHK
:
927 case BUILT_IN_MEMPCPY_CHKP
:
928 case BUILT_IN_MEMPCPY_CHK_CHKP
:
929 case BUILT_IN_MEMSET
:
930 case BUILT_IN_STPCPY
:
931 case BUILT_IN_STPCPY_CHK
:
932 case BUILT_IN_STPCPY_CHKP
:
933 case BUILT_IN_STPCPY_CHK_CHKP
:
934 case BUILT_IN_STRCAT
:
935 case BUILT_IN_STRCAT_CHK
:
936 case BUILT_IN_STRCAT_CHKP
:
937 case BUILT_IN_STRCAT_CHK_CHKP
:
938 case BUILT_IN_STRCPY
:
939 case BUILT_IN_STRCPY_CHK
:
940 case BUILT_IN_STRCPY_CHKP
:
941 case BUILT_IN_STRCPY_CHK_CHKP
:
942 /* The above functions should be neither const nor pure. Punt if they
944 if (gimple_vdef (stmt
) == NULL_TREE
|| gimple_vuse (stmt
) == NULL_TREE
)
955 /* If the last .MEM setter statement before STMT is
956 memcpy (x, y, strlen (y) + 1), the only .MEM use of it is STMT
957 and STMT is known to overwrite x[strlen (x)], adjust the last memcpy to
958 just memcpy (x, y, strlen (y)). SI must be the zero length
962 adjust_last_stmt (strinfo
*si
, gimple
*stmt
, bool is_strcat
)
964 tree vuse
, callee
, len
;
965 struct laststmt_struct last
= laststmt
;
966 strinfo
*lastsi
, *firstsi
;
967 unsigned len_arg_no
= 2;
969 laststmt
.stmt
= NULL
;
970 laststmt
.len
= NULL_TREE
;
973 if (last
.stmt
== NULL
)
976 vuse
= gimple_vuse (stmt
);
977 if (vuse
== NULL_TREE
978 || SSA_NAME_DEF_STMT (vuse
) != last
.stmt
979 || !has_single_use (vuse
))
982 gcc_assert (last
.stridx
> 0);
983 lastsi
= get_strinfo (last
.stridx
);
989 if (lastsi
->first
== 0 || lastsi
->first
!= si
->first
)
992 firstsi
= verify_related_strinfos (si
);
995 while (firstsi
!= lastsi
)
997 firstsi
= get_next_strinfo (firstsi
);
1005 if (si
->length
== NULL_TREE
|| !integer_zerop (si
->length
))
1009 if (is_gimple_assign (last
.stmt
))
1011 gimple_stmt_iterator gsi
;
1013 if (!integer_zerop (gimple_assign_rhs1 (last
.stmt
)))
1015 if (stmt_could_throw_p (last
.stmt
))
1017 gsi
= gsi_for_stmt (last
.stmt
);
1018 unlink_stmt_vdef (last
.stmt
);
1019 release_defs (last
.stmt
);
1020 gsi_remove (&gsi
, true);
1024 if (!valid_builtin_call (last
.stmt
))
1027 callee
= gimple_call_fndecl (last
.stmt
);
1028 switch (DECL_FUNCTION_CODE (callee
))
1030 case BUILT_IN_MEMCPY
:
1031 case BUILT_IN_MEMCPY_CHK
:
1033 case BUILT_IN_MEMCPY_CHKP
:
1034 case BUILT_IN_MEMCPY_CHK_CHKP
:
1041 len
= gimple_call_arg (last
.stmt
, len_arg_no
);
1042 if (tree_fits_uhwi_p (len
))
1044 if (!tree_fits_uhwi_p (last
.len
)
1045 || integer_zerop (len
)
1046 || tree_to_uhwi (len
) != tree_to_uhwi (last
.len
) + 1)
1048 /* Don't adjust the length if it is divisible by 4, it is more efficient
1049 to store the extra '\0' in that case. */
1050 if ((tree_to_uhwi (len
) & 3) == 0)
1053 else if (TREE_CODE (len
) == SSA_NAME
)
1055 gimple
*def_stmt
= SSA_NAME_DEF_STMT (len
);
1056 if (!is_gimple_assign (def_stmt
)
1057 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1058 || gimple_assign_rhs1 (def_stmt
) != last
.len
1059 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1065 gimple_call_set_arg (last
.stmt
, len_arg_no
, last
.len
);
1066 update_stmt (last
.stmt
);
1069 /* Handle a strlen call. If strlen of the argument is known, replace
1070 the strlen call with the known value, otherwise remember that strlen
1071 of the argument is stored in the lhs SSA_NAME. */
1074 handle_builtin_strlen (gimple_stmt_iterator
*gsi
)
1078 gimple
*stmt
= gsi_stmt (*gsi
);
1079 tree lhs
= gimple_call_lhs (stmt
);
1081 if (lhs
== NULL_TREE
)
1084 src
= gimple_call_arg (stmt
, 0);
1085 idx
= get_stridx (src
);
1092 rhs
= build_int_cst (TREE_TYPE (lhs
), ~idx
);
1096 si
= get_strinfo (idx
);
1098 rhs
= get_string_length (si
);
1100 if (rhs
!= NULL_TREE
)
1102 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1104 fprintf (dump_file
, "Optimizing: ");
1105 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1107 rhs
= unshare_expr (rhs
);
1108 if (!useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (rhs
)))
1109 rhs
= fold_convert_loc (gimple_location (stmt
),
1110 TREE_TYPE (lhs
), rhs
);
1111 if (!update_call_from_tree (gsi
, rhs
))
1112 gimplify_and_update_call_from_tree (gsi
, rhs
);
1113 stmt
= gsi_stmt (*gsi
);
1115 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1117 fprintf (dump_file
, "into: ");
1118 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1121 && TREE_CODE (si
->length
) != SSA_NAME
1122 && TREE_CODE (si
->length
) != INTEGER_CST
1123 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1125 si
= unshare_strinfo (si
);
1131 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1134 idx
= new_stridx (src
);
1135 else if (get_strinfo (idx
) != NULL
)
1139 strinfo
*si
= new_strinfo (src
, idx
, lhs
);
1140 set_strinfo (idx
, si
);
1141 find_equal_ptrs (src
, idx
);
1145 /* Handle a strchr call. If strlen of the first argument is known, replace
1146 the strchr (x, 0) call with the endptr or x + strlen, otherwise remember
1147 that lhs of the call is endptr and strlen of the argument is endptr - x. */
1150 handle_builtin_strchr (gimple_stmt_iterator
*gsi
)
1154 gimple
*stmt
= gsi_stmt (*gsi
);
1155 tree lhs
= gimple_call_lhs (stmt
);
1156 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1158 if (lhs
== NULL_TREE
)
1161 if (!integer_zerop (gimple_call_arg (stmt
, with_bounds
? 2 : 1)))
1164 src
= gimple_call_arg (stmt
, 0);
1165 idx
= get_stridx (src
);
1172 rhs
= build_int_cst (size_type_node
, ~idx
);
1176 si
= get_strinfo (idx
);
1178 rhs
= get_string_length (si
);
1180 if (rhs
!= NULL_TREE
)
1182 location_t loc
= gimple_location (stmt
);
1184 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1186 fprintf (dump_file
, "Optimizing: ");
1187 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1189 if (si
!= NULL
&& si
->endptr
!= NULL_TREE
)
1191 rhs
= unshare_expr (si
->endptr
);
1192 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1194 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1198 rhs
= fold_convert_loc (loc
, sizetype
, unshare_expr (rhs
));
1199 rhs
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1200 TREE_TYPE (src
), src
, rhs
);
1201 if (!useless_type_conversion_p (TREE_TYPE (lhs
),
1203 rhs
= fold_convert_loc (loc
, TREE_TYPE (lhs
), rhs
);
1205 if (!update_call_from_tree (gsi
, rhs
))
1206 gimplify_and_update_call_from_tree (gsi
, rhs
);
1207 stmt
= gsi_stmt (*gsi
);
1209 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1211 fprintf (dump_file
, "into: ");
1212 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1215 && si
->endptr
== NULL_TREE
1216 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1218 si
= unshare_strinfo (si
);
1221 zero_length_string (lhs
, si
);
1225 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs
))
1227 if (TREE_CODE (src
) != SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (src
))
1230 idx
= new_stridx (src
);
1231 else if (get_strinfo (idx
) != NULL
)
1233 zero_length_string (lhs
, NULL
);
1238 location_t loc
= gimple_location (stmt
);
1239 tree lhsu
= fold_convert_loc (loc
, size_type_node
, lhs
);
1240 tree srcu
= fold_convert_loc (loc
, size_type_node
, src
);
1241 tree length
= fold_build2_loc (loc
, MINUS_EXPR
,
1242 size_type_node
, lhsu
, srcu
);
1243 strinfo
*si
= new_strinfo (src
, idx
, length
);
1245 set_strinfo (idx
, si
);
1246 find_equal_ptrs (src
, idx
);
1247 zero_length_string (lhs
, si
);
1251 zero_length_string (lhs
, NULL
);
1254 /* Handle a strcpy-like ({st{r,p}cpy,__st{r,p}cpy_chk}) call.
1255 If strlen of the second argument is known, strlen of the first argument
1256 is the same after this call. Furthermore, attempt to convert it to
1260 handle_builtin_strcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1263 tree src
, dst
, srclen
, len
, lhs
, args
, type
, fn
, oldlen
;
1265 gimple
*stmt
= gsi_stmt (*gsi
);
1266 strinfo
*si
, *dsi
, *olddsi
, *zsi
;
1268 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1270 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1271 dst
= gimple_call_arg (stmt
, 0);
1272 lhs
= gimple_call_lhs (stmt
);
1273 idx
= get_stridx (src
);
1276 si
= get_strinfo (idx
);
1278 didx
= get_stridx (dst
);
1282 olddsi
= get_strinfo (didx
);
1287 adjust_last_stmt (olddsi
, stmt
, false);
1291 srclen
= get_string_length (si
);
1293 srclen
= build_int_cst (size_type_node
, ~idx
);
1295 loc
= gimple_location (stmt
);
1296 if (srclen
== NULL_TREE
)
1299 case BUILT_IN_STRCPY
:
1300 case BUILT_IN_STRCPY_CHK
:
1301 case BUILT_IN_STRCPY_CHKP
:
1302 case BUILT_IN_STRCPY_CHK_CHKP
:
1303 if (lhs
!= NULL_TREE
|| !builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1306 case BUILT_IN_STPCPY
:
1307 case BUILT_IN_STPCPY_CHK
:
1308 case BUILT_IN_STPCPY_CHKP
:
1309 case BUILT_IN_STPCPY_CHK_CHKP
:
1310 if (lhs
== NULL_TREE
)
1314 tree lhsuint
= fold_convert_loc (loc
, size_type_node
, lhs
);
1315 srclen
= fold_convert_loc (loc
, size_type_node
, dst
);
1316 srclen
= fold_build2_loc (loc
, MINUS_EXPR
, size_type_node
,
1326 didx
= new_stridx (dst
);
1332 oldlen
= olddsi
->length
;
1333 dsi
= unshare_strinfo (olddsi
);
1334 dsi
->length
= srclen
;
1335 /* Break the chain, so adjust_related_strinfo on later pointers in
1336 the chain won't adjust this one anymore. */
1339 dsi
->endptr
= NULL_TREE
;
1343 dsi
= new_strinfo (dst
, didx
, srclen
);
1344 set_strinfo (didx
, dsi
);
1345 find_equal_ptrs (dst
, didx
);
1347 dsi
->writable
= true;
1348 dsi
->dont_invalidate
= true;
1350 if (dsi
->length
== NULL_TREE
)
1354 /* If string length of src is unknown, use delayed length
1355 computation. If string lenth of dst will be needed, it
1356 can be computed by transforming this strcpy call into
1357 stpcpy and subtracting dst from the return value. */
1359 /* Look for earlier strings whose length could be determined if
1360 this strcpy is turned into an stpcpy. */
1362 if (dsi
->prev
!= 0 && (chainsi
= verify_related_strinfos (dsi
)) != NULL
)
1364 for (; chainsi
&& chainsi
!= dsi
; chainsi
= get_strinfo (chainsi
->next
))
1366 /* When setting a stmt for delayed length computation
1367 prevent all strinfos through dsi from being
1369 chainsi
= unshare_strinfo (chainsi
);
1370 chainsi
->stmt
= stmt
;
1371 chainsi
->length
= NULL_TREE
;
1372 chainsi
->endptr
= NULL_TREE
;
1373 chainsi
->dont_invalidate
= true;
1382 tree adj
= NULL_TREE
;
1383 if (oldlen
== NULL_TREE
)
1385 else if (integer_zerop (oldlen
))
1387 else if (TREE_CODE (oldlen
) == INTEGER_CST
1388 || TREE_CODE (srclen
) == INTEGER_CST
)
1389 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1390 TREE_TYPE (srclen
), srclen
,
1391 fold_convert_loc (loc
, TREE_TYPE (srclen
),
1393 if (adj
!= NULL_TREE
)
1394 adjust_related_strinfos (loc
, dsi
, adj
);
1398 /* strcpy src may not overlap dst, so src doesn't need to be
1399 invalidated either. */
1401 si
->dont_invalidate
= true;
1407 case BUILT_IN_STRCPY
:
1408 case BUILT_IN_STRCPY_CHKP
:
1409 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1411 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1413 case BUILT_IN_STRCPY_CHK
:
1414 case BUILT_IN_STRCPY_CHK_CHKP
:
1415 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1417 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1419 case BUILT_IN_STPCPY
:
1420 case BUILT_IN_STPCPY_CHKP
:
1421 /* This would need adjustment of the lhs (subtract one),
1422 or detection that the trailing '\0' doesn't need to be
1423 written, if it will be immediately overwritten.
1424 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
1428 zsi
= zero_length_string (lhs
, dsi
);
1431 case BUILT_IN_STPCPY_CHK
:
1432 case BUILT_IN_STPCPY_CHK_CHKP
:
1433 /* This would need adjustment of the lhs (subtract one),
1434 or detection that the trailing '\0' doesn't need to be
1435 written, if it will be immediately overwritten.
1436 fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
1440 zsi
= zero_length_string (lhs
, dsi
);
1447 zsi
->dont_invalidate
= true;
1449 if (fn
== NULL_TREE
)
1452 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1453 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1455 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1456 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
, build_int_cst (type
, 1));
1457 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1459 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1461 fprintf (dump_file
, "Optimizing: ");
1462 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1466 fn
= chkp_maybe_create_clone (fn
)->decl
;
1467 if (gimple_call_num_args (stmt
) == 4)
1468 success
= update_gimple_call (gsi
, fn
, 5, dst
,
1469 gimple_call_arg (stmt
, 1),
1471 gimple_call_arg (stmt
, 3),
1474 success
= update_gimple_call (gsi
, fn
, 6, dst
,
1475 gimple_call_arg (stmt
, 1),
1477 gimple_call_arg (stmt
, 3),
1479 gimple_call_arg (stmt
, 4));
1482 if (gimple_call_num_args (stmt
) == 2)
1483 success
= update_gimple_call (gsi
, fn
, 3, dst
, src
, len
);
1485 success
= update_gimple_call (gsi
, fn
, 4, dst
, src
, len
,
1486 gimple_call_arg (stmt
, 2));
1489 stmt
= gsi_stmt (*gsi
);
1490 gimple_call_set_with_bounds (stmt
, with_bounds
);
1492 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1494 fprintf (dump_file
, "into: ");
1495 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1497 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1498 laststmt
.stmt
= stmt
;
1499 laststmt
.len
= srclen
;
1500 laststmt
.stridx
= dsi
->idx
;
1502 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1503 fprintf (dump_file
, "not possible.\n");
1506 /* Handle a memcpy-like ({mem{,p}cpy,__mem{,p}cpy_chk}) call.
1507 If strlen of the second argument is known and length of the third argument
1508 is that plus one, strlen of the first argument is the same after this
1512 handle_builtin_memcpy (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1515 tree src
, dst
, len
, lhs
, oldlen
, newlen
;
1516 gimple
*stmt
= gsi_stmt (*gsi
);
1517 strinfo
*si
, *dsi
, *olddsi
;
1518 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1520 len
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1521 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1522 dst
= gimple_call_arg (stmt
, 0);
1523 idx
= get_stridx (src
);
1527 didx
= get_stridx (dst
);
1530 olddsi
= get_strinfo (didx
);
1535 && tree_fits_uhwi_p (len
)
1536 && !integer_zerop (len
))
1537 adjust_last_stmt (olddsi
, stmt
, false);
1543 /* Handle memcpy (x, y, l) where l is strlen (y) + 1. */
1544 si
= get_strinfo (idx
);
1545 if (si
== NULL
|| si
->length
== NULL_TREE
)
1547 if (TREE_CODE (len
) != SSA_NAME
)
1549 def_stmt
= SSA_NAME_DEF_STMT (len
);
1550 if (!is_gimple_assign (def_stmt
)
1551 || gimple_assign_rhs_code (def_stmt
) != PLUS_EXPR
1552 || gimple_assign_rhs1 (def_stmt
) != si
->length
1553 || !integer_onep (gimple_assign_rhs2 (def_stmt
)))
1559 /* Handle memcpy (x, "abcd", 5) or
1560 memcpy (x, "abc\0uvw", 7). */
1561 if (!tree_fits_uhwi_p (len
)
1562 || tree_to_uhwi (len
) <= (unsigned HOST_WIDE_INT
) ~idx
)
1566 if (olddsi
!= NULL
&& TREE_CODE (len
) == SSA_NAME
)
1567 adjust_last_stmt (olddsi
, stmt
, false);
1571 didx
= new_stridx (dst
);
1576 newlen
= si
->length
;
1578 newlen
= build_int_cst (size_type_node
, ~idx
);
1582 dsi
= unshare_strinfo (olddsi
);
1583 oldlen
= olddsi
->length
;
1584 dsi
->length
= newlen
;
1585 /* Break the chain, so adjust_related_strinfo on later pointers in
1586 the chain won't adjust this one anymore. */
1589 dsi
->endptr
= NULL_TREE
;
1593 dsi
= new_strinfo (dst
, didx
, newlen
);
1594 set_strinfo (didx
, dsi
);
1595 find_equal_ptrs (dst
, didx
);
1597 dsi
->writable
= true;
1598 dsi
->dont_invalidate
= true;
1601 tree adj
= NULL_TREE
;
1602 location_t loc
= gimple_location (stmt
);
1603 if (oldlen
== NULL_TREE
)
1605 else if (integer_zerop (oldlen
))
1607 else if (TREE_CODE (oldlen
) == INTEGER_CST
1608 || TREE_CODE (dsi
->length
) == INTEGER_CST
)
1609 adj
= fold_build2_loc (loc
, MINUS_EXPR
,
1610 TREE_TYPE (dsi
->length
), dsi
->length
,
1611 fold_convert_loc (loc
, TREE_TYPE (dsi
->length
),
1613 if (adj
!= NULL_TREE
)
1614 adjust_related_strinfos (loc
, dsi
, adj
);
1618 /* memcpy src may not overlap dst, so src doesn't need to be
1619 invalidated either. */
1621 si
->dont_invalidate
= true;
1623 lhs
= gimple_call_lhs (stmt
);
1626 case BUILT_IN_MEMCPY
:
1627 case BUILT_IN_MEMCPY_CHK
:
1628 case BUILT_IN_MEMCPY_CHKP
:
1629 case BUILT_IN_MEMCPY_CHK_CHKP
:
1630 /* Allow adjust_last_stmt to decrease this memcpy's size. */
1631 laststmt
.stmt
= stmt
;
1632 laststmt
.len
= dsi
->length
;
1633 laststmt
.stridx
= dsi
->idx
;
1635 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = didx
;
1637 case BUILT_IN_MEMPCPY
:
1638 case BUILT_IN_MEMPCPY_CHK
:
1639 case BUILT_IN_MEMPCPY_CHKP
:
1640 case BUILT_IN_MEMPCPY_CHK_CHKP
:
1647 /* Handle a strcat-like ({strcat,__strcat_chk}) call.
1648 If strlen of the second argument is known, strlen of the first argument
1649 is increased by the length of the second argument. Furthermore, attempt
1650 to convert it to memcpy/strcpy if the length of the first argument
1654 handle_builtin_strcat (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1657 tree src
, dst
, srclen
, dstlen
, len
, lhs
, args
, type
, fn
, objsz
, endptr
;
1659 gimple
*stmt
= gsi_stmt (*gsi
);
1662 bool with_bounds
= gimple_call_with_bounds_p (stmt
);
1664 src
= gimple_call_arg (stmt
, with_bounds
? 2 : 1);
1665 dst
= gimple_call_arg (stmt
, 0);
1666 lhs
= gimple_call_lhs (stmt
);
1668 didx
= get_stridx (dst
);
1674 dsi
= get_strinfo (didx
);
1675 if (dsi
== NULL
|| get_string_length (dsi
) == NULL_TREE
)
1677 /* strcat (p, q) can be transformed into
1678 tmp = p + strlen (p); endptr = strpcpy (tmp, q);
1679 with length endptr - p if we need to compute the length
1680 later on. Don't do this transformation if we don't need
1682 if (builtin_decl_implicit_p (BUILT_IN_STPCPY
) && lhs
== NULL_TREE
)
1686 didx
= new_stridx (dst
);
1692 dsi
= new_strinfo (dst
, didx
, NULL_TREE
);
1693 set_strinfo (didx
, dsi
);
1694 find_equal_ptrs (dst
, didx
);
1698 dsi
= unshare_strinfo (dsi
);
1699 dsi
->length
= NULL_TREE
;
1701 dsi
->endptr
= NULL_TREE
;
1703 dsi
->writable
= true;
1705 dsi
->dont_invalidate
= true;
1712 idx
= get_stridx (src
);
1714 srclen
= build_int_cst (size_type_node
, ~idx
);
1717 si
= get_strinfo (idx
);
1719 srclen
= get_string_length (si
);
1722 loc
= gimple_location (stmt
);
1723 dstlen
= dsi
->length
;
1724 endptr
= dsi
->endptr
;
1726 dsi
= unshare_strinfo (dsi
);
1727 dsi
->endptr
= NULL_TREE
;
1729 dsi
->writable
= true;
1731 if (srclen
!= NULL_TREE
)
1733 dsi
->length
= fold_build2_loc (loc
, PLUS_EXPR
, TREE_TYPE (dsi
->length
),
1734 dsi
->length
, srclen
);
1735 adjust_related_strinfos (loc
, dsi
, srclen
);
1736 dsi
->dont_invalidate
= true;
1741 if (lhs
== NULL_TREE
&& builtin_decl_implicit_p (BUILT_IN_STPCPY
))
1742 dsi
->dont_invalidate
= true;
1746 /* strcat src may not overlap dst, so src doesn't need to be
1747 invalidated either. */
1748 si
->dont_invalidate
= true;
1750 /* For now. Could remove the lhs from the call and add
1751 lhs = dst; afterwards. */
1759 case BUILT_IN_STRCAT
:
1760 case BUILT_IN_STRCAT_CHKP
:
1761 if (srclen
!= NULL_TREE
)
1762 fn
= builtin_decl_implicit (BUILT_IN_MEMCPY
);
1764 fn
= builtin_decl_implicit (BUILT_IN_STRCPY
);
1766 case BUILT_IN_STRCAT_CHK
:
1767 case BUILT_IN_STRCAT_CHK_CHKP
:
1768 if (srclen
!= NULL_TREE
)
1769 fn
= builtin_decl_explicit (BUILT_IN_MEMCPY_CHK
);
1771 fn
= builtin_decl_explicit (BUILT_IN_STRCPY_CHK
);
1772 objsz
= gimple_call_arg (stmt
, with_bounds
? 4 : 2);
1778 if (fn
== NULL_TREE
)
1782 if (srclen
!= NULL_TREE
)
1784 args
= TYPE_ARG_TYPES (TREE_TYPE (fn
));
1785 type
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args
)));
1787 len
= fold_convert_loc (loc
, type
, unshare_expr (srclen
));
1788 len
= fold_build2_loc (loc
, PLUS_EXPR
, type
, len
,
1789 build_int_cst (type
, 1));
1790 len
= force_gimple_operand_gsi (gsi
, len
, true, NULL_TREE
, true,
1794 dst
= fold_convert_loc (loc
, TREE_TYPE (dst
), unshare_expr (endptr
));
1796 dst
= fold_build2_loc (loc
, POINTER_PLUS_EXPR
,
1797 TREE_TYPE (dst
), unshare_expr (dst
),
1798 fold_convert_loc (loc
, sizetype
,
1799 unshare_expr (dstlen
)));
1800 dst
= force_gimple_operand_gsi (gsi
, dst
, true, NULL_TREE
, true,
1802 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1804 fprintf (dump_file
, "Optimizing: ");
1805 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1809 fn
= chkp_maybe_create_clone (fn
)->decl
;
1810 if (srclen
!= NULL_TREE
)
1811 success
= update_gimple_call (gsi
, fn
, 5 + (objsz
!= NULL_TREE
),
1813 gimple_call_arg (stmt
, 1),
1815 gimple_call_arg (stmt
, 3),
1818 success
= update_gimple_call (gsi
, fn
, 4 + (objsz
!= NULL_TREE
),
1820 gimple_call_arg (stmt
, 1),
1822 gimple_call_arg (stmt
, 3),
1826 if (srclen
!= NULL_TREE
)
1827 success
= update_gimple_call (gsi
, fn
, 3 + (objsz
!= NULL_TREE
),
1828 dst
, src
, len
, objsz
);
1830 success
= update_gimple_call (gsi
, fn
, 2 + (objsz
!= NULL_TREE
),
1834 stmt
= gsi_stmt (*gsi
);
1835 gimple_call_set_with_bounds (stmt
, with_bounds
);
1837 if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1839 fprintf (dump_file
, "into: ");
1840 print_gimple_stmt (dump_file
, stmt
, 0, TDF_SLIM
);
1842 /* If srclen == NULL, note that current string length can be
1843 computed by transforming this strcpy into stpcpy. */
1844 if (srclen
== NULL_TREE
&& dsi
->dont_invalidate
)
1846 adjust_last_stmt (dsi
, stmt
, true);
1847 if (srclen
!= NULL_TREE
)
1849 laststmt
.stmt
= stmt
;
1850 laststmt
.len
= srclen
;
1851 laststmt
.stridx
= dsi
->idx
;
1854 else if (dump_file
&& (dump_flags
& TDF_DETAILS
) != 0)
1855 fprintf (dump_file
, "not possible.\n");
1858 /* Handle a call to malloc or calloc. */
1861 handle_builtin_malloc (enum built_in_function bcode
, gimple_stmt_iterator
*gsi
)
1863 gimple
*stmt
= gsi_stmt (*gsi
);
1864 tree lhs
= gimple_call_lhs (stmt
);
1865 if (lhs
== NULL_TREE
)
1868 gcc_assert (get_stridx (lhs
) == 0);
1869 int idx
= new_stridx (lhs
);
1870 tree length
= NULL_TREE
;
1871 if (bcode
== BUILT_IN_CALLOC
)
1872 length
= build_int_cst (size_type_node
, 0);
1873 strinfo
*si
= new_strinfo (lhs
, idx
, length
);
1874 if (bcode
== BUILT_IN_CALLOC
)
1876 set_strinfo (idx
, si
);
1877 si
->writable
= true;
1879 si
->dont_invalidate
= true;
1882 /* Handle a call to memset.
1883 After a call to calloc, memset(,0,) is unnecessary.
1884 memset(malloc(n),0,n) is calloc(n,1). */
1887 handle_builtin_memset (gimple_stmt_iterator
*gsi
)
1889 gimple
*stmt2
= gsi_stmt (*gsi
);
1890 if (!integer_zerop (gimple_call_arg (stmt2
, 1)))
1892 tree ptr
= gimple_call_arg (stmt2
, 0);
1893 int idx1
= get_stridx (ptr
);
1896 strinfo
*si1
= get_strinfo (idx1
);
1899 gimple
*stmt1
= si1
->stmt
;
1900 if (!stmt1
|| !is_gimple_call (stmt1
))
1902 tree callee1
= gimple_call_fndecl (stmt1
);
1903 if (!valid_builtin_call (stmt1
))
1905 enum built_in_function code1
= DECL_FUNCTION_CODE (callee1
);
1906 tree size
= gimple_call_arg (stmt2
, 2);
1907 if (code1
== BUILT_IN_CALLOC
)
1908 /* Not touching stmt1 */ ;
1909 else if (code1
== BUILT_IN_MALLOC
1910 && operand_equal_p (gimple_call_arg (stmt1
, 0), size
, 0))
1912 gimple_stmt_iterator gsi1
= gsi_for_stmt (stmt1
);
1913 update_gimple_call (&gsi1
, builtin_decl_implicit (BUILT_IN_CALLOC
), 2,
1914 size
, build_one_cst (size_type_node
));
1915 si1
->length
= build_int_cst (size_type_node
, 0);
1916 si1
->stmt
= gsi_stmt (gsi1
);
1920 tree lhs
= gimple_call_lhs (stmt2
);
1921 unlink_stmt_vdef (stmt2
);
1924 gimple
*assign
= gimple_build_assign (lhs
, ptr
);
1925 gsi_replace (gsi
, assign
, false);
1929 gsi_remove (gsi
, true);
1930 release_defs (stmt2
);
1936 /* Handle a call to memcmp. We try to handle small comparisons by
1937 converting them to load and compare, and replacing the call to memcmp
1938 with a __builtin_memcmp_eq call where possible. */
1941 handle_builtin_memcmp (gimple_stmt_iterator
*gsi
)
1943 gcall
*stmt2
= as_a
<gcall
*> (gsi_stmt (*gsi
));
1944 tree res
= gimple_call_lhs (stmt2
);
1945 tree arg1
= gimple_call_arg (stmt2
, 0);
1946 tree arg2
= gimple_call_arg (stmt2
, 1);
1947 tree len
= gimple_call_arg (stmt2
, 2);
1948 unsigned HOST_WIDE_INT leni
;
1949 use_operand_p use_p
;
1950 imm_use_iterator iter
;
1955 FOR_EACH_IMM_USE_FAST (use_p
, iter
, res
)
1957 gimple
*ustmt
= USE_STMT (use_p
);
1959 if (is_gimple_debug (ustmt
))
1961 if (gimple_code (ustmt
) == GIMPLE_ASSIGN
)
1963 gassign
*asgn
= as_a
<gassign
*> (ustmt
);
1964 tree_code code
= gimple_assign_rhs_code (asgn
);
1965 if ((code
!= EQ_EXPR
&& code
!= NE_EXPR
)
1966 || !integer_zerop (gimple_assign_rhs2 (asgn
)))
1969 else if (gimple_code (ustmt
) == GIMPLE_COND
)
1971 tree_code code
= gimple_cond_code (ustmt
);
1972 if ((code
!= EQ_EXPR
&& code
!= NE_EXPR
)
1973 || !integer_zerop (gimple_cond_rhs (ustmt
)))
1980 if (tree_fits_uhwi_p (len
)
1981 && (leni
= tree_to_uhwi (len
)) <= GET_MODE_SIZE (word_mode
)
1982 && pow2p_hwi (leni
))
1984 leni
*= CHAR_TYPE_SIZE
;
1985 unsigned align1
= get_pointer_alignment (arg1
);
1986 unsigned align2
= get_pointer_alignment (arg2
);
1987 unsigned align
= MIN (align1
, align2
);
1988 machine_mode mode
= mode_for_size (leni
, MODE_INT
, 1);
1990 && (align
>= leni
|| !SLOW_UNALIGNED_ACCESS (mode
, align
)))
1992 location_t loc
= gimple_location (stmt2
);
1994 type
= build_nonstandard_integer_type (leni
, 1);
1995 gcc_assert (GET_MODE_BITSIZE (TYPE_MODE (type
)) == leni
);
1996 tree ptrtype
= build_pointer_type_for_mode (char_type_node
,
1998 off
= build_int_cst (ptrtype
, 0);
1999 arg1
= build2_loc (loc
, MEM_REF
, type
, arg1
, off
);
2000 arg2
= build2_loc (loc
, MEM_REF
, type
, arg2
, off
);
2001 tree tem1
= fold_const_aggregate_ref (arg1
);
2004 tree tem2
= fold_const_aggregate_ref (arg2
);
2007 res
= fold_convert_loc (loc
, TREE_TYPE (res
),
2008 fold_build2_loc (loc
, NE_EXPR
,
2011 gimplify_and_update_call_from_tree (gsi
, res
);
2016 gimple_call_set_fndecl (stmt2
, builtin_decl_explicit (BUILT_IN_MEMCMP_EQ
));
2020 /* Handle a POINTER_PLUS_EXPR statement.
2021 For p = "abcd" + 2; compute associated length, or if
2022 p = q + off is pointing to a '\0' character of a string, call
2023 zero_length_string on it. */
2026 handle_pointer_plus (gimple_stmt_iterator
*gsi
)
2028 gimple
*stmt
= gsi_stmt (*gsi
);
2029 tree lhs
= gimple_assign_lhs (stmt
), off
;
2030 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2038 tree off
= gimple_assign_rhs2 (stmt
);
2039 if (tree_fits_uhwi_p (off
)
2040 && tree_to_uhwi (off
) <= (unsigned HOST_WIDE_INT
) ~idx
)
2041 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)]
2042 = ~(~idx
- (int) tree_to_uhwi (off
));
2046 si
= get_strinfo (idx
);
2047 if (si
== NULL
|| si
->length
== NULL_TREE
)
2050 off
= gimple_assign_rhs2 (stmt
);
2052 if (operand_equal_p (si
->length
, off
, 0))
2053 zsi
= zero_length_string (lhs
, si
);
2054 else if (TREE_CODE (off
) == SSA_NAME
)
2056 gimple
*def_stmt
= SSA_NAME_DEF_STMT (off
);
2057 if (gimple_assign_single_p (def_stmt
)
2058 && operand_equal_p (si
->length
, gimple_assign_rhs1 (def_stmt
), 0))
2059 zsi
= zero_length_string (lhs
, si
);
2062 && si
->endptr
!= NULL_TREE
2063 && si
->endptr
!= lhs
2064 && TREE_CODE (si
->endptr
) == SSA_NAME
)
2066 enum tree_code rhs_code
2067 = useless_type_conversion_p (TREE_TYPE (lhs
), TREE_TYPE (si
->endptr
))
2068 ? SSA_NAME
: NOP_EXPR
;
2069 gimple_assign_set_rhs_with_ops (gsi
, rhs_code
, si
->endptr
);
2070 gcc_assert (gsi_stmt (*gsi
) == stmt
);
2075 /* Handle a single character store. */
2078 handle_char_store (gimple_stmt_iterator
*gsi
)
2082 gimple
*stmt
= gsi_stmt (*gsi
);
2083 tree ssaname
= NULL_TREE
, lhs
= gimple_assign_lhs (stmt
);
2085 if (TREE_CODE (lhs
) == MEM_REF
2086 && TREE_CODE (TREE_OPERAND (lhs
, 0)) == SSA_NAME
)
2088 if (integer_zerop (TREE_OPERAND (lhs
, 1)))
2090 ssaname
= TREE_OPERAND (lhs
, 0);
2091 idx
= get_stridx (ssaname
);
2095 idx
= get_addr_stridx (lhs
, NULL_TREE
);
2099 si
= get_strinfo (idx
);
2100 if (si
!= NULL
&& si
->length
!= NULL_TREE
&& integer_zerop (si
->length
))
2102 if (initializer_zerop (gimple_assign_rhs1 (stmt
)))
2104 /* When storing '\0', the store can be removed
2105 if we know it has been stored in the current function. */
2106 if (!stmt_could_throw_p (stmt
) && si
->writable
)
2108 unlink_stmt_vdef (stmt
);
2109 release_defs (stmt
);
2110 gsi_remove (gsi
, true);
2115 si
->writable
= true;
2121 /* Otherwise this statement overwrites the '\0' with
2122 something, if the previous stmt was a memcpy,
2123 its length may be decreased. */
2124 adjust_last_stmt (si
, stmt
, false);
2126 else if (si
!= NULL
&& integer_zerop (gimple_assign_rhs1 (stmt
)))
2128 si
= unshare_strinfo (si
);
2129 si
->length
= build_int_cst (size_type_node
, 0);
2135 si
->writable
= true;
2136 if (ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname
))
2137 si
->endptr
= ssaname
;
2138 si
->dont_invalidate
= true;
2140 /* If si->length is non-zero constant, we aren't overwriting '\0',
2141 and if we aren't storing '\0', we know that the length of the
2142 string and any other zero terminated string in memory remains
2143 the same. In that case we move to the next gimple statement and
2144 return to signal the caller that it shouldn't invalidate anything.
2146 This is benefical for cases like:
2151 strcpy (p, "foobar");
2152 size_t len = strlen (p); // This can be optimized into 6
2153 size_t len2 = strlen (q); // This has to be computed
2155 size_t len3 = strlen (p); // This can be optimized into 6
2156 size_t len4 = strlen (q); // This can be optimized into len2
2157 bar (len, len2, len3, len4);
2160 else if (si
!= NULL
&& si
->length
!= NULL_TREE
2161 && TREE_CODE (si
->length
) == INTEGER_CST
2162 && integer_nonzerop (gimple_assign_rhs1 (stmt
)))
2168 else if (idx
== 0 && initializer_zerop (gimple_assign_rhs1 (stmt
)))
2172 si
= zero_length_string (ssaname
, NULL
);
2174 si
->dont_invalidate
= true;
2178 int idx
= new_addr_stridx (lhs
);
2181 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2182 build_int_cst (size_type_node
, 0));
2183 set_strinfo (idx
, si
);
2184 si
->dont_invalidate
= true;
2188 si
->writable
= true;
2191 && TREE_CODE (gimple_assign_rhs1 (stmt
)) == STRING_CST
2192 && ssaname
== NULL_TREE
2193 && TREE_CODE (TREE_TYPE (lhs
)) == ARRAY_TYPE
)
2195 size_t l
= strlen (TREE_STRING_POINTER (gimple_assign_rhs1 (stmt
)));
2196 HOST_WIDE_INT a
= int_size_in_bytes (TREE_TYPE (lhs
));
2197 if (a
> 0 && (unsigned HOST_WIDE_INT
) a
> l
)
2199 int idx
= new_addr_stridx (lhs
);
2202 si
= new_strinfo (build_fold_addr_expr (lhs
), idx
,
2203 build_int_cst (size_type_node
, l
));
2204 set_strinfo (idx
, si
);
2205 si
->dont_invalidate
= true;
2210 if (si
!= NULL
&& initializer_zerop (gimple_assign_rhs1 (stmt
)))
2212 /* Allow adjust_last_stmt to remove it if the stored '\0'
2213 is immediately overwritten. */
2214 laststmt
.stmt
= stmt
;
2215 laststmt
.len
= build_int_cst (size_type_node
, 1);
2216 laststmt
.stridx
= si
->idx
;
2221 /* Try to fold strstr (s, t) eq/ne s to strncmp (s, t, strlen (t)) eq/ne 0. */
2224 fold_strstr_to_strncmp (tree rhs1
, tree rhs2
, gimple
*stmt
)
2226 if (TREE_CODE (rhs1
) != SSA_NAME
2227 || TREE_CODE (rhs2
) != SSA_NAME
)
2230 gimple
*call_stmt
= NULL
;
2231 for (int pass
= 0; pass
< 2; pass
++)
2233 gimple
*g
= SSA_NAME_DEF_STMT (rhs1
);
2234 if (gimple_call_builtin_p (g
, BUILT_IN_STRSTR
)
2235 && has_single_use (rhs1
)
2236 && gimple_call_arg (g
, 0) == rhs2
)
2241 std::swap (rhs1
, rhs2
);
2246 tree arg0
= gimple_call_arg (call_stmt
, 0);
2250 tree arg1
= gimple_call_arg (call_stmt
, 1);
2251 tree arg1_len
= NULL_TREE
;
2252 int idx
= get_stridx (arg1
);
2257 arg1_len
= build_int_cst (size_type_node
, ~idx
);
2260 strinfo
*si
= get_strinfo (idx
);
2262 arg1_len
= get_string_length (si
);
2266 if (arg1_len
!= NULL_TREE
)
2268 gimple_stmt_iterator gsi
= gsi_for_stmt (call_stmt
);
2269 tree strncmp_decl
= builtin_decl_explicit (BUILT_IN_STRNCMP
);
2270 gcall
*strncmp_call
= gimple_build_call (strncmp_decl
, 3,
2271 arg0
, arg1
, arg1_len
);
2272 tree strncmp_lhs
= make_ssa_name (integer_type_node
);
2273 gimple_set_vuse (strncmp_call
, gimple_vuse (call_stmt
));
2274 gimple_call_set_lhs (strncmp_call
, strncmp_lhs
);
2275 gsi_remove (&gsi
, true);
2276 gsi_insert_before (&gsi
, strncmp_call
, GSI_SAME_STMT
);
2277 tree zero
= build_zero_cst (TREE_TYPE (strncmp_lhs
));
2279 if (is_gimple_assign (stmt
))
2281 if (gimple_assign_rhs_code (stmt
) == COND_EXPR
)
2283 tree cond
= gimple_assign_rhs1 (stmt
);
2284 TREE_OPERAND (cond
, 0) = strncmp_lhs
;
2285 TREE_OPERAND (cond
, 1) = zero
;
2289 gimple_assign_set_rhs1 (stmt
, strncmp_lhs
);
2290 gimple_assign_set_rhs2 (stmt
, zero
);
2295 gcond
*cond
= as_a
<gcond
*> (stmt
);
2296 gimple_cond_set_lhs (cond
, strncmp_lhs
);
2297 gimple_cond_set_rhs (cond
, zero
);
2305 /* Attempt to optimize a single statement at *GSI using string length
2309 strlen_optimize_stmt (gimple_stmt_iterator
*gsi
)
2311 gimple
*stmt
= gsi_stmt (*gsi
);
2313 if (is_gimple_call (stmt
))
2315 tree callee
= gimple_call_fndecl (stmt
);
2316 if (valid_builtin_call (stmt
))
2317 switch (DECL_FUNCTION_CODE (callee
))
2319 case BUILT_IN_STRLEN
:
2320 case BUILT_IN_STRLEN_CHKP
:
2321 handle_builtin_strlen (gsi
);
2323 case BUILT_IN_STRCHR
:
2324 case BUILT_IN_STRCHR_CHKP
:
2325 handle_builtin_strchr (gsi
);
2327 case BUILT_IN_STRCPY
:
2328 case BUILT_IN_STRCPY_CHK
:
2329 case BUILT_IN_STPCPY
:
2330 case BUILT_IN_STPCPY_CHK
:
2331 case BUILT_IN_STRCPY_CHKP
:
2332 case BUILT_IN_STRCPY_CHK_CHKP
:
2333 case BUILT_IN_STPCPY_CHKP
:
2334 case BUILT_IN_STPCPY_CHK_CHKP
:
2335 handle_builtin_strcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2337 case BUILT_IN_MEMCPY
:
2338 case BUILT_IN_MEMCPY_CHK
:
2339 case BUILT_IN_MEMPCPY
:
2340 case BUILT_IN_MEMPCPY_CHK
:
2341 case BUILT_IN_MEMCPY_CHKP
:
2342 case BUILT_IN_MEMCPY_CHK_CHKP
:
2343 case BUILT_IN_MEMPCPY_CHKP
:
2344 case BUILT_IN_MEMPCPY_CHK_CHKP
:
2345 handle_builtin_memcpy (DECL_FUNCTION_CODE (callee
), gsi
);
2347 case BUILT_IN_STRCAT
:
2348 case BUILT_IN_STRCAT_CHK
:
2349 case BUILT_IN_STRCAT_CHKP
:
2350 case BUILT_IN_STRCAT_CHK_CHKP
:
2351 handle_builtin_strcat (DECL_FUNCTION_CODE (callee
), gsi
);
2353 case BUILT_IN_MALLOC
:
2354 case BUILT_IN_CALLOC
:
2355 handle_builtin_malloc (DECL_FUNCTION_CODE (callee
), gsi
);
2357 case BUILT_IN_MEMSET
:
2358 if (!handle_builtin_memset (gsi
))
2361 case BUILT_IN_MEMCMP
:
2362 if (!handle_builtin_memcmp (gsi
))
2369 else if (is_gimple_assign (stmt
) && !gimple_clobber_p (stmt
))
2371 tree lhs
= gimple_assign_lhs (stmt
);
2373 if (TREE_CODE (lhs
) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (lhs
)))
2375 if (gimple_assign_single_p (stmt
)
2376 || (gimple_assign_cast_p (stmt
)
2377 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt
)))))
2379 int idx
= get_stridx (gimple_assign_rhs1 (stmt
));
2380 ssa_ver_to_stridx
[SSA_NAME_VERSION (lhs
)] = idx
;
2382 else if (gimple_assign_rhs_code (stmt
) == POINTER_PLUS_EXPR
)
2383 handle_pointer_plus (gsi
);
2385 else if (TREE_CODE (lhs
) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (lhs
)))
2387 enum tree_code code
= gimple_assign_rhs_code (stmt
);
2388 if (code
== COND_EXPR
)
2390 tree cond
= gimple_assign_rhs1 (stmt
);
2391 enum tree_code cond_code
= TREE_CODE (cond
);
2393 if (cond_code
== EQ_EXPR
|| cond_code
== NE_EXPR
)
2394 fold_strstr_to_strncmp (TREE_OPERAND (cond
, 0),
2395 TREE_OPERAND (cond
, 1), stmt
);
2397 else if (code
== EQ_EXPR
|| code
== NE_EXPR
)
2398 fold_strstr_to_strncmp (gimple_assign_rhs1 (stmt
),
2399 gimple_assign_rhs2 (stmt
), stmt
);
2401 else if (TREE_CODE (lhs
) != SSA_NAME
&& !TREE_SIDE_EFFECTS (lhs
))
2403 tree type
= TREE_TYPE (lhs
);
2404 if (TREE_CODE (type
) == ARRAY_TYPE
)
2405 type
= TREE_TYPE (type
);
2406 if (TREE_CODE (type
) == INTEGER_TYPE
2407 && TYPE_MODE (type
) == TYPE_MODE (char_type_node
)
2408 && TYPE_PRECISION (type
) == TYPE_PRECISION (char_type_node
))
2410 if (! handle_char_store (gsi
))
2415 else if (gcond
*cond
= dyn_cast
<gcond
*> (stmt
))
2417 enum tree_code code
= gimple_cond_code (cond
);
2418 if (code
== EQ_EXPR
|| code
== NE_EXPR
)
2419 fold_strstr_to_strncmp (gimple_cond_lhs (stmt
),
2420 gimple_cond_rhs (stmt
), stmt
);
2423 if (gimple_vdef (stmt
))
2424 maybe_invalidate (stmt
);
2428 /* Recursively call maybe_invalidate on stmts that might be executed
2429 in between dombb and current bb and that contain a vdef. Stop when
2430 *count stmts are inspected, or if the whole strinfo vector has
2431 been invalidated. */
2434 do_invalidate (basic_block dombb
, gimple
*phi
, bitmap visited
, int *count
)
2436 unsigned int i
, n
= gimple_phi_num_args (phi
);
2438 for (i
= 0; i
< n
; i
++)
2440 tree vuse
= gimple_phi_arg_def (phi
, i
);
2441 gimple
*stmt
= SSA_NAME_DEF_STMT (vuse
);
2442 basic_block bb
= gimple_bb (stmt
);
2445 || !bitmap_set_bit (visited
, bb
->index
)
2446 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2450 if (gimple_code (stmt
) == GIMPLE_PHI
)
2452 do_invalidate (dombb
, stmt
, visited
, count
);
2459 if (!maybe_invalidate (stmt
))
2464 vuse
= gimple_vuse (stmt
);
2465 stmt
= SSA_NAME_DEF_STMT (vuse
);
2466 if (gimple_bb (stmt
) != bb
)
2468 bb
= gimple_bb (stmt
);
2471 || !bitmap_set_bit (visited
, bb
->index
)
2472 || !dominated_by_p (CDI_DOMINATORS
, bb
, dombb
))
2479 class strlen_dom_walker
: public dom_walker
2482 strlen_dom_walker (cdi_direction direction
) : dom_walker (direction
) {}
2484 virtual edge
before_dom_children (basic_block
);
2485 virtual void after_dom_children (basic_block
);
2488 /* Callback for walk_dominator_tree. Attempt to optimize various
2489 string ops by remembering string lengths pointed by pointer SSA_NAMEs. */
2492 strlen_dom_walker::before_dom_children (basic_block bb
)
2494 basic_block dombb
= get_immediate_dominator (CDI_DOMINATORS
, bb
);
2497 stridx_to_strinfo
= NULL
;
2500 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) dombb
->aux
);
2501 if (stridx_to_strinfo
)
2503 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2506 gphi
*phi
= gsi
.phi ();
2507 if (virtual_operand_p (gimple_phi_result (phi
)))
2509 bitmap visited
= BITMAP_ALLOC (NULL
);
2510 int count_vdef
= 100;
2511 do_invalidate (dombb
, phi
, visited
, &count_vdef
);
2512 BITMAP_FREE (visited
);
2513 if (count_vdef
== 0)
2515 /* If there were too many vdefs in between immediate
2516 dominator and current bb, invalidate everything.
2517 If stridx_to_strinfo has been unshared, we need
2518 to free it, otherwise just set it to NULL. */
2519 if (!strinfo_shared ())
2525 vec_safe_iterate (stridx_to_strinfo
, i
, &si
);
2529 (*stridx_to_strinfo
)[i
] = NULL
;
2533 stridx_to_strinfo
= NULL
;
2541 /* If all PHI arguments have the same string index, the PHI result
2543 for (gphi_iterator gsi
= gsi_start_phis (bb
); !gsi_end_p (gsi
);
2546 gphi
*phi
= gsi
.phi ();
2547 tree result
= gimple_phi_result (phi
);
2548 if (!virtual_operand_p (result
) && POINTER_TYPE_P (TREE_TYPE (result
)))
2550 int idx
= get_stridx (gimple_phi_arg_def (phi
, 0));
2553 unsigned int i
, n
= gimple_phi_num_args (phi
);
2554 for (i
= 1; i
< n
; i
++)
2555 if (idx
!= get_stridx (gimple_phi_arg_def (phi
, i
)))
2558 ssa_ver_to_stridx
[SSA_NAME_VERSION (result
)] = idx
;
2563 /* Attempt to optimize individual statements. */
2564 for (gimple_stmt_iterator gsi
= gsi_start_bb (bb
); !gsi_end_p (gsi
); )
2565 if (strlen_optimize_stmt (&gsi
))
2568 bb
->aux
= stridx_to_strinfo
;
2569 if (vec_safe_length (stridx_to_strinfo
) && !strinfo_shared ())
2570 (*stridx_to_strinfo
)[0] = (strinfo
*) bb
;
2574 /* Callback for walk_dominator_tree. Free strinfo vector if it is
2575 owned by the current bb, clear bb->aux. */
2578 strlen_dom_walker::after_dom_children (basic_block bb
)
2582 stridx_to_strinfo
= ((vec
<strinfo
*, va_heap
, vl_embed
> *) bb
->aux
);
2583 if (vec_safe_length (stridx_to_strinfo
)
2584 && (*stridx_to_strinfo
)[0] == (strinfo
*) bb
)
2589 for (i
= 1; vec_safe_iterate (stridx_to_strinfo
, i
, &si
); ++i
)
2591 vec_free (stridx_to_strinfo
);
2597 /* Main entry point. */
2601 const pass_data pass_data_strlen
=
2603 GIMPLE_PASS
, /* type */
2604 "strlen", /* name */
2605 OPTGROUP_NONE
, /* optinfo_flags */
2606 TV_TREE_STRLEN
, /* tv_id */
2607 ( PROP_cfg
| PROP_ssa
), /* properties_required */
2608 0, /* properties_provided */
2609 0, /* properties_destroyed */
2610 0, /* todo_flags_start */
2611 0, /* todo_flags_finish */
2614 class pass_strlen
: public gimple_opt_pass
2617 pass_strlen (gcc::context
*ctxt
)
2618 : gimple_opt_pass (pass_data_strlen
, ctxt
)
2621 /* opt_pass methods: */
2622 virtual bool gate (function
*) { return flag_optimize_strlen
!= 0; }
2623 virtual unsigned int execute (function
*);
2625 }; // class pass_strlen
2628 pass_strlen::execute (function
*fun
)
2630 ssa_ver_to_stridx
.safe_grow_cleared (num_ssa_names
);
2633 calculate_dominance_info (CDI_DOMINATORS
);
2635 /* String length optimization is implemented as a walk of the dominator
2636 tree and a forward walk of statements within each block. */
2637 strlen_dom_walker (CDI_DOMINATORS
).walk (fun
->cfg
->x_entry_block_ptr
);
2639 ssa_ver_to_stridx
.release ();
2640 strinfo_pool
.release ();
2641 if (decl_to_stridxlist_htab
)
2643 obstack_free (&stridx_obstack
, NULL
);
2644 delete decl_to_stridxlist_htab
;
2645 decl_to_stridxlist_htab
= NULL
;
2647 laststmt
.stmt
= NULL
;
2648 laststmt
.len
= NULL_TREE
;
2649 laststmt
.stridx
= 0;
2657 make_pass_strlen (gcc::context
*ctxt
)
2659 return new pass_strlen (ctxt
);